/** * ConfirmForgetDialog — AWS-style confirmation for destructive memory actions. * * The user must type the persona name exactly to enable the confirm button. * This prevents accidental deletions while keeping the UX lightweight * (no password re-entry needed). * * Used for: * - Forgetting a single memory * - Forgetting ALL memories for a persona * * Safety: memories are deleted, the persona itself is NEVER deleted. */ import React, { useState, useRef, useEffect } from 'react' import { AlertTriangle, Brain, X } from 'lucide-react' // --------------------------------------------------------------------------- // Types // --------------------------------------------------------------------------- export interface ConfirmForgetDialogProps { /** What we're confirming — drives the copy & styling */ mode: 'single' | 'all' /** Persona display name — user must type this to confirm */ personaName: string /** How many memories will be deleted (shown in "all" mode) */ memoryCount?: number /** Description of the single memory being deleted */ memoryLabel?: string /** Category of the single memory */ memoryCategory?: string /** Called when user confirms the deletion */ onConfirm: () => void /** Called when user cancels */ onCancel: () => void /** Show loading spinner on the confirm button */ loading?: boolean } // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- export default function ConfirmForgetDialog({ mode, personaName, memoryCount = 0, memoryLabel, memoryCategory, onConfirm, onCancel, loading = false, }: ConfirmForgetDialogProps) { const [typed, setTyped] = useState('') const inputRef = useRef(null) // Auto-focus the input on mount useEffect(() => { const t = setTimeout(() => inputRef.current?.focus(), 80) return () => clearTimeout(t) }, []) const nameMatches = typed.trim().toLowerCase() === personaName.trim().toLowerCase() const canConfirm = nameMatches && !loading const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && canConfirm) onConfirm() if (e.key === 'Escape') onCancel() } return (
{ if (e.target === e.currentTarget) onCancel() }} >
e.stopPropagation()} > {/* Header */}
{mode === 'all' ? (
) : (
)}
{mode === 'all' ? 'Forget All Memories?' : 'Forget This Memory?'}
This action cannot be undone
{/* Body */}
{/* What's being deleted */} {mode === 'single' && memoryLabel && (
“{memoryLabel}”
{memoryCategory && (
category: {memoryCategory}
)}
)} {mode === 'all' && (
This will erase{' '} {memoryCount === 1 ? '1 memory' : `all ${memoryCount} memories`} {' '} stored for {personaName}.
The persona itself will NOT be deleted — only memories will be cleared.
)} {mode === 'single' && (
This memory will be permanently removed from{' '} {personaName}. The persona itself will not be affected.
)} {/* Type-to-confirm input */}
setTyped(e.target.value)} onKeyDown={handleKeyDown} placeholder={personaName} className={[ 'w-full px-4 py-3 rounded-2xl border text-sm text-white outline-none transition-all', 'bg-white/5 placeholder:text-white/15', nameMatches ? 'border-green-500/30 bg-green-500/5' : 'border-white/10 focus:border-white/20', ].join(' ')} autoComplete="off" spellCheck={false} />
{/* Footer */}
) }