- Replaced `DailyCalendar` with a new `Calendar` component for improved functionality and consistency. - Introduced `AlertBanner` to replace `DeadlineReminder`, providing a more flexible way to display urgent tasks. - Updated `DailyAddForm` to use new options for task types, enhancing user experience when adding tasks. - Removed unused state and components, streamlining the DailyPageClient for better performance and maintainability. - Enhanced `DailySection` to utilize new `CheckboxItem` format for better integration with the UI. - Cleaned up imports and improved overall structure for better readability.
221 lines
6.2 KiB
TypeScript
221 lines
6.2 KiB
TypeScript
'use client';
|
||
|
||
import React, { useState } from 'react';
|
||
import { Button } from '@/components/ui/Button';
|
||
import { Card } from '@/components/ui/Card';
|
||
import { formatDateForAPI, createDate, getToday } from '@/lib/date-utils';
|
||
import { format } from 'date-fns';
|
||
import { fr } from 'date-fns/locale';
|
||
|
||
interface CalendarProps {
|
||
currentDate: Date;
|
||
onDateSelect: (date: Date) => void;
|
||
markedDates?: string[]; // Liste des dates marquées (format YYYY-MM-DD)
|
||
showTodayButton?: boolean;
|
||
showLegend?: boolean;
|
||
className?: string;
|
||
}
|
||
|
||
export function Calendar({
|
||
currentDate,
|
||
onDateSelect,
|
||
markedDates = [],
|
||
showTodayButton = true,
|
||
showLegend = true,
|
||
className = ''
|
||
}: CalendarProps) {
|
||
const [viewDate, setViewDate] = useState(createDate(currentDate));
|
||
|
||
// Formatage des dates pour comparaison (éviter le décalage timezone)
|
||
const formatDateKey = (date: Date) => {
|
||
return formatDateForAPI(date);
|
||
};
|
||
|
||
const currentDateKey = formatDateKey(currentDate);
|
||
|
||
// Navigation mois
|
||
const goToPreviousMonth = () => {
|
||
const newDate = createDate(viewDate);
|
||
newDate.setMonth(newDate.getMonth() - 1);
|
||
setViewDate(newDate);
|
||
};
|
||
|
||
const goToNextMonth = () => {
|
||
const newDate = createDate(viewDate);
|
||
newDate.setMonth(newDate.getMonth() + 1);
|
||
setViewDate(newDate);
|
||
};
|
||
|
||
const goToToday = () => {
|
||
const today = getToday();
|
||
setViewDate(today);
|
||
onDateSelect(today);
|
||
};
|
||
|
||
// Obtenir les jours du mois
|
||
const getDaysInMonth = () => {
|
||
const year = viewDate.getFullYear();
|
||
const month = viewDate.getMonth();
|
||
|
||
// Premier jour du mois
|
||
const firstDay = new Date(year, month, 1);
|
||
// Dernier jour du mois
|
||
const lastDay = new Date(year, month + 1, 0);
|
||
|
||
// Premier lundi de la semaine contenant le premier jour
|
||
const startDate = createDate(firstDay);
|
||
const dayOfWeek = firstDay.getDay();
|
||
const daysToSubtract = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Lundi = 0
|
||
startDate.setDate(firstDay.getDate() - daysToSubtract);
|
||
|
||
// Générer toutes les dates du calendrier (6 semaines)
|
||
const days = [];
|
||
const currentDay = createDate(startDate);
|
||
|
||
for (let i = 0; i < 42; i++) {
|
||
// 6 semaines × 7 jours
|
||
days.push(createDate(currentDay));
|
||
currentDay.setDate(currentDay.getDate() + 1);
|
||
}
|
||
|
||
return { days, firstDay, lastDay };
|
||
};
|
||
|
||
const { days } = getDaysInMonth();
|
||
|
||
const handleDateClick = (date: Date) => {
|
||
onDateSelect(date);
|
||
};
|
||
|
||
const isTodayDate = (date: Date) => {
|
||
const today = getToday();
|
||
return formatDateKey(date) === formatDateKey(today);
|
||
};
|
||
|
||
const isCurrentMonth = (date: Date) => {
|
||
return date.getMonth() === viewDate.getMonth();
|
||
};
|
||
|
||
const hasMarkedDate = (date: Date) => {
|
||
return markedDates.includes(formatDateKey(date));
|
||
};
|
||
|
||
const isSelected = (date: Date) => {
|
||
return formatDateKey(date) === currentDateKey;
|
||
};
|
||
|
||
const formatMonthYear = () => {
|
||
return format(viewDate, 'MMMM yyyy', { locale: fr });
|
||
};
|
||
|
||
const weekDays = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'];
|
||
|
||
return (
|
||
<Card className={`p-4 ${className}`}>
|
||
{/* Header avec navigation */}
|
||
<div className="flex items-center justify-between mb-4">
|
||
<Button
|
||
onClick={goToPreviousMonth}
|
||
variant="ghost"
|
||
size="sm"
|
||
className="text-[var(--foreground)]"
|
||
>
|
||
←
|
||
</Button>
|
||
|
||
<h3 className="text-lg font-bold text-[var(--foreground)] capitalize">
|
||
{formatMonthYear()}
|
||
</h3>
|
||
|
||
<Button
|
||
onClick={goToNextMonth}
|
||
variant="ghost"
|
||
size="sm"
|
||
className="text-[var(--foreground)]"
|
||
>
|
||
→
|
||
</Button>
|
||
</div>
|
||
|
||
{/* Bouton Aujourd'hui */}
|
||
{showTodayButton && (
|
||
<div className="mb-4 text-center">
|
||
<Button onClick={goToToday} variant="primary" size="sm">
|
||
Aujourd'hui
|
||
</Button>
|
||
</div>
|
||
)}
|
||
|
||
{/* Jours de la semaine */}
|
||
<div className="grid grid-cols-7 gap-1 mb-2">
|
||
{weekDays.map((day) => (
|
||
<div
|
||
key={day}
|
||
className="text-center text-xs font-medium text-[var(--muted-foreground)] p-2"
|
||
>
|
||
{day}
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Grille du calendrier */}
|
||
<div className="grid grid-cols-7 gap-1">
|
||
{days.map((date, index) => {
|
||
const isCurrentMonthDay = isCurrentMonth(date);
|
||
const isTodayDay = isTodayDate(date);
|
||
const hasMarked = hasMarkedDate(date);
|
||
const isSelectedDay = isSelected(date);
|
||
|
||
return (
|
||
<button
|
||
key={index}
|
||
onClick={() => handleDateClick(date)}
|
||
className={`
|
||
relative p-2 text-sm rounded transition-all hover:bg-[var(--muted)]/50
|
||
${
|
||
isCurrentMonthDay
|
||
? 'text-[var(--foreground)]'
|
||
: 'text-[var(--muted-foreground)]'
|
||
}
|
||
${
|
||
isTodayDay
|
||
? 'bg-[var(--primary)]/20 border border-[var(--primary)]'
|
||
: ''
|
||
}
|
||
${isSelectedDay ? 'bg-[var(--primary)] text-white' : ''}
|
||
${hasMarked ? 'font-bold' : ''}
|
||
`}
|
||
>
|
||
{date.getDate()}
|
||
|
||
{/* Indicateur de date marquée */}
|
||
{hasMarked && (
|
||
<div
|
||
className={`
|
||
absolute bottom-1 right-1 w-2 h-2 rounded-full
|
||
${isSelectedDay ? 'bg-white' : 'bg-[var(--primary)]'}
|
||
`}
|
||
/>
|
||
)}
|
||
</button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* Légende */}
|
||
{showLegend && (
|
||
<div className="mt-4 text-xs text-[var(--muted-foreground)] space-y-1">
|
||
<div className="flex items-center gap-2">
|
||
<div className="w-2 h-2 rounded-full bg-[var(--primary)]"></div>
|
||
<span>Jour avec des éléments</span>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<div className="w-4 h-4 rounded border border-[var(--primary)] bg-[var(--primary)]/20"></div>
|
||
<span>Aujourd'hui</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</Card>
|
||
);
|
||
}
|