add sort button

This commit is contained in:
Manmeet
2023-05-23 13:10:50 +05:30
parent 9999066487
commit 316807a0ed
4 changed files with 219 additions and 9 deletions

View File

@@ -0,0 +1,133 @@
import { useAtom } from "jotai";
import {
Grid,
IconButton,
MenuItem,
Stack,
TextField,
Typography,
alpha,
} from "@mui/material";
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import {
tableColumnsOrderedAtom,
tableScope,
tableSettingsAtom,
tableSortsAtom,
} from "@src/atoms/tableScope";
import SortPopover from "./SortPopover";
import ColumnSelect from "@src/components/Table/ColumnSelect";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import { projectScope, userRolesAtom } from "@src/atoms/projectScope";
import useSaveTableSorts from "@src/components/Table/ColumnHeader/useSaveTableSorts";
export default function Sort() {
const [userRoles] = useAtom(userRolesAtom, projectScope);
const [tableSettings] = useAtom(tableSettingsAtom, tableScope);
const canEditColumns = Boolean(
userRoles.includes("ADMIN") ||
tableSettings.modifiableBy?.some((r) => userRoles.includes(r))
);
const [tableSorts, setTableSorts] = useAtom(tableSortsAtom, tableScope);
const triggerSaveTableSorts = useSaveTableSorts(canEditColumns);
const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope);
const sortColumns = tableColumnsOrdered.map(({ key, name, type, index }) => ({
value: key,
label: name,
type,
index,
}));
return (
<SortPopover>
{({ handleClose }) => (
<Grid container spacing={2} sx={{ p: 3 }}>
<Grid item xs={5.5}>
<ColumnSelect
multiple={false}
label="Column"
options={sortColumns}
value={tableSorts[0].key}
onChange={(value: string | null) => {
if (value) {
setTableSorts([
{ key: value, direction: tableSorts[0].direction },
]);
triggerSaveTableSorts([
{ key: value, direction: tableSorts[0].direction },
]);
} else {
setTableSorts([]);
}
}}
/>
</Grid>
<Grid item xs={5.5}>
<TextField
label="Sort"
select
variant="filled"
fullWidth
value={tableSorts[0].direction}
onChange={(e) => {
setTableSorts([
{
key: tableSorts[0].key,
direction: e.target.value === "asc" ? "asc" : "desc",
},
]);
triggerSaveTableSorts([
{
key: tableSorts[0].key,
direction: e.target.value === "asc" ? "asc" : "desc",
},
]);
}}
>
<MenuItem key="asc" value="asc">
<Stack direction="row" gap={1} alignItems="center">
<ArrowUpwardIcon />
<Typography>Sort ascending</Typography>
</Stack>
</MenuItem>
<MenuItem key="desc" value="desc">
<Stack direction="row" gap={1} alignItems="center">
<ArrowDownwardIcon />
<Typography>Sort descending</Typography>
</Stack>
</MenuItem>
</TextField>
</Grid>
<Grid item xs={1} alignSelf="flex-end">
<IconButton
size="small"
onClick={() => setTableSorts([])}
sx={{
"&:hover, &:focus": {
color: "error.main",
backgroundColor: (theme) =>
alpha(
theme.palette.error.main,
theme.palette.action.hoverOpacity * 2
),
},
}}
>
<DeleteIcon />
</IconButton>
</Grid>
</Grid>
)}
</SortPopover>
);
}

View File

@@ -0,0 +1,67 @@
import { useRef, useState } from "react";
import { useAtom } from "jotai";
import { Popover } from "@mui/material";
import ButtonWithStatus from "@src/components/ButtonWithStatus";
import { tableScope, tableSortsAtom } from "@src/atoms/tableScope";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
export interface ISortPopoverProps {
children: (props: { handleClose: () => void }) => React.ReactNode;
}
export default function SortPopover({ children }: ISortPopoverProps) {
const [tableSortPopoverState, setTableSortPopoverState] = useState(false);
const anchorEl = useRef<HTMLButtonElement>(null);
const popoverId = tableSortPopoverState ? "sort-popover" : undefined;
const handleClose = () => setTableSortPopoverState(false);
const [tableSorts] = useAtom(tableSortsAtom, tableScope);
return (
<>
<ButtonWithStatus
ref={anchorEl}
variant="outlined"
color="primary"
onClick={() => setTableSortPopoverState(true)}
active={true}
startIcon={
<ArrowDownwardIcon
sx={{
transition: (theme) =>
theme.transitions.create("transform", {
duration: theme.transitions.duration.short,
}),
transform:
tableSorts[0].direction === "asc" ? "rotate(180deg)" : "none",
}}
/>
}
aria-describedby={popoverId}
>
Sorted: {tableSorts[0].key}
</ButtonWithStatus>
<Popover
id={popoverId}
open={tableSortPopoverState}
anchorEl={anchorEl.current}
onClose={handleClose}
anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
transformOrigin={{ vertical: "top", horizontal: "left" }}
sx={{
"& .MuiPaper-root": { width: 640 },
"& .content": { p: 3 },
}}
>
{children({ handleClose })}
</Popover>
</>
);
}

View File

@@ -0,0 +1,2 @@
export * from "./Sort";
export { default } from "./Sort";

View File

@@ -32,11 +32,15 @@ import {
tableSettingsAtom,
tableSchemaAtom,
tableModalAtom,
tableSortsAtom,
} from "@src/atoms/tableScope";
import { FieldType } from "@src/constants/fields";
import { TableToolsType } from "@src/types/table";
import FilterIcon from "@mui/icons-material/FilterList";
// prettier-ignore
const Sort = lazy(() => import("./Sort" /* webpackChunkName: "Filters" */));
// prettier-ignore
const Filters = lazy(() => import("./Filters" /* webpackChunkName: "Filters" */));
// prettier-ignore
@@ -62,6 +66,7 @@ export default function TableToolbar({
const [tableSettings] = useAtom(tableSettingsAtom, tableScope);
const [tableSchema] = useAtom(tableSchemaAtom, tableScope);
const openTableModal = useSetAtom(tableModalAtom, tableScope);
const [tableSorts] = useAtom(tableSortsAtom, tableScope);
const hasDerivatives =
Object.values(tableSchema.columns ?? {}).filter(
(column) => column.type === FieldType.derivative
@@ -116,6 +121,11 @@ export default function TableToolbar({
<Filters />
</Suspense>
)}
{tableSorts.length > 0 && tableSettings.isCollection !== false && (
<Suspense fallback={<ButtonSkeleton />}>
<Sort />
</Suspense>
)}
<div /> {/* Spacer */}
<LoadedRowsStatus />
<div style={{ flexGrow: 1, minWidth: 64 }} />
@@ -134,22 +144,20 @@ export default function TableToolbar({
</Suspense>
)
)}
{(!projectSettings.exporterRoles ||
projectSettings.exporterRoles.length === 0 ||
userRoles.some((role) =>
projectSettings.exporterRoles?.includes(role)
)) && (
<Suspense fallback={<ButtonSkeleton />}>
<TableToolbarButton
title="Export/Download"
onClick={() => openTableModal("export")}
icon={<ExportIcon />}
disabled={disabledTools.includes("export")}
/>
<Suspense fallback={<ButtonSkeleton />}>
<TableToolbarButton
title="Export/Download"
onClick={() => openTableModal("export")}
icon={<ExportIcon />}
disabled={disabledTools.includes("export")}
/>
</Suspense>
)}
{userRoles.includes("ADMIN") && (
<>
<div /> {/* Spacer */}