diff --git a/src/components/modules/issue/ui/TemplateSelector.tsx b/src/components/modules/issue/ui/TemplateSelector.tsx index 5d01b9e..9b0eeea 100644 --- a/src/components/modules/issue/ui/TemplateSelector.tsx +++ b/src/components/modules/issue/ui/TemplateSelector.tsx @@ -1,5 +1,6 @@ 'use client'; +import { useEffect, useMemo, useRef, useState } from 'react'; import type { CredentialTemplate } from '@/@types/templates'; export default function TemplateSelector({ @@ -15,67 +16,164 @@ export default function TemplateSelector({ onCreateCustom?: () => void; onDeleteCustom?: (id: string) => void; }) { + const [open, setOpen] = useState(false); + const wrapperRef = useRef(null); + const isCustom = (id: string) => id.startsWith('custom-'); const selectedIsCustom = selectedId ? isCustom(selectedId) : false; + const selectedTemplate = useMemo( + () => templates.find((template) => template.id === selectedId) ?? null, + [templates, selectedId] + ); + const builtInTemplates = useMemo( + () => templates.filter((template) => !isCustom(template.id)), + [templates] + ); + const customTemplates = useMemo( + () => templates.filter((template) => isCustom(template.id)), + [templates] + ); + + useEffect(() => { + const onPointerDownOutside = (event: MouseEvent) => { + if (!wrapperRef.current?.contains(event.target as Node)) { + setOpen(false); + } + }; + + const onEscape = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + setOpen(false); + } + }; + + document.addEventListener('mousedown', onPointerDownOutside); + document.addEventListener('keydown', onEscape); + + return () => { + document.removeEventListener('mousedown', onPointerDownOutside); + document.removeEventListener('keydown', onEscape); + }; + }, []); return (
- +
- +
{onCreateCustom && ( )}
+ {templates.length === 0 && ( +

+ No templates available yet. Create one with{' '} + {onCreateCustom ? + Custom : 'template builder'}. +

+ )} + {selectedIsCustom && onDeleteCustom && selectedId && (