bulk-email/src/redux/slices/bookSlice.ts

218 lines
5.5 KiB
TypeScript

import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
import http from "../../lib/https";
import { toast } from "sonner";
// Define the structure for carDetails
interface CarDetails {
name: string;
number: string;
model: string;
}
interface Booking {
id: number;
slotId: number;
stationId: string;
stationName: string;
stationLocation: string;
date: string;
startTime: string;
endTime: string;
carDetails: CarDetails;
carNames: string[]; // For car names
carPorts: string[]; // For car ports
}
interface BookingState {
bookings: Booking[];
loading: boolean;
error: string | null;
carNames: string[]; // For car names
carPorts: string[]; // For car ports
}
const initialState: BookingState = {
bookings: [],
loading: false,
error: null,
carNames: [], // Initialize carNames
carPorts: [], // Initialize carPorts
};
// Redux slice for fetching car names and ports
export const getCarNames = createAsyncThunk<
string[],
void,
{ rejectValue: string }
>("fetchCarNames", async (_, { rejectWithValue }) => {
try {
const response = await http.get("/get-vehicle-dropdown");
return response.data.data; // Adjust based on actual API response
} catch (error: any) {
return rejectWithValue(
error?.response?.data?.message || "An error occurred"
);
}
});
export const getCarPorts = createAsyncThunk<
string[],
void,
{ rejectValue: string }
>("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"
);
}
});
// Fetch booking list
export const bookingList = createAsyncThunk<
Booking[],
void,
{ rejectValue: string }
>("fetchBooking", async (_, { rejectWithValue }) => {
try {
const token = localStorage?.getItem("authToken");
if (!token) throw new Error("No token found");
const response = await http.get("/user-bookings");
console.log("API Response:", response);
if (!response.data?.data) throw new Error("Invalid API response");
return response.data.data; // Updated to access data
} catch (error: any) {
toast.error("Error Fetching User Booking List: " + error.message);
return rejectWithValue(
error?.response?.data?.message || "An error occurred"
);
}
});
// Add a new booking
export const addBooking = createAsyncThunk<
Booking,
{
stationId: string;
date: string;
startTime: string;
endTime: string;
carName: string;
carNumber: string;
carPort: string;
},
{ rejectValue: string }
>("/AddBooking", async (data, { rejectWithValue }) => {
try {
const response = await http.post("/book-slot", data);
toast.success("EV Booked Successfully!");
return response.data.data; // Adjust to match the new API response structure
} catch (error: any) {
toast.error(
"The requested time slot doesn't fall within any available slot "
);
return rejectWithValue(
error.response?.data?.message || "An error occurred"
);
}
});
export const deleteBooking = createAsyncThunk<
string, // Return type (id of deleted slot)
string,
{ rejectValue: string }
>("booking/deleteBooking", async (id, { rejectWithValue }) => {
try {
const response = await http.delete(`/delete-booking/${id}`);
toast.success("Slot deleted successfully");
return id; // Return the id of the deleted slot
} catch (error: any) {
toast.error("Error deleting the slot: " + error?.message);
return rejectWithValue(
error.response?.data?.message || "An error occurred"
);
}
});
const bookSlice = createSlice({
name: "booking",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(bookingList.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(
bookingList.fulfilled,
(state, action: PayloadAction<Booking[]>) => {
state.loading = false;
state.bookings = action.payload;
}
)
.addCase(bookingList.rejected, (state, action) => {
state.loading = false;
state.error =
action.error.message || "Failed to fetch bookings";
})
.addCase(addBooking.pending, (state) => {
state.loading = true;
})
.addCase(
addBooking.fulfilled,
(state, action: PayloadAction<Booking>) => {
state.loading = false;
state.bookings.push(action.payload); // Add new booking to state
}
)
.addCase(addBooking.rejected, (state) => {
state.loading = false;
})
// Add case reducers for fetching car names and ports
.addCase(
getCarNames.fulfilled,
(state, action: PayloadAction<string[]>) => {
state.carNames = action.payload;
}
)
.addCase(
getCarPorts.fulfilled,
(state, action: PayloadAction<string[]>) => {
state.carPorts = action.payload;
}
)
.addCase(deleteBooking.pending, (state) => {
state.loading = true;
})
.addCase(
deleteBooking.fulfilled,
(state, action: PayloadAction<string>) => {
state.loading = false;
// Ensure we're filtering the correct array (bookings)
state.bookings = state.bookings.filter(
(booking) =>
String(booking.id) !== String(action.payload)
);
// Also update slots array if it exists
if (state.bookings) {
state.bookings = state.bookings.filter(
(booking) =>
String(booking.id) !== String(action.payload)
);
}
}
)
.addCase(deleteBooking.rejected, (state, action) => {
state.loading = false;
state.error = action.payload || "Failed to delete slot";
});
},
});
export default bookSlice.reducer;