expo-popcore-app/hooks/use-category-templates.ts

146 lines
4.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { root } from '@repo/core'
import { type ListTemplatesInput, type ListTemplatesResult, TemplateController, type TemplateDetail } from '@repo/sdk'
import { useCallback, useRef, useState } from 'react'
import { type ApiError } from '@/lib/types'
import { OWNER_ID } from '@/lib/auth'
import { handleError } from './use-error'
type ListCategoryTemplatesParams = Partial<Omit<ListTemplatesInput, 'ownerId'>>
interface UseCategoryTemplatesOptions {
categoryId?: string
limit?: number
sortBy?: 'createdAt' | 'updatedAt'
sortOrder?: 'asc' | 'desc'
}
const DEFAULT_PARAMS = {
limit: 20,
sortBy: 'createdAt' as const,
sortOrder: 'desc' as const,
}
export const useCategoryTemplates = (
categoryIdOrOptions?: string | UseCategoryTemplatesOptions,
additionalOptions?: Omit<UseCategoryTemplatesOptions, 'categoryId'>
) => {
// 支持多种调用方式:
// useCategoryTemplates('category-id')
// useCategoryTemplates('category-id', { limit: 50 })
// useCategoryTemplates({ categoryId: 'category-id', limit: 50 })
const options: UseCategoryTemplatesOptions | undefined = typeof categoryIdOrOptions === 'string'
? { categoryId: categoryIdOrOptions, ...additionalOptions }
: categoryIdOrOptions
const [loading, setLoading] = useState(false)
const [loadingMore, setLoadingMore] = useState(false)
const [error, setError] = useState<ApiError | null>(null)
const [data, setData] = useState<ListTemplatesResult>()
const currentPageRef = useRef(1)
const hasMoreRef = useRef(true)
const currentCategoryIdRef = useRef<string | undefined>(options?.categoryId)
const execute = useCallback(async (params?: ListCategoryTemplatesParams) => {
setLoading(true)
setError(null)
currentPageRef.current = params?.page || 1
// 确定要使用的 categoryIdparams > options来自 props> currentCategoryIdRef
const categoryIdToUse = params?.categoryId ?? options?.categoryId ?? currentCategoryIdRef.current
// 更新当前 categoryId ref
if (categoryIdToUse !== undefined) {
currentCategoryIdRef.current = categoryIdToUse
}
const template = root.get(TemplateController)
const requestParams: ListTemplatesInput = {
...DEFAULT_PARAMS,
...options,
...params,
page: params?.page ?? 1,
categoryId: categoryIdToUse,
ownerId: OWNER_ID,
}
const { data, error } = await handleError(
async () => await template.list(requestParams),
)
if (error) {
setError(error)
setLoading(false)
return { data: undefined, error }
}
const templates = data?.templates || []
const currentPage = requestParams.page || 1
const totalPages = data?.totalPages || 1
hasMoreRef.current = currentPage < totalPages
setData(data)
setLoading(false)
return { data, error: null }
}, [options])
const loadMore = useCallback(async () => {
if (loadingMore || loading || !hasMoreRef.current) return { data: undefined, error: null }
setLoadingMore(true)
const nextPage = currentPageRef.current + 1
// 使用最新的 categoryIdoptions来自 props> currentCategoryIdRef
const categoryIdToUse = options?.categoryId ?? currentCategoryIdRef.current
const template = root.get(TemplateController)
const requestParams: ListTemplatesInput = {
...DEFAULT_PARAMS,
...options,
page: nextPage,
categoryId: categoryIdToUse,
ownerId: OWNER_ID,
}
const { data: newData, error } = await handleError(
async () => await template.list(requestParams),
)
if (error) {
setLoadingMore(false)
return { data: undefined, error }
}
const newTemplates = newData?.templates || []
const totalPages = newData?.totalPages || 1
hasMoreRef.current = nextPage < totalPages
currentPageRef.current = nextPage
setData((prev) => ({
...newData,
templates: [...(prev?.templates || []), ...newTemplates],
}))
setLoadingMore(false)
return { data: newData, error: null }
}, [loading, loadingMore, options])
const refetch = useCallback(() => {
hasMoreRef.current = true
return execute()
}, [execute])
return {
data,
templates: data?.templates || [],
loading,
loadingMore,
error,
execute,
refetch,
loadMore,
hasMore: hasMoreRef.current,
}
}
export type { TemplateDetail }