fix
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
import { use, useState, useMemo } from 'react'
|
||||
import {
|
||||
use,
|
||||
useState,
|
||||
useMemo,
|
||||
forwardRef,
|
||||
type InputHTMLAttributes
|
||||
} from 'react'
|
||||
import { useToggle } from 'ahooks'
|
||||
import Fuse from 'fuse.js'
|
||||
import {
|
||||
@@ -32,124 +38,129 @@ import {
|
||||
|
||||
import { type Course } from './data'
|
||||
|
||||
interface CoursePickerProps {
|
||||
interface CoursePickerProps extends Omit<
|
||||
InputHTMLAttributes<HTMLInputElement>,
|
||||
'value' | 'onChange'
|
||||
> {
|
||||
value?: Course
|
||||
options: Promise<{ hits: any[] }>
|
||||
onChange?: (value: any) => void
|
||||
error?: any
|
||||
}
|
||||
|
||||
export function CoursePicker({
|
||||
value,
|
||||
onChange,
|
||||
options,
|
||||
error
|
||||
}: CoursePickerProps) {
|
||||
const { hits } = use(options)
|
||||
const [search, setSearch] = useState<string>('')
|
||||
const [open, { set }] = useToggle()
|
||||
const [sort, { toggle }] = useToggle('a-z', 'z-a')
|
||||
const fuse = useMemo(() => {
|
||||
return new Fuse(hits, {
|
||||
keys: ['name'],
|
||||
threshold: 0.3,
|
||||
includeMatches: true
|
||||
})
|
||||
}, [hits])
|
||||
export const CoursePicker = forwardRef<HTMLInputElement, CoursePickerProps>(
|
||||
({ value, onChange, options, error, ...props }, ref) => {
|
||||
const { hits } = use(options)
|
||||
const [search, setSearch] = useState<string>('')
|
||||
const [open, { set }] = useToggle()
|
||||
const [sort, { toggle }] = useToggle('a-z', 'z-a')
|
||||
const fuse = useMemo(() => {
|
||||
return new Fuse(hits, {
|
||||
keys: ['name'],
|
||||
threshold: 0.3,
|
||||
includeMatches: true
|
||||
})
|
||||
}, [hits])
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
const results = !search ? hits : fuse.search(search).map(({ item }) => item)
|
||||
const filtered = useMemo(() => {
|
||||
const results = !search
|
||||
? hits
|
||||
: fuse.search(search).map(({ item }) => item)
|
||||
|
||||
return results.sort((a, b) => {
|
||||
const comparison = a.name.localeCompare(b.name)
|
||||
return sort === 'a-z' ? comparison : -comparison
|
||||
})
|
||||
}, [search, fuse, hits, sort])
|
||||
return results.sort((a, b) => {
|
||||
const comparison = a.name.localeCompare(b.name)
|
||||
return sort === 'a-z' ? comparison : -comparison
|
||||
})
|
||||
}, [search, fuse, hits, sort])
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={set}>
|
||||
<PopoverTrigger asChild>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
readOnly
|
||||
placeholder="Curso"
|
||||
value={value?.name || ''}
|
||||
aria-invalid={!!error}
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<BookIcon />
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<ChevronsUpDownIcon />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</PopoverTrigger>
|
||||
return (
|
||||
<Popover open={open} onOpenChange={set}>
|
||||
<PopoverTrigger asChild>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
ref={ref}
|
||||
placeholder="Curso"
|
||||
value={value?.name || ''}
|
||||
aria-invalid={!!error}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
<PopoverContent className="lg:w-84 p-0" align="start">
|
||||
<Command shouldFilter={false}>
|
||||
<div className="flex">
|
||||
<div className="flex-1">
|
||||
<CommandInput
|
||||
placeholder="Curso"
|
||||
autoComplete="off"
|
||||
onValueChange={setSearch}
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<BookIcon />
|
||||
</InputGroupAddon>
|
||||
|
||||
<InputGroupAddon align="inline-end">
|
||||
<ChevronsUpDownIcon />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent className="lg:w-84 p-0" align="start">
|
||||
<Command shouldFilter={false}>
|
||||
<div className="flex">
|
||||
<div className="flex-1">
|
||||
<CommandInput
|
||||
placeholder="Curso"
|
||||
autoComplete="off"
|
||||
onValueChange={setSearch}
|
||||
/>
|
||||
</div>
|
||||
<div className="border-b flex items-center justify-end">
|
||||
<Button
|
||||
variant="link"
|
||||
size="icon-sm"
|
||||
tabIndex={-1}
|
||||
className="cursor-pointer text-muted-foreground"
|
||||
onClick={toggle}
|
||||
>
|
||||
{sort == 'a-z' ? <ArrowDownAZIcon /> : <ArrowUpAZIcon />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-b flex items-center justify-end">
|
||||
<Button
|
||||
variant="link"
|
||||
size="icon-sm"
|
||||
tabIndex={-1}
|
||||
className="cursor-pointer text-muted-foreground"
|
||||
onClick={toggle}
|
||||
>
|
||||
{sort == 'a-z' ? <ArrowDownAZIcon /> : <ArrowUpAZIcon />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/* Force rerender to reset the scroll position */}
|
||||
<CommandList key={sort}>
|
||||
<CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{filtered
|
||||
.filter(
|
||||
({ metadata__unit_price = 0 }) => metadata__unit_price > 0
|
||||
)
|
||||
.map(
|
||||
({
|
||||
id,
|
||||
name,
|
||||
access_period,
|
||||
metadata__unit_price: unit_price
|
||||
}) => (
|
||||
<CommandItem
|
||||
key={id}
|
||||
value={id}
|
||||
className="cursor-pointer"
|
||||
onSelect={() => {
|
||||
onChange?.({
|
||||
id,
|
||||
name,
|
||||
access_period: Number(access_period),
|
||||
unit_price: Number(unit_price)
|
||||
})
|
||||
set(false)
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
'ml-auto',
|
||||
value?.id === id ? 'opacity-100' : 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
{/* Force rerender to reset the scroll position */}
|
||||
<CommandList key={sort}>
|
||||
<CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{filtered
|
||||
.filter(
|
||||
({ metadata__unit_price = 0 }) => metadata__unit_price > 0
|
||||
)
|
||||
)}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
.map(
|
||||
({
|
||||
id,
|
||||
name,
|
||||
access_period,
|
||||
metadata__unit_price: unit_price
|
||||
}) => (
|
||||
<CommandItem
|
||||
key={id}
|
||||
value={id}
|
||||
className="cursor-pointer"
|
||||
onSelect={() => {
|
||||
onChange?.({
|
||||
id,
|
||||
name,
|
||||
access_period: Number(access_period),
|
||||
unit_price: Number(unit_price)
|
||||
})
|
||||
set(false)
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
'ml-auto',
|
||||
value?.id === id ? 'opacity-100' : 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
)
|
||||
)}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user