From 8265914627c1bb64470ad1ac64563e324096ae57 Mon Sep 17 00:00:00 2001 From: Carter Date: Mon, 25 Nov 2024 18:42:56 -0600 Subject: [PATCH] responsive table added and partly implemented. Has optional gutter component for rendering a subcomponent on the press of a button --- src/common/ResponsiveTable.tsx | 194 +++++++++++++++++++++++++++++++++ src/pages/Users.tsx | 29 ++++- 2 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 src/common/ResponsiveTable.tsx diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx new file mode 100644 index 0000000..a232654 --- /dev/null +++ b/src/common/ResponsiveTable.tsx @@ -0,0 +1,194 @@ +import { Box, CircularProgress, Collapse, darken, IconButton, InputAdornment, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Theme, Typography } from "@mui/material"; +import { makeStyles } from "@mui/styles"; +import { ChevronRight, Search } from "@mui/icons-material" +import { useEffect, useState } from "react"; +import React from "react"; + +const useStyles = makeStyles((theme: Theme) => { + // const isMobile = useMobile() + return ({ + gutter: { + backgroundColor: darken(theme.palette.background.paper, 0.03), + border: "none" + }, + tableContainer: { + margin: theme.spacing(1), + [theme.breakpoints.up("sm")]: { + margin: theme.spacing(2) + }, + width: "auto" + }, + title: { + padding: theme.spacing(1) + }, + titleContainer: { + border: "none" + }, + searchContainer: { + border: "none", + textAlign: "right", + }, + addIcon: { + color: "var(--status-ok)" + } + })}, +); + +interface Props { + rows: T[], + columns?: any, + title?: string; + total: number, + pageSize: number, + page: number, + setPage: (value: React.SetStateAction) => void, + handleRowsPerPageChange: (event: any) => void, + renderGutter?: (row: T) => JSX.Element, + setSearchText?: React.Dispatch>, + isLoading?: boolean; + multiGutter?: boolean; +} + +export default function ResponsiveTable(props: Props) { + const { + rows, + total, + page, + pageSize, + setPage, + handleRowsPerPageChange, + title, + renderGutter, + setSearchText, + isLoading, + multiGutter + } = props + const classes = useStyles(); + + const [inputSearchText, setInputSearchText] = useState(""); + const [openGutters, setOpenGutters] = useState([]) + + useEffect(() => { + if (!setSearchText) return; + if (inputSearchText === undefined) return; + const handler = setTimeout(() => { + setSearchText(inputSearchText); + }, 750); // Delay of 750ms + + return () => clearTimeout(handler); // Cleanup on change + }, [inputSearchText]); + + const handleCollapse = (index: number) => { + if (multiGutter) { + if (openGutters.includes(index)) { + setOpenGutters(openGutters => openGutters.filter(num => num !== index)); + } else { + setOpenGutters(openGutters => [...openGutters, index]); + } + } else { + if (openGutters.includes(index)) { + setOpenGutters([]) + } else { + setOpenGutters([index]) + } + } + } + + const handlePageChange = (page: number) => { + setOpenGutters([]) + setPage(page) + } + + return( + + + + + {title && + {typeof(title) === "string" ? + + {title} + + : + + title + + } + } + { setSearchText && + + setInputSearchText(e.currentTarget.value)} + InputProps={{ + startAdornment: ( + + + + ), + }} + /> + + } + + + { renderGutter && } + Profile + + + + { isLoading ? + + { isLoading && + + + + } + + : + rows.map((row, index) => { + return ( + + + {renderGutter && + + handleCollapse(index)}> + + + + } + + {renderGutter && + + + + {renderGutter(row)} + + + + } + + ) + }) + } + +
+ handlePageChange(page)} + onRowsPerPageChange={handleRowsPerPageChange} + /> +
+ ) +} \ No newline at end of file diff --git a/src/pages/Users.tsx b/src/pages/Users.tsx index 8cd6c8b..b5c7a9b 100644 --- a/src/pages/Users.tsx +++ b/src/pages/Users.tsx @@ -42,6 +42,7 @@ import { makeStyles } from "@mui/styles"; import { pond } from "protobuf-ts/pond"; import { getSecondaryColour, getSignatureAccentColour } from "services/whiteLabel"; import { Add, ChevronRight, Face, Remove } from "@mui/icons-material"; +import ResponsiveTable from "common/ResponsiveTable"; const useStyles = makeStyles((theme: Theme) => { // const isMobile = useMobile() @@ -108,6 +109,7 @@ export default function Users(props: Props) { // let tableRef: any = React.createRef(); const { error, success } = useSnackbar(); const [pageSize, setPageSize] = useState(5); + const [isLoading, setIsLoading] = useState(false); const [page, setPage] = useState(0); const [total, setTotal] = useState(0); const [showAllowAction, setShowAllowAction] = useState(false); @@ -115,6 +117,7 @@ export default function Users(props: Props) { const [showEnableFeature, setShowEnableFeature] = useState(false); const [selectedFeature, setSelectedFeature] = useState