Skip to content

Commit

Permalink
chore: frontend fixes for mobile table layout
Browse files Browse the repository at this point in the history
  • Loading branch information
brunotot committed Nov 14, 2024
1 parent 509288e commit b05c997
Show file tree
Hide file tree
Showing 16 changed files with 334 additions and 222 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ import { VALIDATORS } from "../validators";
export class UserController {
@autowired() private userService: UserService;

@contract(contracts.User.findAll, withRouteSecured(Role.Enum["avr-admin"]))
async findAll(): RouteOutput<typeof contracts.User.findAll> {
return {
status: 200,
body: await this.userService.findAll(),
};
}

@contract(contracts.User.findOneByUsername, withRouteSecured(Role.Enum["avr-admin"]))
async findOneByUsername(
payload: RouteInput<typeof contracts.User.findOneByUsername>,
Expand All @@ -34,14 +42,6 @@ export class UserController {
};
}

@contract(contracts.User.findAll, withRouteSecured(Role.Enum["avr-admin"]))
async findAll(): RouteOutput<typeof contracts.User.findAll> {
return {
status: 200,
body: await this.userService.findAll(),
};
}

@contract(contracts.User.findAllPaginated, withRouteSecured(Role.Enum["avr-admin"]))
async findAllPaginated(
payload: RouteInput<typeof contracts.User.findAllPaginated>,
Expand Down
1 change: 0 additions & 1 deletion packages/mern-sample-app/app-vite-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"i18next-http-backend": "^2.5.0",
"jwt-decode": "^4.0.0",
"keycloak-js": "^25.0.4",
"material-ui-confirm": "^3.0.16",
"material-ui-popup-state": "^5.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ClientDatatableProps } from "@org/app-vite-react/app/components/Da
import type { DtBaseOrder } from "@org/app-vite-react/app/components/Datatable/types";
import type { MouseEvent } from "react";

import * as mui from "@mui/material";
import {
TableContainer,
Table,
Expand All @@ -13,14 +14,12 @@ import {
} from "@mui/material";
import { DtSortableCell } from "@org/app-vite-react/app/components/Datatable/components/DtSortableCell/DtSortableCell";
import { DEFAULT_PAGINATION_OPTIONS } from "@org/app-vite-react/app/components/Datatable/types";
import { ClientResponsiveTable } from "@org/app-vite-react/app/pages/admin-settings/manage-users/components";
import { Fragment, useMemo, useState } from "react";


export function ClientDatatable<T>({
data,
columns,
disablePagination = false,
}: ClientDatatableProps<T>) {
export function ClientDatatable<T>(props: ClientDatatableProps<T>) {
const { data, columns, disablePagination = false, renderMobileRow } = props;
const matchesMobile = mui.useMediaQuery("(max-width:678px)");
const [sortData, setSortData] = useState<DtBaseOrder>([]);
const [paginationOptions, setPaginationOptions] = useState(DEFAULT_PAGINATION_OPTIONS);

Expand Down Expand Up @@ -69,6 +68,38 @@ export function ClientDatatable<T>({
setSortData([{ id, direction: "desc" }]);
};

const paginationComponent = disablePagination ? (
<></>
) : (
<TablePagination
sx={{
"& .MuiTablePagination-spacer": { display: matchesMobile ? "none" : undefined },
"& .MuiTablePagination-selectLabel": { display: matchesMobile ? "none" : undefined },
}}
component="div"
labelRowsPerPage={"Results per page:"}
labelDisplayedRows={({ from, to, count }) => `${from}-${to} to ${count}`}
rowsPerPageOptions={[5, 10, 25, 50, 100]}
count={data.length}
page={paginationOptions.page}
rowsPerPage={paginationOptions.rowsPerPage}
showFirstButton
showLastButton
onPageChange={(_, newPage) => onPageChange(newPage)}
onRowsPerPageChange={e => onRowsPerPageChange(+e.target.value)}
classes={{ toolbar: "toolbar-class" }}
/>
);

if (matchesMobile) {
return (
<>
<ClientResponsiveTable {...props} data={filteredData} renderRow={renderMobileRow} />
{paginationComponent}
</>
);
}

return (
<>
<TableContainer>
Expand Down Expand Up @@ -112,30 +143,15 @@ export function ClientDatatable<T>({
>
{columns.map(({ id, align, renderBody }) => (
<TableCell key={id} align={align}>
{renderBody(item)}
{renderBody(item, { cleanup: () => {} })}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
{!disablePagination && (
<TablePagination
component="div"
labelRowsPerPage="Results per page:"
labelDisplayedRows={({ from, to, count }) => `${from}-${to} to ${count}`}
rowsPerPageOptions={[10, 25, 50, 100]}
count={data.length}
page={paginationOptions.page}
rowsPerPage={paginationOptions.rowsPerPage}
showFirstButton
showLastButton
onPageChange={(_, newPage) => onPageChange(newPage)}
onRowsPerPageChange={e => onRowsPerPageChange(+e.target.value)}
classes={{ toolbar: "toolbar-class" }}
/>
)}
{paginationComponent}
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export type ClientDatatableProps<T> = {
data: T[];
columns: DtClientColumn<T>[];
disablePagination?: boolean;
renderMobileRow: (item: T) => React.ReactNode;
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { PaginationOptions } from "@org/lib-api-client";
import type { ReactNode } from "react";

export type DtBaseColumnConfig = {
cleanup: () => void;
};
export type DtBaseColumnAlign = "left" | "center" | "right";
export type DtBaseColumnRenderHeader = () => ReactNode;
export type DtBaseColumnRenderBody<T> = (value: T) => ReactNode;
export type DtBaseColumnRenderBody<T> = (value: T, config: DtBaseColumnConfig) => ReactNode;
export type DtBaseOrder = DtBaseSortItem[];
export type DtBaseSortItem = { id: string; direction: "asc" | "desc" };
export type DtBaseColumn<T> = {
Expand All @@ -16,7 +19,7 @@ export type DtBaseColumn<T> = {
export const DEFAULT_PAGINATION_OPTIONS: PaginationOptions = {
order: [],
page: 0,
rowsPerPage: 10,
rowsPerPage: 5,
search: "",
filters: {},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import type { ClientDatatableProps } from "@org/app-vite-react/app/components/Datatable";
import * as icons from "@mui/icons-material";
import * as mui from "@mui/material";
import React, { useState } from "react";

export type ClientResponsiveTableProps<T> = ClientDatatableProps<T> & {
renderRow: (item: T) => React.ReactNode;
};

export function ClientResponsiveTable<T>({
columns,
data,
disablePagination,
renderRow,
}: ClientResponsiveTableProps<T>) {
const [selectedItem, setSelectedItem] = useState<T | null>(null);
const [dialogOpen, setDialogOpen] = useState(false);

const handleItemClick = (item: T) => {
setSelectedItem(item);
setDialogOpen(true);
};

const cleanup = () => {
setDialogOpen(false);
//setSelectedItem(null); // Reset selected item when dialog closes
};

return (
<>
<mui.List
sx={{ height: "100%", maxHeight: "calc(100vh - 320px)", overflow: "auto" }}
component="div"
>
{data.map((item, index) => (
<mui.ListItem
component="div"
key={index}
onClick={() => handleItemClick(item)}
sx={{
cursor: "pointer",
//backgroundColor: "red",
borderRadius: 1,
//marginBottom: 1,
//padding: 2,
"&:hover": {
//backgroundColor: "rgba(255, 255, 255, 0.1)",
},
}}
>
{renderRow(item)}
</mui.ListItem>
))}
</mui.List>

<mui.Dialog open={dialogOpen} onClose={cleanup} fullWidth maxWidth="sm">
<mui.DialogTitle>
Item Details
<mui.IconButton
aria-label="close"
onClick={cleanup}
sx={{
position: "absolute",
right: 8,
top: 8,
color: theme => theme.palette.grey[500],
}}
>
<icons.Close />
</mui.IconButton>
</mui.DialogTitle>

<mui.DialogContent dividers>
{selectedItem && (
<mui.Box>
{columns.map((column, idx) => (
<mui.Box
key={idx}
sx={{
display: "flex",
justifyContent: "space-between",
marginBottom: 1.5,
paddingY: 1,
borderBottom: "1px solid",
borderColor: "divider",
}}
>
<mui.Typography component="div" variant="body2" color="text.secondary">
{column.renderHeader()}
</mui.Typography>
<mui.Typography
component="div"
variant="body2"
color="text.primary"
sx={{ fontWeight: 500 }}
>
{column.renderBody(selectedItem, { cleanup })}
</mui.Typography>
</mui.Box>
))}
</mui.Box>
)}
</mui.DialogContent>

<mui.DialogActions>
<mui.Button onClick={cleanup} color="primary" variant="contained">
Close
</mui.Button>
</mui.DialogActions>
</mui.Dialog>
</>
);
}

This file was deleted.

Loading

0 comments on commit b05c997

Please sign in to comment.