388 lines
10 KiB
TypeScript
388 lines
10 KiB
TypeScript
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
|
import axios from "axios";
|
|
import http from "../../lib/https";
|
|
import { toast } from "sonner";
|
|
|
|
// Define TypeScript types
|
|
interface Station {
|
|
id: number;
|
|
name: string;
|
|
registeredAddress: string;
|
|
totalSlots: number;
|
|
status: number;
|
|
allowedCarIds: number[];
|
|
city: string;
|
|
}
|
|
|
|
interface StationState {
|
|
stations: Station[];
|
|
loading: boolean;
|
|
error: string | null;
|
|
}
|
|
|
|
// Initial state
|
|
const initialState: StationState = {
|
|
stations: [],
|
|
loading: false,
|
|
error: null,
|
|
};
|
|
|
|
export const stationList = createAsyncThunk<any, void, { rejectValue: string }>(
|
|
"fetchStations",
|
|
async (_, { rejectWithValue }) => {
|
|
try {
|
|
const token = localStorage?.getItem("authToken");
|
|
if (!token) throw new Error("No token found");
|
|
|
|
const response = await http.get("/get-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"
|
|
);
|
|
}
|
|
}
|
|
);
|
|
export const externalStationList = createAsyncThunk<
|
|
any,
|
|
void,
|
|
{ rejectValue: string }
|
|
>("fetchExternalStations", async (_, { rejectWithValue }) => {
|
|
try {
|
|
const response = await http.get("/external-charging-stations");
|
|
if (!response.data) throw new Error("Invalid API response");
|
|
// Return the response data directly, the structure will be handled in the reducer
|
|
return response.data;
|
|
} catch (error: any) {
|
|
console.error("Error fetching external stations:", error);
|
|
toast.error(
|
|
"Error Fetching Stations: " +
|
|
(error.response?.data?.message || error.message)
|
|
);
|
|
return rejectWithValue(
|
|
error.response?.data?.message ||
|
|
error.message ||
|
|
"An error occurred"
|
|
);
|
|
}
|
|
});
|
|
export const addStationLocation = createAsyncThunk<
|
|
any,
|
|
{
|
|
city: string;
|
|
},
|
|
{ rejectValue: string }
|
|
>("Station/addStationLocation", async ({ city }, { rejectWithValue }) => {
|
|
try {
|
|
const response = await http.post("/charging-stations/fetch", { city });
|
|
toast.success("Station created successfully");
|
|
return response.data; // Assuming the response contains the created station data
|
|
} catch (error: any) {
|
|
toast.error(
|
|
"Failed to create Station: " +
|
|
(error.response?.data?.message || "Unknown error")
|
|
);
|
|
return rejectWithValue(
|
|
error.response?.data?.message || "An error occurred"
|
|
);
|
|
}
|
|
});
|
|
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: number;
|
|
allowedCarIds: number[];
|
|
},
|
|
{ rejectValue: string }
|
|
>("Station/createStation", async (data, { rejectWithValue }) => {
|
|
try {
|
|
const response = await http.post("/create-station", data);
|
|
toast.success("Station created successfully");
|
|
return response.data; // Assuming the response contains the created station data
|
|
} catch (error: any) {
|
|
toast.error(
|
|
"Failed to create Station: " +
|
|
(error.response?.data?.message || "Unknown error")
|
|
);
|
|
return rejectWithValue(
|
|
error.response?.data?.message || "An error occurred"
|
|
);
|
|
}
|
|
});
|
|
|
|
// 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}`,
|
|
updateData
|
|
);
|
|
toast.success("Station Details updated successfully");
|
|
return response?.data;
|
|
} catch (error: any) {
|
|
toast.error("Error updating the station: " + error);
|
|
return rejectWithValue(
|
|
error.response?.data?.message || "An error occurred"
|
|
);
|
|
}
|
|
}
|
|
);
|
|
|
|
export const deleteStation = createAsyncThunk<
|
|
string,
|
|
string,
|
|
{ rejectValue: string }
|
|
>("deleteStation", async (id, { rejectWithValue }) => {
|
|
try {
|
|
await http.delete(`/delete-station/${id}`);
|
|
toast.success("Station deleted successfully!");
|
|
return id;
|
|
} catch (error: any) {
|
|
toast.error("Error deleting the Station" + error);
|
|
|
|
return rejectWithValue(
|
|
error.response?.data?.message || "An error occurred"
|
|
);
|
|
}
|
|
});
|
|
|
|
export const toggleStatus = createAsyncThunk<
|
|
any,
|
|
{ id: string; status: number },
|
|
{ rejectValue: string }
|
|
>("station/toggleStatus", async ({ id, status }, { rejectWithValue }) => {
|
|
try {
|
|
const response = await http.patch(`/update-station/${id}`, { status });
|
|
|
|
if (response.data.statusCode === 200) {
|
|
toast.success(
|
|
response.data.message || "Status updated successfully"
|
|
);
|
|
// Return both the response data and the requested status for reliable state updates
|
|
return {
|
|
responseData: response.data,
|
|
id,
|
|
status,
|
|
};
|
|
} else {
|
|
throw new Error(response.data.message || "Failed to update status");
|
|
}
|
|
} catch (error: any) {
|
|
toast.error(
|
|
"Error updating status: " + (error.message || "Unknown error")
|
|
);
|
|
return rejectWithValue(
|
|
error.response?.data?.message ||
|
|
error.message ||
|
|
"An error occurred"
|
|
);
|
|
}
|
|
});
|
|
|
|
const stationSlice = createSlice({
|
|
name: "stations",
|
|
initialState,
|
|
reducers: {},
|
|
extraReducers: (builder) => {
|
|
builder
|
|
.addCase(stationList.pending, (state) => {
|
|
state.loading = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(
|
|
stationList.fulfilled,
|
|
(state, action: PayloadAction<any>) => {
|
|
state.loading = false;
|
|
// 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(externalStationList.pending, (state) => {
|
|
state.loading = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(
|
|
externalStationList.fulfilled,
|
|
|
|
(state, action: PayloadAction<any>) => {
|
|
state.loading = false;
|
|
|
|
console.log("first", action.payload.data);
|
|
|
|
state.stations = action.payload.data || [];
|
|
}
|
|
)
|
|
|
|
.addCase(externalStationList.rejected, (state, action) => {
|
|
state.loading = false;
|
|
state.error =
|
|
action.payload || "Failed to fetch external stations";
|
|
})
|
|
.addCase(addStationLocation.pending, (state) => {
|
|
state.loading = true;
|
|
})
|
|
.addCase(
|
|
addStationLocation.fulfilled,
|
|
(state, action: PayloadAction<any>) => {
|
|
state.loading = false;
|
|
if (action.payload.data) {
|
|
state.stations.push(action.payload.data);
|
|
}
|
|
}
|
|
)
|
|
|
|
.addCase(
|
|
addStationLocation.rejected,
|
|
(state, action: PayloadAction<string | undefined>) => {
|
|
state.loading = false;
|
|
state.error = action.payload || "Failed to create station";
|
|
}
|
|
)
|
|
.addCase(createStation.pending, (state) => {
|
|
state.loading = true;
|
|
})
|
|
.addCase(
|
|
createStation.fulfilled,
|
|
(state, action: PayloadAction<any>) => {
|
|
state.loading = false;
|
|
if (action.payload.data) {
|
|
state.stations.push(action.payload.data);
|
|
}
|
|
}
|
|
)
|
|
|
|
.addCase(
|
|
createStation.rejected,
|
|
(state, action: PayloadAction<string | undefined>) => {
|
|
state.loading = false;
|
|
state.error = action.payload || "Failed to create station";
|
|
}
|
|
)
|
|
.addCase(toggleStatus.pending, (state) => {
|
|
state.loading = true;
|
|
})
|
|
.addCase(
|
|
toggleStatus.fulfilled,
|
|
(state, action: PayloadAction<any>) => {
|
|
state.loading = false;
|
|
|
|
// Get the id and updated status from the action payload
|
|
const { id, status } = action.payload;
|
|
|
|
// Find and update the station with the new status
|
|
const stationIndex = state.stations.findIndex(
|
|
(station) => station.id === id
|
|
);
|
|
if (stationIndex !== -1) {
|
|
state.stations[stationIndex] = {
|
|
...state.stations[stationIndex],
|
|
status: status,
|
|
};
|
|
}
|
|
}
|
|
)
|
|
.addCase(
|
|
toggleStatus.rejected,
|
|
(state, action: PayloadAction<string | undefined>) => {
|
|
state.loading = false;
|
|
state.error =
|
|
action.payload || "Failed to toggle station status";
|
|
}
|
|
)
|
|
.addCase(updateStation.pending, (state) => {
|
|
state.loading = true;
|
|
})
|
|
.addCase(updateStation.fulfilled, (state, action) => {
|
|
state.loading = false;
|
|
// 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;
|
|
})
|
|
.addCase(deleteStation.pending, (state) => {
|
|
state.loading = true;
|
|
})
|
|
.addCase(deleteStation.fulfilled, (state, action) => {
|
|
state.loading = false;
|
|
state.stations = state.stations.filter(
|
|
(station) => String(station.id) !== String(action.payload)
|
|
);
|
|
})
|
|
.addCase(deleteStation.rejected, (state) => {
|
|
state.loading = false;
|
|
});
|
|
},
|
|
});
|
|
|
|
export default stationSlice.reducer;
|