Files
towercontrol/src/app/daily/DailyPageClient.tsx
Julien Froidefond dfa8d34855 feat: add workday utility functions
- 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.
2025-09-20 15:43:38 +02:00

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&apos;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>
);
}