dev-jaanvi #1

Open
jaanvi wants to merge 155 commits from dev-jaanvi into main
5 changed files with 547 additions and 473 deletions
Showing only changes of commit 85dbeb7537 - Show all commits

View file

@ -1,33 +1,60 @@
import React,{useEffect} from "react"; import React, { useEffect } from "react";
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from "@mui/material"; import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
TextField,
} from "@mui/material";
import { useForm, Controller } from "react-hook-form"; import { useForm, Controller } from "react-hook-form";
interface AddEditCategoryModalProps { interface AddEditCategoryModalProps {
open: boolean; open: boolean;
handleClose: () => void; handleClose: () => void;
editRow:any; handleUpdate: (id: string, name: string, role: string) => void;
editRow: any;
} }
interface FormData { interface FormData {
category: string; category: string;
role: string;
name: string;
} }
const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({ open, handleClose,editRow }) => { const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
const { control, handleSubmit, formState: { errors },setValue,reset } = useForm<FormData>({ open,
handleClose,
editRow,
handleUpdate,
}) => {
const {
control,
handleSubmit,
formState: { errors },
setValue,
reset,
} = useForm<FormData>({
defaultValues: { defaultValues: {
category: "", category: "",
name: "",
role: "",
}, },
}); });
const onSubmit = (data: FormData) => { const onSubmit = (data: FormData) => {
console.log(data.category); if (editRow) {
handleUpdate(editRow.id, data.name, data.role);
}
handleClose(); handleClose();
reset(); reset();
}; };
useEffect(() => { useEffect(() => {
if (editRow) { if (editRow) {
setValue('category', editRow.name); setValue("category", editRow.name);
setValue("name", editRow.name);
setValue("role", editRow.role);
} else { } else {
reset(); reset();
} }
@ -41,18 +68,17 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({ open, handl
maxWidth="md" maxWidth="md"
fullWidth fullWidth
PaperProps={{ PaperProps={{
component: 'form', component: "form",
onSubmit: handleSubmit(onSubmit), onSubmit: handleSubmit(onSubmit),
}} }}
> >
<DialogTitle>{editRow ? "Edit" : 'Add'} Category</DialogTitle> <DialogTitle>{editRow ? "Edit" : "Add"} Category</DialogTitle>
<DialogContent> <DialogContent>
<Controller <Controller
name="category" name="category"
control={control} control={control}
rules={{ rules={{
required: "Category Name is required", required: "Category Name is required",
}} }}
render={({ field }) => ( render={({ field }) => (
<TextField <TextField
@ -69,6 +95,47 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({ open, handl
/> />
)} )}
/> />
<Controller
name="name"
control={control}
rules={{
required: "Admin Name is required",
}}
render={({ field }) => (
<TextField
{...field}
autoFocus
required
margin="dense"
label="Admin Name"
type="text"
fullWidth
variant="standard"
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
<Controller
name="role"
control={control}
rules={{
required: "Role is required",
}}
render={({ field }) => (
<TextField
{...field}
margin="dense"
label="Role"
type="text"
fullWidth
variant="standard"
error={!!errors.role}
helperText={errors.role?.message}
/>
)}
/>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={handleClose}>Cancel</Button> <Button onClick={handleClose}>Cancel</Button>

View file

@ -41,7 +41,7 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
}, },
})) }))
interface Column { export interface Column {
id: string id: string
label: string label: string
align?: "left" | "center" | "right" align?: "left" | "center" | "right"
@ -137,7 +137,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
<IconButton <IconButton
onClick={(e) => { onClick={(e) => {
handleClick(e, row) handleClick(e, row)
setSelectedRow(row) // Store the selected row setRowData(row) // Store the selected row
}} }}
> >
<MoreVertRoundedIcon /> <MoreVertRoundedIcon />

View file

@ -1,19 +1,19 @@
import * as React from 'react'; import * as React from "react";
import { styled } from '@mui/material/styles'; import { styled } from "@mui/material/styles";
import Divider, { dividerClasses } from '@mui/material/Divider'; import Divider, { dividerClasses } from "@mui/material/Divider";
import Menu from '@mui/material/Menu'; import Menu from "@mui/material/Menu";
import MuiMenuItem from '@mui/material/MenuItem'; import MuiMenuItem from "@mui/material/MenuItem";
import { paperClasses } from '@mui/material/Paper'; import { paperClasses } from "@mui/material/Paper";
import { listClasses } from '@mui/material/List'; import { listClasses } from "@mui/material/List";
import ListItemText from '@mui/material/ListItemText'; import ListItemText from "@mui/material/ListItemText";
import ListItemIcon, { listItemIconClasses } from '@mui/material/ListItemIcon'; import ListItemIcon, { listItemIconClasses } from "@mui/material/ListItemIcon";
import LogoutRoundedIcon from '@mui/icons-material/LogoutRounded'; import LogoutRoundedIcon from "@mui/icons-material/LogoutRounded";
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded'; import MoreVertRoundedIcon from "@mui/icons-material/MoreVertRounded";
import MenuButton from '../MenuButton'; import MenuButton from "../MenuButton";
import { Avatar } from '@mui/material'; import { Avatar } from "@mui/material";
const MenuItem = styled(MuiMenuItem)({ const MenuItem = styled(MuiMenuItem)({
margin: '2px 0', margin: "2px 0",
}); });
export default function OptionsMenu({ avatar }: { avatar?: boolean }) { export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
@ -30,7 +30,7 @@ export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
<MenuButton <MenuButton
aria-label="Open menu" aria-label="Open menu"
onClick={handleClick} onClick={handleClick}
sx={{ borderColor: 'transparent' }} sx={{ borderColor: "transparent" }}
> >
{avatar ? ( {avatar ? (
<MoreVertRoundedIcon /> <MoreVertRoundedIcon />
@ -49,17 +49,17 @@ export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
open={open} open={open}
onClose={handleClose} onClose={handleClose}
onClick={handleClose} onClick={handleClose}
transformOrigin={{ horizontal: 'right', vertical: 'top' }} transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
sx={{ sx={{
[`& .${listClasses.root}`]: { [`& .${listClasses.root}`]: {
padding: '4px', padding: "4px",
}, },
[`& .${paperClasses.root}`]: { [`& .${paperClasses.root}`]: {
padding: 0, padding: 0,
}, },
[`& .${dividerClasses.root}`]: { [`& .${dividerClasses.root}`]: {
margin: '4px -4px', margin: "4px -4px",
}, },
}} }}
> >
@ -73,7 +73,7 @@ export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
onClick={handleClose} onClick={handleClose}
sx={{ sx={{
[`& .${listItemIconClasses.root}`]: { [`& .${listItemIconClasses.root}`]: {
ml: 'auto', ml: "auto",
minWidth: 0, minWidth: 0,
}, },
}} }}

View file

@ -1,52 +1,53 @@
import React, { useEffect, useState } from "react" import React, { useEffect, useState } from "react";
import { Box, Button, Typography } from "@mui/material" import { Box, Button, Typography } from "@mui/material";
import AddEditCategoryModal from "../../components/AddEditCategoryModal" import AddEditCategoryModal from "../../components/AddEditCategoryModal";
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form";
import CustomTable from "../../components/CustomTable" import CustomTable, { Column } from "../../components/CustomTable";
// import DeleteModal from "../../components/Modals/DeleteModal/DeleteModal" import { useDispatch, useSelector } from "react-redux";
import { useDispatch, useSelector } from "react-redux" import { adminList, updateAdmin } from "../../redux/slices/authSlice";
import { adminList } from "../../redux/slices/authSlice" import { AppDispatch, RootState } from "../../redux/store/store"; // Import RootState for selector
import { AppDispatch, RootState } from "../../redux/store/store" // Import RootState for selector
// Sample data for categories
export default function AdminList() { export default function AdminList() {
const [modalOpen, setModalOpen] = useState(false) const [modalOpen, setModalOpen] = useState(false);
const [editRow, setEditRow] = useState<any>(null) const { reset } = useForm();
const { reset } = useForm()
const [deleteModal, setDeleteModal] = React.useState<boolean>(false) const [deleteModal, setDeleteModal] = React.useState<boolean>(false);
const [rowData, setRowData] = React.useState<any | null>(null) const [rowData, setRowData] = React.useState<any | null>(null);
const dispatch = useDispatch<AppDispatch>() const dispatch = useDispatch<AppDispatch>();
// Fetching admin data from the Redux store // Fetching admin data from the Redux store
const admins = useSelector((state: RootState) => state.auth.admins) const admins = useSelector((state: RootState) => state.auth.admins);
// Dispatching the API call when the component mounts // Dispatching the API call when the component mounts
useEffect(() => { useEffect(() => {
dispatch(adminList()) dispatch(adminList());
}, [dispatch]) }, [dispatch]);
const handleClickOpen = () => { const handleClickOpen = () => {
setModalOpen(true) setModalOpen(true);
setEditRow(null) };
}
const handleCloseModal = () => { const handleCloseModal = () => {
setModalOpen(false) setModalOpen(false);
reset() reset();
};
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);
} }
};
// const handleDelete = () => { const categoryColumns: Column[] = [
// setDeleteModal(false)
// }
const categoryColumns = [
{ id: "srno", label: "Sr No" }, { id: "srno", label: "Sr No" },
{ id: "name", label: "Name" }, { id: "name", label: "Name" },
{ id: "role", label: "Role" }, { id: "role", label: "Role" },
{ id: "action", label: "Action", align: "center" }, { id: "action", label: "Action", align: "center" },
] ];
// If no admins are available, display the sample data // If no admins are available, display the sample data
const categoryRows = admins?.length const categoryRows = admins?.length
@ -55,13 +56,13 @@ export default function AdminList() {
admin: { id: string; name: string; role: string }, admin: { id: string; name: string; role: string },
index: number index: number
) => ({ ) => ({
id: admin.id, id: admin?.id,
srno: index + 1, srno: index + 1,
name: admin?.name, name: admin?.name,
role: admin.role, role: admin?.role,
}) })
) )
: [] : [];
return ( return (
<> <>
@ -97,7 +98,6 @@ export default function AdminList() {
<CustomTable <CustomTable
columns={categoryColumns} columns={categoryColumns}
rows={categoryRows} rows={categoryRows}
editRow={editRow}
setDeleteModal={setDeleteModal} setDeleteModal={setDeleteModal}
deleteModal={deleteModal} deleteModal={deleteModal}
setRowData={setRowData} setRowData={setRowData}
@ -107,12 +107,8 @@ export default function AdminList() {
open={modalOpen} open={modalOpen}
handleClose={handleCloseModal} handleClose={handleCloseModal}
editRow={rowData} editRow={rowData}
handleUpdate={handleUpdate}
/> />
{/* <DeleteModal
open={deleteModal}
setDeleteModal={setDeleteModal}
handleDelete={handleDelete}
/> */}
</> </>
) );
} }

View file

@ -2,11 +2,10 @@ import {
createSlice, createSlice,
createAsyncThunk, createAsyncThunk,
PayloadAction, PayloadAction,
isRejectedWithValue, } from "@reduxjs/toolkit";
} from "@reduxjs/toolkit" import axios from "axios";
import axios from "axios" import { backendHttp, apiHttp } from "../../lib/https";
import { backendHttp, apiHttp } from "../../lib/https" import { toast } from "react-toastify";
import { toast } from "react-toastify"
// Define types for state // Define types for state
interface User { interface User {
@ -15,22 +14,22 @@ interface User {
admin: { name: any; role: any }, admin: { name: any; role: any },
index: number index: number
) => { srno: number; name: any; role: any } ) => { srno: number; name: any; role: any }
): unknown ): unknown;
id: string id: string;
email: string email: string;
} }
interface Admin { interface Admin {
id: string id: string;
name: string name: string;
role: string role: string;
} }
interface AuthState { interface AuthState {
user: User | null user: User | null;
admins: Admin[] admins: Admin[];
isAuthenticated: boolean isAuthenticated: boolean;
isLoading: boolean isLoading: boolean;
error: string | null error: object | string | null;
} }
// Async thunk for login // Async thunk for login
@ -43,16 +42,16 @@ export const loginUser = createAsyncThunk<
const response = await backendHttp.post("admin/login", { const response = await backendHttp.post("admin/login", {
email, email,
password, password,
}) });
localStorage.setItem("authToken", response.data?.data?.token) // Save token localStorage.setItem("authToken", response.data?.data?.token); // Save token
toast.success(response.data?.message) toast.success(response.data?.message);
return response.data return response.data;
} catch (error: any) { } catch (error: any) {
return rejectWithValue( return rejectWithValue(
error.response?.data?.message || "An error occurred" error.response?.data?.message || "An error occurred"
) );
} }
}) });
// Async thunk for register // Async thunk for register
export const registerUser = createAsyncThunk< export const registerUser = createAsyncThunk<
@ -64,14 +63,18 @@ export const registerUser = createAsyncThunk<
const response = await axios.post( const response = await axios.post(
"https://health-digi.dmlabs.in/auth/register", "https://health-digi.dmlabs.in/auth/register",
data data
) );
return response.data return response.data;
} catch (error: any) { } catch (error: any) {
return rejectWithValue( return rejectWithValue(
error.response?.data?.message || "An error occurred" error.response?.data?.message || "An error occurred"
) );
} }
}) });
//created by Eknoor and jaanvi
//date: 10-Feb-2025
//Fetching list of admins
export const adminList = createAsyncThunk< export const adminList = createAsyncThunk<
Admin[], Admin[],
@ -79,22 +82,25 @@ export const adminList = createAsyncThunk<
{ rejectValue: string } { rejectValue: string }
>("/auth", async (_, { rejectWithValue }) => { >("/auth", async (_, { rejectWithValue }) => {
try { try {
const response = await apiHttp.get("/auth") const response = await apiHttp.get("/auth");
console.log(response?.data?.data) console.log(response?.data?.data);
return response?.data?.data?.map( return response?.data?.data?.map(
(admin: { id: string; name: string; role: string }) => ({ (admin: { id: string; name: string; role: string }) => ({
id: admin.id, id: admin.id,
name: admin?.name, name: admin?.name,
role: admin?.role || "N/A", role: admin?.role || "N/A",
}) })
) );
console.log(response.data.data)
} catch (error: any) { } catch (error: any) {
return rejectWithValue( return rejectWithValue(
error.response?.data?.message || "An error occurred" error.response?.data?.message || "An error occurred"
) );
} }
}) });
//created by Eknoor
//date: 11-Feb-2025
//function for deleting admin
export const deleteAdmin = createAsyncThunk< export const deleteAdmin = createAsyncThunk<
string, string,
@ -102,33 +108,34 @@ export const deleteAdmin = createAsyncThunk<
{ rejectValue: string } { rejectValue: string }
>("deleteAdmin", async (id, { rejectWithValue }) => { >("deleteAdmin", async (id, { rejectWithValue }) => {
try { try {
const response = await apiHttp.delete(`/auth/${id}`) const response = await apiHttp.delete(`/auth/${id}`);
// console.log(response, "response of deletion") toast.success(response.data?.message);
return id // Returning the deleted admin's ID return id;
} catch (error: any) { } catch (error: any) {
return rejectWithValue( return rejectWithValue(
error.response?.data?.message || "An error occurred" error.response?.data?.message || "An error occurred"
) );
} }
}) });
// export const putAdmin = createAsyncThunk< export const updateAdmin = createAsyncThunk(
// Admin, // Return type (updated admin object) "/auth/id",
// { id: string; data: Partial<Admin> }, // Argument type async (
// { rejectValue: string } // Rejection type { id, name, role }: { id: any; name: string; role: string },
// >( { rejectWithValue }
// "updateAdmin", ) => {
// async ({ id, data }, { rejectWithValue }) => { try {
// try { const response = await apiHttp.put(`/auth/${id}`, { name, role });
// const response = await apiHttp.put(`/auth/${id}`, data) toast.success("Admin updated successfully");
// return response.data // Ensure response contains the updated admin object console.log(response.data);
// } catch (error: any) { return response.data;
// return rejectWithValue( } catch (error: any) {
// error.response?.data?.message || "An error occurred" return rejectWithValue(
// ) error.response?.data?.message || "An error occurred"
// } );
// } }
// ) }
);
const initialState: AuthState = { const initialState: AuthState = {
user: null, user: null,
@ -136,114 +143,118 @@ const initialState: AuthState = {
isAuthenticated: false, isAuthenticated: false,
isLoading: false, isLoading: false,
error: null, error: null,
} };
const authSlice = createSlice({ const authSlice = createSlice({
name: "auth", name: "auth",
initialState, initialState,
reducers: { reducers: {
logout: (state) => { logout: (state) => {
state.user = null state.user = null;
state.isAuthenticated = false state.isAuthenticated = false;
}, },
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
builder builder
// Login // Login
.addCase(loginUser.pending, (state) => { .addCase(loginUser.pending, (state) => {
state.isLoading = true state.isLoading = true;
state.error = null state.error = null;
}) })
.addCase( .addCase(
loginUser.fulfilled, loginUser.fulfilled,
(state, action: PayloadAction<User>) => { (state, action: PayloadAction<User>) => {
state.isLoading = false state.isLoading = false;
state.isAuthenticated = true state.isAuthenticated = true;
state.user = action.payload state.user = action.payload;
} }
) )
.addCase( .addCase(
loginUser.rejected, loginUser.rejected,
(state, action: PayloadAction<string | undefined>) => { (state, action: PayloadAction<string | undefined>) => {
state.isLoading = false state.isLoading = false;
state.error = action.payload || "An error occurred" state.error = action.payload || "An error occurred";
} }
) )
// Register // Register
.addCase(registerUser.pending, (state) => { .addCase(registerUser.pending, (state) => {
state.isLoading = true state.isLoading = true;
state.error = null state.error = null;
}) })
.addCase( .addCase(
registerUser.fulfilled, registerUser.fulfilled,
(state, action: PayloadAction<User>) => { (state, action: PayloadAction<User>) => {
state.isLoading = false state.isLoading = false;
state.isAuthenticated = true state.isAuthenticated = true;
state.user = action.payload state.user = action.payload;
} }
) )
.addCase( .addCase(
registerUser.rejected, registerUser.rejected,
(state, action: PayloadAction<string | undefined>) => { (state, action: PayloadAction<string | undefined>) => {
state.isLoading = false state.isLoading = false;
state.error = action.payload || "An error occurred" state.error = action.payload || "An error occurred";
} }
) )
// created by Jaanvi and Eknoor // created by Jaanvi and Eknoor
//AdminList //AdminList
.addCase(adminList.pending, (state) => { .addCase(adminList.pending, (state) => {
state.isLoading = true state.isLoading = true;
state.error = null state.error = null;
}) })
.addCase( .addCase(
adminList.fulfilled, adminList.fulfilled,
(state, action: PayloadAction<Admin[]>) => { (state, action: PayloadAction<Admin[]>) => {
state.isLoading = false state.isLoading = false;
state.admins = action.payload state.admins = action.payload;
} }
) )
.addCase( .addCase(
adminList.rejected, adminList.rejected,
(state, action: PayloadAction<string | undefined>) => { (state, action: PayloadAction<string | undefined>) => {
state.isLoading = false state.isLoading = false;
state.error = action.payload || "An error occurred" state.error = action.payload || "An error occurred";
} }
) )
//created by Eknoor
//date: 11-Feb-2025
//cases for deleting admin
.addCase(deleteAdmin.pending, (state) => { .addCase(deleteAdmin.pending, (state) => {
state.isLoading = true state.isLoading = true;
}) })
.addCase(deleteAdmin.fulfilled, (state, action) => { .addCase(deleteAdmin.fulfilled, (state, action) => {
state.isLoading = false state.isLoading = false;
state.admins = state.admins.filter( state.admins = state.admins.filter(
(admin) => String(admin.id) !== String(action.payload) (admin) => String(admin.id) !== String(action.payload)
) );
}) })
.addCase(deleteAdmin.rejected, (state, action) => { .addCase(deleteAdmin.rejected, (state, action) => {
state.isLoading = false state.isLoading = false;
state.error = action.payload || "Failed to delete admin" state.error = action.payload || "Failed to delete admin";
}) })
//update Admin .addCase(updateAdmin.pending, (state) => {
state.isLoading = true;
// .addCase(putAdmin.pending, (state) => { state.error = null;
// state.isLoading = true })
// state.error = null .addCase(updateAdmin.fulfilled, (state, action) => {
// }) const updatedAdmin = action.payload;
// .addCase(putAdmin.fulfilled, (state, action: PayloadAction<Admin>) => { state.admins = state.admins.map((admin) =>
// state.isLoading = false admin.id === updatedAdmin.id ? updatedAdmin : admin
// state.admins = state.admins.map((admin) => );
// admin.id === action.payload.id ? action.payload : admin
// )
// })
// .addCase(putAdmin.rejected, (state, action: PayloadAction<string | undefined>) => {
// 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 const { logout } = authSlice.actions;
export default authSlice.reducer export default authSlice.reducer;