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