fix: search school

This commit is contained in:
zxhlyh 2025-03-18 15:10:33 +08:00
parent f1efaabf97
commit ce180706d0
4 changed files with 87 additions and 39 deletions

View File

@ -6,6 +6,7 @@ import {
flip,
offset,
shift,
size,
useDismiss,
useFloating,
useFocus,
@ -27,6 +28,7 @@ export type PortalToFollowElemOptions = {
open?: boolean
offset?: number | OffsetOptions
onOpenChange?: (open: boolean) => void
triggerPopupSameWidth?: boolean
}
export function usePortalToFollowElem({
@ -34,6 +36,7 @@ export function usePortalToFollowElem({
open,
offset: offsetValue = 0,
onOpenChange: setControlledOpen,
triggerPopupSameWidth,
}: PortalToFollowElemOptions = {}) {
const setOpen = setControlledOpen
@ -50,6 +53,12 @@ export function usePortalToFollowElem({
padding: 5,
}),
shift({ padding: 5 }),
size({
apply({ rects, elements }) {
if (triggerPopupSameWidth)
elements.floating.style.width = `${rects.reference.width}px`
},
}),
],
})

View File

@ -10,15 +10,16 @@ export const useEducation = () => {
const {
mutateAsync,
isPending,
data,
} = useEducationAutocomplete()
const [prevSchools, setPrevSchools] = useState<string[]>([])
const handleUpdateSchools = useCallback((searchParams: SearchParams) => {
if (searchParams.keywords) {
mutateAsync(searchParams).then((res) => {
const currentPage = searchParams.page || 1
const currentPage = searchParams.page || 0
const resSchools = res.data
if (currentPage > 1)
if (currentPage > 0)
setPrevSchools(prevSchools => [...(prevSchools || []), ...resSchools])
else
setPrevSchools(resSchools)
@ -29,12 +30,15 @@ export const useEducation = () => {
const { run: querySchoolsWithDebounced } = useDebounceFn((searchParams: SearchParams) => {
handleUpdateSchools(searchParams)
}, {
wait: 1000,
wait: 300,
})
return {
schools: prevSchools,
setSchools: setPrevSchools,
querySchoolsWithDebounced,
handleUpdateSchools,
isLoading: isPending,
hasNext: data?.has_next,
}
}

View File

@ -1,10 +1,9 @@
import {
useCallback,
useEffect,
useRef,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
import { useDebounceFn } from 'ahooks'
import { useEducation } from './hooks'
import Input from '@/app/components/base/input'
import {
@ -25,29 +24,53 @@ const SearchInput = ({
const [open, setOpen] = useState(false)
const {
schools,
isLoading,
setSchools,
querySchoolsWithDebounced,
handleUpdateSchools,
hasNext,
} = useEducation()
const pageRef = useRef(0)
const valueRef = useRef(value)
const {
run: handleSearch,
} = useDebounceFn(() => {
querySchoolsWithDebounced({
keywords: value,
page: 1,
const handleSearch = useCallback((debounced?: boolean) => {
const keywords = valueRef.current
const page = pageRef.current
if (debounced) {
querySchoolsWithDebounced({
keywords,
page,
})
return
}
handleUpdateSchools({
keywords,
page,
})
}, {
wait: 300,
})
const handleValueChange = useCallback((e: { target: { value: string } }) => {
onChange(e.target.value)
handleSearch()
}, [handleSearch, onChange])
}, [querySchoolsWithDebounced, handleUpdateSchools])
useEffect(() => {
if (!isLoading && !open && schools.length)
setOpen(true)
}, [isLoading, open, schools])
const handleValueChange = useCallback((e: any) => {
setOpen(true)
setSchools([])
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 (
<PortalToFollowElem
@ -55,6 +78,7 @@ const SearchInput = ({
onOpenChange={setOpen}
placement='bottom'
offset={4}
triggerPopupSameWidth
>
<PortalToFollowElemTrigger className='block w-full'>
<Input
@ -64,20 +88,31 @@ const SearchInput = ({
onChange={handleValueChange}
/>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent>
<div className='p-1 border-[0.5px] border-components-panel-border bg-components-panel-bg-blur rounded-xl'>
{
schools.map((school, index) => (
<div
key={index}
className='flex items-center px-2 py-1.5 h-8 system-md-regular text-text-secondary truncate'
title={school}
>
{school}
</div>
))
}
</div>
<PortalToFollowElemContent className='z-10'>
{
!!schools.length && value && (
<div
className='p-1 max-h-[330px] overflow-y-auto border-[0.5px] border-components-panel-border bg-components-panel-bg-blur rounded-xl'
onScroll={handleScroll as any}
>
{
schools.map((school, index) => (
<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}
onClick={() => {
onChange(school)
setOpen(false)
}}
>
{school}
</div>
))
}
</div>
)
}
</PortalToFollowElemContent>
</PortalToFollowElem>
)

View File

@ -44,8 +44,8 @@ export const useEducationAutocomplete = () => {
mutationFn: (searchParams: SearchParams) => {
const {
keywords = '',
page = 1,
limit = 20,
page = 0,
limit = 40,
} = searchParams
return get<{ data: string[]; has_next: boolean; curr_page: number }>(`/account/education/autocomplete?keywords=${keywords}&page=${page}&limit=${limit}`)
},