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 { TaskPriority, TaskStatus } from '@/lib/types';
import { getAllStatuses, getAllPriorities } from '@/lib/status-config';
import { ensureDate, formatDateForDateTimeInput } from '@/lib/date-utils';
interface TaskBasicFieldsProps {
title: string;
@@ -109,7 +110,10 @@ export function TaskBasicFields({
<Input
label="Date d'échéance"
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)}
disabled={loading}
/>

View File

@@ -34,26 +34,28 @@ export function normalizeDate(date: Date): Date {
* @param date - Date à formater
* @returns Format YYYY-MM-DD
*/
export function formatDateForAPI(date: Date): string {
if (!isValid(date)) {
export function formatDateForAPI(date: Date | string): string {
const ensuredDate = ensureDate(date);
if (!ensuredDate || !isValid(ensuredDate)) {
throw new Error('Date invalide fournie à formatDateForAPI');
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const year = ensuredDate.getFullYear();
const month = String(ensuredDate.getMonth() + 1).padStart(2, '0');
const day = String(ensuredDate.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
/**
* Formate une date pour l'affichage en français
*/
export function formatDateForDisplay(date: Date, formatType: keyof typeof DATE_FORMATS = 'DISPLAY_MEDIUM'): string {
if (!isValid(date)) {
export function formatDateForDisplay(date: Date | string, formatType: keyof typeof DATE_FORMATS = 'DISPLAY_MEDIUM'): string {
const ensuredDate = ensureDate(date);
if (!ensuredDate || !isValid(ensuredDate)) {
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
*/
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 diffTime = today.getTime() - normalizeDate(date).getTime();
const diffTime = today.getTime() - normalizeDate(ensuredDate).getTime();
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
*/
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();
return normalizeDate(date).getTime() === normalizeDate(today).getTime();
return normalizeDate(ensuredDate).getTime() === normalizeDate(today).getTime();
}
/**
* 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();
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)
*/
export function isSameDay(date1: Date, date2: Date): boolean {
return normalizeDate(date1).getTime() === normalizeDate(date2).getTime();
export function isSameDay(date1: Date | string, date2: Date | string): boolean {
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
});
}
/**
* 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;
}