import { MessageSquare, Pencil, Plus, Trash2, X } from "lucide-react"; import React, { useCallback, useMemo, useState } from "react"; import type { AIQuickMessage } from "../../../../infrastructure/ai/quickMessages"; import { createQuickMessageId, isValidQuickMessageSlug, normalizeQuickMessageSlug, QUICK_MESSAGE_LIMITS, slugFromQuickMessageName, } from "../../../../infrastructure/ai/quickMessages"; import { useI18n } from "../../../../application/i18n/I18nProvider"; import { Button } from "../../../ui/button"; import { SettingCard, SettingsSection } from "../../settings-ui"; interface QuickMessagesSettingsProps { quickMessages: AIQuickMessage[]; setQuickMessages: (value: AIQuickMessage[] | ((prev: AIQuickMessage[]) => AIQuickMessage[])) => void; reservedUserSkillSlugs?: string[]; } type DraftQuickMessage = { name: string; slug: string; content: string; description: string; }; const emptyDraft = (): DraftQuickMessage => ({ name: "", slug: "", content: "", description: "", }); export const QuickMessagesSettings: React.FC = ({ quickMessages, setQuickMessages, reservedUserSkillSlugs = [], }) => { const { t } = useI18n(); const [editingId, setEditingId] = useState(null); const [isCreating, setIsCreating] = useState(false); const [draft, setDraft] = useState(emptyDraft); const [slugTouched, setSlugTouched] = useState(false); const [error, setError] = useState(null); const sortedMessages = useMemo( () => [...quickMessages].sort((a, b) => a.name.localeCompare(b.name)), [quickMessages], ); const resetEditor = useCallback(() => { setEditingId(null); setIsCreating(false); setDraft(emptyDraft()); setSlugTouched(false); setError(null); }, []); const beginCreate = useCallback(() => { setEditingId(null); setIsCreating(true); setDraft(emptyDraft()); setSlugTouched(false); setError(null); }, []); const beginEdit = useCallback((message: AIQuickMessage) => { setIsCreating(false); setEditingId(message.id); setDraft({ name: message.name, slug: message.slug, content: message.content, description: message.description ?? "", }); setSlugTouched(true); setError(null); }, []); const handleNameChange = useCallback((name: string) => { setDraft((prev) => ({ ...prev, name, slug: slugTouched ? prev.slug : slugFromQuickMessageName(name), })); }, [slugTouched]); const handleSlugChange = useCallback((slug: string) => { setSlugTouched(true); setDraft((prev) => ({ ...prev, slug: normalizeQuickMessageSlug(slug) })); }, []); const validateDraft = useCallback((nextDraft: DraftQuickMessage, excludeId?: string | null): string | null => { const name = nextDraft.name.trim(); const slug = normalizeQuickMessageSlug(nextDraft.slug); const content = nextDraft.content.trim(); if (!name) return t("ai.quickMessages.error.nameRequired"); if (!isValidQuickMessageSlug(slug)) return t("ai.quickMessages.error.invalidSlug"); if (!content) return t("ai.quickMessages.error.contentRequired"); if (!excludeId && quickMessages.length >= QUICK_MESSAGE_LIMITS.maxItems) { return t("ai.quickMessages.error.maxItems", { max: String(QUICK_MESSAGE_LIMITS.maxItems) }); } const slugTaken = quickMessages.some( (message) => message.slug === slug && message.id !== excludeId, ); if (slugTaken) return t("ai.quickMessages.error.slugTaken"); const skillConflict = reservedUserSkillSlugs.some((skillSlug) => skillSlug === slug); if (skillConflict) { return t("ai.quickMessages.error.slugConflictsWithSkill", { slug }); } return null; }, [quickMessages, reservedUserSkillSlugs, t]); const handleSave = useCallback(() => { const validationError = validateDraft(draft, editingId); if (validationError) { setError(validationError); return; } const payload: AIQuickMessage = { id: editingId ?? createQuickMessageId(), name: draft.name.trim(), slug: normalizeQuickMessageSlug(draft.slug), content: draft.content.trim(), description: draft.description.trim() || undefined, }; if (editingId) { setQuickMessages((prev) => prev.map((message) => ( message.id === editingId ? payload : message ))); } else { setQuickMessages((prev) => [...prev, payload]); } resetEditor(); }, [draft, editingId, resetEditor, setQuickMessages, validateDraft]); const handleDelete = useCallback((message: AIQuickMessage) => { const ok = window.confirm(t("ai.quickMessages.confirmDelete", { name: message.name })); if (!ok) return; setQuickMessages((prev) => prev.filter((item) => item.id !== message.id)); if (editingId === message.id) { resetEditor(); } }, [editingId, resetEditor, setQuickMessages, t]); const showEditor = isCreating || editingId != null; return ( {t("ai.quickMessages.add")} )} >

{t("ai.quickMessages.description")}

{showEditor ? (
{isCreating ? t("ai.quickMessages.createTitle") : t("ai.quickMessages.editTitle")}