fix: search school
This commit is contained in:
parent
f1efaabf97
commit
ce180706d0
@ -6,6 +6,7 @@ import {
|
|||||||
flip,
|
flip,
|
||||||
offset,
|
offset,
|
||||||
shift,
|
shift,
|
||||||
|
size,
|
||||||
useDismiss,
|
useDismiss,
|
||||||
useFloating,
|
useFloating,
|
||||||
useFocus,
|
useFocus,
|
||||||
@ -27,6 +28,7 @@ export type PortalToFollowElemOptions = {
|
|||||||
open?: boolean
|
open?: boolean
|
||||||
offset?: number | OffsetOptions
|
offset?: number | OffsetOptions
|
||||||
onOpenChange?: (open: boolean) => void
|
onOpenChange?: (open: boolean) => void
|
||||||
|
triggerPopupSameWidth?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePortalToFollowElem({
|
export function usePortalToFollowElem({
|
||||||
@ -34,6 +36,7 @@ export function usePortalToFollowElem({
|
|||||||
open,
|
open,
|
||||||
offset: offsetValue = 0,
|
offset: offsetValue = 0,
|
||||||
onOpenChange: setControlledOpen,
|
onOpenChange: setControlledOpen,
|
||||||
|
triggerPopupSameWidth,
|
||||||
}: PortalToFollowElemOptions = {}) {
|
}: PortalToFollowElemOptions = {}) {
|
||||||
const setOpen = setControlledOpen
|
const setOpen = setControlledOpen
|
||||||
|
|
||||||
@ -50,6 +53,12 @@ export function usePortalToFollowElem({
|
|||||||
padding: 5,
|
padding: 5,
|
||||||
}),
|
}),
|
||||||
shift({ padding: 5 }),
|
shift({ padding: 5 }),
|
||||||
|
size({
|
||||||
|
apply({ rects, elements }) {
|
||||||
|
if (triggerPopupSameWidth)
|
||||||
|
elements.floating.style.width = `${rects.reference.width}px`
|
||||||
|
},
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -10,15 +10,16 @@ export const useEducation = () => {
|
|||||||
const {
|
const {
|
||||||
mutateAsync,
|
mutateAsync,
|
||||||
isPending,
|
isPending,
|
||||||
|
data,
|
||||||
} = useEducationAutocomplete()
|
} = useEducationAutocomplete()
|
||||||
|
|
||||||
const [prevSchools, setPrevSchools] = useState<string[]>([])
|
const [prevSchools, setPrevSchools] = useState<string[]>([])
|
||||||
const handleUpdateSchools = useCallback((searchParams: SearchParams) => {
|
const handleUpdateSchools = useCallback((searchParams: SearchParams) => {
|
||||||
if (searchParams.keywords) {
|
if (searchParams.keywords) {
|
||||||
mutateAsync(searchParams).then((res) => {
|
mutateAsync(searchParams).then((res) => {
|
||||||
const currentPage = searchParams.page || 1
|
const currentPage = searchParams.page || 0
|
||||||
const resSchools = res.data
|
const resSchools = res.data
|
||||||
if (currentPage > 1)
|
if (currentPage > 0)
|
||||||
setPrevSchools(prevSchools => [...(prevSchools || []), ...resSchools])
|
setPrevSchools(prevSchools => [...(prevSchools || []), ...resSchools])
|
||||||
else
|
else
|
||||||
setPrevSchools(resSchools)
|
setPrevSchools(resSchools)
|
||||||
@ -29,12 +30,15 @@ export const useEducation = () => {
|
|||||||
const { run: querySchoolsWithDebounced } = useDebounceFn((searchParams: SearchParams) => {
|
const { run: querySchoolsWithDebounced } = useDebounceFn((searchParams: SearchParams) => {
|
||||||
handleUpdateSchools(searchParams)
|
handleUpdateSchools(searchParams)
|
||||||
}, {
|
}, {
|
||||||
wait: 1000,
|
wait: 300,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
schools: prevSchools,
|
schools: prevSchools,
|
||||||
|
setSchools: setPrevSchools,
|
||||||
querySchoolsWithDebounced,
|
querySchoolsWithDebounced,
|
||||||
|
handleUpdateSchools,
|
||||||
isLoading: isPending,
|
isLoading: isPending,
|
||||||
|
hasNext: data?.has_next,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useDebounceFn } from 'ahooks'
|
|
||||||
import { useEducation } from './hooks'
|
import { useEducation } from './hooks'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
import {
|
import {
|
||||||
@ -25,29 +24,53 @@ const SearchInput = ({
|
|||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const {
|
const {
|
||||||
schools,
|
schools,
|
||||||
isLoading,
|
setSchools,
|
||||||
querySchoolsWithDebounced,
|
querySchoolsWithDebounced,
|
||||||
|
handleUpdateSchools,
|
||||||
|
hasNext,
|
||||||
} = useEducation()
|
} = useEducation()
|
||||||
|
const pageRef = useRef(0)
|
||||||
|
const valueRef = useRef(value)
|
||||||
|
|
||||||
const {
|
const handleSearch = useCallback((debounced?: boolean) => {
|
||||||
run: handleSearch,
|
const keywords = valueRef.current
|
||||||
} = useDebounceFn(() => {
|
const page = pageRef.current
|
||||||
querySchoolsWithDebounced({
|
if (debounced) {
|
||||||
keywords: value,
|
querySchoolsWithDebounced({
|
||||||
page: 1,
|
keywords,
|
||||||
|
page,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handleUpdateSchools({
|
||||||
|
keywords,
|
||||||
|
page,
|
||||||
})
|
})
|
||||||
}, {
|
}, [querySchoolsWithDebounced, handleUpdateSchools])
|
||||||
wait: 300,
|
|
||||||
})
|
|
||||||
const handleValueChange = useCallback((e: { target: { value: string } }) => {
|
|
||||||
onChange(e.target.value)
|
|
||||||
handleSearch()
|
|
||||||
}, [handleSearch, onChange])
|
|
||||||
|
|
||||||
useEffect(() => {
|
const handleValueChange = useCallback((e: any) => {
|
||||||
if (!isLoading && !open && schools.length)
|
setOpen(true)
|
||||||
setOpen(true)
|
setSchools([])
|
||||||
}, [isLoading, open, schools])
|
pageRef.current = 0
|
||||||
|
const inputValue = e.target.value
|
||||||
|
valueRef.current = inputValue
|
||||||
|
onChange(inputValue)
|
||||||
|
handleSearch(true)
|
||||||
|
}, [onChange, handleSearch, setSchools])
|
||||||
|
|
||||||
|
const handleScroll = useCallback((e: Event) => {
|
||||||
|
const target = e.target as HTMLDivElement
|
||||||
|
const {
|
||||||
|
scrollTop,
|
||||||
|
scrollHeight,
|
||||||
|
clientHeight,
|
||||||
|
} = target
|
||||||
|
if (scrollTop + clientHeight >= scrollHeight - 5 && scrollTop > 0 && hasNext) {
|
||||||
|
pageRef.current += 1
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
}, [handleSearch, hasNext])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PortalToFollowElem
|
<PortalToFollowElem
|
||||||
@ -55,6 +78,7 @@ const SearchInput = ({
|
|||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
placement='bottom'
|
placement='bottom'
|
||||||
offset={4}
|
offset={4}
|
||||||
|
triggerPopupSameWidth
|
||||||
>
|
>
|
||||||
<PortalToFollowElemTrigger className='block w-full'>
|
<PortalToFollowElemTrigger className='block w-full'>
|
||||||
<Input
|
<Input
|
||||||
@ -64,20 +88,31 @@ const SearchInput = ({
|
|||||||
onChange={handleValueChange}
|
onChange={handleValueChange}
|
||||||
/>
|
/>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
<PortalToFollowElemContent>
|
<PortalToFollowElemContent className='z-10'>
|
||||||
<div className='p-1 border-[0.5px] border-components-panel-border bg-components-panel-bg-blur rounded-xl'>
|
{
|
||||||
{
|
!!schools.length && value && (
|
||||||
schools.map((school, index) => (
|
<div
|
||||||
<div
|
className='p-1 max-h-[330px] overflow-y-auto border-[0.5px] border-components-panel-border bg-components-panel-bg-blur rounded-xl'
|
||||||
key={index}
|
onScroll={handleScroll as any}
|
||||||
className='flex items-center px-2 py-1.5 h-8 system-md-regular text-text-secondary truncate'
|
>
|
||||||
title={school}
|
{
|
||||||
>
|
schools.map((school, index) => (
|
||||||
{school}
|
<div
|
||||||
</div>
|
key={index}
|
||||||
))
|
className='flex items-center px-2 py-1.5 h-8 system-md-regular text-text-secondary truncate cursor-pointer hover:bg-state-base-hover rounded-lg'
|
||||||
}
|
title={school}
|
||||||
</div>
|
onClick={() => {
|
||||||
|
onChange(school)
|
||||||
|
setOpen(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{school}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
</PortalToFollowElemContent>
|
</PortalToFollowElemContent>
|
||||||
</PortalToFollowElem>
|
</PortalToFollowElem>
|
||||||
)
|
)
|
||||||
|
@ -44,8 +44,8 @@ export const useEducationAutocomplete = () => {
|
|||||||
mutationFn: (searchParams: SearchParams) => {
|
mutationFn: (searchParams: SearchParams) => {
|
||||||
const {
|
const {
|
||||||
keywords = '',
|
keywords = '',
|
||||||
page = 1,
|
page = 0,
|
||||||
limit = 20,
|
limit = 40,
|
||||||
} = searchParams
|
} = searchParams
|
||||||
return get<{ data: string[]; has_next: boolean; curr_page: number }>(`/account/education/autocomplete?keywords=${keywords}&page=${page}&limit=${limit}`)
|
return get<{ data: string[]; has_next: boolean; curr_page: number }>(`/account/education/autocomplete?keywords=${keywords}&page=${page}&limit=${limit}`)
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user