From fadaaf0b592efa5a19ec414cae1c575ef0042901 Mon Sep 17 00:00:00 2001 From: Ayobami Akingbade Date: Mon, 1 Jul 2024 14:05:28 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(select):=20implement=20select?= =?UTF-8?q?=20async?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/app/form/input/search.tsx | 5 ++-- .../app/form/input/select-async.tsx | 22 +++++++++----- src/components/app/form/input/select.tsx | 11 +++---- .../app/table/filters/Date/index.tsx | 1 - src/components/ui/select.tsx | 30 +++++++++++++++---- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/components/app/form/input/search.tsx b/src/components/app/form/input/search.tsx index 39e9ffde..6959ff83 100644 --- a/src/components/app/form/input/search.tsx +++ b/src/components/app/form/input/search.tsx @@ -7,12 +7,13 @@ import { Input } from "@/components/ui/input"; interface IProps { onChange: (value: string) => void; loading?: boolean; + initialValue?: string; } -export function FormSearch({ onChange, loading }: IProps) { +export function FormSearch({ onChange, loading, initialValue }: IProps) { const { _ } = useLingui(); - const [value, setValue] = useState(""); + const [value, setValue] = useState(initialValue || ""); return (
diff --git a/src/components/app/form/input/select-async.tsx b/src/components/app/form/input/select-async.tsx index 2a782b0d..ad98d04e 100644 --- a/src/components/app/form/input/select-async.tsx +++ b/src/components/app/form/input/select-async.tsx @@ -34,7 +34,7 @@ export function AsyncFormSelect(props: IProps) { const currentLabelFromSelection = useMemo(() => { const isValueInFirstDataLoad = fullData.data.find( - ({ value }: ISelectData) => value === input.value + ({ value }: ISelectData) => String(value) === String(input.value) ); if (isValueInFirstDataLoad) { @@ -42,7 +42,7 @@ export function AsyncFormSelect(props: IProps) { } const isValueInSelectionOptions = selectOptions.data.find( - ({ value }: ISelectData) => value === input.value + ({ value }: ISelectData) => String(value) === String(input.value) ); if (isValueInSelectionOptions) { @@ -50,11 +50,14 @@ export function AsyncFormSelect(props: IProps) { } return undefined; - }, [url, fullData.isLoading]); + }, [url, fullData, selectOptions, input.value]); const referenceLabel = useApi(referenceUrl?.(input.value), { defaultData: "", - enabled: !!referenceUrl && !!input.value && !currentLabelFromSelection, + enabled: + !!referenceUrl && + !!input.value && + !(currentLabelFromSelection || fullData.isLoading), }); useDebounce( @@ -69,22 +72,25 @@ export function AsyncFormSelect(props: IProps) { return ; } + const isLoading = selectOptions.isLoading || fullData.isLoading; + if (fullData.data.length >= limit) { return ( ); } - return ; + return ( + + ); } diff --git a/src/components/app/form/input/select.tsx b/src/components/app/form/input/select.tsx index 5aa678c7..29a21221 100644 --- a/src/components/app/form/input/select.tsx +++ b/src/components/app/form/input/select.tsx @@ -13,6 +13,7 @@ import { IBaseFormSelect } from "@/frontend/design-system/components/Form/Select interface IFormSelect extends IBaseFormSelect { selectData: ISelectData[]; onSearch?: ISelectProps["onSearch"]; + isLoading?: boolean; } export function FormSelect(formInput: IFormSelect) { @@ -23,7 +24,7 @@ export function FormSelect(formInput: IFormSelect) { disabled, label: formLabel, disabledOptions, - placeholder, + isLoading, onSearch, } = formInput; const { _ } = useLingui(); @@ -34,11 +35,11 @@ export function FormSelect(formInput: IFormSelect) { {...input} {...generateFormArias(meta)} className={generateClassNames(meta)} + isLoading={isLoading} options={selectData} - placeholder={ - placeholder || - fakeMessageDescriptor(`--- ${_(msg`Select ${_(formLabel)}`)} ---`) - } + placeholder={fakeMessageDescriptor( + `--- ${_(msg`Select ${_(formLabel)}`)} ---` + )} disabled={disabled} disabledOptions={disabledOptions} onSearch={onSearch} diff --git a/src/components/app/table/filters/Date/index.tsx b/src/components/app/table/filters/Date/index.tsx index 8da2b836..d0d1cf47 100644 --- a/src/components/app/table/filters/Date/index.tsx +++ b/src/components/app/table/filters/Date/index.tsx @@ -37,7 +37,6 @@ export function FilterTableByDate({ /> {new Date(filterValue?.value || "").toString() !== "Invalid Date" ? ( <> - {/* TODO date not changing */} { setFilter({ diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx index 51d20221..7f9265ff 100644 --- a/src/components/ui/select.tsx +++ b/src/components/ui/select.tsx @@ -10,9 +10,13 @@ import * as SelectPrimitive from "@radix-ui/react-select"; import { useLingui } from "@lingui/react"; import { MessageDescriptor } from "@lingui/core"; +import { Loader } from "react-feather"; +import { msg } from "@lingui/macro"; import { cn } from "@/lib/utils"; import { ISelectData } from "@/shared/types/options"; import { FormSearch } from "../app/form/input/search"; +import { EmptyWrapper } from "../app/empty-wrapper"; +import { ListSkeleton } from "../app/skeleton/list"; const SelectRoot = SelectPrimitive.Root; @@ -20,19 +24,25 @@ const SelectValue = SelectPrimitive.Value; const SelectTrigger = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( + React.ComponentPropsWithoutRef & { + isLoading?: boolean; + } +>(({ className, children, isLoading, ...props }, ref) => ( span]:line-clamp-1", + "flex h-9 w-full items-center justify-between font-normal whitespace-nowrap rounded-md border border-border bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-base data-[placeholder]:text-muted focus:outline-none focus:ring-1 focus:ring-primary disabled:cursor-not-allowed disabled:bg-soft [&>span]:line-clamp-1", className )} {...props} > {children} - + {isLoading ? ( + + ) : ( + + )} )); @@ -160,6 +170,7 @@ export interface ISelectProps { placeholder: MessageDescriptor; disabled?: boolean; disabledOptions?: Array; + isLoading?: boolean; onSearch?: { onChange: (value: string) => void; value: string; @@ -172,6 +183,7 @@ export function Select({ onChange, options, disabled, + isLoading, value, name, placeholder, @@ -181,7 +193,9 @@ export function Select({ }: ISelectProps) { const { _ } = useLingui(); - const valueLabel = options.find((option) => option.value === value)?.label; + const valueLabel = options.find( + (option) => String(option.value) === String(value) + )?.label; return ( @@ -190,6 +204,7 @@ export function Select({ name={name} id={name} disabled={disabled} + isLoading={isLoading} > {onSearch?.valueLabel || (valueLabel ? _(valueLabel) : null)} @@ -199,11 +214,16 @@ export function Select({ {onSearch && (
)} + {onSearch?.value && options.length === 0 && !onSearch?.isLoading && ( + + )} + {onSearch?.isLoading && } {options.map(({ value: value$1, label }) => (