dev-jaanvi #1

Open
jaanvi wants to merge 155 commits from dev-jaanvi into main
7 changed files with 414 additions and 283 deletions
Showing only changes of commit 9220143bbb - Show all commits

View file

@ -45,7 +45,7 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({ open, handl
onSubmit: handleSubmit(onSubmit), onSubmit: handleSubmit(onSubmit),
}} }}
> >
<DialogTitle>{editRow ? "Editwefwefwe" : 'Add'} Category</DialogTitle> <DialogTitle>{editRow ? "Edit" : 'Add'} Category</DialogTitle>
<DialogContent> <DialogContent>
<Controller <Controller
name="category" name="category"

View file

@ -45,7 +45,7 @@ const AddEditTagsModal: React.FC<AddEditTagsModalProps> = ({ open, handleClose,e
onSubmit: handleSubmit(onSubmit), onSubmit: handleSubmit(onSubmit),
}} }}
> >
<DialogTitle>{editRow ? "Editsefwefwe" : 'Add'} Tag</DialogTitle> <DialogTitle>{editRow ? "Edit" : 'Add'} Tag</DialogTitle>
<DialogContent> <DialogContent>
<Controller <Controller
name="tag" name="tag"

View file

@ -1,12 +1,14 @@
import * as React from 'react'; import * as React from "react"
import { styled } from '@mui/material/styles'; import { styled } from "@mui/material/styles"
import Table from '@mui/material/Table'; import Table from "@mui/material/Table"
import TableBody from '@mui/material/TableBody'; import TableBody from "@mui/material/TableBody"
import TableCell, { tableCellClasses } from '@mui/material/TableCell'; import TableCell, { tableCellClasses } from "@mui/material/TableCell"
import TableContainer from '@mui/material/TableContainer'; import TableContainer from "@mui/material/TableContainer"
import TableHead from '@mui/material/TableHead'; import TableHead from "@mui/material/TableHead"
import TableRow from '@mui/material/TableRow'; import TableRow from "@mui/material/TableRow"
import Paper, { paperClasses } from '@mui/material/Paper'; import Paper, { paperClasses } from "@mui/material/Paper"
import { deleteAdmin } from "../../redux/slices/authSlice"
import { useDispatch } from "react-redux"
import { import {
Box, Box,
Button, Button,
@ -14,71 +16,87 @@ import {
IconButton, IconButton,
listClasses, listClasses,
Menu, Menu,
} from '@mui/material'; } from "@mui/material"
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded'; import MoreVertRoundedIcon from "@mui/icons-material/MoreVertRounded"
import DeleteModal from "../Modals/DeleteModal/DeleteModal"
import { AppDispatch } from "../../redux/store/store"
// Styled components for customization // Styled components for customization
const StyledTableCell = styled(TableCell)(({ theme }) => ({ const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: { [`&.${tableCellClasses.head}`]: {
backgroundColor: ' #1565c0', backgroundColor: " #1565c0",
color: theme.palette.common.white, color: theme.palette.common.white,
}, },
[`&.${tableCellClasses.body}`]: { [`&.${tableCellClasses.body}`]: {
fontSize: 14, fontSize: 14,
}, },
})); }))
const StyledTableRow = styled(TableRow)(({ theme }) => ({ const StyledTableRow = styled(TableRow)(({ theme }) => ({
'&:nth-of-type(odd)': { "&:nth-of-type(odd)": {
backgroundColor: theme.palette.action.hover, backgroundColor: theme.palette.action.hover,
}, },
'&:last-child td, &:last-child th': { "&:last-child td, &:last-child th": {
border: 0, border: 0,
}, },
})); }))
interface Column { interface Column {
id: string; id: string
label: string; label: string
align?: 'left' | 'center' | 'right'; align?: "left" | "center" | "right"
} }
interface Row { interface Row {
[key: string]: any; [key: string]: any
} }
interface CustomTableProps { interface CustomTableProps {
columns: Column[]; columns: Column[]
rows: Row[]; rows: Row[]
setDeleteModal: Function; setDeleteModal: Function
setRowData: Function; setRowData: Function
setModalOpen: Function; setModalOpen: Function
deleteModal: boolean
} }
const CustomTable: React.FC<CustomTableProps> = ({ const CustomTable: React.FC<CustomTableProps> = ({
columns, columns,
rows, rows,
setDeleteModal, setDeleteModal,
deleteModal,
setRowData, setRowData,
setModalOpen, setModalOpen,
}) => { }) => {
console.log('columnsss', columns, rows); // console.log("columnsss", columns, rows)
const dispatch = useDispatch<AppDispatch>()
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
const [selectedRow, setSelectedRow] = React.useState<Row | null>(null)
const open = Boolean(anchorEl)
const handleClick = (event: React.MouseEvent<HTMLElement>, row: Row) => {
setAnchorEl(event.currentTarget)
setSelectedRow(row) // Ensure the row data is set
}
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => { const handleClose = () => {
setAnchorEl(null); setAnchorEl(null)
}; }
const isImage = (value: any) => { const isImage = (value: any) => {
if (typeof value === 'string') { if (typeof value === "string") {
return value.startsWith('http') || value.startsWith('data:image'); // Check for URL or base64 image return value.startsWith("http") || value.startsWith("data:image") // Check for URL or base64 image
}
return false
}
const handleDeleteButton = (id: string | undefined) => {
if (!id) console.error("ID not found", id)
dispatch(deleteAdmin(id || ""))
setDeleteModal(false) // Close the modal only after deletion
handleClose()
} }
return false;
};
return ( return (
<TableContainer component={Paper}> <TableContainer component={Paper}>
@ -86,7 +104,10 @@ const CustomTable: React.FC<CustomTableProps> = ({
<TableHead> <TableHead>
<TableRow> <TableRow>
{columns.map((column) => ( {columns.map((column) => (
<StyledTableCell key={column.id} align={column.align || 'left'}> <StyledTableCell
key={column.id}
align={column.align || "left"}
>
{column.label} {column.label}
</StyledTableCell> </StyledTableCell>
))} ))}
@ -96,24 +117,27 @@ const CustomTable: React.FC<CustomTableProps> = ({
{rows.map((row, rowIndex) => ( {rows.map((row, rowIndex) => (
<StyledTableRow key={rowIndex}> <StyledTableRow key={rowIndex}>
{columns.map((column) => ( {columns.map((column) => (
<StyledTableCell key={column.id} align={column.align || 'left'}> <StyledTableCell
key={column.id}
align={column.align || "left"}
>
{isImage(row[column.id]) ? ( {isImage(row[column.id]) ? (
<img <img
src={row[column.id]} src={row[column.id]}
alt="Row " alt="Row "
style={{ style={{
width: '50px', width: "50px",
height: '50px', height: "50px",
objectFit: 'cover', objectFit: "cover",
}} }}
/> />
) : column.id !== 'action' ? ( ) : column.id !== "action" ? (
row[column.id] row[column.id]
) : ( ) : (
<IconButton <IconButton
onClick={(e) => { onClick={(e) => {
handleClick(e); handleClick(e, row)
setRowData(row); setSelectedRow(row) // Store the selected row
}} }}
> >
<MoreVertRoundedIcon /> <MoreVertRoundedIcon />
@ -132,25 +156,25 @@ const CustomTable: React.FC<CustomTableProps> = ({
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",
}, },
}} }}
> >
<Box <Box
sx={{ sx={{
display: 'flex', display: "flex",
flexDirection: 'column', flexDirection: "column",
justifyContent: 'flex-start', justifyContent: "flex-start",
}} }}
> >
<Button <Button
@ -158,30 +182,44 @@ const CustomTable: React.FC<CustomTableProps> = ({
onClick={() => setModalOpen(true)} onClick={() => setModalOpen(true)}
color="primary" color="primary"
sx={{ sx={{
justifyContent: 'flex-start', justifyContent: "flex-start",
py: 0, py: 0,
textTransform: 'capitalize', textTransform: "capitalize",
}} }}
> >
Edit Edit
</Button> </Button>
<Button <Button
variant="text" variant="text"
onClick={() => setDeleteModal(true)} onClick={(e) => {
e.stopPropagation()
setDeleteModal(true)
}}
color="error" color="error"
sx={{ sx={{
justifyContent: 'flex-start', justifyContent: "flex-start",
py: 0, py: 0,
textTransform: 'capitalize', textTransform: "capitalize",
}} }}
> >
Delete Delete
</Button> </Button>
{deleteModal && (
<DeleteModal
handleDelete={() =>
handleDeleteButton(selectedRow?.id)
}
open={deleteModal}
setDeleteModal={setDeleteModal}
id={selectedRow?.id}
/>
)}
</Box> </Box>
</Menu> </Menu>
)} )}
</TableContainer> </TableContainer>
); )
}; }
export default CustomTable; export default CustomTable

View file

@ -1,31 +1,34 @@
import { Box, Button, Modal, Typography } from '@mui/material'; import { Box, Button, Modal, Typography } from "@mui/material"
import { MouseEventHandler } from 'react';
type Props = { type Props = {
open: boolean; open: boolean
setDeleteModal: Function; setDeleteModal: Function
handleDelete: MouseEventHandler; handleDelete: (id: string | undefined) => void
}; id?: string | undefined
}
const style = { const style = {
position: 'absolute', position: "absolute",
top: '50%', top: "50%",
left: '50%', left: "50%",
transform: 'translate(-50%, -50%)', transform: "translate(-50%, -50%)",
width: 330, width: 330,
bgcolor: 'background.paper', bgcolor: "background.paper",
borderRadius: 1.5, borderRadius: 1.5,
boxShadow: 24, boxShadow: 24,
p: 3, p: 3,
}; }
const btnStyle = { py: 1, px: 5, width: '50%', textTransform: 'capitalize' }; const btnStyle = { py: 1, px: 5, width: "50%", textTransform: "capitalize" }
export default function DeleteModal({ export default function DeleteModal({
open, open,
setDeleteModal, setDeleteModal,
handleDelete, handleDelete,
id,
}: Props) { }: Props) {
// console.log("DeleteModal opened with ID:", id)
return ( return (
<Modal <Modal
open={open} open={open}
@ -41,13 +44,17 @@ export default function DeleteModal({
> >
Delete Record Delete Record
</Typography> </Typography>
<Typography id="modal-modal-description" sx={{ mt: 2 }} align="center"> <Typography
id="modal-modal-description"
sx={{ mt: 2 }}
align="center"
>
Are you sure you want to delete this record? Are you sure you want to delete this record?
</Typography> </Typography>
<Box <Box
sx={{ sx={{
display: 'flex', display: "flex",
justifyContent: 'space-between', justifyContent: "space-between",
mt: 4, mt: 4,
gap: 2, gap: 2,
}} }}
@ -66,12 +73,12 @@ export default function DeleteModal({
type="button" type="button"
color="primary" color="primary"
sx={btnStyle} sx={btnStyle}
onClick={handleDelete} onClick={() => handleDelete(id || "")}
> >
Delete Delete
</Button> </Button>
</Box> </Box>
</Box> </Box>
</Modal> </Modal>
); )
} }

View file

@ -17,7 +17,6 @@
import axios, { AxiosInstance } from 'axios'; import axios, { AxiosInstance } from 'axios';
// Axios instance for the production backend
const backendHttp = axios.create({ const backendHttp = axios.create({
baseURL: process.env.REACT_APP_BACKEND_URL, baseURL: process.env.REACT_APP_BACKEND_URL,
}); });

View file

@ -3,12 +3,11 @@ 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 from "../../components/CustomTable"
import DeleteModal from "../../components/Modals/DeleteModal/DeleteModal" // import DeleteModal from "../../components/Modals/DeleteModal/DeleteModal"
import { useDispatch, useSelector } from "react-redux" import { useDispatch, useSelector } from "react-redux"
import { adminList } 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 // Sample data for categories
export default function AdminList() { export default function AdminList() {
@ -19,19 +18,14 @@ export default function AdminList() {
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)
console.log(admins, "woihfiuwhfownfownefoi")
// 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)
@ -43,9 +37,9 @@ export default function AdminList() {
reset() reset()
} }
const handleDelete = () => { // const handleDelete = () => {
setDeleteModal(false) // setDeleteModal(false)
} // }
const categoryColumns = [ const categoryColumns = [
{ id: "srno", label: "Sr No" }, { id: "srno", label: "Sr No" },
@ -55,11 +49,19 @@ export default function AdminList() {
] ]
// If no admins are available, display the sample data // If no admins are available, display the sample data
const categoryRows = admins?.length ? admins?.map((admin: { name: any; role: any }, index: number) => ({ const categoryRows = admins?.length
? admins?.map(
(
admin: { id: string; name: string; role: string },
index: number
) => ({
id: admin.id,
srno: index + 1, srno: index + 1,
name: admin?.name, name: admin?.name,
role: admin.role, role: admin.role,
})) : [] })
)
: []
return ( return (
<> <>
@ -97,6 +99,7 @@ export default function AdminList() {
rows={categoryRows} rows={categoryRows}
editRow={editRow} editRow={editRow}
setDeleteModal={setDeleteModal} setDeleteModal={setDeleteModal}
deleteModal={deleteModal}
setRowData={setRowData} setRowData={setRowData}
setModalOpen={setModalOpen} setModalOpen={setModalOpen}
/> />
@ -105,11 +108,11 @@ export default function AdminList() {
handleClose={handleCloseModal} handleClose={handleCloseModal}
editRow={rowData} editRow={rowData}
/> />
<DeleteModal {/* <DeleteModal
open={deleteModal} open={deleteModal}
setDeleteModal={setDeleteModal} setDeleteModal={setDeleteModal}
handleDelete={handleDelete} handleDelete={handleDelete}
/> /> */}
</> </>
) )
} }

View file

@ -1,26 +1,36 @@
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit" import {
createSlice,
createAsyncThunk,
PayloadAction,
isRejectedWithValue,
} 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 {
map(arg0: (admin: { name: any; role: any }, index: number) => { srno: number; name: any; role: any }): unknown map(
arg0: (
admin: { name: any; role: any },
index: number
) => { srno: number; name: any; role: any }
): 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: string | null
} }
// Async thunk for login // Async thunk for login
@ -30,7 +40,10 @@ export const loginUser = createAsyncThunk<
{ rejectValue: string } { rejectValue: string }
>("auth/login", async ({ email, password }, { rejectWithValue }) => { >("auth/login", async ({ email, password }, { rejectWithValue }) => {
try { try {
const response = await backendHttp.post("admin/login", { email, password }) const response = await backendHttp.post("admin/login", {
email,
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
@ -66,19 +79,56 @@ 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) console.log(response?.data?.data)
return response?.data?.data?.map((admin: { name: string; role: string }) => ({ return response?.data?.data?.map(
(admin: { id: string; name: string; role: string }) => ({
id: admin.id,
name: admin?.name, name: admin?.name,
role: admin?.role || "N/A", role: admin?.role || "N/A",
})); })
)
console.log(response.data.data) console.log(response.data.data)
} catch (error: any) { } catch (error: any) {
return rejectWithValue(error.response?.data?.message || "An error occurred"); return rejectWithValue(
error.response?.data?.message || "An error occurred"
)
} }
}); })
export const deleteAdmin = createAsyncThunk<
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"
)
}
})
// export const putAdmin = createAsyncThunk<
// Admin, // Return type (updated admin object)
// { id: string; data: Partial<Admin> }, // 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"
// )
// }
// }
// )
const initialState: AuthState = { const initialState: AuthState = {
user: null, user: null,
@ -86,7 +136,7 @@ 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",
@ -141,15 +191,18 @@ const authSlice = createSlice({
) )
// created by Jaanvi and Eknoor // created by Jaanvi and Eknoor
//AdminList
.addCase(adminList.pending, (state) => { .addCase(adminList.pending, (state) => {
state.isLoading = true state.isLoading = true
state.error = null state.error = null
}) })
.addCase(adminList.fulfilled, (state, action: PayloadAction<Admin[]>) => { .addCase(
state.isLoading = false; adminList.fulfilled,
state.admins = action.payload; // ✅ Store admins correctly (state, action: PayloadAction<Admin[]>) => {
}) state.isLoading = false
state.admins = action.payload
}
)
.addCase( .addCase(
adminList.rejected, adminList.rejected,
@ -158,6 +211,37 @@ const authSlice = createSlice({
state.error = action.payload || "An error occurred" 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
// .addCase(putAdmin.pending, (state) => {
// state.isLoading = true
// state.error = null
// })
// .addCase(putAdmin.fulfilled, (state, action: PayloadAction<Admin>) => {
// state.isLoading = false
// 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"
// })
}, },
}) })