'use client'; import { useEffect, useState, useCallback } from 'react'; import { Plus, Trash2, GripVertical } from 'lucide-react'; import { toast } from 'sonner'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Badge } from '@/components/ui/badge'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; const STORAGE_KEY = 'pe_custom_field_schemas'; type FieldType = 'text' | 'number' | 'select' | 'checkbox'; type FieldScope = 'task' | 'habit' | 'project' | 'note'; interface FieldSchema { id: string; name: string; type: FieldType; options?: string[]; scope: FieldScope; } const FIELD_TYPES: { value: FieldType; label: string }[] = [ { value: 'text', label: 'Text' }, { value: 'number', label: 'Number' }, { value: 'select', label: 'Select' }, { value: 'checkbox', label: 'Checkbox' }, ]; const SCOPE_OPTIONS: { value: FieldScope; label: string }[] = [ { value: 'task', label: 'Task' }, { value: 'habit', label: 'Habit' }, { value: 'project', label: 'Project' }, { value: 'note', label: 'Note' }, ]; function loadSchemas(): FieldSchema[] { if (typeof window === 'undefined') return []; try { const raw = localStorage.getItem(STORAGE_KEY); return raw ? JSON.parse(raw) : []; } catch { return []; } } function saveSchemas(schemas: FieldSchema[]) { localStorage.setItem(STORAGE_KEY, JSON.stringify(schemas)); } export function SettingsCustomFields() { const [schemas, setSchemas] = useState([]); const [filterScope, setFilterScope] = useState('all'); // Create form const [newName, setNewName] = useState(''); const [newType, setNewType] = useState('text'); const [newScope, setNewScope] = useState('task'); const [newOptions, setNewOptions] = useState(''); // Delete const [deletingId, setDeletingId] = useState(null); useEffect(() => { setSchemas(loadSchemas()); }, []); const filteredSchemas = filterScope === 'all' ? schemas : schemas.filter((s) => s.scope === filterScope); function handleAdd() { if (!newName.trim()) return; const newSchema: FieldSchema = { id: crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`, name: newName.trim(), type: newType, scope: newScope, options: newType === 'select' ? newOptions.split(',').map((o) => o.trim()).filter(Boolean) : undefined, }; const updated = [...schemas, newSchema]; saveSchemas(updated); setSchemas(updated); toast.success('Custom field added'); setNewName(''); setNewType('text'); setNewOptions(''); } function handleDelete(id: string) { const updated = schemas.filter((s) => s.id !== id); saveSchemas(updated); setSchemas(updated); setDeletingId(null); toast.success('Custom field removed'); } return ( Custom Fields Define custom field schemas for tasks, habits, projects, and notes. Stored locally in your browser. {/* Scope filter */}
{/* Schema list */}
{filteredSchemas.length === 0 ? (

{schemas.length === 0 ? 'No custom fields defined yet. Add one below.' : 'No custom fields match the selected scope.'}

) : ( filteredSchemas.map((field) => (
)) )}
{/* Add form */}
setNewName(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleAdd()} />
{newType === 'select' && (
setNewOptions(e.target.value)} />
)}
{/* Delete confirmation */} !open && setDeletingId(null)}> Remove custom field? This removes the field definition from your browser storage. Existing task data is not affected. Cancel deletingId && handleDelete(deletingId)} className="bg-destructive text-destructive-foreground hover:bg-destructive/90" > Remove
); }