feat: implement optimistic UI for checkbox toggling in DailyCheckboxItem
- Added optimistic state handling in `DailyCheckboxItem` for immediate feedback on checkbox toggles, improving user experience. - Updated `useDaily` hook to handle checkbox state updates without blocking UI, ensuring smoother interactions. - Enhanced error handling to rollback state on toggle failures, maintaining data integrity.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { DailyCheckbox, DailyCheckboxType } from '@/lib/types';
|
||||
import { Input } from '@/components/ui/Input';
|
||||
@@ -24,6 +24,36 @@ export function DailyCheckboxItem({
|
||||
const [inlineEditingId, setInlineEditingId] = useState<string | null>(null);
|
||||
const [inlineEditingText, setInlineEditingText] = useState('');
|
||||
const [editingCheckbox, setEditingCheckbox] = useState<DailyCheckbox | null>(null);
|
||||
const [optimisticChecked, setOptimisticChecked] = useState<boolean | null>(null);
|
||||
|
||||
// État optimiste local pour une réponse immédiate
|
||||
const isChecked = optimisticChecked !== null ? optimisticChecked : checkbox.isChecked;
|
||||
|
||||
// Synchroniser l'état optimiste avec les changements externes
|
||||
useEffect(() => {
|
||||
if (optimisticChecked !== null && optimisticChecked === checkbox.isChecked) {
|
||||
// L'état serveur a été mis à jour, on peut reset l'optimiste
|
||||
setOptimisticChecked(null);
|
||||
}
|
||||
}, [checkbox.isChecked, optimisticChecked]);
|
||||
|
||||
// Handler optimiste pour le toggle
|
||||
const handleOptimisticToggle = async () => {
|
||||
const newCheckedState = !isChecked;
|
||||
|
||||
// Mise à jour optimiste immédiate
|
||||
setOptimisticChecked(newCheckedState);
|
||||
|
||||
try {
|
||||
await onToggle(checkbox.id);
|
||||
// Reset l'état optimiste après succès
|
||||
setOptimisticChecked(null);
|
||||
} catch (error) {
|
||||
// Rollback en cas d'erreur
|
||||
setOptimisticChecked(null);
|
||||
console.error('Erreur lors du toggle:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Édition inline simple
|
||||
const handleStartInlineEdit = () => {
|
||||
@@ -82,8 +112,8 @@ export function DailyCheckboxItem({
|
||||
{/* Checkbox */}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checkbox.isChecked}
|
||||
onChange={() => onToggle(checkbox.id)}
|
||||
checked={isChecked}
|
||||
onChange={handleOptimisticToggle}
|
||||
disabled={saving}
|
||||
className="w-4 h-4 md:w-3.5 md:h-3.5 rounded border border-[var(--border)] text-[var(--primary)] focus:ring-[var(--primary)]/20 focus:ring-1"
|
||||
/>
|
||||
|
||||
@@ -209,7 +209,6 @@ export function useDaily(initialDate?: Date, initialDailyView?: DailyView): UseD
|
||||
if (!dailyView) return Promise.resolve();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
startTransition(async () => {
|
||||
// Trouver la checkbox dans yesterday ou today
|
||||
let checkbox = dailyView.yesterday.find(cb => cb.id === checkboxId);
|
||||
if (!checkbox) {
|
||||
@@ -235,22 +234,22 @@ export function useDaily(initialDate?: Date, initialDailyView?: DailyView): UseD
|
||||
)
|
||||
} : null);
|
||||
|
||||
try {
|
||||
const result = await toggleCheckboxAction(checkboxId);
|
||||
|
||||
// Appel serveur en arrière-plan (sans startTransition)
|
||||
toggleCheckboxAction(checkboxId)
|
||||
.then(result => {
|
||||
if (!result.success) {
|
||||
// Rollback en cas d'erreur
|
||||
setDailyView(previousDailyView);
|
||||
setError(result.error || 'Erreur lors de la mise à jour de la checkbox');
|
||||
}
|
||||
resolve();
|
||||
} catch (err) {
|
||||
})
|
||||
.catch(err => {
|
||||
// Rollback en cas d'erreur
|
||||
setDailyView(previousDailyView);
|
||||
setError(err instanceof Error ? err.message : 'Erreur lors de la mise à jour de la checkbox');
|
||||
console.error('Erreur toggleCheckbox:', err);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}, [dailyView]);
|
||||
|
||||
Reference in New Issue
Block a user