From 3f9672442226ffae63ee44ffef2885b21d8282d8 Mon Sep 17 00:00:00 2001 From: Carter Date: Tue, 26 Nov 2024 11:51:11 -0600 Subject: [PATCH] responsive table now has optional mobile render prop; users now has functional mobile view --- package-lock.json | 87 ++++++++++++++++++++++ package.json | 1 + src/common/ResponsiveTable.tsx | 132 +++++++++++++++++++++++++++++++-- src/pages/Users.tsx | 23 +++++- src/user/ShareObject.tsx | 3 +- 5 files changed, 238 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a73d9b..bc6b43f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@mui/icons-material": "^6.1.6", "@mui/material": "^6.1.6", "@mui/styles": "^6.1.6", + "@mui/x-date-pickers": "^7.22.3", "@sentry/react": "^8.38.0", "@types/classnames": "^2.3.0", "axios": "^1.7.7", @@ -1510,6 +1511,92 @@ } } }, + "node_modules/@mui/x-date-pickers": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.22.3.tgz", + "integrity": "sha512-shNp92IrST5BiVy2f4jbrmRaD32QhyUthjh1Oexvpcn0v6INyuWgxfodoTi5ZCnE5Ue5UVFSs4R9Xre0UbJ5DQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0", + "@mui/x-internals": "7.21.0", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", + "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0", + "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2 || ^3.0.0", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, + "node_modules/@mui/x-internals": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.21.0.tgz", + "integrity": "sha512-94YNyZ0BhK5Z+Tkr90RKf47IVCW8R/1MvdUhh6MCQg6sZa74jsX+x+gEZ4kzuCqOsuyTyxikeQ8vVuCIQiP7UQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/package.json b/package.json index 90413e1..c0afe29 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@mui/icons-material": "^6.1.6", "@mui/material": "^6.1.6", "@mui/styles": "^6.1.6", + "@mui/x-date-pickers": "^7.22.3", "@sentry/react": "^8.38.0", "@types/classnames": "^2.3.0", "axios": "^1.7.7", diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx index d0a58dd..4baf530 100644 --- a/src/common/ResponsiveTable.tsx +++ b/src/common/ResponsiveTable.tsx @@ -1,9 +1,10 @@ -import { Box, CircularProgress, Collapse, darken, Grid2, IconButton, InputAdornment, Paper, SxProps, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Theme, Typography } from "@mui/material"; +import { Box, Button, Card, CircularProgress, Collapse, darken, Divider, Grid2, IconButton, InputAdornment, List, ListItem, Paper, SxProps, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Theme, Typography } from "@mui/material"; import { makeStyles } from "@mui/styles"; import { ChevronRight, Close, Search } from "@mui/icons-material" import { useEffect, useState } from "react"; import React from "react"; import { useMobile } from "hooks"; +import { render } from "react-dom"; const useStyles = makeStyles((theme: Theme) => { // const isMobile = useMobile() @@ -29,13 +30,22 @@ const useStyles = makeStyles((theme: Theme) => { border: "none", textAlign: "right", }, + mobileTitleBox: { + margin: theme.spacing(1), + marginBottom: theme.spacing(1.5), + }, + card: { + // padding: theme.spacing(1), + margin: theme.spacing(1), + + } })}, ); export interface Column { title: string | JSX.Element; - cellStyle?: SxProps | undefined - render?: (row: T) => JSX.Element; + cellStyle?: SxProps; + render: (row: T) => JSX.Element; } interface Props { @@ -53,6 +63,7 @@ interface Props { multiGutter?: boolean; rowsPerPageOptions?: number[]; noDataMessage?: string; + renderMobile?: (row: T) => JSX.Element; } export default function ResponsiveTable(props: Props) { @@ -71,6 +82,7 @@ export default function ResponsiveTable(props: Props) { columns, rowsPerPageOptions, noDataMessage, + renderMobile, } = props const classes = useStyles(); @@ -125,6 +137,7 @@ export default function ResponsiveTable(props: Props) { const searchBar = () => { return ( (props: Props) { ) } + const renderTitle = () => { + if (typeof(title) === "string" ) return ( + + {title} + + ) + if (title) return ( + + title + + ) + return null + } + + function capitalize(val: any) { + return String(val).charAt(0).toUpperCase() + String(val).slice(1); + } + + const renderMobileRow = (row: T) => { + if (renderMobile) return ( + renderMobile(row) + ) + if (columns) { + return ( + + {columns.map((column, index) => { + return ( + + + + {column.title+": "} + + + + {column.render(row)} + + + ) + })} + + ) + } + return ( + Object.keys(row).map((key, index) => { + let value = row[key as keyof typeof row] + + return ( + + + + {capitalize(key)+": "} + + + + + {value+""} + + + + ) + }) + ) + } + if (isMobile) return ( - - Hello! - + + + {renderTitle()} + {setSearchText && searchBar()} + + + {rows.map((row, index) => { + return ( + + {renderMobileRow(row)} + {renderGutter && + <> + + + {renderGutter(row)} + + {openGutters.includes(index) && } + handleCollapse(index)} + sx={{ + transform: openGutters.includes(index) ? + 'rotate(-90deg)' : 'rotate(90deg)', + transition: 'transform 0.3s ease', + width: "100%", + }} + > + + + + } + + ) + })} + {rows.length < 1 && + (!isLoading ? + + { noDataMessage ? noDataMessage : "No data."} + + : + + + + ) + } + ) return ( @@ -222,6 +341,7 @@ export default function ResponsiveTable(props: Props) { transform: openGutters.includes(index) ? 'rotate(90deg)' : 'rotate(0deg)', transition: 'transform 0.3s ease', + marginRight: -1 }} onClick={() => handleCollapse(index)}> diff --git a/src/pages/Users.tsx b/src/pages/Users.tsx index e94114b..3b1e2d3 100644 --- a/src/pages/Users.tsx +++ b/src/pages/Users.tsx @@ -1,5 +1,6 @@ import { Avatar, + Box, Button, Chip, darken, @@ -326,9 +327,28 @@ export default function Users() { ); }; + const renderMobile = (user: User) => { + const avatarURL = user.settings.avatar; + const avatar = avatarURL ? ( + + ) : ( + + + + ); + return ( + + + {avatar} + + + + ) + } + return ( - + title="Users" rows={rows} columns={columns()} @@ -340,6 +360,7 @@ export default function Users() { setSearchText={setSearchText} isLoading={isLoading} renderGutter={details} + renderMobile={renderMobile} // multiGutter /> } label="Expiration Date" value={newLinkExpiration} - onChange={date => setNewLinkExpiration(date as Moment)} + // onChange={(date: moment.Moment) => setNewLinkExpiration(date as Moment)} + onChange={(value) => setNewLinkExpiration(value as Moment)} disablePast />