refactor: date utils and all calls

This commit is contained in:
Julien Froidefond
2025-09-21 11:41:17 +02:00
parent 799a21df5c
commit 557cdebc13
23 changed files with 300 additions and 117 deletions

View File

@@ -2,6 +2,7 @@
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { Card } from '@/components/ui/Card';
import { parseDate, formatDateShort } from '@/lib/date-utils';
interface CompletionTrendData {
date: string;
@@ -18,11 +19,11 @@ interface CompletionTrendChartProps {
export function CompletionTrendChart({ data, title = "Tendance de Completion" }: CompletionTrendChartProps) {
// Formatter pour les dates
const formatDate = (dateStr: string) => {
const date = new Date(dateStr);
return date.toLocaleDateString('fr-FR', {
day: 'numeric',
month: 'short'
});
try {
return formatDateShort(parseDate(dateStr));
} catch {
return dateStr;
}
};
// Tooltip personnalisé

View File

@@ -3,6 +3,7 @@
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';
interface DailyCalendarProps {
currentDate: Date;
@@ -15,33 +16,30 @@ export function DailyCalendar({
onDateSelect,
dailyDates,
}: DailyCalendarProps) {
const [viewDate, setViewDate] = useState(new Date(currentDate));
const [viewDate, setViewDate] = useState(createDate(currentDate));
// Formatage des dates pour comparaison (éviter le décalage timezone)
const formatDateKey = (date: Date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
return formatDateForAPI(date);
};
const currentDateKey = formatDateKey(currentDate);
// Navigation mois
const goToPreviousMonth = () => {
const newDate = new Date(viewDate);
const newDate = createDate(viewDate);
newDate.setMonth(newDate.getMonth() - 1);
setViewDate(newDate);
};
const goToNextMonth = () => {
const newDate = new Date(viewDate);
const newDate = createDate(viewDate);
newDate.setMonth(newDate.getMonth() + 1);
setViewDate(newDate);
};
const goToToday = () => {
const today = new Date();
const today = getToday();
setViewDate(today);
onDateSelect(today);
};
@@ -57,18 +55,18 @@ export function DailyCalendar({
const lastDay = new Date(year, month + 1, 0);
// Premier lundi de la semaine contenant le premier jour
const startDate = new Date(firstDay);
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 = new Date(startDate);
const currentDay = createDate(startDate);
for (let i = 0; i < 42; i++) {
// 6 semaines × 7 jours
days.push(new Date(currentDay));
days.push(createDate(currentDay));
currentDay.setDate(currentDay.getDate() + 1);
}
@@ -81,8 +79,8 @@ export function DailyCalendar({
onDateSelect(date);
};
const isToday = (date: Date) => {
const today = new Date();
const isTodayDate = (date: Date) => {
const today = getToday();
return formatDateKey(date) === formatDateKey(today);
};
@@ -157,7 +155,7 @@ export function DailyCalendar({
<div className="grid grid-cols-7 gap-1">
{days.map((date, index) => {
const isCurrentMonthDay = isCurrentMonth(date);
const isTodayDay = isToday(date);
const isTodayDay = isTodayDate(date);
const hasCheckboxes = hasDaily(date);
const isSelectedDay = isSelected(date);

View File

@@ -2,6 +2,7 @@
import { useState } from 'react';
import { useWeeklyMetrics, useVelocityTrends } from '@/hooks/use-metrics';
import { getToday } from '@/lib/date-utils';
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { DailyStatusChart } from './charts/DailyStatusChart';
@@ -19,7 +20,7 @@ interface MetricsTabProps {
}
export function MetricsTab({ className }: MetricsTabProps) {
const [selectedDate] = useState<Date>(new Date());
const [selectedDate] = useState<Date>(getToday());
const [weeksBack, setWeeksBack] = useState(4);
const { metrics, loading: metricsLoading, error: metricsError, refetch: refetchMetrics } = useWeeklyMetrics(selectedDate);

View File

@@ -2,6 +2,7 @@
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { DailyMetrics } from '@/services/metrics';
import { parseDate, formatDateShort } from '@/lib/date-utils';
interface DailyStatusChartProps {
data: DailyMetrics[];
@@ -12,7 +13,7 @@ export function DailyStatusChart({ data, className }: DailyStatusChartProps) {
// Transformer les données pour le graphique
const chartData = data.map(day => ({
day: day.dayName.substring(0, 3), // Lun, Mar, etc.
date: new Date(day.date).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit' }),
date: formatDateShort(parseDate(day.date)),
'Complétées': day.completed,
'En cours': day.inProgress,
'Bloquées': day.blocked,

View File

@@ -1,6 +1,7 @@
'use client';
import { DailyMetrics } from '@/services/metrics';
import { parseDate, isToday } from '@/lib/date-utils';
interface WeeklyActivityHeatmapProps {
data: DailyMetrics[];
@@ -67,7 +68,7 @@ export function WeeklyActivityHeatmap({ data, className }: WeeklyActivityHeatmap
</div>
{/* Indicator si jour actuel */}
{new Date(day.date).toDateString() === new Date().toDateString() && (
{isToday(parseDate(day.date)) && (
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
)}
</div>

View File

@@ -4,6 +4,7 @@ import { useState, useEffect, useCallback, useTransition } from 'react';
import { DailyCheckbox } from '@/lib/types';
import { tasksClient } from '@/clients/tasks-client';
import { Button } from '@/components/ui/Button';
import { formatDateSmart } from '@/lib/date-utils';
import { Input } from '@/components/ui/Input';
import { addTodoToTask, toggleCheckbox } from '@/actions/daily';
@@ -82,11 +83,7 @@ export function RelatedTodos({ taskId }: RelatedTodosProps) {
if (isNaN(dateObj.getTime())) {
return 'Date invalide';
}
return new Intl.DateTimeFormat('fr-FR', {
day: 'numeric',
month: 'short',
year: 'numeric'
}).format(dateObj);
return formatDateSmart(dateObj);
} catch (error) {
console.error('Erreur formatage date:', error, date);
return 'Date invalide';

View File

@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { Modal } from '@/components/ui/Modal';
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
import { formatDateForDisplay, getToday } from '@/lib/date-utils';
interface AnomalyDetectionPanelProps {
className?: string;
@@ -42,7 +43,7 @@ export default function AnomalyDetectionPanel({ className = '' }: AnomalyDetecti
if (result.success && result.data) {
setAnomalies(result.data);
setLastUpdate(new Date().toLocaleString('fr-FR'));
setLastUpdate(formatDateForDisplay(getToday(), 'DISPLAY_LONG'));
} else {
setError(result.error || 'Erreur lors de la détection');
}

View File

@@ -8,6 +8,7 @@ import { Card, CardHeader, CardContent } from '@/components/ui/Card';
import { Input } from '@/components/ui/Input';
import { Modal } from '@/components/ui/Modal';
import { Header } from '@/components/ui/Header';
import { formatDateForDisplay } from '@/lib/date-utils';
import Link from 'next/link';
interface BackupSettingsPageClientProps {
@@ -193,16 +194,8 @@ export default function BackupSettingsPageClient({ initialData }: BackupSettings
const formatDate = (date: string | Date): string => {
// Format cohérent serveur/client pour éviter les erreurs d'hydratation
const d = new Date(date);
return d.toLocaleDateString('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
const d = typeof date === 'string' ? new Date(date) : date;
return formatDateForDisplay(d, 'DISPLAY_MEDIUM');
};
if (isLoading) {