Frontend API structure.
This commit is contained in:
parent
7d2b7fc90c
commit
c443a13a14
10 changed files with 1810 additions and 4 deletions
160
frontend/app/hooks/useTasks.ts
Normal file
160
frontend/app/hooks/useTasks.ts
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
import { useState, useCallback, useEffect } from 'react'
|
||||
import { Task, CreateTaskRequest, TaskStatus, ApiError } from '~/types/task'
|
||||
import { apiClient } from '~/services/api'
|
||||
|
||||
interface UseTasksState {
|
||||
tasks: Task[]
|
||||
loading: boolean
|
||||
error: string | null
|
||||
lastFetch: Date | null
|
||||
}
|
||||
|
||||
interface UseTasksActions {
|
||||
fetchTasks: () => Promise<void>
|
||||
createTask: (data: CreateTaskRequest) => Promise<Task | null>
|
||||
refreshTasks: () => Promise<void>
|
||||
clearError: () => void
|
||||
getTaskById: (id: string) => Task | undefined
|
||||
filterTasksByStatus: (status: TaskStatus) => Task[]
|
||||
}
|
||||
|
||||
interface UseTasksOptions {
|
||||
autoFetch?: boolean
|
||||
refreshInterval?: number
|
||||
}
|
||||
|
||||
export function useTasks(
|
||||
options: UseTasksOptions = {}
|
||||
): UseTasksState & UseTasksActions {
|
||||
const { autoFetch = true, refreshInterval } = options
|
||||
|
||||
const [state, setState] = useState<UseTasksState>({
|
||||
tasks: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
lastFetch: null,
|
||||
})
|
||||
|
||||
const clearError = useCallback(() => {
|
||||
setState(prev => ({ ...prev, error: null }))
|
||||
}, [])
|
||||
|
||||
const fetchTasks = useCallback(async () => {
|
||||
setState(prev => ({ ...prev, loading: true, error: null }))
|
||||
|
||||
try {
|
||||
const tasks = await apiClient.listTasks()
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
tasks,
|
||||
loading: false,
|
||||
lastFetch: new Date(),
|
||||
}))
|
||||
} catch (error) {
|
||||
const apiError = error as ApiError
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: apiError.message,
|
||||
}))
|
||||
}
|
||||
}, [])
|
||||
|
||||
const createTask = useCallback(
|
||||
async (data: CreateTaskRequest): Promise<Task | null> => {
|
||||
setState(prev => ({ ...prev, loading: true, error: null }))
|
||||
|
||||
try {
|
||||
const newTask = await apiClient.createTask(data)
|
||||
|
||||
// Add the new task to the beginning of the list (most recent first)
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
tasks: [newTask, ...prev.tasks],
|
||||
loading: false,
|
||||
}))
|
||||
|
||||
return newTask
|
||||
} catch (error) {
|
||||
const apiError = error as ApiError
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: apiError.message,
|
||||
}))
|
||||
return null
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const refreshTasks = useCallback(async () => {
|
||||
// Force refresh without showing loading state if tasks already exist
|
||||
const showLoading = state.tasks.length === 0
|
||||
|
||||
if (showLoading) {
|
||||
setState(prev => ({ ...prev, loading: true, error: null }))
|
||||
} else {
|
||||
setState(prev => ({ ...prev, error: null }))
|
||||
}
|
||||
|
||||
try {
|
||||
const tasks = await apiClient.listTasks()
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
tasks,
|
||||
loading: false,
|
||||
lastFetch: new Date(),
|
||||
}))
|
||||
} catch (error) {
|
||||
const apiError = error as ApiError
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: apiError.message,
|
||||
}))
|
||||
}
|
||||
}, [state.tasks])
|
||||
|
||||
const getTaskById = useCallback(
|
||||
(id: string): Task | undefined => {
|
||||
return state.tasks.find(task => task.id === id)
|
||||
},
|
||||
[state.tasks]
|
||||
)
|
||||
|
||||
const filterTasksByStatus = useCallback(
|
||||
(status: TaskStatus): Task[] => {
|
||||
return state.tasks.filter(task => task.status === status)
|
||||
},
|
||||
[state.tasks]
|
||||
)
|
||||
|
||||
// Auto-fetch tasks on mount
|
||||
useEffect(() => {
|
||||
if (autoFetch) {
|
||||
fetchTasks()
|
||||
}
|
||||
}, [autoFetch, fetchTasks])
|
||||
|
||||
// Set up refresh interval if specified
|
||||
useEffect(() => {
|
||||
if (!refreshInterval) return
|
||||
|
||||
const interval = setInterval(() => {
|
||||
refreshTasks()
|
||||
}, refreshInterval)
|
||||
|
||||
return () => clearInterval(interval)
|
||||
}, [refreshInterval, refreshTasks])
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetchTasks,
|
||||
createTask,
|
||||
refreshTasks,
|
||||
clearError,
|
||||
getTaskById,
|
||||
filterTasksByStatus,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue