// ======================================== // Hook Form Dialog Component // ======================================== // Dialog for creating and editing hooks import { useState, useEffect } from 'react'; import { useIntl } from 'react-intl'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/Dialog'; import { Input } from '@/components/ui/Input'; import { Textarea } from '@/components/ui/Textarea'; import { Button } from '@/components/ui/Button'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/Select'; import type { HookCardData, HookTriggerType } from './HookCard'; // ========== Types ========== export type HookFormMode = 'create' | 'edit'; export interface HookFormData { name: string; description: string; trigger: HookTriggerType; matcher: string; command: string; } export interface HookFormDialogProps { mode: HookFormMode; hook?: HookCardData; open: boolean; onClose: () => void; onSave: (data: HookFormData) => Promise; } // ========== Helper: Form Validation ========== interface FormErrors { name?: string; trigger?: string; command?: string; } function validateForm(data: HookFormData): FormErrors { const errors: FormErrors = {}; if (!data.name.trim()) { errors.name = 'validation.nameRequired'; } else if (!/^[a-zA-Z0-9_-]+$/.test(data.name)) { errors.name = 'validation.nameInvalid'; } if (!data.trigger) { errors.trigger = 'validation.triggerRequired'; } if (!data.command.trim()) { errors.command = 'validation.commandRequired'; } return errors; } // ========== Component ========== export function HookFormDialog({ mode, hook, open, onClose, onSave, }: HookFormDialogProps) { const { formatMessage } = useIntl(); const [formData, setFormData] = useState({ name: '', description: '', trigger: 'PostToolUse', matcher: '', command: '', }); const [errors, setErrors] = useState({}); const [isSubmitting, setIsSubmitting] = useState(false); // Reset form when dialog opens or hook changes useEffect(() => { if (open) { if (mode === 'edit' && hook) { setFormData({ name: hook.name, description: hook.description || '', trigger: hook.trigger, matcher: hook.matcher || '', command: hook.command || hook.script || '', }); } else { setFormData({ name: '', description: '', trigger: 'PostToolUse', matcher: '', command: '', }); } setErrors({}); } }, [open, mode, hook]); const handleFieldChange = ( field: keyof HookFormData, value: string ) => { setFormData((prev) => ({ ...prev, [field]: value })); // Clear error for this field when user starts typing if (errors[field as keyof FormErrors]) { setErrors((prev) => ({ ...prev, [field]: undefined })); } }; const handleSubmit = async () => { // Validate form const validationErrors = validateForm(formData); if (Object.keys(validationErrors).length > 0) { setErrors(validationErrors); return; } setIsSubmitting(true); try { await onSave(formData); onClose(); } catch (error) { console.error('Failed to save hook:', error); } finally { setIsSubmitting(false); } }; const TRIGGER_OPTIONS: { value: HookTriggerType; label: string }[] = [ { value: 'UserPromptSubmit', label: 'cliHooks.trigger.UserPromptSubmit' }, { value: 'PreToolUse', label: 'cliHooks.trigger.PreToolUse' }, { value: 'PostToolUse', label: 'cliHooks.trigger.PostToolUse' }, { value: 'Stop', label: 'cliHooks.trigger.Stop' }, ]; return ( {mode === 'create' ? formatMessage({ id: 'cliHooks.dialog.createTitle' }) : formatMessage({ id: 'cliHooks.dialog.editTitle' }, { hookName: hook?.name }) }
{/* Name */}
handleFieldChange('name', e.target.value)} placeholder={formatMessage({ id: 'cliHooks.form.namePlaceholder' })} className="mt-1" error={!!errors.name} /> {errors.name && (

{formatMessage({ id: `cliHooks.${errors.name}` })}

)}
{/* Description */}