feat(frontend): updated `Records` to be collapsible

pull/85/head
Samuel Rowe 3 years ago
parent 968c1ac9bc
commit 064123c013

@ -1,6 +1,16 @@
import { styled } from "@mui/joy"; import { styled } from "@mui/joy";
import { Fragment, FunctionComponent, ReactElement, useCallback } from "react"; import {
import { PlusIcon } from "@heroicons/react/outline"; Fragment,
FunctionComponent,
ReactElement,
useCallback,
useState
} from "react";
import {
ChevronDownIcon,
ChevronUpIcon,
PlusIcon
} from "@heroicons/react/outline";
import Record, { IFieldType } from "./Record"; import Record, { IFieldType } from "./Record";
import { useFormikContext } from "formik"; import { useFormikContext } from "formik";
import lodash from "lodash"; import lodash from "lodash";
@ -29,6 +39,7 @@ const Group = styled("div", {
flex-direction: column; flex-direction: column;
align-items: ${({ empty }) => (empty ? "center" : "flex-end")}; align-items: ${({ empty }) => (empty ? "center" : "flex-end")};
row-gap: ${({ theme }) => theme.spacing(1)}; row-gap: ${({ theme }) => theme.spacing(1)};
width: 100%;
`; `;
const GroupTitle = styled("h5")` const GroupTitle = styled("h5")`
@ -62,6 +73,23 @@ const Description = styled("p")`
width: 100%; width: 100%;
`; `;
const Top = styled("div")`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
&:hover {
cursor: pointer;
user-select: none;
}
`;
const ExpandButton = styled(IconButton)`
border-radius: ${({ theme }) => theme.spacing(2)};
`;
const Records: FunctionComponent<IRecordsProps> = ( const Records: FunctionComponent<IRecordsProps> = (
props: IRecordsProps props: IRecordsProps
): ReactElement => { ): ReactElement => {
@ -77,12 +105,14 @@ const Records: FunctionComponent<IRecordsProps> = (
renderBorder renderBorder
} = props; } = props;
const [open, setOpen] = useState(false);
const formik = useFormikContext(); const formik = useFormikContext();
const items = lodash.get(formik.values, name); const items = lodash.get(formik.values, name);
if (!items) { const handleToggle = useCallback(() => {
throw new Error(`"${name}" is falsy.`); setOpen((open) => !open);
} }, []);
const handleNew = useCallback(() => { const handleNew = useCallback(() => {
formik.setFieldValue(`${name}[${items.length}]`, newValue); formik.setFieldValue(`${name}[${items.length}]`, newValue);
@ -98,12 +128,22 @@ const Records: FunctionComponent<IRecordsProps> = (
[formik] [formik]
); );
if (!items) {
throw new Error(`"${name}" is falsy.`);
}
const empty = items && items.length === 0; const empty = items && items.length === 0;
return ( return (
<Group empty={empty}> <Group empty={empty}>
<GroupTitle>{title}</GroupTitle> <Top onClick={handleToggle}>
{!empty && ( <GroupTitle>{title}</GroupTitle>
<ExpandButton size="sm" variant="plain">
{open && <ChevronUpIcon className="h-5 w-5" />}
{!open && <ChevronDownIcon className="h-5 w-5" />}
</ExpandButton>
</Top>
{open && !empty && (
<RecordList> <RecordList>
{items.map((_: unknown, index: number) => ( {items.map((_: unknown, index: number) => (
<Fragment key={index}> <Fragment key={index}>
@ -121,11 +161,13 @@ const Records: FunctionComponent<IRecordsProps> = (
</RecordList> </RecordList>
)} )}
{empty && <Description>No items available</Description>} {open && empty && <Description>No items available</Description>}
<AddButton size="sm" variant="soft" onClick={handleNew}> {open && (
<PlusIcon className="h-4 w-4" /> <AddButton size="sm" variant="soft" onClick={handleNew}>
</AddButton> <PlusIcon className="h-4 w-4" />
</AddButton>
)}
</Group> </Group>
); );
}; };

Loading…
Cancel
Save