96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import { useState, useCallback } from 'react'
|
|
import type { WorkItem } from '@/components/WorksGallery'
|
|
|
|
interface UseWorksListResult {
|
|
works: WorkItem[]
|
|
loading: boolean
|
|
error: string | null
|
|
refreshing: boolean
|
|
hasMore: boolean
|
|
loadMore: () => Promise<void>
|
|
refresh: () => Promise<void>
|
|
}
|
|
|
|
const PAGE_SIZE = 20
|
|
|
|
// TODO: Replace with actual API call when backend is ready
|
|
const mockFetchWorks = async (page: number): Promise<WorkItem[]> => {
|
|
await new Promise(resolve => setTimeout(resolve, 800))
|
|
|
|
if (page > 2) return []
|
|
|
|
const baseData: WorkItem[] = [
|
|
{ id: 1, date: new Date(2025, 10, 28), duration: '00:05', category: '萌宠' },
|
|
{ id: 2, date: new Date(2025, 10, 28), duration: '00:05', category: '写真' },
|
|
{ id: 3, date: new Date(2025, 10, 27), duration: '00:05', category: '萌宠' },
|
|
{ id: 4, date: new Date(2025, 10, 27), duration: '00:05', category: '合拍' },
|
|
{ id: 5, date: new Date(2025, 10, 27), duration: '00:05', category: '写真' },
|
|
{ id: 6, date: new Date(2025, 10, 27), duration: '00:05', category: '萌宠' },
|
|
{ id: 7, date: new Date(2025, 10, 26), duration: '00:05', category: '合拍' },
|
|
{ id: 8, date: new Date(2025, 10, 26), duration: '00:05', category: '写真' },
|
|
]
|
|
|
|
return baseData.map(item => ({
|
|
...item,
|
|
id: item.id + (page * PAGE_SIZE),
|
|
}))
|
|
}
|
|
|
|
export function useWorksList(): UseWorksListResult {
|
|
const [works, setWorks] = useState<WorkItem[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState<string | null>(null)
|
|
const [refreshing, setRefreshing] = useState(false)
|
|
const [page, setPage] = useState(0)
|
|
const [hasMore, setHasMore] = useState(true)
|
|
|
|
const loadWorks = useCallback(async (pageNum: number, isRefresh = false) => {
|
|
try {
|
|
const data = await mockFetchWorks(pageNum)
|
|
|
|
if (isRefresh) {
|
|
setWorks(data)
|
|
} else {
|
|
setWorks(prev => [...prev, ...data])
|
|
}
|
|
|
|
setHasMore(data.length === PAGE_SIZE)
|
|
setError(null)
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Failed to load works')
|
|
}
|
|
}, [])
|
|
|
|
const loadMore = useCallback(async () => {
|
|
if (!hasMore || loading) return
|
|
|
|
const nextPage = page + 1
|
|
setPage(nextPage)
|
|
await loadWorks(nextPage)
|
|
}, [hasMore, loading, page, loadWorks])
|
|
|
|
const refresh = useCallback(async () => {
|
|
setRefreshing(true)
|
|
setPage(0)
|
|
await loadWorks(0, true)
|
|
setRefreshing(false)
|
|
}, [loadWorks])
|
|
|
|
// Initial load
|
|
const [initialized, setInitialized] = useState(false)
|
|
if (!initialized) {
|
|
setInitialized(true)
|
|
loadWorks(0).finally(() => setLoading(false))
|
|
}
|
|
|
|
return {
|
|
works,
|
|
loading,
|
|
error,
|
|
refreshing,
|
|
hasMore,
|
|
loadMore,
|
|
refresh,
|
|
}
|
|
}
|