feat(frontend): added new capabilities to `Record` component

* Added `records` type and extended `options` to accept `IRecordProps`.
 * Added `renderLayout`, `renderField`, and `renderRemove` props.
pull/78/head
Samuel Rowe 3 years ago
parent f42461cf26
commit cbeea12114

@ -1,25 +1,38 @@
import { Fragment, FunctionComponent, ReactElement, useCallback } from "react"; import {
Fragment,
FunctionComponent,
ReactElement,
useCallback,
useMemo
} from "react";
import { styled } from "@mui/joy"; import { styled } from "@mui/joy";
import IconButton from "@mui/joy/IconButton"; import IconButton from "@mui/joy/IconButton";
import { MinusSmIcon } from "@heroicons/react/solid"; import { MinusSmIcon } from "@heroicons/react/solid";
import TextField from "./global/FormElements/TextField"; import TextField from "./global/FormElements/TextField";
import Toggle from "./global/FormElements/Toggle"; import Toggle from "./global/FormElements/Toggle";
import Records, { IRecordsProps } from "./Records";
export interface IFieldType { export interface IFieldType {
name: string; name: string;
placeholder: string; placeholder?: string;
required?: boolean; required?: boolean;
type: "text" | "toggle"; type: "text" | "toggle" | "records";
options?: { options?:
| {
text: string; text: string;
value: string; value: string;
}[]; }[]
| IRecordsProps;
} }
export interface IRecordProps { export interface IRecordProps {
fields: IFieldType[]; fields: IFieldType[];
index: number; index: number;
onRemove: (index: number) => void; onRemove: (index: number) => void;
direction?: "column" | "row";
renderLayout?: (elements: ReactElement[]) => ReactElement;
renderField?: (element: ReactElement, field: IFieldType) => ReactElement;
renderRemove?: (element: ReactElement) => ReactElement;
} }
const Root = styled("div")` const Root = styled("div")`
@ -28,6 +41,8 @@ const Root = styled("div")`
justify-content: flex-start; justify-content: flex-start;
align-items: flex-start; align-items: flex-start;
column-gap: ${({ theme }) => theme.spacing(2)}; column-gap: ${({ theme }) => theme.spacing(2)};
width: 100%;
@media (max-width: 768px) { @media (max-width: 768px) {
column-gap: ${({ theme }) => theme.spacing(1)}; column-gap: ${({ theme }) => theme.spacing(1)};
} }
@ -38,29 +53,65 @@ const RemoveButton = styled(IconButton)``;
const Record: FunctionComponent<IRecordProps> = ( const Record: FunctionComponent<IRecordProps> = (
props: IRecordProps props: IRecordProps
): ReactElement => { ): ReactElement => {
const { fields, index, onRemove } = props; const { fields, index, onRemove, renderLayout, renderField, renderRemove } =
props;
const handleRemove = useCallback(() => { const handleRemove = useCallback(() => {
onRemove(index); onRemove(index);
}, [index, onRemove]); }, [index, onRemove]);
const renderLayoutWrapper = useMemo(
() => renderLayout || ((elements: ReactElement[]) => <>{elements}</>),
[renderLayout]
);
const renderFieldWrapper = useMemo(
() => renderField || ((element: ReactElement) => element),
[renderField]
);
const renderRemoveWrapper = useMemo(
() => renderRemove || ((element: ReactElement) => element),
[renderRemove]
);
return ( return (
<Root> <Root>
{fields.map(({ type, name, placeholder, required, options }) => ( {renderLayoutWrapper(
<Fragment key={name}> fields.map((field) => (
{type === "text" && ( <Fragment key={field.name}>
{renderFieldWrapper(
<>
{field.type === "text" && (
<TextField <TextField
id={name} id={field.name}
name={name} name={field.name}
placeholder={placeholder + (required ? "*" : "")} placeholder={
required={required} field.placeholder && !(field as any).label
? field.placeholder + (field.required ? "*" : "")
: ""
}
label={(field as any).label}
required={field.required}
/>
)}
{field.type === "toggle" && (
<Toggle
name={field.name}
label={field.placeholder || ""}
options={(field.options as any) || []}
/> />
)} )}
{type === "toggle" && ( {field.type === "records" && (
<Toggle name={name} label={placeholder} options={options || []} /> <Records {...(field.options as any)} />
)}
</>,
field
)} )}
</Fragment> </Fragment>
))} ))
)}
{renderRemoveWrapper(
<RemoveButton <RemoveButton
variant="soft" variant="soft"
size="sm" size="sm"
@ -69,6 +120,7 @@ const Record: FunctionComponent<IRecordProps> = (
> >
<MinusSmIcon className="h-5 w-5" /> <MinusSmIcon className="h-5 w-5" />
</RemoveButton> </RemoveButton>
)}
</Root> </Root>
); );
}; };

Loading…
Cancel
Save