import { styled } from "@mui/joy"; import { Fragment, FunctionComponent, ReactElement, useCallback } from "react"; import { ChevronDownIcon, ChevronUpIcon, PlusIcon } from "@heroicons/react/outline"; import Record, { IFieldType } from "./Record"; import { useFormikContext } from "formik"; import lodash from "lodash"; import IconButton from "@mui/joy/IconButton"; import { useAccordionState } from "../hooks"; import { useParams } from "react-router-dom"; export interface IRecordsProps { collapsible?: boolean; defaultOpen?: boolean; title: string; name: string; fields: (index: number) => IFieldType[]; newValue: any; renderLayout?: (elements: ReactElement[]) => ReactElement; renderField?: (element: ReactElement, field: IFieldType) => ReactElement; renderRemove?: (element: ReactElement) => ReactElement; renderBorder?: () => ReactElement; } interface IGroupProps { empty: boolean; } const Group = styled("div", { shouldForwardProp: (propName) => propName !== "empty" })` display: flex; flex-direction: column; align-items: ${({ empty }) => (empty ? "center" : "flex-end")}; row-gap: ${({ theme }) => theme.spacing(1)}; width: 100%; @media (max-width: 640px) { row-gap: 0; } `; const GroupTitle = styled("h5")` font-size: 0.85rem; color: #374151; font-weight: 700; width: 100%; text-align: left; `; const RecordList = styled("div")` display: flex; flex-direction: column; justify-content: center; align-items: center; row-gap: ${({ theme }) => theme.spacing(1)}; margin-top: ${({ theme }) => theme.spacing(1)}; width: 100%; `; const AddButton = styled(IconButton)` border-radius: ${({ theme }) => theme.spacing(2)}; `; const Description = styled("p")` margin-top: ${({ theme }) => theme.spacing(1)}; text-align: center; color: #7a7a7a; font-size: 14px; 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 = ( props: IRecordsProps ): ReactElement => { const { collapsible = true, defaultOpen = false, title, name, fields, newValue, renderLayout, renderField, renderRemove, renderBorder } = props; const formik = useFormikContext(); const items = lodash.get(formik.values, name); const { uuid } = useParams<{ uuid: string }>(); const id = `${uuid}.${name}`; const { open, toggle } = useAccordionState(id, defaultOpen); const handleNew = useCallback(() => { formik.setFieldValue(`${name}[${items.length}]`, newValue); }, [formik]); const handleRemove = useCallback( (index: number) => { const newOptions = items.filter( (_: unknown, currentIndex: number) => currentIndex != index ); formik.setFieldValue(name, newOptions); }, [formik] ); if (!items) { throw new Error(`"${name}" is falsy.`); } if (!Array.isArray(items)) { throw new Error(`Expected "${name}" to be an array.`); } const empty = items && items.length === 0; return ( {title && {title}} {collapsible && ( {open && } {!open && } )} {(!collapsible || open) && !empty && ( {items.map((_: unknown, index: number) => ( {renderBorder && renderBorder()} ))} )} {(!collapsible || open) && empty && ( No items available )} {(!collapsible || open) && ( )} ); }; export default Records;