dify/web/app/education-apply/hooks.ts
Stephen Zhou a84c2d36a3
style: format with vp fmt (#38803)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-12 15:57:46 +00:00

156 lines
5.4 KiB
TypeScript

import type { SearchParams } from './types'
import { useQuery } from '@tanstack/react-query'
import { useDebounceFn } from 'ahooks'
import dayjs from 'dayjs'
import timezone from 'dayjs/plugin/timezone'
import utc from 'dayjs/plugin/utc'
import { useCallback, useEffect, useState } from 'react'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
import {
useEducationExpiredHasNoticed,
useEducationReverifyHasNoticed,
useEducationReverifyPrevExpireAt,
useEducationVerifying,
} from '@/app/education-apply/storage'
import { useModalContextSelector } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { userProfileQueryOptions } from '@/features/account-profile/client'
import { useRouter, useSearchParams } from '@/next/navigation'
import { useEducationAutocomplete, useEducationVerify } from '@/service/use-education'
import { EDUCATION_RE_VERIFY_ACTION, EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION } from './constants'
dayjs.extend(utc)
dayjs.extend(timezone)
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 || 0
const resSchools = res.data
if (currentPage > 0)
setPrevSchools((prevSchools) => [...(prevSchools || []), ...resSchools])
else setPrevSchools(resSchools)
})
}
},
[mutateAsync],
)
const { run: querySchoolsWithDebounced } = useDebounceFn(
(searchParams: SearchParams) => {
handleUpdateSchools(searchParams)
},
{
wait: 300,
},
)
return {
schools: prevSchools,
setSchools: setPrevSchools,
querySchoolsWithDebounced,
handleUpdateSchools,
isLoading: isPending,
hasNext: data?.has_next,
}
}
type useEducationReverifyNoticeParams = {
onNotice: ({ expireAt, expired }: { expireAt: number; expired: boolean }) => void
}
const isExpired = (expireAt?: number, timezone?: string) => {
if (!expireAt || !timezone) return false
const today = dayjs().tz(timezone).startOf('day')
const expiredDay = dayjs.unix(expireAt).tz(timezone).startOf('day')
return today.isSame(expiredDay) || today.isAfter(expiredDay)
}
const useEducationReverifyNotice = ({ onNotice }: useEducationReverifyNoticeParams) => {
const { data: timezone } = useQuery({
...userProfileQueryOptions(),
select: (data) => data.profile.timezone ?? undefined,
})
// const [educationInfo, setEducationInfo] = useState<{ is_student: boolean, allow_refresh: boolean, expire_at: number | null } | null>(null)
// const isLoading = !educationInfo
const {
educationAccountExpireAt,
allowRefreshEducationVerify,
isLoadingEducationAccountInfo: isLoading,
} = useProviderContext()
const [prevExpireAt, setPrevExpireAt] = useEducationReverifyPrevExpireAt()
const [reverifyHasNoticed, setReverifyHasNoticed] = useEducationReverifyHasNoticed()
const [expiredHasNoticed, setExpiredHasNoticed] = useEducationExpiredHasNoticed()
useEffect(() => {
if (isLoading || !timezone) return
if (allowRefreshEducationVerify) {
const expired = isExpired(educationAccountExpireAt!, timezone)
const isExpireAtChanged = prevExpireAt !== educationAccountExpireAt
if (isExpireAtChanged) {
setPrevExpireAt(educationAccountExpireAt!)
setReverifyHasNoticed(false)
setExpiredHasNoticed(false)
}
const shouldNotice = (() => {
if (isExpireAtChanged) return true
return expired ? !expiredHasNoticed : !reverifyHasNoticed
})()
if (shouldNotice) {
onNotice({
expireAt: educationAccountExpireAt!,
expired,
})
if (expired) setExpiredHasNoticed(true)
else setReverifyHasNoticed(true)
}
}
}, [allowRefreshEducationVerify, timezone])
return {
isLoading,
expireAt: educationAccountExpireAt!,
expired: isExpired(educationAccountExpireAt!, timezone),
}
}
export const useEducationInit = () => {
const setShowAccountSettingModal = useModalContextSelector((s) => s.setShowAccountSettingModal)
const setShowEducationExpireNoticeModal = useModalContextSelector(
(s) => s.setShowEducationExpireNoticeModal,
)
const [educationVerifying, setEducationVerifying] = useEducationVerifying()
const searchParams = useSearchParams()
const educationVerifyAction = searchParams.get('action')
useEducationReverifyNotice({
onNotice: (payload) => {
setShowEducationExpireNoticeModal({ payload })
},
})
const router = useRouter()
const { mutateAsync } = useEducationVerify()
const handleVerify = async () => {
const { token } = await mutateAsync()
if (token) router.push(`/education-apply?token=${token}`)
}
useEffect(() => {
if (
educationVerifying === 'yes' ||
educationVerifyAction === EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION
) {
setShowAccountSettingModal({ payload: ACCOUNT_SETTING_TAB.BILLING })
if (educationVerifyAction === EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION)
setEducationVerifying('yes')
}
if (educationVerifyAction === EDUCATION_RE_VERIFY_ACTION) handleVerify()
}, [setShowAccountSettingModal, setEducationVerifying, educationVerifying, educationVerifyAction])
}