Files
towercontrol/src/components/ui/Calendar.tsx
Julien Froidefond d45a04d347 feat: refactor Daily components and enhance UI integration
- 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.
2025-09-29 09:47:13 +02:00

221 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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&apos;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&apos;hui</span>
</div>
</div>
)}
</Card>
);
}