diff --git a/js/src/features/emails/TemplateManager.tsx b/js/src/features/emails/TemplateManager.tsx new file mode 100644 index 0000000..58b41b9 --- /dev/null +++ b/js/src/features/emails/TemplateManager.tsx @@ -0,0 +1,347 @@ +import type { + EmailTemplate, + SendRequest, + MessagePreview, +} from "@/features/emails/dto/emailDto"; + +import { EmailPreviewer } from "@/features/emails/_components/EmailPreviewer"; +import { + listTemplates, + createTemplate, + deleteTemplate, + sendToLegacyPreviewApi, +} from "@/features/emails/api/emailAPI"; +import { + showEmailSuccess, + showEmailError, +} from "@/features/emails/api/emailError"; +import { + Tabs, + Stack, + Table, + Button, + Modal, + Text, + TextInput, + Textarea, + Group, + ActionIcon, + Tooltip, + Box, + Flex, +} from "@mantine/core"; +import { IconTrash, IconPlus } from "@tabler/icons-react"; +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; + +/** + * UNREACHABLE: This component is currently not reachable in the app's UI. It is intended for future implementation in managing email templates. + * TemplateManager component allows users to view, create, and delete email templates. + * It also provides a preview feature to visualize how the email will look with sample data. + */ +export function TemplateManager() { + const queryClient = useQueryClient(); + const [showCreateModal, setShowCreateModal] = useState(false); + const [formData, setFormData] = useState({ name: "", subject: "", body: "" }); + const [previewData, setPreviewData] = useState(null); + + const { data: templates, isLoading } = useQuery({ + queryKey: ["emailTemplates"], + queryFn: () => listTemplates(), + }); + + const createMutation = useMutation({ + mutationFn: async () => { + return await createTemplate({ + name: formData.name, + subject: formData.subject, + body: formData.body, + }); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["emailTemplates"] }); + showEmailSuccess( + "Template Created", + `"${formData.name}" created successfully`, + ); + setFormData({ name: "", subject: "", body: "" }); + setShowCreateModal(false); + }, + onError: (error) => { + showEmailError( + "Creation Failed", + error instanceof Error ? error.message : "Unknown error", + ); + }, + }); + + const deleteMutation = useMutation({ + mutationFn: async (templateId: string) => { + return await deleteTemplate(templateId); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["emailTemplates"] }); + showEmailSuccess("Template Deleted", "Template removed successfully"); + }, + onError: (error) => { + showEmailError( + "Delete Failed", + error instanceof Error ? error.message : "Unknown error", + ); + }, + }); + + const handlePreviewTemplate = async () => { + if (!formData.subject || !formData.body) { + showEmailError("Missing Fields", "Subject and body are required"); + return; + } + + try { + // Create fake messages with sample variables to preview + const request: SendRequest = { + subject: formData.subject, + body: formData.body, + replyTo: null, + messages: [ + { + recipients: [ + { + email: "sample@example.com", + variableToValue: { + "per1.name": "Alice", + "per1.email": "alice@example.com", + "per2.name": "Bob", + "per2.email": "bob@example.com", + }, + }, + ], + }, + ], + }; + + const previews = await sendToLegacyPreviewApi(request); + setPreviewData(previews || []); + } catch (error) { + showEmailError( + "Preview Failed", + error instanceof Error ? error.message : "Unknown error", + ); + } + }; + + const rows = (templates || []).map((template) => ( + + + + {template.name} + + + + + {new Date(template.createdAt).toLocaleDateString()} + + + + + { + if (confirm(`Delete template "${template.name}"?`)) { + deleteMutation.mutate(template.id); + } + }} + loading={deleteMutation.isPending} + > + + + + + + )); + + return ( + + + Templates ({templates?.length || 0}) + Create New + + + + + Available Templates + + + {isLoading ? + Loading templates... + : (templates || []).length === 0 ? + No templates yet. Create one to get started. + : + + + Name + Created + Action + + + {rows} +
+ } +
+
+ + + + Create New Template + + setFormData({ + ...formData, + name: e.currentTarget.value, + }) + } + /> +