925e077afe
- TodoForm : domaines en chips multi-select colorés, priorité en 3 boutons colorés (haute/moyenne/basse), date initialisée à aujourd'hui, description et URL toujours visibles, boutons photo et GPS - TodosPage : suppression filtres domaine/priorité, tags colorés par domaine dans les lignes, userSelect:none, groupage multi-domaines - todos.ts : ajout domains[], photo_path, gps_lat/lng dans les interfaces TS - index.html : viewport maximum-scale=1.0, user-scalable=no Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
114 lines
3.0 KiB
TypeScript
114 lines
3.0 KiB
TypeScript
// frontend/src/api/todos.ts
|
|
export interface Todo {
|
|
id: string
|
|
title: string
|
|
body: string | null
|
|
url: string | null
|
|
domains: string[]
|
|
category: string | null
|
|
tags: string[]
|
|
status: 'pending' | 'done' | 'cancelled'
|
|
priority: 'low' | 'medium' | 'high'
|
|
due_date: string | null
|
|
postponed_count: number
|
|
photo_path: string | null
|
|
gps_lat: number | null
|
|
gps_lng: number | null
|
|
created_at: string
|
|
updated_at: string | null
|
|
owner_id: string | null
|
|
}
|
|
|
|
export interface TodoCreate {
|
|
title: string
|
|
body?: string
|
|
url?: string
|
|
domain?: string
|
|
domains?: string[]
|
|
category?: string
|
|
tags?: string[]
|
|
status?: 'pending' | 'done' | 'cancelled'
|
|
priority?: 'low' | 'medium' | 'high'
|
|
due_date?: string
|
|
photo_path?: string
|
|
gps_lat?: number
|
|
gps_lng?: number
|
|
}
|
|
|
|
export interface TodoUpdate {
|
|
title?: string
|
|
body?: string
|
|
url?: string
|
|
domain?: string
|
|
domains?: string[]
|
|
category?: string
|
|
tags?: string[]
|
|
status?: 'pending' | 'done' | 'cancelled'
|
|
priority?: 'low' | 'medium' | 'high'
|
|
due_date?: string
|
|
photo_path?: string
|
|
gps_lat?: number
|
|
gps_lng?: number
|
|
}
|
|
|
|
export interface TodoFilters {
|
|
domain?: string
|
|
status?: string
|
|
priority?: string
|
|
tag?: string
|
|
due_after?: string
|
|
due_before?: string
|
|
}
|
|
|
|
const BASE = '/api/todos'
|
|
|
|
async function handleResponse<T>(res: Response): Promise<T> {
|
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)
|
|
if (res.status === 204) return undefined as T
|
|
return res.json() as Promise<T>
|
|
}
|
|
|
|
export async function fetchTodos(filters?: TodoFilters): Promise<Todo[]> {
|
|
const qs = new URLSearchParams()
|
|
if (filters?.domain) qs.set('domain', filters.domain)
|
|
if (filters?.status !== undefined) qs.set('status', filters.status)
|
|
if (filters?.priority) qs.set('priority', filters.priority)
|
|
if (filters?.tag) qs.set('tag', filters.tag)
|
|
if (filters?.due_after) qs.set('due_after', filters.due_after)
|
|
if (filters?.due_before) qs.set('due_before', filters.due_before)
|
|
const res = await fetch(`${BASE}/?${qs}`)
|
|
return handleResponse<Todo[]>(res)
|
|
}
|
|
|
|
export async function createTodo(data: TodoCreate): Promise<Todo> {
|
|
const res = await fetch(`${BASE}/`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data),
|
|
})
|
|
return handleResponse<Todo>(res)
|
|
}
|
|
|
|
export async function updateTodo(id: string, data: TodoUpdate): Promise<Todo> {
|
|
const res = await fetch(`${BASE}/${id}`, {
|
|
method: 'PATCH',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data),
|
|
})
|
|
return handleResponse<Todo>(res)
|
|
}
|
|
|
|
export async function deleteTodo(id: string): Promise<void> {
|
|
const res = await fetch(`${BASE}/${id}`, { method: 'DELETE' })
|
|
await handleResponse<void>(res)
|
|
}
|
|
|
|
export async function postponeTodo(id: string, days: 1 | 7): Promise<Todo> {
|
|
const res = await fetch(`${BASE}/${id}/postpone`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ days }),
|
|
})
|
|
return handleResponse<Todo>(res)
|
|
}
|