Frontend Api integration
This commit is contained in:
parent
74038b9295
commit
292ea123a0
|
@ -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<AddEditCategoryModalProps> = ({
|
||||
|
@ -52,6 +54,7 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
|||
email: "",
|
||||
phone: "",
|
||||
registeredAddress: "",
|
||||
password: "",
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -62,7 +65,8 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
|||
data.name,
|
||||
data.email,
|
||||
data.phone,
|
||||
data.registeredAddress
|
||||
data.registeredAddress,
|
||||
data.password
|
||||
);
|
||||
} else {
|
||||
handleCreate(data);
|
||||
|
@ -168,7 +172,26 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="password"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "password is required",
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
{...field}
|
||||
required
|
||||
margin="dense"
|
||||
label="Password"
|
||||
type="password"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
error={!!errors.password}
|
||||
helperText={errors.password?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="phone"
|
||||
control={control}
|
||||
|
|
300
src/components/AddEditRoleModal/index.tsx
Normal file
300
src/components/AddEditRoleModal/index.tsx
Normal file
|
@ -0,0 +1,300 @@
|
|||
import React, { useEffect } from "react";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
|
||||
interface AddRoleModalProps {
|
||||
open: boolean;
|
||||
handleClose: () => 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<AddRoleModalProps> = ({
|
||||
open,
|
||||
handleClose,
|
||||
handleCreate,
|
||||
handleUpdate,
|
||||
editRow,
|
||||
data,
|
||||
}) => {
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset,
|
||||
getValues, // Access getValues from the form methods here
|
||||
} = useForm<FormData>({
|
||||
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 (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
component: "form",
|
||||
onSubmit: handleSubmit(onSubmit),
|
||||
}}
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
{editRow ? "Edit Role" : "Add Role"}
|
||||
<Box
|
||||
onClick={handleClose}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</Box>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
{/* Role Name Field */}
|
||||
<Controller
|
||||
name="name"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Role Name is required",
|
||||
minLength: {
|
||||
value: 3,
|
||||
message: "Minimum 3 characters required",
|
||||
},
|
||||
maxLength: {
|
||||
value: 30,
|
||||
message: "Maximum 30 characters allowed",
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
{...field}
|
||||
autoFocus
|
||||
required
|
||||
margin="dense"
|
||||
label="Role Name"
|
||||
type="text"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
error={!!errors.name}
|
||||
helperText={errors.name?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Resource Field */}
|
||||
<Controller
|
||||
name="resource"
|
||||
control={control}
|
||||
rules={{ required: "Resource is required" }}
|
||||
render={({ field }) => (
|
||||
<FormControl
|
||||
fullWidth
|
||||
margin="dense"
|
||||
error={!!errors.resource}
|
||||
>
|
||||
<InputLabel>Resource</InputLabel>
|
||||
<Select
|
||||
{...field}
|
||||
label="Resource"
|
||||
required
|
||||
fullWidth
|
||||
variant="standard"
|
||||
>
|
||||
{/* Mapping over the resource array to display the options */}
|
||||
{data.resource?.map((resourceItem, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
value={resourceItem.moduleId}
|
||||
>
|
||||
{resourceItem.moduleName}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{errors.resource?.message}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Permissions Checkbox Fields for each resource */}
|
||||
{getValues().resource &&
|
||||
getValues().resource.length > 0 &&
|
||||
getValues().resource.map((resource, resourceIndex) => (
|
||||
<React.Fragment key={resourceIndex}>
|
||||
<FormControl fullWidth margin="dense">
|
||||
<FormLabel>
|
||||
{resource.moduleName} Permissions
|
||||
</FormLabel>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
value="view"
|
||||
checked={resource.permissions.includes(
|
||||
"view"
|
||||
)}
|
||||
onChange={(e) =>
|
||||
handlePermissionChange(
|
||||
resourceIndex,
|
||||
"view",
|
||||
e.target.checked
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="View"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
value="edit"
|
||||
checked={resource.permissions.includes(
|
||||
"edit"
|
||||
)}
|
||||
onChange={(e) =>
|
||||
handlePermissionChange(
|
||||
resourceIndex,
|
||||
"edit",
|
||||
e.target.checked
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="Edit"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
value="delete"
|
||||
checked={resource.permissions.includes(
|
||||
"delete"
|
||||
)}
|
||||
onChange={(e) =>
|
||||
handlePermissionChange(
|
||||
resourceIndex,
|
||||
"delete",
|
||||
e.target.checked
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="Delete"
|
||||
/>
|
||||
<FormHelperText>
|
||||
{
|
||||
errors.resource?.[resourceIndex]
|
||||
?.permissions?.message
|
||||
}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Cancel</Button>
|
||||
<Button type="submit">{editRow ? "Update" : "Create"}</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddRoleModal;
|
212
src/components/AddUserModel/index.tsx
Normal file
212
src/components/AddUserModel/index.tsx
Normal file
|
@ -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<AddUserModalProps> = ({
|
||||
open,
|
||||
handleClose,
|
||||
handleCreate,
|
||||
|
||||
editRow,
|
||||
}) => {
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset,
|
||||
} = useForm<FormData>({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
password: "",
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = (data: FormData) => {
|
||||
handleCreate(data);
|
||||
|
||||
handleClose();
|
||||
reset();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
component: "form",
|
||||
onSubmit: handleSubmit(onSubmit),
|
||||
}}
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
{editRow ? "Edit Admin" : "Add Admin"}
|
||||
<Box
|
||||
onClick={handleClose}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</Box>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<Controller
|
||||
name="name"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Admin Name is required",
|
||||
minLength: {
|
||||
value: 3,
|
||||
message: "Minimum 3 characters required",
|
||||
},
|
||||
maxLength: {
|
||||
value: 30,
|
||||
message: "Maximum 30 characters allowed",
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
{...field}
|
||||
autoFocus
|
||||
required
|
||||
margin="dense"
|
||||
label="User Name"
|
||||
type="text"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
error={!!errors.name}
|
||||
helperText={errors.name?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="email"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Email is required",
|
||||
pattern: {
|
||||
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
||||
message: "Invalid email address",
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
{...field}
|
||||
required
|
||||
margin="dense"
|
||||
label="Email"
|
||||
type="email"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
error={!!errors.email}
|
||||
helperText={errors.email?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="password"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "password is required",
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
{...field}
|
||||
required
|
||||
margin="dense"
|
||||
label="Password"
|
||||
type="password"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
error={!!errors.password}
|
||||
helperText={errors.password?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="phone"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Phone number is required",
|
||||
pattern: {
|
||||
value: /^[0-9]*$/,
|
||||
message: "Only numbers are allowed",
|
||||
},
|
||||
minLength: {
|
||||
value: 6,
|
||||
message: "Phone number must be exactly 6 digits",
|
||||
},
|
||||
maxLength: {
|
||||
value: 14,
|
||||
message: "Phone number must be exactly 14 digits",
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
{...field}
|
||||
required
|
||||
margin="dense"
|
||||
label="Phone Number"
|
||||
type="tel"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
error={!!errors.phone}
|
||||
helperText={errors.phone?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Cancel</Button>
|
||||
<Button type="submit">Create</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddUserModal;
|
|
@ -29,6 +29,11 @@ const baseMenuItems = [
|
|||
icon: <AnalyticsRoundedIcon />,
|
||||
url: "/panel/user-list",
|
||||
},
|
||||
{
|
||||
text: "Roles",
|
||||
icon: <AnalyticsRoundedIcon />,
|
||||
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
|
||||
);
|
||||
|
||||
|
||||
|
|
137
src/pages/RoleList/index.tsx
Normal file
137
src/pages/RoleList/index.tsx
Normal file
|
@ -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<boolean>(false);
|
||||
const [viewModal, setViewModal] = React.useState<boolean>(false);
|
||||
const [rowData, setRowData] = React.useState<any | null>(null);
|
||||
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
|
||||
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 (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
maxWidth: {
|
||||
sm: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
component="h2"
|
||||
variant="h6"
|
||||
sx={{ mt: 2, fontWeight: 600 }}
|
||||
>
|
||||
Roles
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="medium"
|
||||
sx={{ textAlign: "right" }}
|
||||
onClick={handleClickOpen}
|
||||
>
|
||||
Add Role
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<CustomTable
|
||||
columns={categoryColumns}
|
||||
rows={categoryRows}
|
||||
setDeleteModal={setDeleteModal}
|
||||
deleteModal={deleteModal}
|
||||
setViewModal={setViewModal}
|
||||
viewModal={viewModal}
|
||||
setRowData={setRowData}
|
||||
setModalOpen={setModalOpen}
|
||||
/>
|
||||
<AddEditRoleModal
|
||||
open={modalOpen}
|
||||
handleClose={handleCloseModal}
|
||||
handleCreate={handleCreate}
|
||||
editRow={rowData}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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<typeof rootReducer>;
|
||||
|
|
|
@ -7,7 +7,7 @@ interface User {
|
|||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
role: string;
|
||||
userType: string;
|
||||
phone: string;
|
||||
}
|
||||
|
||||
|
|
115
src/redux/slices/roleSlice.ts
Normal file
115
src/redux/slices/roleSlice.ts
Normal file
|
@ -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<Role[], void, { rejectValue: string }>(
|
||||
"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<any>) => {
|
||||
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<Role>) => {
|
||||
state.loading = false;
|
||||
state.roles.push(action.payload);
|
||||
}
|
||||
)
|
||||
.addCase(
|
||||
createRole.rejected,
|
||||
(state, action: PayloadAction<string | undefined>) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload || "Failed to create role";
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default roleSlice.reducer;
|
|
@ -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<User[]>("users/fetchUsers", async () => {
|
||||
// export const userList = createAsyncThunk<User[]>("users/fetchUsers", async () => {
|
||||
// try {
|
||||
// const response = await axios.get<User[]>("/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<User, void, { rejectValue: string }>(
|
||||
"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<User[]>("/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<User[]>) => {
|
||||
state.loading = false;
|
||||
state.users = action.payload;
|
||||
})
|
||||
.addCase(
|
||||
userList.fulfilled,
|
||||
(state, action: PayloadAction<User[]>) => {
|
||||
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<User>) => {
|
||||
state.loading = false;
|
||||
state.users.push(action.payload);
|
||||
}
|
||||
)
|
||||
.addCase(
|
||||
createUser.rejected,
|
||||
(state, action: PayloadAction<string | undefined>) => {
|
||||
state.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -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() {
|
|||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="role-list"
|
||||
element={
|
||||
<ProtectedRoute
|
||||
caps={[]}
|
||||
component={<RoleList />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="profile"
|
||||
|
|
Loading…
Reference in a new issue