- Introduced utility functions for workday calculations in `workday-utils.ts`, including `getPreviousWorkday`, `getNextWorkday`, `isWorkday`, and `getDayName`. - Updated `DailyService` and `DailyPageClient` to utilize `getPreviousWorkday` for accurate date handling instead of simple date subtraction.
266 lines
8.2 KiB
TypeScript
266 lines
8.2 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import React from 'react';
|
|
import { useDaily } from '@/hooks/useDaily';
|
|
import { DailyView, DailyCheckboxType } from '@/lib/types';
|
|
import { Button } from '@/components/ui/Button';
|
|
import { Card } from '@/components/ui/Card';
|
|
import { DailyCalendar } from '@/components/daily/DailyCalendar';
|
|
import { DailySection } from '@/components/daily/DailySection';
|
|
import { dailyClient } from '@/clients/daily-client';
|
|
import { Header } from '@/components/ui/Header';
|
|
import { getPreviousWorkday } from '@/lib/workday-utils';
|
|
|
|
interface DailyPageClientProps {
|
|
initialDailyView?: DailyView;
|
|
initialDailyDates?: string[];
|
|
initialDate?: Date;
|
|
}
|
|
|
|
export function DailyPageClient({
|
|
initialDailyView,
|
|
initialDailyDates = [],
|
|
initialDate
|
|
}: DailyPageClientProps = {}) {
|
|
const {
|
|
dailyView,
|
|
loading,
|
|
refreshing,
|
|
error,
|
|
saving,
|
|
currentDate,
|
|
addTodayCheckbox,
|
|
addYesterdayCheckbox,
|
|
toggleCheckbox,
|
|
toggleAllToday,
|
|
toggleAllYesterday,
|
|
updateCheckbox,
|
|
deleteCheckbox,
|
|
reorderCheckboxes,
|
|
goToPreviousDay,
|
|
goToNextDay,
|
|
goToToday,
|
|
setDate
|
|
} = useDaily(initialDate, initialDailyView);
|
|
|
|
const [dailyDates, setDailyDates] = useState<string[]>(initialDailyDates);
|
|
|
|
// Fonction pour rafraîchir la liste des dates avec des dailies
|
|
const refreshDailyDates = async () => {
|
|
try {
|
|
const dates = await dailyClient.getDailyDates();
|
|
setDailyDates(dates);
|
|
} catch (error) {
|
|
console.error('Erreur lors du refresh des dates:', error);
|
|
}
|
|
};
|
|
|
|
// Charger les dates avec des dailies pour le calendrier (seulement si pas de données SSR)
|
|
useEffect(() => {
|
|
if (initialDailyDates.length === 0) {
|
|
import('@/clients/daily-client').then(({ dailyClient }) => {
|
|
return dailyClient.getDailyDates();
|
|
}).then(setDailyDates).catch(console.error);
|
|
}
|
|
}, [initialDailyDates.length]);
|
|
|
|
const handleAddTodayCheckbox = async (text: string, type: DailyCheckboxType) => {
|
|
await addTodayCheckbox(text, type);
|
|
// Recharger aussi les dates pour le calendrier
|
|
await refreshDailyDates();
|
|
};
|
|
|
|
const handleAddYesterdayCheckbox = async (text: string, type: DailyCheckboxType) => {
|
|
await addYesterdayCheckbox(text, type);
|
|
// Recharger aussi les dates pour le calendrier
|
|
await refreshDailyDates();
|
|
};
|
|
|
|
const handleToggleCheckbox = async (checkboxId: string) => {
|
|
await toggleCheckbox(checkboxId);
|
|
};
|
|
|
|
const handleDeleteCheckbox = async (checkboxId: string) => {
|
|
await deleteCheckbox(checkboxId);
|
|
// Refresh dates après suppression pour mettre à jour le calendrier
|
|
await refreshDailyDates();
|
|
};
|
|
|
|
const handleUpdateCheckbox = async (checkboxId: string, text: string, type: DailyCheckboxType, taskId?: string) => {
|
|
await updateCheckbox(checkboxId, {
|
|
text,
|
|
type,
|
|
taskId // Permet la liaison tâche pour tous les types
|
|
});
|
|
};
|
|
|
|
const handleReorderCheckboxes = async (date: Date, checkboxIds: string[]) => {
|
|
await reorderCheckboxes({ date, checkboxIds });
|
|
};
|
|
|
|
const getYesterdayDate = () => {
|
|
return getPreviousWorkday(currentDate);
|
|
};
|
|
|
|
const getTodayDate = () => {
|
|
return currentDate;
|
|
};
|
|
|
|
const handleDateSelect = (date: Date) => {
|
|
setDate(date);
|
|
};
|
|
|
|
const formatCurrentDate = () => {
|
|
return currentDate.toLocaleDateString('fr-FR', {
|
|
weekday: 'long',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
});
|
|
};
|
|
|
|
const isToday = () => {
|
|
const today = new Date();
|
|
return currentDate.toDateString() === today.toDateString();
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="container mx-auto px-4 py-8">
|
|
<div className="flex items-center justify-center min-h-[200px]">
|
|
<div className="text-[var(--muted-foreground)] font-mono">
|
|
Chargement du daily...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="container mx-auto px-4 py-8">
|
|
<div className="bg-[var(--destructive)]/10 border border-[var(--destructive)]/20 rounded-lg p-4 text-center">
|
|
<p className="text-[var(--destructive)] font-mono mb-4">
|
|
Erreur: {error}
|
|
</p>
|
|
<Button onClick={() => window.location.reload()} variant="primary">
|
|
Réessayer
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[var(--background)]">
|
|
{/* Header uniforme */}
|
|
<Header
|
|
title="TowerControl"
|
|
subtitle="Daily - Gestion quotidienne"
|
|
syncing={saving}
|
|
/>
|
|
|
|
{/* Navigation Daily spécifique */}
|
|
<div className="bg-[var(--card)]/50 border-b border-[var(--border)]/30">
|
|
<div className="container mx-auto px-4 py-3">
|
|
<div className="flex items-center justify-center gap-2">
|
|
<Button
|
|
onClick={goToPreviousDay}
|
|
variant="ghost"
|
|
size="sm"
|
|
disabled={saving}
|
|
>
|
|
←
|
|
</Button>
|
|
|
|
<div className="text-center min-w-[200px]">
|
|
<div className="text-sm font-bold text-[var(--foreground)] font-mono">
|
|
{formatCurrentDate()}
|
|
</div>
|
|
{!isToday() && (
|
|
<button
|
|
onClick={goToToday}
|
|
className="text-xs text-[var(--primary)] hover:text-[var(--primary)]/80 font-mono"
|
|
>
|
|
Aller à aujourd'hui
|
|
</button>
|
|
)}
|
|
</div>
|
|
|
|
<Button
|
|
onClick={goToNextDay}
|
|
variant="ghost"
|
|
size="sm"
|
|
disabled={saving}
|
|
>
|
|
→
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Contenu principal */}
|
|
<main className="container mx-auto px-4 py-8">
|
|
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6">
|
|
{/* Calendrier - toujours visible */}
|
|
<div className="xl:col-span-1">
|
|
<DailyCalendar
|
|
currentDate={currentDate}
|
|
onDateSelect={handleDateSelect}
|
|
dailyDates={dailyDates}
|
|
/>
|
|
</div>
|
|
|
|
{/* Sections daily */}
|
|
{dailyView && (
|
|
<div className="xl:col-span-2 grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
{/* Section Hier */}
|
|
<DailySection
|
|
title="📋 Hier"
|
|
date={getYesterdayDate()}
|
|
checkboxes={dailyView.yesterday}
|
|
onAddCheckbox={handleAddYesterdayCheckbox}
|
|
onToggleCheckbox={handleToggleCheckbox}
|
|
onUpdateCheckbox={handleUpdateCheckbox}
|
|
onDeleteCheckbox={handleDeleteCheckbox}
|
|
onReorderCheckboxes={handleReorderCheckboxes}
|
|
onToggleAll={toggleAllYesterday}
|
|
saving={saving}
|
|
refreshing={refreshing}
|
|
/>
|
|
|
|
{/* Section Aujourd'hui */}
|
|
<DailySection
|
|
title="🎯 Aujourd'hui"
|
|
date={getTodayDate()}
|
|
checkboxes={dailyView.today}
|
|
onAddCheckbox={handleAddTodayCheckbox}
|
|
onToggleCheckbox={handleToggleCheckbox}
|
|
onUpdateCheckbox={handleUpdateCheckbox}
|
|
onDeleteCheckbox={handleDeleteCheckbox}
|
|
onReorderCheckboxes={handleReorderCheckboxes}
|
|
onToggleAll={toggleAllToday}
|
|
saving={saving}
|
|
refreshing={refreshing}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Footer avec stats - dans le flux normal */}
|
|
{dailyView && (
|
|
<Card className="mt-8 p-4">
|
|
<div className="text-center text-sm text-[var(--muted-foreground)] font-mono">
|
|
Daily pour {formatCurrentDate()}
|
|
{' • '}
|
|
{dailyView.yesterday.length + dailyView.today.length} tâche{dailyView.yesterday.length + dailyView.today.length > 1 ? 's' : ''} au total
|
|
{' • '}
|
|
{dailyView.yesterday.filter(cb => cb.isChecked).length + dailyView.today.filter(cb => cb.isChecked).length} complétée{(dailyView.yesterday.filter(cb => cb.isChecked).length + dailyView.today.filter(cb => cb.isChecked).length) > 1 ? 's' : ''}
|
|
</div>
|
|
</Card>
|
|
)}
|
|
</main>
|
|
</div>
|
|
);
|
|
} |