Latest changes
This commit is contained in:
parent
e96759ef3b
commit
87b971d97d
15296
pnpm-lock.yaml
15296
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -26,7 +26,7 @@ import {
|
|||
CustomIconButton,
|
||||
CustomTextField,
|
||||
} from "../AddEditUserModel/styled.css.tsx";
|
||||
import { stationList } from "../../redux/slices/stationSlice.ts";
|
||||
import { getAllStations, stationList } from "../../redux/slices/stationSlice.ts";
|
||||
import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
|
@ -56,7 +56,7 @@ export default function AddBookingModal({
|
|||
console.log("first", availableSlots);
|
||||
useEffect(() => {
|
||||
dispatch(fetchAvailableSlots());
|
||||
dispatch(stationList());
|
||||
dispatch(getAllStations());
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -74,7 +74,7 @@ export default function AddBookingModal({
|
|||
// Fetch the bookings after this
|
||||
dispatch(bookingList());
|
||||
}, [dispatch]);
|
||||
|
||||
console.log("Car Ports: ", carPorts);
|
||||
// Get today's date in yyyy-mm-dd format
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
|
||||
|
@ -266,9 +266,9 @@ export default function AddBookingModal({
|
|||
{carPorts.map((port, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
value={port.chargeType}
|
||||
value={port}
|
||||
>
|
||||
{port.chargeType}
|
||||
{port}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
|
@ -290,7 +290,6 @@ export default function AddBookingModal({
|
|||
|
||||
{/* Start Time and End Time */}
|
||||
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
||||
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
Start Time
|
||||
|
@ -311,7 +310,6 @@ export default function AddBookingModal({
|
|||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
End Time
|
||||
|
@ -487,4 +485,4 @@ export default function AddBookingModal({
|
|||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -38,13 +38,13 @@ export default function AddManagerModal({
|
|||
reset,
|
||||
} = useForm();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const stations = useSelector(
|
||||
const stations = useSelector(
|
||||
(state: RootState) => state?.stationReducer.stations
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(stationList());
|
||||
}, [dispatch]);
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(stationList());
|
||||
}, [dispatch]);
|
||||
|
||||
// Handle form submission
|
||||
const onSubmit = async (data: any) => {
|
||||
|
@ -172,14 +172,21 @@ useEffect(() => {
|
|||
defaultValue=""
|
||||
size="small"
|
||||
>
|
||||
{stations.map((station) => (
|
||||
<MenuItem
|
||||
key={station.id}
|
||||
value={station.name}
|
||||
>
|
||||
{station.name}
|
||||
{Array.isArray(stations) &&
|
||||
stations.length > 0 ? (
|
||||
stations.map((station) => (
|
||||
<MenuItem
|
||||
key={station.id}
|
||||
value={station.name}
|
||||
>
|
||||
{station.name}
|
||||
</MenuItem>
|
||||
))
|
||||
) : (
|
||||
<MenuItem disabled>
|
||||
No stations available
|
||||
</MenuItem>
|
||||
))}
|
||||
)}
|
||||
</Select>
|
||||
{errors.stationName && (
|
||||
<Typography color="error" variant="body2">
|
||||
|
|
|
@ -46,6 +46,8 @@ export default function AddStationModal({
|
|||
const vehicleBrands = useSelector(
|
||||
(state: RootState) => state.vehicleReducer.vehicleBrands
|
||||
);
|
||||
|
||||
console.log("vehicle Brands", vehicleBrands);
|
||||
const [selectedBrand, setSelectedBrand] = useState<string | "">("");
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -86,7 +88,7 @@ export default function AddStationModal({
|
|||
const payload = {
|
||||
...data,
|
||||
status: 1, // Default status, can be adjusted if needed
|
||||
allowedCarIds: vehicleIds, // Pass the vehicle ids to the backend
|
||||
allowedCars: vehicleIds, // Pass the vehicle ids to the backend
|
||||
totalSlots: Number(data.totalSlots), // Ensure this is a number
|
||||
};
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ export default function Header() {
|
|||
sx={{ width: 36, height: 36 }}
|
||||
/>
|
||||
<Typography variant="body1" sx={{ color: "#FFFFFF" }}>
|
||||
{user?.name || "No Admin"}
|
||||
{user?.name || "No Adminsss"}
|
||||
</Typography>
|
||||
|
||||
<OptionsMenu />
|
||||
|
|
|
@ -103,13 +103,13 @@ export default function MenuContent({ hidden }: PropType) {
|
|||
<ListItem
|
||||
key={index}
|
||||
disablePadding
|
||||
sx={{ display: "block", py: 1 }}
|
||||
sx={{ display: "block", py: 1, px: 0.9 }}
|
||||
>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={item.url}
|
||||
selected={item.url === location.pathname}
|
||||
sx={{ alignItems: "center", columnGap: 1 }}
|
||||
sx={{ alignItems: "center", columnGap: 0.5 }}
|
||||
>
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
|
|
|
@ -1,27 +1,37 @@
|
|||
import axios from "axios";
|
||||
// import { useHistory } from "react-router-dom";
|
||||
|
||||
const http = axios.create({
|
||||
baseURL: process.env.REACT_APP_BACKEND_URL,
|
||||
});
|
||||
|
||||
http.interceptors.request.use((config) => {
|
||||
const authToken = localStorage.getItem("authToken");
|
||||
if (authToken) {
|
||||
config.headers.Authorization = `Bearer ${authToken}`;
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
http.interceptors.response.use(
|
||||
(response) => response,
|
||||
(response) => response,
|
||||
(error) => {
|
||||
|
||||
if (error.response && error.response.status === 403 ) {
|
||||
window.location.href = "/login";
|
||||
|
||||
// const history = useHistory();
|
||||
// history.push("/login");
|
||||
if (error.response) {
|
||||
const status = error.response.status;
|
||||
const requestUrl = error.config.url; // Get the API route
|
||||
|
||||
// Handle token expiration (401) but NOT for login failures
|
||||
if (status === 401 && !requestUrl.includes("/login")) {
|
||||
localStorage.removeItem("authToken");
|
||||
window.location.href = "/login";
|
||||
}
|
||||
|
||||
// Handle forbidden access
|
||||
if (status === 403) {
|
||||
localStorage.removeItem("authToken");
|
||||
window.location.href = "/login";
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -88,9 +88,13 @@ export default function StationList() {
|
|||
await dispatch(toggleStatus({ id, status: newStatus }));
|
||||
};
|
||||
|
||||
const filterStations = stations?.filter((station) =>
|
||||
station.name.toLocaleLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
const filterStations = Array.isArray(stations)
|
||||
? stations.filter((station) =>
|
||||
station.name
|
||||
.toLocaleLowerCase()
|
||||
.includes(searchTerm.toLowerCase())
|
||||
)
|
||||
: [];
|
||||
|
||||
// Mapping and formatting vehicles
|
||||
const categoryRows = filterStations?.length
|
||||
|
|
|
@ -37,11 +37,10 @@ export const fetchVehicleBrands = createAsyncThunk<
|
|||
if (!response.data || !Array.isArray(response.data.data)) {
|
||||
throw new Error("Expected array of vehicle brands");
|
||||
}
|
||||
|
||||
console.log("beans", response.data.data)
|
||||
// Assuming that 'data' contains an array of objects with a 'company' field
|
||||
return response.data.data.map((item: any) => ({
|
||||
id: item.company, // You can use 'company' as the unique identifier
|
||||
name: item.company, // The name field will be used in the dropdown
|
||||
}));
|
||||
return response.data.data;
|
||||
} catch (error: any) {
|
||||
return rejectWithValue("Failed to fetch vehicle brands");
|
||||
}
|
||||
|
|
|
@ -60,7 +60,9 @@ export const getCarPorts = createAsyncThunk<
|
|||
>("fetchCarPorts", async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await http.get("/get-vehicle-port-dropdown");
|
||||
|
||||
return response.data.data; // Adjust based on actual API response
|
||||
|
||||
} catch (error: any) {
|
||||
return rejectWithValue(
|
||||
error?.response?.data?.message || "An error occurred"
|
||||
|
@ -171,4 +173,4 @@ const bookSlice = createSlice({
|
|||
},
|
||||
});
|
||||
|
||||
export default bookSlice.reducer;
|
||||
export default bookSlice.reducer;
|
|
@ -8,7 +8,7 @@ interface Station {
|
|||
id: string;
|
||||
name: string;
|
||||
registeredAddress: string;
|
||||
totalSlots: string;
|
||||
totalSlots: number;
|
||||
status: number;
|
||||
allowedCarIds: number[];
|
||||
}
|
||||
|
@ -47,14 +47,35 @@ export const stationList = createAsyncThunk<any, void, { rejectValue: string }>(
|
|||
}
|
||||
}
|
||||
);
|
||||
export const getAllStations = createAsyncThunk<
|
||||
any,
|
||||
void,
|
||||
{ rejectValue: string }
|
||||
>("getAllStations", async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const token = localStorage?.getItem("authToken");
|
||||
if (!token) throw new Error("No token found");
|
||||
|
||||
const response = await http.get("/get-all-stations");
|
||||
|
||||
if (!response.data) throw new Error("Invalid API response");
|
||||
|
||||
// Return the full response to handle in the reducer
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
toast.error("Error Fetching Stations: " + error.message);
|
||||
return rejectWithValue(
|
||||
error?.response?.data?.message || "An error occurred"
|
||||
);
|
||||
}
|
||||
});
|
||||
// Create Station
|
||||
export const createStation = createAsyncThunk<
|
||||
any,
|
||||
{
|
||||
name: string;
|
||||
registeredAddress: string;
|
||||
totalSlots: string;
|
||||
totalSlots: number;
|
||||
allowedCarIds: number[];
|
||||
},
|
||||
{ rejectValue: string }
|
||||
|
@ -62,7 +83,7 @@ export const createStation = createAsyncThunk<
|
|||
try {
|
||||
const response = await http.post("/create-station", data);
|
||||
toast.success("Station created successfully");
|
||||
return response.data;
|
||||
return response.data; // Assuming the response contains the created station data
|
||||
} catch (error: any) {
|
||||
toast.error(
|
||||
"Failed to create Station: " +
|
||||
|
@ -74,25 +95,31 @@ export const createStation = createAsyncThunk<
|
|||
}
|
||||
});
|
||||
|
||||
// Update Station details
|
||||
// Update Station details
|
||||
export const updateStation = createAsyncThunk(
|
||||
"updateStation",
|
||||
async ({ id, ...stationData }: Station, { rejectWithValue }) => {
|
||||
try {
|
||||
// Exclude the `status` from the update payload
|
||||
const { status, ...updateData } = stationData;
|
||||
|
||||
// Send the update request without the `status`
|
||||
const response = await http.patch(
|
||||
`/update-station/${id}`,
|
||||
stationData
|
||||
updateData
|
||||
);
|
||||
toast.success("Station Deatils updated successfully");
|
||||
toast.success("Station Details updated successfully");
|
||||
return response?.data;
|
||||
} catch (error: any) {
|
||||
toast.error("Error updating the user: " + error);
|
||||
toast.error("Error updating the station: " + error);
|
||||
return rejectWithValue(
|
||||
error.response?.data?.message || "An error occurred"
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteStation = createAsyncThunk<
|
||||
string,
|
||||
string,
|
||||
|
@ -158,17 +185,30 @@ const stationSlice = createSlice({
|
|||
stationList.fulfilled,
|
||||
(state, action: PayloadAction<any>) => {
|
||||
state.loading = false;
|
||||
// Properly extract stations from the response data structure
|
||||
state.stations =
|
||||
action.payload.data?.results ||
|
||||
action.payload.data ||
|
||||
[];
|
||||
// Correct data extraction
|
||||
state.stations = action.payload.data?.stations || [];
|
||||
}
|
||||
)
|
||||
.addCase(stationList.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload || "Failed to fetch stations";
|
||||
})
|
||||
.addCase(getAllStations.pending, (state) => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(
|
||||
getAllStations.fulfilled,
|
||||
(state, action: PayloadAction<any>) => {
|
||||
state.loading = false;
|
||||
state.stations = action.payload.data || [];
|
||||
}
|
||||
)
|
||||
|
||||
.addCase(getAllStations.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload || "Failed to fetch stations";
|
||||
})
|
||||
.addCase(createStation.pending, (state) => {
|
||||
state.loading = true;
|
||||
})
|
||||
|
@ -176,12 +216,12 @@ const stationSlice = createSlice({
|
|||
createStation.fulfilled,
|
||||
(state, action: PayloadAction<any>) => {
|
||||
state.loading = false;
|
||||
// Add the newly created station to the state if it exists in the response
|
||||
if (action.payload.data) {
|
||||
state.stations.push(action.payload.data);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
.addCase(
|
||||
createStation.rejected,
|
||||
(state, action: PayloadAction<string | undefined>) => {
|
||||
|
@ -225,8 +265,21 @@ const stationSlice = createSlice({
|
|||
})
|
||||
.addCase(updateStation.fulfilled, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload;
|
||||
// If the station was updated, find and update it in the state
|
||||
const updatedStation = action.payload;
|
||||
const stationIndex = state.stations.findIndex(
|
||||
(station) => station.id === updatedStation.id
|
||||
);
|
||||
if (stationIndex !== -1) {
|
||||
// Here, merge the updated station with the existing one
|
||||
// Ensure `status` is not overwritten if not explicitly updated
|
||||
state.stations[stationIndex] = {
|
||||
...state.stations[stationIndex],
|
||||
...updatedStation,
|
||||
};
|
||||
}
|
||||
})
|
||||
|
||||
.addCase(updateStation.rejected, (state) => {
|
||||
state.loading = false;
|
||||
})
|
||||
|
@ -245,4 +298,4 @@ const stationSlice = createSlice({
|
|||
},
|
||||
});
|
||||
|
||||
export default stationSlice.reducer;
|
||||
export default stationSlice.reducer;
|
Loading…
Reference in a new issue