Skip to content

Commit

Permalink
feat: add loadData functionality to QueryItem Cascader
Browse files Browse the repository at this point in the history
  • Loading branch information
ZoeAstra committed May 8, 2024
1 parent 098b81b commit ced4994
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 12 deletions.
12 changes: 11 additions & 1 deletion src/components/data-entry/QueryItem/Cascader.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const Icon: Story = {
args: {
placeholder: "QueryItem.ValueSelector.Cascader Icon",
options: exampleOptions,
icon: 'events',
icon: 'event',
},
}

Expand All @@ -127,3 +127,13 @@ export const PreSelectedValue: Story = {
onChange: async (values, _) => {console.log(values)},
},
}

export const LoadData: Story = {
args: {
placeholder: 'QueryItem.ValueSelector.Cascader Load',
options: exampleOptions,
loadData: (value: string) => {
console.log(value)
},
},
}
51 changes: 40 additions & 11 deletions src/components/data-entry/QueryItem/Cascader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './query-item.css'
import { GetProp } from 'antd'
import { ReactNode, useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import {
Cascader as BaseCascader,
Flex,
Expand All @@ -10,43 +10,58 @@ import {
Icon,
} from 'src/components'
import { Icons } from 'src/constants/Icons'
import { debounce } from 'src/utils/utils'

export interface CascaderOption {
export interface ICascaderOption {
value: string
label: string
children?: CascaderOption[]
children?: ICascaderOption[]
disabled?: boolean
}

export interface ICascaderProps {
options: CascaderOption[]
icon?: keyof Pick<typeof Icons, ("empty" | "events" | "userAttributes" | "eventAttribute")>
options: ICascaderOption[]
icon?: keyof Pick<typeof Icons, ("empty" | "event" | "userAttribute" | "eventAttribute")>
errorMessage?: string
placeholder?: string
onChange?: (values: (number | string)[], selectedOptions: any) => Promise<void>
loadData?: (value: string) => void
value?: (number | string)[]
}

export const Cascader = (props: ICascaderProps) => {
type DefaultOptionType = GetProp<IBaseCascaderProps, 'options'>[number]

const options: CascaderOption[] = []
const options: ICascaderOption[] = []
const [items, setItems] = useState(props.options ?? options)
const [searchValue, setSearchValue] = useState('')
const [selectedValue, setSelectedValue] = useState<(number | string)[]>(props.value ?? [])
const [selectedDisplayValue, setSelectedDisplayValue] = useState("")
const [selectedDisplayValue, setSelectedDisplayValue] = useState(props.value ? (props.value.slice(-1)[0] as any).label : "")
const [isOpen, setIsOpen] = useState(false)

useEffect(() => {
setItems(props.options)
}, [props.options])

const onSearch = (value: string) => {
const onSearch = ({ target: { value: value}}: { target: { value: string}}) => {
if (debouncedLoadData) {
if (value.length > 3) {
if (transformOptionsToPaths(items,[]).filter((path) => filter(value, path)).length == 0) {
debouncedLoadData(value)
}
}
}
setSearchValue(value)
}

const filter = (inputValue: string, path: DefaultOptionType[]) =>
path.some(option => (option.label as string).toLowerCase().indexOf(inputValue.toLowerCase()) > -1)
const filter = (inputValue: string, path: DefaultOptionType[]) => {
return path.some(option => (option.label as string).toLowerCase().indexOf(inputValue.toLowerCase()) > -1)
}

let debouncedLoadData: (value: string) => void;
if (props.loadData) {
debouncedLoadData = useCallback(debounce(props.loadData, 500),[])
}

const baseProps: IBaseCascaderProps = {
getPopupContainer: triggerNode => triggerNode.parentElement,
Expand All @@ -61,7 +76,7 @@ export const Cascader = (props: ICascaderProps) => {
},
dropdownRender: menu => (
<div className={'query-item__dropdown'}>
<Input.Search allowClear className={'query-item__input-search'} placeholder="Search" onSearch={onSearch} />
<Input.Search allowClear className={'query-item__input-search'} placeholder="Search" onChange={onSearch} />
<Flex justify="center">{menu}</Flex>
</div>
),
Expand Down Expand Up @@ -90,4 +105,18 @@ export const Cascader = (props: ICascaderProps) => {
{props.errorMessage && <Typography.Text type={'danger'}>{props.errorMessage}</Typography.Text>}
</>
)

function transformOptionsToPaths(options: DefaultOptionType[], prefixPath: DefaultOptionType[]): DefaultOptionType[][] {
let result: DefaultOptionType[][] = [];
options.forEach((option) => {
if (option.children && option.children.length > 0) {
const newPrefix = prefixPath.concat([{label: option.label, value: option.value}]);
result = result.concat(transformOptionsToPaths(option.children, newPrefix));
} else {
const path = prefixPath.concat([{label: option.label, value: option.value}]);
result.push(path);
}
})
return result;
}
}

0 comments on commit ced4994

Please sign in to comment.