import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"; import axios from "axios"; import http from "../../lib/https"; import { toast } from "sonner"; // Define TypeScript types interface Role { id: string; name: string; resource: { moduleName: string; moduleId: string; permissions: string[]; }[]; status: number; } interface RoleState { roles: Role[]; loading: boolean; error: string | null; } // Initial state const initialState: RoleState = { roles: [], loading: false, error: null, }; export const roleList = createAsyncThunk( "fetchRoles", async (_, { rejectWithValue }) => { try { const token = localStorage?.getItem("authToken"); if (!token) throw new Error("No token found"); const response = await http.get("get"); 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 Roles: " + error.message); return rejectWithValue( error?.response?.data?.message || "An error occurred" ); } } ); // Create Role export const createRole = createAsyncThunk< any, { name: string; resource: { moduleName: string; moduleId: string; permissions: string[]; }[]; }, { rejectValue: string } >("role/createRole", async (data, { rejectWithValue }) => { try { const response = await http.post("create", data); toast.success("Role created successfully"); return response.data; } catch (error: any) { toast.error( "Failed to create role: " + (error.response?.data?.message || "Unknown error") ); return rejectWithValue( error.response?.data?.message || "An error occurred" ); } }); export const toggleStatus = createAsyncThunk< any, { id: string; status: number }, { rejectValue: string } >("role/toggleStatus", async ({ id, status }, { rejectWithValue }) => { try { const response = await http.patch(`${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 roleSlice = createSlice({ name: "roles", initialState, reducers: {}, extraReducers: (builder) => { builder .addCase(roleList.pending, (state) => { state.loading = true; state.error = null; }) .addCase( roleList.fulfilled, (state, action: PayloadAction) => { state.loading = false; // Properly extract roles from the response data structure state.roles = action.payload.data?.results || action.payload.data || []; } ) .addCase(roleList.rejected, (state, action) => { state.loading = false; state.error = action.payload || "Failed to fetch roles"; }) .addCase(createRole.pending, (state) => { state.loading = true; }) .addCase( createRole.fulfilled, (state, action: PayloadAction) => { state.loading = false; // Add the newly created role to the state if it exists in the response if (action.payload.data) { state.roles.push(action.payload.data); } } ) .addCase( createRole.rejected, (state, action: PayloadAction) => { state.loading = false; state.error = action.payload || "Failed to create role"; } ) .addCase(toggleStatus.pending, (state) => { state.loading = true; }) .addCase( toggleStatus.fulfilled, (state, action: PayloadAction) => { state.loading = false; // Get the id and updated status from the action payload const { id, status } = action.payload; // Find and update the role with the new status const roleIndex = state.roles.findIndex( (role) => role.id === id ); if (roleIndex !== -1) { state.roles[roleIndex] = { ...state.roles[roleIndex], status: status, }; } } ) .addCase( toggleStatus.rejected, (state, action: PayloadAction) => { state.loading = false; state.error = action.payload || "Failed to toggle role status"; } ); }, }); export default roleSlice.reducer;