/** * Hook for AddTriggerForm event handlers. * Extracts handler logic from AddTriggerForm for mode changes, content type changes, etc. */ import { useCallback } from 'react'; import { getAvailableMatchFields } from '../utils/trigger'; import type { AddTriggerFormStateReturn } from './useAddTriggerFormState'; import type { RepositoryDropdownItem } from '@renderer/components/settings/hooks/useSettingsConfig'; import type { NotificationTrigger, TriggerContentType, TriggerMatchField, TriggerMode, } from '@renderer/types/data'; interface UseAddTriggerFormHandlersOptions { formState: AddTriggerFormStateReturn; validatePattern: (pattern: string) => boolean; clearPreview: () => void; } export interface AddTriggerFormHandlersReturn { handleModeChange: (newMode: TriggerMode) => void; handleContentTypeChange: (newContentType: TriggerContentType) => void; handleToolNameChange: (newToolName: string) => void; handleAddRepository: (item: RepositoryDropdownItem) => void; handleRemoveIgnorePattern: (idx: number) => void; handleAddIgnorePattern: (pattern: string) => void; handleRemoveRepository: (idx: number) => void; handleMatchPatternChange: (value: string) => void; handleTokenThresholdChange: (value: string) => void; handleCancel: () => void; buildNewTrigger: (generateId: () => string) => Omit; } /** * Hook for managing AddTriggerForm event handlers. */ export function useAddTriggerFormHandlers({ formState, validatePattern, clearPreview, }: UseAddTriggerFormHandlersOptions): AddTriggerFormHandlersReturn { const { name, toolName, mode, contentType, matchField, matchPattern, tokenThreshold, tokenType, ignorePatterns, repositoryIds, color, setMode, setContentType, setToolName, setMatchField, setMatchPattern, setTokenThreshold, setIgnorePatterns, setRepositoryIds, setIsExpanded, resetForm, } = formState; // When mode changes, adjust content type defaults const handleModeChange = useCallback( (newMode: TriggerMode) => { setMode(newMode); if (newMode === 'error_status') { setContentType('tool_result'); } }, [setMode, setContentType] ); // When content type changes, reset matchField to first available option const handleContentTypeChange = useCallback( (newContentType: TriggerContentType) => { setContentType(newContentType); const newMatchFields = getAvailableMatchFields(newContentType, toolName || undefined); setMatchField(newMatchFields[0]?.value || ''); // Reset tool name if not applicable if (newContentType !== 'tool_use' && newContentType !== 'tool_result') { setToolName(''); } }, [toolName, setContentType, setMatchField, setToolName] ); // When tool name changes, reset matchField to first available option const handleToolNameChange = useCallback( (newToolName: string) => { setToolName(newToolName); const newMatchFields = getAvailableMatchFields(contentType, newToolName || undefined); setMatchField(newMatchFields[0]?.value || ''); }, [contentType, setToolName, setMatchField] ); // Handler for adding repository const handleAddRepository = useCallback( (item: RepositoryDropdownItem) => { if (!repositoryIds.includes(item.id)) { setRepositoryIds([...repositoryIds, item.id]); } }, [repositoryIds, setRepositoryIds] ); // Handler for removing ignore pattern const handleRemoveIgnorePattern = useCallback( (idx: number) => { const newPatterns = [...ignorePatterns]; newPatterns.splice(idx, 1); setIgnorePatterns(newPatterns); }, [ignorePatterns, setIgnorePatterns] ); // Handler for adding ignore pattern const handleAddIgnorePattern = useCallback( (pattern: string) => { setIgnorePatterns([...ignorePatterns, pattern]); }, [ignorePatterns, setIgnorePatterns] ); // Handler for removing repository const handleRemoveRepository = useCallback( (idx: number) => { const newIds = [...repositoryIds]; newIds.splice(idx, 1); setRepositoryIds(newIds); }, [repositoryIds, setRepositoryIds] ); // Handler for match pattern change with validation const handleMatchPatternChange = useCallback( (value: string) => { setMatchPattern(value); validatePattern(value); }, [setMatchPattern, validatePattern] ); // Handler for token threshold change const handleTokenThresholdChange = useCallback( (value: string) => { const val = value.replace(/\D/g, ''); setTokenThreshold(parseInt(val) || 0); }, [setTokenThreshold] ); // Handler for cancel button const handleCancel = useCallback(() => { resetForm(); clearPreview(); setIsExpanded(false); }, [resetForm, clearPreview, setIsExpanded]); // Build new trigger object from form state const buildNewTrigger = useCallback( (generateId: () => string): Omit => { return { id: `custom-${generateId()}`, name: name.trim(), enabled: true, contentType, mode, ...(mode === 'error_status' && { requireError: true }), ...(mode === 'content_match' && matchField && { matchField: matchField as TriggerMatchField }), ...(mode === 'content_match' && matchPattern && { matchPattern }), ...(mode === 'token_threshold' && { tokenThreshold, tokenType }), ...((contentType === 'tool_use' || contentType === 'tool_result') && toolName && { toolName }), ...(ignorePatterns.length > 0 && { ignorePatterns }), ...(repositoryIds.length > 0 && { repositoryIds }), color, }; }, [ name, contentType, mode, matchField, matchPattern, tokenThreshold, tokenType, toolName, ignorePatterns, repositoryIds, color, ] ); return { handleModeChange, handleContentTypeChange, handleToolNameChange, handleAddRepository, handleRemoveIgnorePattern, handleAddIgnorePattern, handleRemoveRepository, handleMatchPatternChange, handleTokenThresholdChange, handleCancel, buildNewTrigger, }; }