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, 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`
},
}),
], ],
}) })

View File

@ -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,
} }
} }

View File

@ -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
if (debounced) {
querySchoolsWithDebounced({ querySchoolsWithDebounced({
keywords: value, keywords,
page: 1, page,
}) })
}, { return
wait: 300, }
})
const handleValueChange = useCallback((e: { target: { value: string } }) => {
onChange(e.target.value)
handleSearch()
}, [handleSearch, onChange])
useEffect(() => { handleUpdateSchools({
if (!isLoading && !open && schools.length) keywords,
page,
})
}, [querySchoolsWithDebounced, handleUpdateSchools])
const handleValueChange = useCallback((e: any) => {
setOpen(true) setOpen(true)
}, [isLoading, open, schools]) 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 ( 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 && (
<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) => ( schools.map((school, index) => (
<div <div
key={index} key={index}
className='flex items-center px-2 py-1.5 h-8 system-md-regular text-text-secondary truncate' 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} title={school}
onClick={() => {
onChange(school)
setOpen(false)
}}
> >
{school} {school}
</div> </div>
)) ))
} }
</div> </div>
)
}
</PortalToFollowElemContent> </PortalToFollowElemContent>
</PortalToFollowElem> </PortalToFollowElem>
) )

View File

@ -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}`)
}, },