feat: enhance date handling in TaskBasicFields and date-utils

- Integrated `ensureDate` and `formatDateForDateTimeInput` in `TaskBasicFields` for improved due date management.
- Updated `date-utils` functions to accept both `Date` and `string` types, ensuring robust date validation and parsing.
- Added `ensureDate` utility to handle various date inputs, improving error handling and consistency across date-related functions.
This commit is contained in:
Julien Froidefond
2025-09-24 13:53:18 +02:00
parent 75aa60cb83
commit 167f90369b
2 changed files with 88 additions and 17 deletions

View File

@@ -3,6 +3,7 @@
import { Input } from '@/components/ui/Input'; import { Input } from '@/components/ui/Input';
import { TaskPriority, TaskStatus } from '@/lib/types'; import { TaskPriority, TaskStatus } from '@/lib/types';
import { getAllStatuses, getAllPriorities } from '@/lib/status-config'; import { getAllStatuses, getAllPriorities } from '@/lib/status-config';
import { ensureDate, formatDateForDateTimeInput } from '@/lib/date-utils';
interface TaskBasicFieldsProps { interface TaskBasicFieldsProps {
title: string; title: string;
@@ -109,7 +110,10 @@ export function TaskBasicFields({
<Input <Input
label="Date d'échéance" label="Date d'échéance"
type="datetime-local" type="datetime-local"
value={dueDate ? new Date(dueDate.getTime() - dueDate.getTimezoneOffset() * 60000).toISOString().slice(0, 16) : ''} value={(() => {
const date = ensureDate(dueDate);
return date ? formatDateForDateTimeInput(date) : '';
})()}
onChange={(e) => onDueDateChange(e.target.value ? new Date(e.target.value) : undefined)} onChange={(e) => onDueDateChange(e.target.value ? new Date(e.target.value) : undefined)}
disabled={loading} disabled={loading}
/> />

View File

@@ -34,26 +34,28 @@ export function normalizeDate(date: Date): Date {
* @param date - Date à formater * @param date - Date à formater
* @returns Format YYYY-MM-DD * @returns Format YYYY-MM-DD
*/ */
export function formatDateForAPI(date: Date): string { export function formatDateForAPI(date: Date | string): string {
if (!isValid(date)) { const ensuredDate = ensureDate(date);
if (!ensuredDate || !isValid(ensuredDate)) {
throw new Error('Date invalide fournie à formatDateForAPI'); throw new Error('Date invalide fournie à formatDateForAPI');
} }
const year = date.getFullYear(); const year = ensuredDate.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); const month = String(ensuredDate.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0'); const day = String(ensuredDate.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
} }
/** /**
* Formate une date pour l'affichage en français * Formate une date pour l'affichage en français
*/ */
export function formatDateForDisplay(date: Date, formatType: keyof typeof DATE_FORMATS = 'DISPLAY_MEDIUM'): string { export function formatDateForDisplay(date: Date | string, formatType: keyof typeof DATE_FORMATS = 'DISPLAY_MEDIUM'): string {
if (!isValid(date)) { const ensuredDate = ensureDate(date);
if (!ensuredDate || !isValid(ensuredDate)) {
throw new Error('Date invalide fournie à formatDateForDisplay'); throw new Error('Date invalide fournie à formatDateForDisplay');
} }
return format(date, DATE_FORMATS[formatType], { locale: fr }); return format(ensuredDate, DATE_FORMATS[formatType], { locale: fr });
} }
/** /**
@@ -66,9 +68,14 @@ export function formatDateShort(date: Date): string {
/** /**
* Calcule le nombre de jours écoulés depuis une date * Calcule le nombre de jours écoulés depuis une date
*/ */
export function getDaysAgo(date: Date): number { export function getDaysAgo(date: Date | string): number {
const ensuredDate = ensureDate(date);
if (!ensuredDate) {
throw new Error('Date invalide fournie à getDaysAgo');
}
const today = getToday(); const today = getToday();
const diffTime = today.getTime() - normalizeDate(date).getTime(); const diffTime = today.getTime() - normalizeDate(ensuredDate).getTime();
return Math.floor(diffTime / (1000 * 60 * 60 * 24)); return Math.floor(diffTime / (1000 * 60 * 60 * 24));
} }
@@ -82,25 +89,36 @@ export function formatDateLong(date: Date): string {
/** /**
* Vérifie si une date est aujourd'hui * Vérifie si une date est aujourd'hui
*/ */
export function isToday(date: Date): boolean { export function isToday(date: Date | string): boolean {
const ensuredDate = ensureDate(date);
if (!ensuredDate) return false;
const today = new Date(); const today = new Date();
return normalizeDate(date).getTime() === normalizeDate(today).getTime(); return normalizeDate(ensuredDate).getTime() === normalizeDate(today).getTime();
} }
/** /**
* Vérifie si une date est hier * Vérifie si une date est hier
*/ */
export function isYesterday(date: Date): boolean { export function isYesterday(date: Date | string): boolean {
const ensuredDate = ensureDate(date);
if (!ensuredDate) return false;
const yesterday = new Date(); const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1); yesterday.setDate(yesterday.getDate() - 1);
return normalizeDate(date).getTime() === normalizeDate(yesterday).getTime(); return normalizeDate(ensuredDate).getTime() === normalizeDate(yesterday).getTime();
} }
/** /**
* Compare deux dates (sans tenir compte de l'heure) * Compare deux dates (sans tenir compte de l'heure)
*/ */
export function isSameDay(date1: Date, date2: Date): boolean { export function isSameDay(date1: Date | string, date2: Date | string): boolean {
return normalizeDate(date1).getTime() === normalizeDate(date2).getTime(); const ensuredDate1 = ensureDate(date1);
const ensuredDate2 = ensureDate(date2);
if (!ensuredDate1 || !ensuredDate2) return false;
return normalizeDate(ensuredDate1).getTime() === normalizeDate(ensuredDate2).getTime();
} }
/** /**
@@ -258,3 +276,52 @@ export function formatDistanceToNow(date: Date, options?: { addSuffix?: boolean
addSuffix: options?.addSuffix ?? true addSuffix: options?.addSuffix ?? true
}); });
} }
/**
* S'assure qu'une valeur est un objet Date valide
* Convertit les chaînes de caractères en Date si nécessaire
*/
export function ensureDate(value: Date | string | null | undefined): Date | null {
if (value === null || value === undefined) {
return null;
}
// Si c'est déjà un objet Date valide
if (value instanceof Date && isValid(value)) {
return value;
}
// Si c'est une chaîne de caractères, essayer de la parser
if (typeof value === 'string') {
try {
const parsed = parseDate(value);
return parsed;
} catch {
console.warn(`Impossible de parser la date: ${value}`);
return null;
}
}
// Si c'est un objet Date mais invalide, essayer de le recréer
if (value instanceof Date) {
try {
const time = value.getTime();
if (!isNaN(time)) {
return value;
}
} catch {
console.warn('Objet Date invalide détecté');
}
}
console.warn('Valeur de date non supportée:', value);
return null;
}
/**
* S'assure qu'une valeur est un objet Date valide, avec une valeur par défaut
*/
export function ensureDateWithDefault(value: Date | string | null | undefined, defaultValue: Date = new Date()): Date {
const result = ensureDate(value);
return result || defaultValue;
}