feat: implement Daily management features and update UI
- Marked tasks as completed in TODO for Daily management service, data model, and interactive checkboxes. - Added a new link to the Daily page in the Header component for easy navigation. - Introduced DailyCheckbox model in Prisma schema and corresponding TypeScript interfaces for better data handling. - Updated database schema to include daily checkboxes, enhancing task management capabilities.
This commit is contained in:
290
hooks/useDaily.ts
Normal file
290
hooks/useDaily.ts
Normal file
@@ -0,0 +1,290 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { dailyClient, DailyHistoryFilters, DailySearchFilters, ReorderCheckboxesData } from '@/clients/daily-client';
|
||||
import { DailyView, DailyCheckbox, UpdateDailyCheckboxData } from '@/lib/types';
|
||||
|
||||
interface UseDailyState {
|
||||
dailyView: DailyView | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
saving: boolean; // Pour indiquer les opérations en cours
|
||||
}
|
||||
|
||||
interface UseDailyActions {
|
||||
refreshDaily: () => Promise<void>;
|
||||
addTodayCheckbox: (text: string, taskId?: string) => Promise<DailyCheckbox | null>;
|
||||
addYesterdayCheckbox: (text: string, taskId?: string) => Promise<DailyCheckbox | null>;
|
||||
updateCheckbox: (checkboxId: string, data: UpdateDailyCheckboxData) => Promise<DailyCheckbox | null>;
|
||||
deleteCheckbox: (checkboxId: string) => Promise<void>;
|
||||
toggleCheckbox: (checkboxId: string) => Promise<void>;
|
||||
reorderCheckboxes: (data: ReorderCheckboxesData) => Promise<void>;
|
||||
goToPreviousDay: () => Promise<void>;
|
||||
goToNextDay: () => Promise<void>;
|
||||
goToToday: () => Promise<void>;
|
||||
setDate: (date: Date) => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook pour la gestion d'une vue daily spécifique
|
||||
*/
|
||||
export function useDaily(initialDate?: Date): UseDailyState & UseDailyActions & { currentDate: Date } {
|
||||
const [currentDate, setCurrentDate] = useState<Date>(initialDate || new Date());
|
||||
const [dailyView, setDailyView] = useState<DailyView | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const refreshDaily = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const view = await dailyClient.getDailyView(currentDate);
|
||||
setDailyView(view);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors du chargement du daily');
|
||||
console.error('Erreur refreshDaily:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [currentDate]);
|
||||
|
||||
const addTodayCheckbox = useCallback(async (text: string, taskId?: string): Promise<DailyCheckbox | null> => {
|
||||
if (!dailyView) return null;
|
||||
|
||||
try {
|
||||
setSaving(true);
|
||||
setError(null);
|
||||
|
||||
const newCheckbox = await dailyClient.addTodayCheckbox(text, taskId);
|
||||
|
||||
// Mise à jour optimiste
|
||||
setDailyView(prev => prev ? {
|
||||
...prev,
|
||||
today: [...prev.today, newCheckbox].sort((a, b) => a.order - b.order)
|
||||
} : null);
|
||||
|
||||
return newCheckbox;
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors de l\'ajout de la checkbox');
|
||||
console.error('Erreur addTodayCheckbox:', err);
|
||||
return null;
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [dailyView]);
|
||||
|
||||
const addYesterdayCheckbox = useCallback(async (text: string, taskId?: string): Promise<DailyCheckbox | null> => {
|
||||
if (!dailyView) return null;
|
||||
|
||||
try {
|
||||
setSaving(true);
|
||||
setError(null);
|
||||
|
||||
const newCheckbox = await dailyClient.addYesterdayCheckbox(text, taskId);
|
||||
|
||||
// Mise à jour optimiste
|
||||
setDailyView(prev => prev ? {
|
||||
...prev,
|
||||
yesterday: [...prev.yesterday, newCheckbox].sort((a, b) => a.order - b.order)
|
||||
} : null);
|
||||
|
||||
return newCheckbox;
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors de l\'ajout de la checkbox');
|
||||
console.error('Erreur addYesterdayCheckbox:', err);
|
||||
return null;
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [dailyView]);
|
||||
|
||||
const updateCheckbox = useCallback(async (checkboxId: string, data: UpdateDailyCheckboxData): Promise<DailyCheckbox | null> => {
|
||||
if (!dailyView) return null;
|
||||
|
||||
try {
|
||||
setSaving(true);
|
||||
setError(null);
|
||||
|
||||
const updatedCheckbox = await dailyClient.updateCheckbox(checkboxId, data);
|
||||
|
||||
// Mise à jour optimiste
|
||||
setDailyView(prev => prev ? {
|
||||
...prev,
|
||||
yesterday: prev.yesterday.map(cb => cb.id === checkboxId ? updatedCheckbox : cb),
|
||||
today: prev.today.map(cb => cb.id === checkboxId ? updatedCheckbox : cb)
|
||||
} : null);
|
||||
|
||||
return updatedCheckbox;
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors de la mise à jour de la checkbox');
|
||||
console.error('Erreur updateCheckbox:', err);
|
||||
return null;
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [dailyView]);
|
||||
|
||||
const deleteCheckbox = useCallback(async (checkboxId: string): Promise<void> => {
|
||||
if (!dailyView) return;
|
||||
|
||||
try {
|
||||
setSaving(true);
|
||||
setError(null);
|
||||
|
||||
await dailyClient.deleteCheckbox(checkboxId);
|
||||
|
||||
// Mise à jour optimiste
|
||||
setDailyView(prev => prev ? {
|
||||
...prev,
|
||||
yesterday: prev.yesterday.filter(cb => cb.id !== checkboxId),
|
||||
today: prev.today.filter(cb => cb.id !== checkboxId)
|
||||
} : null);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors de la suppression de la checkbox');
|
||||
console.error('Erreur deleteCheckbox:', err);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [dailyView]);
|
||||
|
||||
const toggleCheckbox = useCallback(async (checkboxId: string): Promise<void> => {
|
||||
if (!dailyView) return;
|
||||
|
||||
// Trouver la checkbox dans yesterday ou today
|
||||
let checkbox = dailyView.yesterday.find(cb => cb.id === checkboxId);
|
||||
if (!checkbox) {
|
||||
checkbox = dailyView.today.find(cb => cb.id === checkboxId);
|
||||
}
|
||||
|
||||
if (!checkbox) return;
|
||||
|
||||
await updateCheckbox(checkboxId, { isChecked: !checkbox.isChecked });
|
||||
}, [dailyView, updateCheckbox]);
|
||||
|
||||
const reorderCheckboxes = useCallback(async (data: ReorderCheckboxesData): Promise<void> => {
|
||||
try {
|
||||
setSaving(true);
|
||||
setError(null);
|
||||
|
||||
await dailyClient.reorderCheckboxes(data);
|
||||
|
||||
// Rafraîchir pour obtenir l'ordre correct
|
||||
await refreshDaily();
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors du réordonnancement');
|
||||
console.error('Erreur reorderCheckboxes:', err);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [refreshDaily]);
|
||||
|
||||
const goToPreviousDay = useCallback(async (): Promise<void> => {
|
||||
const previousDay = new Date(currentDate);
|
||||
previousDay.setDate(previousDay.getDate() - 1);
|
||||
setCurrentDate(previousDay);
|
||||
}, [currentDate]);
|
||||
|
||||
const goToNextDay = useCallback(async (): Promise<void> => {
|
||||
const nextDay = new Date(currentDate);
|
||||
nextDay.setDate(nextDay.getDate() + 1);
|
||||
setCurrentDate(nextDay);
|
||||
}, [currentDate]);
|
||||
|
||||
const goToToday = useCallback(async (): Promise<void> => {
|
||||
setCurrentDate(new Date());
|
||||
}, []);
|
||||
|
||||
const setDate = useCallback(async (date: Date): Promise<void> => {
|
||||
setCurrentDate(date);
|
||||
}, []);
|
||||
|
||||
// Charger le daily quand la date change
|
||||
useEffect(() => {
|
||||
refreshDaily();
|
||||
}, [refreshDaily]);
|
||||
|
||||
return {
|
||||
// State
|
||||
dailyView,
|
||||
loading,
|
||||
error,
|
||||
saving,
|
||||
currentDate,
|
||||
|
||||
// Actions
|
||||
refreshDaily,
|
||||
addTodayCheckbox,
|
||||
addYesterdayCheckbox,
|
||||
updateCheckbox,
|
||||
deleteCheckbox,
|
||||
toggleCheckbox,
|
||||
reorderCheckboxes,
|
||||
goToPreviousDay,
|
||||
goToNextDay,
|
||||
goToToday,
|
||||
setDate
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook pour l'historique des checkboxes
|
||||
*/
|
||||
export function useDailyHistory() {
|
||||
const [history, setHistory] = useState<{ date: Date; checkboxes: DailyCheckbox[] }[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const loadHistory = useCallback(async (filters?: DailyHistoryFilters) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const historyData = await dailyClient.getCheckboxHistory(filters);
|
||||
setHistory(historyData);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors du chargement de l\'historique');
|
||||
console.error('Erreur loadHistory:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const searchCheckboxes = useCallback(async (filters: DailySearchFilters) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const checkboxes = await dailyClient.searchCheckboxes(filters);
|
||||
// Grouper par date pour l'affichage
|
||||
const groupedHistory = checkboxes.reduce((acc, checkbox) => {
|
||||
const dateKey = checkbox.date.toDateString();
|
||||
const existing = acc.find(item => item.date.toDateString() === dateKey);
|
||||
|
||||
if (existing) {
|
||||
existing.checkboxes.push(checkbox);
|
||||
} else {
|
||||
acc.push({ date: checkbox.date, checkboxes: [checkbox] });
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, [] as { date: Date; checkboxes: DailyCheckbox[] }[]);
|
||||
|
||||
setHistory(groupedHistory);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors de la recherche');
|
||||
console.error('Erreur searchCheckboxes:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return {
|
||||
history,
|
||||
loading,
|
||||
error,
|
||||
loadHistory,
|
||||
searchCheckboxes
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user