Files
towercontrol/components/daily/DailyCheckboxItem.tsx
Julien Froidefond adfef551ab feat: enhance DailyCheckbox model and service for type management
- Added `DailyCheckboxType` to define checkbox types ('task' | 'meeting') in TypeScript.
- Updated `DailyCheckbox` model in Prisma schema to include `type` field with a default value of 'task'.
- Modified `DailyService` to handle checkbox type during creation and updates.
- Adjusted API route to accept checkbox type in requests.
- Refactored `DailyPageClient` to support type management in checkbox operations.
2025-09-15 22:16:34 +02:00

163 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 { useState } from 'react';
import Link from 'next/link';
import { DailyCheckbox, DailyCheckboxType } from '@/lib/types';
import { Input } from '@/components/ui/Input';
import { EditCheckboxModal } from './EditCheckboxModal';
interface DailyCheckboxItemProps {
checkbox: DailyCheckbox;
onToggle: (checkboxId: string) => Promise<void>;
onUpdate: (checkboxId: string, text: string, type: DailyCheckboxType, taskId?: string) => Promise<void>;
onDelete: (checkboxId: string) => Promise<void>;
saving?: boolean;
}
export function DailyCheckboxItem({
checkbox,
onToggle,
onUpdate,
onDelete,
saving = false
}: DailyCheckboxItemProps) {
const [inlineEditingId, setInlineEditingId] = useState<string | null>(null);
const [inlineEditingText, setInlineEditingText] = useState('');
const [editingCheckbox, setEditingCheckbox] = useState<DailyCheckbox | null>(null);
// Édition inline simple
const handleStartInlineEdit = () => {
setInlineEditingId(checkbox.id);
setInlineEditingText(checkbox.text);
};
const handleSaveInlineEdit = async () => {
if (!inlineEditingText.trim()) return;
try {
await onUpdate(checkbox.id, inlineEditingText.trim(), checkbox.type, checkbox.taskId);
setInlineEditingId(null);
setInlineEditingText('');
} catch (error) {
console.error('Erreur lors de la modification:', error);
}
};
const handleCancelInlineEdit = () => {
setInlineEditingId(null);
setInlineEditingText('');
};
const handleInlineEditKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
e.preventDefault();
handleSaveInlineEdit();
} else if (e.key === 'Escape') {
e.preventDefault();
handleCancelInlineEdit();
}
};
// Modal d'édition avancée
const handleStartAdvancedEdit = () => {
setEditingCheckbox(checkbox);
};
const handleSaveAdvancedEdit = async (text: string, type: DailyCheckboxType, taskId?: string) => {
await onUpdate(checkbox.id, text, type, taskId);
setEditingCheckbox(null);
};
const handleCloseAdvancedEdit = () => {
setEditingCheckbox(null);
};
return (
<>
<div className={`flex items-center gap-3 p-2 rounded border transition-colors group ${
checkbox.type === 'meeting'
? 'border-l-4 border-l-blue-500 border-t-[var(--border)]/30 border-r-[var(--border)]/30 border-b-[var(--border)]/30 hover:border-t-[var(--border)] hover:border-r-[var(--border)] hover:border-b-[var(--border)]'
: 'border-l-4 border-l-green-500 border-t-[var(--border)]/30 border-r-[var(--border)]/30 border-b-[var(--border)]/30 hover:border-t-[var(--border)] hover:border-r-[var(--border)] hover:border-b-[var(--border)]'
}`}>
{/* Checkbox */}
<input
type="checkbox"
checked={checkbox.isChecked}
onChange={() => onToggle(checkbox.id)}
disabled={saving}
className="w-4 h-4 rounded border border-[var(--border)] text-[var(--primary)] focus:ring-[var(--primary)]/20 focus:ring-2"
/>
{/* Contenu principal */}
{inlineEditingId === checkbox.id ? (
<Input
value={inlineEditingText}
onChange={(e) => setInlineEditingText(e.target.value)}
onKeyDown={handleInlineEditKeyPress}
onBlur={handleSaveInlineEdit}
autoFocus
className="flex-1 h-8 text-sm"
/>
) : (
<div className="flex-1 flex items-center gap-2">
{/* Texte cliquable pour édition inline */}
<span
className={`flex-1 text-sm font-mono transition-all cursor-pointer hover:bg-[var(--muted)]/50 p-1 rounded ${
checkbox.isChecked
? 'line-through text-[var(--muted-foreground)]'
: 'text-[var(--foreground)]'
}`}
onClick={handleStartInlineEdit}
title="Cliquer pour éditer le texte"
>
{checkbox.text}
</span>
{/* Icône d'édition avancée */}
<button
onClick={handleStartAdvancedEdit}
disabled={saving}
className="opacity-0 group-hover:opacity-100 w-6 h-6 rounded-full bg-[var(--muted)]/50 hover:bg-[var(--muted)] border border-[var(--border)]/30 hover:border-[var(--border)] flex items-center justify-center transition-all duration-200 text-[var(--foreground)] text-xs"
title="Éditer les options (type, liaison tâche)"
>
</button>
</div>
)}
{/* Lien vers la tâche si liée */}
{checkbox.task && (
<Link
href={`/?highlight=${checkbox.task.id}`}
className="text-xs text-[var(--primary)] hover:text-[var(--primary)]/80 font-mono"
title={`Tâche: ${checkbox.task.title}`}
>
#{checkbox.task.id.slice(-6)}
</Link>
)}
{/* Bouton de suppression */}
<button
onClick={() => onDelete(checkbox.id)}
disabled={saving}
className="opacity-0 group-hover:opacity-100 w-6 h-6 rounded-full bg-[var(--destructive)]/20 hover:bg-[var(--destructive)]/30 border border-[var(--destructive)]/30 hover:border-[var(--destructive)]/50 flex items-center justify-center transition-all duration-200 text-[var(--destructive)] text-xs"
title="Supprimer"
>
×
</button>
</div>
{/* Modal d'édition avancée */}
{editingCheckbox && (
<EditCheckboxModal
checkbox={editingCheckbox}
isOpen={true}
onClose={handleCloseAdvancedEdit}
onSave={handleSaveAdvancedEdit}
saving={saving}
/>
)}
</>
);
}