diff options
Diffstat (limited to 'packages/exchange-backoffice-ui/src/forms/InputArray.tsx')
-rw-r--r-- | packages/exchange-backoffice-ui/src/forms/InputArray.tsx | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/packages/exchange-backoffice-ui/src/forms/InputArray.tsx b/packages/exchange-backoffice-ui/src/forms/InputArray.tsx new file mode 100644 index 000000000..f60ed4160 --- /dev/null +++ b/packages/exchange-backoffice-ui/src/forms/InputArray.tsx @@ -0,0 +1,166 @@ +import { Fragment, VNode, h } from "preact"; +import { useEffect, useState } from "preact/hooks"; +import { FormProvider } from "./FormProvider.js"; +import { LabelWithTooltipMaybeRequired, UIFormProps } from "./InputLine.js"; +import { RenderAllFieldsByUiConfig, UIFormField } from "./forms.js"; +import { useField } from "./useField.js"; + +export function InputArray( + props: { + fields: UIFormField[]; + labelField: string; + } & UIFormProps<Array<{}>>, +): VNode { + const { fields, labelField, name, label, required, tooltip } = props; + const { value, onChange } = useField<{ [s: string]: Array<any> }>(name); + const list = value ?? []; + const [selectedIndex, setSelected] = useState<number | undefined>(undefined); + const selected = + selectedIndex === undefined ? undefined : list[selectedIndex]; + const formState = useState(selected ?? {}); + useEffect(() => { + const [, update] = formState; + update(selected); + }, [selected]); + return ( + <div class="sm:col-span-6"> + <LabelWithTooltipMaybeRequired + label={label} + required={required} + tooltip={tooltip} + /> + + <div class="flex mb-4 items-center pt-3"> + <div class="flex-auto"> + {selectedIndex !== undefined && ( + <button + type="button" + onClick={() => { + setSelected(undefined); + }} + class="block rounded-md bg-white px-3 py-2 text-center text-sm font-semibold shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50" + > + Cancel + </button> + )} + </div> + <div class="flex-none"> + {selectedIndex === undefined && ( + <button + type="button" + onClick={() => { + setSelected(list.length); + }} + class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-indigo-500 " + > + Add + </button> + )} + </div> + </div> + <div class="-space-y-px rounded-md bg-white "> + {list.map((v, idx) => { + const isFirst = idx === 0; + const isLast = idx === list.length - 1; + const isSelected = selectedIndex === idx; + const disabled = selectedIndex !== undefined && !isSelected; + let clazz = + "relative flex border p-4 focus:outline-none disabled:text-grey"; + if (isFirst) { + clazz += " rounded-tl-md rounded-tr-md "; + } + if (isLast) { + clazz += " rounded-bl-md rounded-br-md "; + } + if (isSelected) { + clazz += " z-10 border-indigo-200 bg-indigo-50 "; + } else { + clazz += " border-gray-200"; + } + if (disabled) { + clazz += + " cursor-not-allowed bg-gray-50 text-gray-500 ring-gray-200 text-gray"; + } else { + clazz += " cursor-pointer"; + } + return ( + <label class={clazz}> + <Fragment> + <input + type="radio" + name="privacy-setting" + checked={isSelected} + disabled={disabled} + onClick={() => setSelected(idx)} + class="mt-0.5 h-4 w-4 shrink-0 text-indigo-600 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500 disabled:ring-gray-200 focus:ring-indigo-600" + aria-labelledby="privacy-setting-0-label" + aria-describedby="privacy-setting-0-description" + /> + <span class="ml-3 flex flex-col"> + <span + id="privacy-setting-0-label" + disabled + class="block text-sm font-medium" + > + {v[labelField]} + </span> + {/* <!-- Checked: "text-indigo-700", Not Checked: "text-gray-500" --> */} + {/* <span + id="privacy-setting-0-description" + class="block text-sm" + > + This project would be available to anyone who has the link + </span> */} + </span> + </Fragment> + </label> + ); + })} + </div> + {selectedIndex !== undefined && ( + <FormProvider state={formState}> + <div class="px-4 py-6"> + <div class="grid grid-cols-1 gap-y-8 "> + <RenderAllFieldsByUiConfig fields={fields} /> + </div> + </div> + </FormProvider> + )} + {selectedIndex !== undefined && ( + <div class="flex items-center pt-3"> + <div class="flex-auto"> + {selected !== undefined && ( + <button + type="button" + onClick={() => { + const newValue = [...list]; + newValue.splice(selectedIndex, 1); + onChange(newValue); + setSelected(undefined); + }} + class="block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 " + > + Remove + </button> + )} + </div> + <div class="flex-none"> + <button + type="button" + onClick={() => { + const newValue = [...list]; + const [confirmed] = formState; + newValue.splice(selectedIndex, 1, confirmed); + onChange(newValue); + setSelected(undefined); + }} + class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-indigo-500 " + > + Confirm + </button> + </div> + </div> + )} + </div> + ); +} |