diff --git a/src/components/AddEditCategoryModal/index.tsx b/src/components/AddEditCategoryModal/index.tsx index b356e3b..a2c27ab 100644 --- a/src/components/AddEditCategoryModal/index.tsx +++ b/src/components/AddEditCategoryModal/index.tsx @@ -1,82 +1,149 @@ -import React,{useEffect} from "react"; -import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from "@mui/material"; +import React, { useEffect } from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + TextField, +} from "@mui/material"; import { useForm, Controller } from "react-hook-form"; interface AddEditCategoryModalProps { - open: boolean; - handleClose: () => void; - editRow:any; + open: boolean; + handleClose: () => void; + handleUpdate: (id: string, name: string, role: string) => void; + editRow: any; } interface FormData { - category: string; + category: string; + role: string; + name: string; } -const AddEditCategoryModal: React.FC = ({ open, handleClose,editRow }) => { - const { control, handleSubmit, formState: { errors },setValue,reset } = useForm({ - defaultValues: { - category: "", - }, - }); +const AddEditCategoryModal: React.FC = ({ + open, + handleClose, + editRow, + handleUpdate, +}) => { + const { + control, + handleSubmit, + formState: { errors }, + setValue, + reset, + } = useForm({ + defaultValues: { + category: "", + name: "", + role: "", + }, + }); - const onSubmit = (data: FormData) => { - console.log(data.category); - handleClose(); - reset(); - }; + const onSubmit = (data: FormData) => { + if (editRow) { + handleUpdate(editRow.id, data.name, data.role); + } + handleClose(); + reset(); + }; - useEffect(() => { - if (editRow) { - setValue('category', editRow.name); - } else { - reset(); - } - }, [editRow, setValue, reset]); + useEffect(() => { + if (editRow) { + setValue("category", editRow.name); + setValue("name", editRow.name); + setValue("role", editRow.role); + } else { + reset(); + } + }, [editRow, setValue, reset]); - return ( - <> - - {editRow ? "Edit" : 'Add'} Category - - ( - - )} - /> - - - - - - - - ); + return ( + <> + + {editRow ? "Edit" : "Add"} Category + + ( + + )} + /> + ( + + )} + /> + + ( + + )} + /> + + + + + + + + ); }; export default AddEditCategoryModal; diff --git a/src/components/CustomTable/index.tsx b/src/components/CustomTable/index.tsx index 05838a4..c03f7bc 100644 --- a/src/components/CustomTable/index.tsx +++ b/src/components/CustomTable/index.tsx @@ -41,7 +41,7 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({ }, })) -interface Column { +export interface Column { id: string label: string align?: "left" | "center" | "right" @@ -137,7 +137,7 @@ const CustomTable: React.FC = ({ { handleClick(e, row) - setSelectedRow(row) // Store the selected row + setRowData(row) // Store the selected row }} > diff --git a/src/components/OptionsMenu/index.tsx b/src/components/OptionsMenu/index.tsx index 3dd788a..43a33fe 100644 --- a/src/components/OptionsMenu/index.tsx +++ b/src/components/OptionsMenu/index.tsx @@ -1,89 +1,89 @@ -import * as React from 'react'; -import { styled } from '@mui/material/styles'; -import Divider, { dividerClasses } from '@mui/material/Divider'; -import Menu from '@mui/material/Menu'; -import MuiMenuItem from '@mui/material/MenuItem'; -import { paperClasses } from '@mui/material/Paper'; -import { listClasses } from '@mui/material/List'; -import ListItemText from '@mui/material/ListItemText'; -import ListItemIcon, { listItemIconClasses } from '@mui/material/ListItemIcon'; -import LogoutRoundedIcon from '@mui/icons-material/LogoutRounded'; -import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded'; -import MenuButton from '../MenuButton'; -import { Avatar } from '@mui/material'; +import * as React from "react"; +import { styled } from "@mui/material/styles"; +import Divider, { dividerClasses } from "@mui/material/Divider"; +import Menu from "@mui/material/Menu"; +import MuiMenuItem from "@mui/material/MenuItem"; +import { paperClasses } from "@mui/material/Paper"; +import { listClasses } from "@mui/material/List"; +import ListItemText from "@mui/material/ListItemText"; +import ListItemIcon, { listItemIconClasses } from "@mui/material/ListItemIcon"; +import LogoutRoundedIcon from "@mui/icons-material/LogoutRounded"; +import MoreVertRoundedIcon from "@mui/icons-material/MoreVertRounded"; +import MenuButton from "../MenuButton"; +import { Avatar } from "@mui/material"; const MenuItem = styled(MuiMenuItem)({ - margin: '2px 0', + margin: "2px 0", }); export default function OptionsMenu({ avatar }: { avatar?: boolean }) { - const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; - return ( - - - {avatar ? ( - - ) : ( - - )} - - - Profile - My account - - Add another account - Settings - - - Logout - - - - - - - ); + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + return ( + + + {avatar ? ( + + ) : ( + + )} + + + Profile + My account + + Add another account + Settings + + + Logout + + + + + + + ); } diff --git a/src/pages/AdminList/index.tsx b/src/pages/AdminList/index.tsx index fc1ae57..6f6492f 100644 --- a/src/pages/AdminList/index.tsx +++ b/src/pages/AdminList/index.tsx @@ -1,118 +1,114 @@ -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 from "../../components/CustomTable" -// import DeleteModal from "../../components/Modals/DeleteModal/DeleteModal" -import { useDispatch, useSelector } from "react-redux" -import { adminList } from "../../redux/slices/authSlice" -import { AppDispatch, RootState } from "../../redux/store/store" // Import RootState for selector - -// Sample data for categories +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 { adminList, updateAdmin } from "../../redux/slices/authSlice"; +import { AppDispatch, RootState } from "../../redux/store/store"; // Import RootState for selector export default function AdminList() { - const [modalOpen, setModalOpen] = useState(false) - const [editRow, setEditRow] = useState(null) - const { reset } = useForm() + const [modalOpen, setModalOpen] = useState(false); + const { reset } = useForm(); - const [deleteModal, setDeleteModal] = React.useState(false) - const [rowData, setRowData] = React.useState(null) + const [deleteModal, setDeleteModal] = React.useState(false); + const [rowData, setRowData] = React.useState(null); - const dispatch = useDispatch() + const dispatch = useDispatch(); - // Fetching admin data from the Redux store - const admins = useSelector((state: RootState) => state.auth.admins) - // Dispatching the API call when the component mounts - useEffect(() => { - dispatch(adminList()) - }, [dispatch]) + // Fetching admin data from the Redux store + const admins = useSelector((state: RootState) => state.auth.admins); - const handleClickOpen = () => { - setModalOpen(true) - setEditRow(null) - } + // Dispatching the API call when the component mounts + useEffect(() => { + dispatch(adminList()); + }, [dispatch]); - const handleCloseModal = () => { - setModalOpen(false) - reset() - } + const handleClickOpen = () => { + setModalOpen(true); + }; - // const handleDelete = () => { - // setDeleteModal(false) - // } + const handleCloseModal = () => { + setModalOpen(false); + reset(); + }; - const categoryColumns = [ - { id: "srno", label: "Sr No" }, - { id: "name", label: "Name" }, - { id: "role", label: "Role" }, - { id: "action", label: "Action", align: "center" }, - ] + const handleUpdate = async (id: string, name: string, role: string) => { + try { + await dispatch(updateAdmin({ id, name, role })); + await dispatch(adminList()); // Fetch updated admins list after update + } catch (error) { + console.error("Update failed", error); + } + }; - // If no admins are available, display the sample data - const categoryRows = admins?.length - ? admins?.map( - ( - admin: { id: string; name: string; role: string }, - index: number - ) => ({ - id: admin.id, - srno: index + 1, - name: admin?.name, - role: admin.role, - }) - ) - : [] + const categoryColumns: Column[] = [ + { id: "srno", label: "Sr No" }, + { id: "name", label: "Name" }, + { id: "role", label: "Role" }, + { id: "action", label: "Action", align: "center" }, + ]; - return ( - <> - - {/* Title and Add Category button */} - - Admins - - - + // If no admins are available, display the sample data + const categoryRows = admins?.length + ? admins?.map( + ( + admin: { id: string; name: string; role: string }, + index: number + ) => ({ + id: admin?.id, + srno: index + 1, + name: admin?.name, + role: admin?.role, + }) + ) + : []; - - - {/* */} - - ) + return ( + <> + + {/* Title and Add Category button */} + + Admins + + + + + + + + ); } diff --git a/src/redux/slices/authSlice.ts b/src/redux/slices/authSlice.ts index f725726..3189bb8 100644 --- a/src/redux/slices/authSlice.ts +++ b/src/redux/slices/authSlice.ts @@ -1,249 +1,260 @@ import { - createSlice, - createAsyncThunk, - PayloadAction, - isRejectedWithValue, -} from "@reduxjs/toolkit" -import axios from "axios" -import { backendHttp, apiHttp } from "../../lib/https" -import { toast } from "react-toastify" + createSlice, + createAsyncThunk, + PayloadAction, +} from "@reduxjs/toolkit"; +import axios from "axios"; +import { backendHttp, apiHttp } from "../../lib/https"; +import { toast } from "react-toastify"; // Define types for state interface User { - map( - arg0: ( - admin: { name: any; role: any }, - index: number - ) => { srno: number; name: any; role: any } - ): unknown - id: string - email: string + map( + arg0: ( + admin: { name: any; role: any }, + index: number + ) => { srno: number; name: any; role: any } + ): unknown; + id: string; + email: string; } interface Admin { - id: string - name: string - role: string + id: string; + name: string; + role: string; } interface AuthState { - user: User | null - admins: Admin[] - isAuthenticated: boolean - isLoading: boolean - error: string | null + user: User | null; + admins: Admin[]; + isAuthenticated: boolean; + isLoading: boolean; + error: object | string | null; } // Async thunk for login export const loginUser = createAsyncThunk< - User, - { email: string; password: string }, - { rejectValue: string } + User, + { email: string; password: string }, + { rejectValue: string } >("auth/login", async ({ email, password }, { rejectWithValue }) => { - try { - const response = await backendHttp.post("admin/login", { - email, - password, - }) - localStorage.setItem("authToken", response.data?.data?.token) // Save token - toast.success(response.data?.message) - return response.data - } catch (error: any) { - return rejectWithValue( - error.response?.data?.message || "An error occurred" - ) - } -}) + try { + const response = await backendHttp.post("admin/login", { + email, + password, + }); + localStorage.setItem("authToken", response.data?.data?.token); // Save token + toast.success(response.data?.message); + return response.data; + } catch (error: any) { + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); // Async thunk for register export const registerUser = createAsyncThunk< - User, - { email: string; password: string }, - { rejectValue: string } + User, + { email: string; password: string }, + { rejectValue: string } >("auth/register", async (data, { rejectWithValue }) => { - try { - const response = await axios.post( - "https://health-digi.dmlabs.in/auth/register", - data - ) - return response.data - } catch (error: any) { - return rejectWithValue( - error.response?.data?.message || "An error occurred" - ) - } -}) + try { + const response = await axios.post( + "https://health-digi.dmlabs.in/auth/register", + data + ); + return response.data; + } catch (error: any) { + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); + +//created by Eknoor and jaanvi +//date: 10-Feb-2025 +//Fetching list of admins export const adminList = createAsyncThunk< - Admin[], - void, - { rejectValue: string } + Admin[], + void, + { rejectValue: string } >("/auth", async (_, { rejectWithValue }) => { - try { - const response = await apiHttp.get("/auth") - console.log(response?.data?.data) - return response?.data?.data?.map( - (admin: { id: string; name: string; role: string }) => ({ - id: admin.id, - name: admin?.name, - role: admin?.role || "N/A", - }) - ) - console.log(response.data.data) - } catch (error: any) { - return rejectWithValue( - error.response?.data?.message || "An error occurred" - ) - } -}) + try { + const response = await apiHttp.get("/auth"); + console.log(response?.data?.data); + return response?.data?.data?.map( + (admin: { id: string; name: string; role: string }) => ({ + id: admin.id, + name: admin?.name, + role: admin?.role || "N/A", + }) + ); + } catch (error: any) { + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); + +//created by Eknoor +//date: 11-Feb-2025 +//function for deleting admin export const deleteAdmin = createAsyncThunk< - string, - string, - { rejectValue: string } + string, + string, + { rejectValue: string } >("deleteAdmin", async (id, { rejectWithValue }) => { - try { - const response = await apiHttp.delete(`/auth/${id}`) - // console.log(response, "response of deletion") - return id // Returning the deleted admin's ID - } catch (error: any) { - return rejectWithValue( - error.response?.data?.message || "An error occurred" - ) - } -}) + try { + const response = await apiHttp.delete(`/auth/${id}`); + toast.success(response.data?.message); + return id; + } catch (error: any) { + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); -// export const putAdmin = createAsyncThunk< -// Admin, // Return type (updated admin object) -// { id: string; data: Partial }, // Argument type -// { rejectValue: string } // Rejection type -// >( -// "updateAdmin", -// async ({ id, data }, { rejectWithValue }) => { -// try { -// const response = await apiHttp.put(`/auth/${id}`, data) -// return response.data // Ensure response contains the updated admin object -// } catch (error: any) { -// return rejectWithValue( -// error.response?.data?.message || "An error occurred" -// ) -// } -// } -// ) +export const updateAdmin = createAsyncThunk( + "/auth/id", + async ( + { id, name, role }: { id: any; name: string; role: string }, + { rejectWithValue } + ) => { + try { + const response = await apiHttp.put(`/auth/${id}`, { name, role }); + toast.success("Admin updated successfully"); + console.log(response.data); + return response.data; + } catch (error: any) { + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } + } +); const initialState: AuthState = { - user: null, - admins: [], - isAuthenticated: false, - isLoading: false, - error: null, -} + user: null, + admins: [], + isAuthenticated: false, + isLoading: false, + error: null, +}; const authSlice = createSlice({ - name: "auth", - initialState, - reducers: { - logout: (state) => { - state.user = null - state.isAuthenticated = false - }, - }, - extraReducers: (builder) => { - builder - // Login - .addCase(loginUser.pending, (state) => { - state.isLoading = true - state.error = null - }) - .addCase( - loginUser.fulfilled, - (state, action: PayloadAction) => { - state.isLoading = false - state.isAuthenticated = true - state.user = action.payload - } - ) - .addCase( - loginUser.rejected, - (state, action: PayloadAction) => { - state.isLoading = false - state.error = action.payload || "An error occurred" - } - ) - // Register - .addCase(registerUser.pending, (state) => { - state.isLoading = true - state.error = null - }) - .addCase( - registerUser.fulfilled, - (state, action: PayloadAction) => { - state.isLoading = false - state.isAuthenticated = true - state.user = action.payload - } - ) - .addCase( - registerUser.rejected, - (state, action: PayloadAction) => { - state.isLoading = false - state.error = action.payload || "An error occurred" - } - ) + name: "auth", + initialState, + reducers: { + logout: (state) => { + state.user = null; + state.isAuthenticated = false; + }, + }, + extraReducers: (builder) => { + builder + // Login + .addCase(loginUser.pending, (state) => { + state.isLoading = true; + state.error = null; + }) + .addCase( + loginUser.fulfilled, + (state, action: PayloadAction) => { + state.isLoading = false; + state.isAuthenticated = true; + state.user = action.payload; + } + ) + .addCase( + loginUser.rejected, + (state, action: PayloadAction) => { + state.isLoading = false; + state.error = action.payload || "An error occurred"; + } + ) + // Register + .addCase(registerUser.pending, (state) => { + state.isLoading = true; + state.error = null; + }) + .addCase( + registerUser.fulfilled, + (state, action: PayloadAction) => { + state.isLoading = false; + state.isAuthenticated = true; + state.user = action.payload; + } + ) + .addCase( + registerUser.rejected, + (state, action: PayloadAction) => { + state.isLoading = false; + state.error = action.payload || "An error occurred"; + } + ) - // created by Jaanvi and Eknoor - //AdminList - .addCase(adminList.pending, (state) => { - state.isLoading = true - state.error = null - }) - .addCase( - adminList.fulfilled, - (state, action: PayloadAction) => { - state.isLoading = false - state.admins = action.payload - } - ) + // created by Jaanvi and Eknoor + //AdminList + .addCase(adminList.pending, (state) => { + state.isLoading = true; + state.error = null; + }) + .addCase( + adminList.fulfilled, + (state, action: PayloadAction) => { + state.isLoading = false; + state.admins = action.payload; + } + ) - .addCase( - adminList.rejected, - (state, action: PayloadAction) => { - state.isLoading = false - state.error = action.payload || "An error occurred" - } - ) + .addCase( + adminList.rejected, + (state, action: PayloadAction) => { + state.isLoading = false; + state.error = action.payload || "An error occurred"; + } + ) - .addCase(deleteAdmin.pending, (state) => { - state.isLoading = true - }) - .addCase(deleteAdmin.fulfilled, (state, action) => { - state.isLoading = false - state.admins = state.admins.filter( - (admin) => String(admin.id) !== String(action.payload) - ) - }) - .addCase(deleteAdmin.rejected, (state, action) => { - state.isLoading = false - state.error = action.payload || "Failed to delete admin" - }) - //update Admin + //created by Eknoor + //date: 11-Feb-2025 + //cases for deleting admin + .addCase(deleteAdmin.pending, (state) => { + state.isLoading = true; + }) + .addCase(deleteAdmin.fulfilled, (state, action) => { + state.isLoading = false; + state.admins = state.admins.filter( + (admin) => String(admin.id) !== String(action.payload) + ); + }) + .addCase(deleteAdmin.rejected, (state, action) => { + state.isLoading = false; + state.error = action.payload || "Failed to delete admin"; + }) + .addCase(updateAdmin.pending, (state) => { + state.isLoading = true; + state.error = null; + }) + .addCase(updateAdmin.fulfilled, (state, action) => { + const updatedAdmin = action.payload; + state.admins = state.admins.map((admin) => + admin.id === updatedAdmin.id ? updatedAdmin : admin + ); - // .addCase(putAdmin.pending, (state) => { - // state.isLoading = true - // state.error = null - // }) - // .addCase(putAdmin.fulfilled, (state, action: PayloadAction) => { - // state.isLoading = false - // state.admins = state.admins.map((admin) => - // admin.id === action.payload.id ? action.payload : admin - // ) - // }) - // .addCase(putAdmin.rejected, (state, action: PayloadAction) => { - // state.isLoading = false - // state.error = action.payload || "Failed to update admin" - // }) - - }, -}) + state.isLoading = false; + }) + .addCase(updateAdmin.rejected, (state, action) => { + state.isLoading = false; + state.error = + action.payload || + "Something went wrong while updating Admin!!"; + }); + }, +}); -export const { logout } = authSlice.actions -export default authSlice.reducer +export const { logout } = authSlice.actions; +export default authSlice.reducer;