From 292ea123a0af678d3ca13ca27c782b33bc93fab6 Mon Sep 17 00:00:00 2001 From: jaanvi Date: Thu, 27 Feb 2025 10:06:07 +0530 Subject: [PATCH] Frontend Api integration --- src/components/AddEditCategoryModal/index.tsx | 29 +- src/components/AddEditRoleModal/index.tsx | 300 +++++ src/components/AddUserModel/index.tsx | 212 ++++ src/components/MenuContent/index.tsx | 7 +- src/pages/RoleList/index.tsx | 137 +++ src/pages/UserList/index.tsx | 1095 ++++++++++++----- src/redux/reducers.ts | 10 +- src/redux/slices/profileSlice.ts | 2 +- src/redux/slices/roleSlice.ts | 115 ++ src/redux/slices/userSlice.ts | 92 +- src/router.tsx | 10 + 11 files changed, 1701 insertions(+), 308 deletions(-) create mode 100644 src/components/AddEditRoleModal/index.tsx create mode 100644 src/components/AddUserModel/index.tsx create mode 100644 src/pages/RoleList/index.tsx create mode 100644 src/redux/slices/roleSlice.ts diff --git a/src/components/AddEditCategoryModal/index.tsx b/src/components/AddEditCategoryModal/index.tsx index aa2092c..ecf4fa9 100644 --- a/src/components/AddEditCategoryModal/index.tsx +++ b/src/components/AddEditCategoryModal/index.tsx @@ -21,7 +21,8 @@ interface AddEditCategoryModalProps { name: string, email: string, phone: string, - registeredAddress: string + registeredAddress: string, + password: string ) => void; editRow: any; } @@ -31,6 +32,7 @@ interface FormData { email: string; phone: string; registeredAddress: string; + password: string; } const AddEditCategoryModal: React.FC = ({ @@ -52,6 +54,7 @@ const AddEditCategoryModal: React.FC = ({ email: "", phone: "", registeredAddress: "", + password: "", }, }); @@ -62,7 +65,8 @@ const AddEditCategoryModal: React.FC = ({ data.name, data.email, data.phone, - data.registeredAddress + data.registeredAddress, + data.password ); } else { handleCreate(data); @@ -168,7 +172,26 @@ const AddEditCategoryModal: React.FC = ({ /> )} /> - + ( + + )} + /> void; + handleCreate: (data: FormData) => void; + handleUpdate: ( + id: string, + name: string, + resource: { + moduleName: string; + moduleId: string; + permissions: string[]; + }[] + ) => void; + editRow: any; + data: { + resource: { + moduleName: string; + moduleId: string; + permissions: string[]; + }[]; + }; // Assuming `data` is passed as a prop +} + +interface FormData { + name: string; + resource: { + moduleName: string; + moduleId: string; + permissions: string[]; + }[]; +} + +const AddRoleModal: React.FC = ({ + open, + handleClose, + handleCreate, + handleUpdate, + editRow, + data, +}) => { + const { + control, + handleSubmit, + formState: { errors }, + setValue, + reset, + getValues, // Access getValues from the form methods here + } = useForm({ + defaultValues: { + name: "", + resource: [], // Ensure resource is initialized as an empty array + }, + }); + + + useEffect(() => { + if (editRow) { + setValue("name", editRow.name); + setValue("resource", editRow.resource); + } + }, [editRow, setValue]); + + // Handles permissions checkbox change for a specific resource + const handlePermissionChange = ( + resourceIndex: number, + permission: string, + checked: boolean + ) => { + const updatedResources = [...getValues().resource]; // Use getValues to get the current form values + const resource = updatedResources[resourceIndex]; + + if (checked) { + // Add permission if checked + resource.permissions = [ + ...new Set([...resource.permissions, permission]), + ]; + } else { + // Remove permission if unchecked + resource.permissions = resource.permissions.filter( + (p) => p !== permission + ); + } + + setValue("resource", updatedResources); // Update the resource field in form state + }; + + const onSubmit = (data: FormData) => { + if (editRow) { + handleUpdate(editRow.id, data.name, data.resource); + } else { + handleCreate(data); + } + + handleClose(); + reset(); + }; + + return ( + + + {editRow ? "Edit Role" : "Add Role"} + + + + + + + {/* Role Name Field */} + ( + + )} + /> + + {/* Resource Field */} + ( + + Resource + + + {errors.resource?.message} + + + )} + /> + + {/* Permissions Checkbox Fields for each resource */} + {getValues().resource && + getValues().resource.length > 0 && + getValues().resource.map((resource, resourceIndex) => ( + + + + {resource.moduleName} Permissions + + + handlePermissionChange( + resourceIndex, + "view", + e.target.checked + ) + } + /> + } + label="View" + /> + + handlePermissionChange( + resourceIndex, + "edit", + e.target.checked + ) + } + /> + } + label="Edit" + /> + + handlePermissionChange( + resourceIndex, + "delete", + e.target.checked + ) + } + /> + } + label="Delete" + /> + + { + errors.resource?.[resourceIndex] + ?.permissions?.message + } + + + + ))} + + + + + + + + ); +}; + +export default AddRoleModal; diff --git a/src/components/AddUserModel/index.tsx b/src/components/AddUserModel/index.tsx new file mode 100644 index 0000000..376adad --- /dev/null +++ b/src/components/AddUserModel/index.tsx @@ -0,0 +1,212 @@ +import React, { useEffect } from "react"; +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + TextField, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { useForm, Controller } from "react-hook-form"; + +//By Jaanvi : Edit Model :: 11-feb-25 +interface AddUserModalProps { + open: boolean; + handleClose: () => void; + handleCreate: (data: FormData) => void; + handleUpdate: ( + id: string, + name: string, + email: string, + phone: string, + password: string + ) => void; + editRow: any; +} + +interface FormData { + name: string; + email: string; + phone: string; + password: string; +} +const AddUserModal: React.FC = ({ + open, + handleClose, + handleCreate, + + editRow, +}) => { + const { + control, + handleSubmit, + formState: { errors }, + setValue, + reset, + } = useForm({ + defaultValues: { + name: "", + email: "", + phone: "", + password: "", + }, + }); + + const onSubmit = (data: FormData) => { + handleCreate(data); + + handleClose(); + reset(); + }; + + return ( + + + {editRow ? "Edit Admin" : "Add Admin"} + + + + + + + ( + + )} + /> + + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + + + + + + + + ); +}; + +export default AddUserModal; diff --git a/src/components/MenuContent/index.tsx b/src/components/MenuContent/index.tsx index 608a7f4..5d58f3c 100644 --- a/src/components/MenuContent/index.tsx +++ b/src/components/MenuContent/index.tsx @@ -29,6 +29,11 @@ const baseMenuItems = [ icon: , url: "/panel/user-list", }, + { + text: "Roles", + icon: , + url: "/panel/role-list", + }, ]; //Eknoor singh and Jaanvi @@ -44,7 +49,7 @@ type PropType = { export default function MenuContent({ hidden }: PropType) { const location = useLocation(); const userRole = useSelector( - (state: RootState) => state.profileReducer.user?.role + (state: RootState) => state.profileReducer.user?.userType ); diff --git a/src/pages/RoleList/index.tsx b/src/pages/RoleList/index.tsx new file mode 100644 index 0000000..416d0b5 --- /dev/null +++ b/src/pages/RoleList/index.tsx @@ -0,0 +1,137 @@ +import React, { useEffect, useState } from "react"; +import { Box, Button, Typography } from "@mui/material"; +import AddEditRoleModal from "../../components/AddEditRoleModal"; +import { useForm } from "react-hook-form"; +import CustomTable, { Column } from "../../components/CustomTable"; +import { useDispatch, useSelector } from "react-redux"; +import { createRole, roleList } from "../../redux/slices/roleSlice"; +import { AppDispatch, RootState } from "../../redux/store/store"; + +export default function RoleList() { + const [modalOpen, setModalOpen] = useState(false); + const { reset } = useForm(); + + const [deleteModal, setDeleteModal] = React.useState(false); + const [viewModal, setViewModal] = React.useState(false); + const [rowData, setRowData] = React.useState(null); + + const dispatch = useDispatch(); + + const roles = useSelector((state: RootState) => state.roleReducer.roles); + + useEffect(() => { + dispatch(roleList()); + }, [dispatch]); + + const handleClickOpen = () => { + setRowData(null); // Reset row data when opening for new role + setModalOpen(true); + }; + + const handleCloseModal = () => { + setModalOpen(false); + setRowData(null); + reset(); + }; + + const handleCreate = async (data: { + name: string; + resource: { + moduleName: string; + moduleId: string; + permissions: string[]; + }[]; + }) => { + try { + await dispatch(createRole(data)); + await dispatch(roleList()); // Refresh the list after creation + handleCloseModal(); + } catch (error) { + console.error("Creation failed", error); + } + }; + + const categoryColumns: Column[] = [ + { id: "srno", label: "Sr No" }, + { id: "name", label: "Name" }, + { id: "action", label: "Action", align: "center" }, + ]; + + const categoryRows = roles?.length + ? roles?.map(function ( + role: { + id: string; + name: string; + // email: string; + + // phone: string; + // location?: string; + // managerAssigned?: string; + // vehicle?: string; + }, + index: number + ) { + return { + id: role?.id, + srno: index + 1, + name: role?.name, + // email: user?.email, + // phone: user?.phone, + // location: user?.location, + // managerAssigned: user?.managerAssigned, + // vehicle: user?.vehicle, + }; + }) + : []; + + console.log("Category Rows:", categoryRows); + + return ( + <> + + + Roles + + + + + + + + ); +} diff --git a/src/pages/UserList/index.tsx b/src/pages/UserList/index.tsx index bddda89..c6e284e 100644 --- a/src/pages/UserList/index.tsx +++ b/src/pages/UserList/index.tsx @@ -1,313 +1,834 @@ -import { useEffect, useState } from "react"; -import { - Box, - Button, - Typography, - TextField, - InputAdornment, - Paper, - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Pagination, - IconButton, -} from "@mui/material"; -import SearchIcon from "@mui/icons-material/Search"; -import MoreHorizIcon from "@mui/icons-material/MoreHoriz"; -import TuneIcon from "@mui/icons-material/Tune"; +// import { useEffect, useState } from "react"; +// import { +// Box, +// Button, +// Typography, +// TextField, +// InputAdornment, +// Paper, +// Table, +// TableBody, +// TableCell, +// TableContainer, +// TableHead, +// TableRow, +// Pagination, +// IconButton, +// } from "@mui/material"; +// import SearchIcon from "@mui/icons-material/Search"; +// import MoreHorizIcon from "@mui/icons-material/MoreHoriz"; +// import TuneIcon from "@mui/icons-material/Tune"; +// import { useDispatch, useSelector } from "react-redux"; +// import { userList } from "../../redux/slices/userSlice"; // Make sure userSlice exists +// import { AppDispatch, RootState } from "../../redux/store/store"; + +// export default function UserList() { +// const [searchQuery, setSearchQuery] = useState(""); +// const [currentPage, setCurrentPage] = useState(1); +// const usersPerPage = 10; + +// const dispatch = useDispatch(); +// const users = useSelector((state: RootState) => state.userReducer.users); + +// useEffect(() => { +// dispatch(userList()); +// }, [dispatch]); + +// const staticUsers = [ +// { +// name: "Alice Johnson", +// email: "alice@example.com", +// role: "User", +// phone: "+1 234 567 8901", +// }, +// { +// name: "Bob Brown", +// email: "bob@example.com", +// role: "Admin", +// phone: "+1 987 654 3210", +// }, +// { +// name: "Charlie Davis", +// email: "charlie@example.com", +// role: "User", +// phone: "+1 312 555 7890", +// }, +// { +// name: "Alice Johnson", +// email: "alice@example.com", +// role: "User", +// phone: "+1 234 567 8901", +// }, +// { +// name: "Bob Brown", +// email: "bob@example.com", +// role: "Admin", +// phone: "+1 987 654 3210", +// }, +// { +// name: "Charlie Davis", +// email: "charlie@example.com", +// role: "User", +// phone: "+1 312 555 7890", +// }, +// { +// name: "Bob Brown", +// email: "bob@example.com", +// role: "Admin", +// phone: "+1 987 654 3210", +// }, +// { +// name: "Charlie Davis", +// email: "charlie@example.com", +// role: "User", +// phone: "+1 312 555 7890", +// }, +// ]; + +// const userData = users.length ? users : staticUsers; + +// const filteredUsers = userData.filter((user) => +// user.name.toLowerCase().includes(searchQuery.toLowerCase()) +// ); + +// const indexOfLastUser = currentPage * usersPerPage; +// const indexOfFirstUser = indexOfLastUser - usersPerPage; +// const currentUsers = filteredUsers.slice(indexOfFirstUser, indexOfLastUser); + +// const handlePageChange = (event, value) => { +// setCurrentPage(value); +// }; + +// return ( +// +// +// User List +// + +// {/* Search & Buttons Section */} +// +// +// +// +// ), +// }} +// value={searchQuery} +// onChange={(e) => setSearchQuery(e.target.value)} +// /> +// +// +// + +// +// +// +// + +// {/* Table Section */} +// +// +// +// +// {["Name", "Email", "Role", "Phone", "Action"].map( +// (header) => ( +// +// {header} +// +// ) +// )} +// +// +// +// {currentUsers.map((user, index) => ( +// +// +// {user.name} +// +// +// {user.email} +// +// +// {user.role} +// +// +// {user.phone} +// +// +// +// +// +// +// +// ))} +// +//
+//
+ +// {/* Pagination */} +// +// +// Page Number : +// +// +// +//
+// ); +// } +// import { useEffect, useState } from "react"; +// import { +// Box, +// Button, +// Typography, +// TextField, +// InputAdornment, +// Paper, +// Table, +// TableBody, +// TableCell, +// TableContainer, +// TableHead, +// TableRow, +// Pagination, +// IconButton, +// } from "@mui/material"; +// import SearchIcon from "@mui/icons-material/Search"; +// import MoreHorizIcon from "@mui/icons-material/MoreHoriz"; +// import TuneIcon from "@mui/icons-material/Tune"; +// import { useDispatch, useSelector } from "react-redux"; +// import { adminList } from "../../redux/slices/adminSlice"; +// import { AppDispatch, RootState } from "../../redux/store/store"; + +// export default function AdminList() { +// const [searchQuery, setSearchQuery] = useState(""); +// const [currentPage, setCurrentPage] = useState(1); +// const adminsPerPage = 10; + +// const dispatch = useDispatch(); +// const admins = useSelector((state: RootState) => state.adminReducer.admins); + +// useEffect(() => { +// dispatch(adminList()); +// }, [dispatch]); + +// const staticAdmins = [ +// { +// name: "John Doe", +// location: "New York", +// managerAssigned: "Alice Johnson", +// vehicle: "Tesla Model S", +// phone: "+1 234 567 8901", +// }, +// { +// name: "Jane Smith", +// location: "Los Angeles", +// managerAssigned: "Bob Brown", +// vehicle: "Ford F-150", +// phone: "+1 987 654 3210", +// }, +// { +// name: "Michael Brown", +// location: "Chicago", +// managerAssigned: "Sarah Lee", +// vehicle: "Chevrolet Bolt", +// phone: "+1 312 555 7890", +// }, +// { +// name: "Emily Davis", +// location: "Houston", +// managerAssigned: "Tom Wilson", +// vehicle: "Nissan Leaf", +// phone: "+1 713 444 5678", +// }, +// { +// name: "Daniel Martinez", +// location: "Phoenix", +// managerAssigned: "Jessica White", +// vehicle: "BMW i3", +// phone: "+1 602 999 4321", +// }, +// { +// name: "Sophia Miller", +// location: "Philadelphia", +// managerAssigned: "Mark Adams", +// vehicle: "Audi e-tron", +// phone: "+1 215 777 6543", +// }, +// { +// name: "James Anderson", +// location: "San Antonio", +// managerAssigned: "Emma Thomas", +// vehicle: "Hyundai Kona EV", +// phone: "+1 210 321 8765", +// }, +// { +// name: "James Anderson", +// location: "San Antonio", +// managerAssigned: "Emma Thomas", +// vehicle: "Hyundai Kona EV", +// phone: "+1 210 321 8765", +// }, +// ]; + +// const adminData = admins.length ? admins : staticAdmins; + +// const filteredAdmins = adminData.filter((admin) => +// admin.name.toLowerCase().includes(searchQuery.toLowerCase()) +// ); + +// const indexOfLastAdmin = currentPage * adminsPerPage; +// const indexOfFirstAdmin = indexOfLastAdmin - adminsPerPage; +// const currentAdmins = filteredAdmins.slice( +// indexOfFirstAdmin, +// indexOfLastAdmin +// ); + +// const handlePageChange = (event, value) => { +// setCurrentPage(value); +// }; + +// return ( +// +// +// Charge stations +// + +// {/* Search & Buttons Section */} +// +// +// +// +// ), +// }} +// value={searchQuery} +// onChange={(e) => setSearchQuery(e.target.value)} +// /> +// +// +// + +// +// +// +// + +// {/* Table Section */} +// +// +// +// +// {[ +// "Name", +// "Location", +// "Manager Assigned", +// "Vehicle", +// "Phone Number", +// "Action", +// ].map((header) => ( +// +// {header} +// +// ))} +// +// +// +// {currentAdmins.map((admin, index) => ( +// +// +// {admin.name} +// +// +// {admin.location || "N/A"} +// +// +// {admin.managerAssigned || "N/A"} +// +// +// {admin.vehicle || "N/A"}{" "} +// +// +6 more +// +// +// +// {admin.phone} +// +// +// +// +// +// +// +// ))} +// +//
+//
+ +// {/* Pagination */} +// +// +// Page Number : +// +// +// +//
+// ); +// } +import React, { useEffect, useState } from "react"; +import { Box, Button, Typography } from "@mui/material"; +import AddEditCategoryModal from "../../components/AddEditCategoryModal"; +import { useForm } from "react-hook-form"; +import CustomTable, { Column } from "../../components/CustomTable"; import { useDispatch, useSelector } from "react-redux"; -import { userList } from "../../redux/slices/userSlice"; // Make sure userSlice exists +import { createUser, userList } from "../../redux/slices/userSlice"; import { AppDispatch, RootState } from "../../redux/store/store"; +import { string } from "prop-types"; +import { adminList, updateAdmin } from "../../redux/slices/adminSlice"; +import AddUserModal from "../../components/AddUserModel"; export default function UserList() { - const [searchQuery, setSearchQuery] = useState(""); - const [currentPage, setCurrentPage] = useState(1); - const usersPerPage = 10; + const [modalOpen, setModalOpen] = useState(false); + const { reset } = useForm(); + + const [deleteModal, setDeleteModal] = React.useState(false); + const [viewModal, setViewModal] = React.useState(false); + const [rowData, setRowData] = React.useState(null); const dispatch = useDispatch(); + const users = useSelector((state: RootState) => state.userReducer.users); useEffect(() => { dispatch(userList()); }, [dispatch]); - const staticUsers = [ - { - name: "Alice Johnson", - email: "alice@example.com", - role: "User", - phone: "+1 234 567 8901", - }, - { - name: "Bob Brown", - email: "bob@example.com", - role: "Admin", - phone: "+1 987 654 3210", - }, - { - name: "Charlie Davis", - email: "charlie@example.com", - role: "User", - phone: "+1 312 555 7890", - }, - { - name: "Alice Johnson", - email: "alice@example.com", - role: "User", - phone: "+1 234 567 8901", - }, - { - name: "Bob Brown", - email: "bob@example.com", - role: "Admin", - phone: "+1 987 654 3210", - }, - { - name: "Charlie Davis", - email: "charlie@example.com", - role: "User", - phone: "+1 312 555 7890", - }, - { - name: "Bob Brown", - email: "bob@example.com", - role: "Admin", - phone: "+1 987 654 3210", - }, - { - name: "Charlie Davis", - email: "charlie@example.com", - role: "User", - phone: "+1 312 555 7890", - }, - ]; - - const userData = users.length ? users : staticUsers; - - const filteredUsers = userData.filter((user) => - user.name.toLowerCase().includes(searchQuery.toLowerCase()) - ); - - const indexOfLastUser = currentPage * usersPerPage; - const indexOfFirstUser = indexOfLastUser - usersPerPage; - const currentUsers = filteredUsers.slice(indexOfFirstUser, indexOfLastUser); - - const handlePageChange = (event, value) => { - setCurrentPage(value); + const handleClickOpen = () => { + setRowData(null); // Reset row data when opening for new admin + setModalOpen(true); }; + const handleCloseModal = () => { + setModalOpen(false); + setRowData(null); + reset(); + }; + + const handleCreate = async (data: { + name: string; + email: string; + phone: string; + registeredAddress: string; + }) => { + try { + await dispatch(createUser(data)); + await dispatch(userList()); // Refresh the list after creation + handleCloseModal(); + } catch (error) { + console.error("Creation failed", error); + } + }; + + const handleUpdate = async ( + id: string, + name: string, + email: string, + phone: string, + registeredAddress: string + ) => { + try { + await dispatch( + updateAdmin({ + id, + name, + email, + phone, + registeredAddress, + }) + ); + await dispatch(adminList()); + } catch (error) { + console.error("Update failed", error); + } + }; + + const categoryColumns: Column[] = [ + { id: "srno", label: "Sr No" }, + { id: "name", label: "Name" }, + { id: "email", label: "Email" }, + { id: "phone", label: "Phone" }, + // { id: "location", label: "Location" }, + // { id: "managerAssigned", label: "ManagerAssigned" }, + // { id: "vehicle", label: "Vehicle" }, + + { id: "action", label: "Action", align: "center" }, + ]; + + const categoryRows = users?.length + ? users?.map(function ( + user: { + id: string; + name: string; + email: string; + + phone: string; + // location?: string; + // managerAssigned?: string; + // vehicle?: string; + }, + index: number + ) { + return { + id: user?.id, + srno: index + 1, + name: user?.name, + email: user?.email, + phone: user?.phone, + // location: user?.location, + // managerAssigned: user?.managerAssigned, + // vehicle: user?.vehicle, + }; + }) + : []; + return ( - - - User List - - - {/* Search & Buttons Section */} + <> - - - - ), - }} - value={searchQuery} - onChange={(e) => setSearchQuery(e.target.value)} - /> - - - - - - - - - - {/* Table Section */} - - - - - {["Name", "Email", "Role", "Phone", "Action"].map( - (header) => ( - - {header} - - ) - )} - - - - {currentUsers.map((user, index) => ( - - - {user.name} - - - {user.email} - - - {user.role} - - - {user.phone} - - - - - - - - ))} - -
-
- - {/* Pagination */} - - Page Number : + Users - + -
+ + + + ); } diff --git a/src/redux/reducers.ts b/src/redux/reducers.ts index 4ad7387..b67ef5f 100644 --- a/src/redux/reducers.ts +++ b/src/redux/reducers.ts @@ -4,12 +4,14 @@ import authReducer from "./slices/authSlice"; import adminReducer from "./slices/adminSlice"; import profileReducer from "./slices/profileSlice"; import userReducer from "./slices/userSlice.ts"; +import roleReducer from "./slices/roleSlice.ts"; const rootReducer = combineReducers({ - authReducer, - adminReducer, - profileReducer, - userReducer, + authReducer, + adminReducer, + profileReducer, + userReducer, + roleReducer, }); export type RootState = ReturnType; diff --git a/src/redux/slices/profileSlice.ts b/src/redux/slices/profileSlice.ts index f881512..58ef006 100644 --- a/src/redux/slices/profileSlice.ts +++ b/src/redux/slices/profileSlice.ts @@ -7,7 +7,7 @@ interface User { id: string; name: string; email: string; - role: string; + userType: string; phone: string; } diff --git a/src/redux/slices/roleSlice.ts b/src/redux/slices/roleSlice.ts new file mode 100644 index 0000000..bc1cef5 --- /dev/null +++ b/src/redux/slices/roleSlice.ts @@ -0,0 +1,115 @@ +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: any; + name: string; + resource: { + moduleName: string; + moduleId: string; + permissions: string[]; + }[]; +} + +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?.data) throw new Error("Invalid API response"); + + return response.data.data; + } catch (error: any) { + toast.error("Error Fetching Roles" + error); + return rejectWithValue( + error?.response?.data?.message || "An error occurred" + ); + } + } +); + +// Create Role +export const createRole = createAsyncThunk< + Role, + { + name: string; + resource: { + moduleName: string; + moduleId: string; + permissions: string[]; + }[]; + }, + { rejectValue: string } +>("/CreateRole", async (data, { rejectWithValue }) => { + try { + const response = await http.post("create", data); + return response.data; + } catch (error: any) { + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); + +const roleSlice = createSlice({ + name: "fetchRoles", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(roleList.pending, (state) => { + state.loading = true; + state.error = null; + }) + .addCase( + roleList.fulfilled, + (state, action: PayloadAction) => { + state.loading = false; + state.roles = action.payload.results; // Extract results from response + } + ) + .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; + state.roles.push(action.payload); + } + ) + .addCase( + createRole.rejected, + (state, action: PayloadAction) => { + state.loading = false; + state.error = action.payload || "Failed to create role"; + } + ); + }, +}); + +export default roleSlice.reducer; diff --git a/src/redux/slices/userSlice.ts b/src/redux/slices/userSlice.ts index d9242fd..73f6066 100644 --- a/src/redux/slices/userSlice.ts +++ b/src/redux/slices/userSlice.ts @@ -1,5 +1,7 @@ import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"; import axios from "axios"; +import http from "../../lib/https"; +import { toast } from "sonner"; // Define TypeScript types interface User { @@ -7,9 +9,10 @@ interface User { name: string; email: string; phone?: string; - location?: string; - managerAssigned?: string; - vehicle?: string; + // location?: string; + // managerAssigned?: string; + // vehicle?: string; + password:string; } interface UserState { @@ -26,17 +29,62 @@ const initialState: UserState = { }; // Async thunk to fetch user list -export const userList = createAsyncThunk("users/fetchUsers", async () => { +// export const userList = createAsyncThunk("users/fetchUsers", async () => { +// try { +// const response = await axios.get("/api/users"); // Adjust the API endpoint as needed +// return response.data; +// } catch (error: any) { +// throw new Error(error.response?.data?.message || "Failed to fetch users"); +// } +// }); +export const userList = createAsyncThunk( + "fetchUsers", + async (_, { rejectWithValue }) => { + try { + const token = localStorage?.getItem("authToken"); + if (!token) throw new Error("No token found"); + + const response = await http.get("users-list"); + + if (!response.data?.data) throw new Error("Invalid API response"); + + return response.data.data; + } catch (error: any) { + toast.error("Error Fetching Profile" + error); + return rejectWithValue( + error?.response?.data?.message || "An error occurred" + ); + } + } +); + +//Create User +export const createUser = createAsyncThunk< + User, + { + name: string; + email: string; + password: string; + phone: string; + + // location?: string; + // managerAssigned?: string; + // vehicle?: string; + }, + { rejectValue: string } +>("/CreateUser", async (data, { rejectWithValue }) => { try { - const response = await axios.get("/api/users"); // Adjust the API endpoint as needed + const response = await http.post("create-user", data); return response.data; } catch (error: any) { - throw new Error(error.response?.data?.message || "Failed to fetch users"); + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); } }); const userSlice = createSlice({ - name: "users", + name: "fetchUsers", initialState, reducers: {}, extraReducers: (builder) => { @@ -45,14 +93,34 @@ const userSlice = createSlice({ state.loading = true; state.error = null; }) - .addCase(userList.fulfilled, (state, action: PayloadAction) => { - state.loading = false; - state.users = action.payload; - }) + .addCase( + userList.fulfilled, + (state, action: PayloadAction) => { + state.loading = false; + state.users = action.payload; + } + ) .addCase(userList.rejected, (state, action) => { state.loading = false; state.error = action.error.message || "Failed to fetch users"; - }); + }) + .addCase(createUser.pending, (state) => { + state.loading = true; + // state.error = null; + }) + .addCase( + createUser.fulfilled, + (state, action: PayloadAction) => { + state.loading = false; + state.users.push(action.payload); + } + ) + .addCase( + createUser.rejected, + (state, action: PayloadAction) => { + state.loading = false; + } + ); }, }); diff --git a/src/router.tsx b/src/router.tsx index 7bbb859..f7af3de 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -2,6 +2,7 @@ import { Routes as BaseRoutes, Navigate, Route } from "react-router-dom"; import React, { lazy, Suspense } from "react"; import LoadingComponent from "./components/Loading"; import DashboardLayout from "./layouts/DashboardLayout"; +import RoleList from "./pages/RoleList"; // Page imports const Login = lazy(() => import("./pages/Auth/Login")); @@ -83,6 +84,15 @@ export default function AppRouter() { /> } /> + } + /> + } + />