diff --git a/src/pages/Admin/index.js b/src/pages/Admin/index.js index ff872e8..27882f3 100644 --- a/src/pages/Admin/index.js +++ b/src/pages/Admin/index.js @@ -58,6 +58,13 @@ const navItems = [ label: __('Invio PEC Massivo', 'gepafin'), subtitle: __('Invia PEC a più destinatari tramite file CSV', 'gepafin'), icon: 'pi pi-envelope' + }, + { + permission: ['ROOT_MANAGE_EMAIL_TEMPLATES'], + route: '/admin/email-templates', + label: __('Template Email', 'gepafin'), + subtitle: __('Gestione dei template per le email', 'gepafin'), + icon: 'pi pi-file-edit' } ]; diff --git a/src/pages/AdminEmailTemplates/index.js b/src/pages/AdminEmailTemplates/index.js new file mode 100644 index 0000000..a70294b --- /dev/null +++ b/src/pages/AdminEmailTemplates/index.js @@ -0,0 +1,343 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { __ } from '@wordpress/i18n'; +import { intersection } from 'ramda'; +import { useNavigate } from 'react-router-dom'; + +// store +import { useStoreValue } from '../../store'; + +// components +import { Button } from 'primereact/button'; +import { DataTable } from 'primereact/datatable'; +import { Column } from 'primereact/column'; +import { Dialog } from 'primereact/dialog'; +import { InputText } from 'primereact/inputtext'; +import { Dropdown } from 'primereact/dropdown'; +import { Editor } from 'primereact/editor'; +import { Tag } from 'primereact/tag'; +import { Toast } from 'primereact/toast'; +import { ConfirmDialog, confirmDialog } from 'primereact/confirmdialog'; + +const TEMPLATE_TYPES = [ + { + value: 'WELCOME', + label: __('Benvenuto', 'gepafin'), + tags: ['companyName', 'userEmail', 'userName'] + }, + { + value: 'APPLICATION_APPROVED', + label: __('Domanda Approvata', 'gepafin'), + tags: ['companyName', 'callTitle', 'applicationId', 'approvalDate'] + }, + { + value: 'APPLICATION_REJECTED', + label: __('Domanda Rifiutata', 'gepafin'), + tags: ['companyName', 'callTitle', 'applicationId', 'rejectionReason'] + }, + { + value: 'AMENDMENT_REQUEST', + label: __('Richiesta Integrazione', 'gepafin'), + tags: ['companyName', 'callTitle', 'applicationId', 'amendmentDeadline', 'amendmentNotes'] + }, + { + value: 'PEC_NOTIFICATION', + label: __('Notifica PEC', 'gepafin'), + tags: ['companyName', 'companyPec', 'callTitle', 'applicationId'] + } +]; + +const INITIAL_TEMPLATES = [ + { + id: 1, + title: 'Email di Benvenuto', + type: 'WELCOME', + content: '
Benvenuto {{userName}},
il tuo account è stato creato con successo. Azienda: {{companyName}}.
' + }, + { + id: 2, + title: 'Approvazione Domanda', + type: 'APPLICATION_APPROVED', + content: 'Gentile {{companyName}},
la domanda {{applicationId}} per il bando {{callTitle}} è stata approvata in data {{approvalDate}}.
' + } +]; + +const getTypeLabel = (value) => { + const found = TEMPLATE_TYPES.find((t) => t.value === value); + return found ? found.label : value; +}; + +const getTypeTags = (value) => { + const found = TEMPLATE_TYPES.find((t) => t.value === value); + return found ? found.tags : []; +}; + +const editorHeader = ( + + + + + + + + + + +); + +const AdminEmailTemplates = () => { + const permissions = useStoreValue('getPermissions'); + const navigate = useNavigate(); + const toast = useRef(null); + const editorRef = useRef(null); + const hasPermission = intersection(permissions, ['ROOT_MANAGE_EMAIL_TEMPLATES']).length > 0; + + const [templates, setTemplates] = useState(INITIAL_TEMPLATES); + const [dialogVisible, setDialogVisible] = useState(false); + const [editingTemplate, setEditingTemplate] = useState(null); + const [modalTitle, setModalTitle] = useState(''); + const [modalType, setModalType] = useState(TEMPLATE_TYPES[0].value); + const [modalContent, setModalContent] = useState(''); + + useEffect(() => { + if (!hasPermission) navigate('/admin'); + }, [hasPermission]); + + const openAddDialog = () => { + setEditingTemplate({}); + setModalTitle(''); + setModalType(TEMPLATE_TYPES[0].value); + setModalContent(''); + setDialogVisible(true); + }; + + const openEditDialog = (template) => { + setEditingTemplate(template); + setModalTitle(template.title); + setModalType(template.type); + setModalContent(template.content); + setDialogVisible(true); + }; + + const closeDialog = () => { + setDialogVisible(false); + setEditingTemplate(null); + }; + + const handleSave = () => { + if (!modalTitle.trim()) { + toast.current.show({ + severity: 'warn', + summary: __('Attenzione', 'gepafin'), + detail: __('Il titolo è obbligatorio.', 'gepafin') + }); + return; + } + + if (editingTemplate && editingTemplate.id) { + setTemplates((prev) => + prev.map((t) => + t.id === editingTemplate.id + ? { ...t, title: modalTitle, type: modalType, content: modalContent } + : t + ) + ); + } else { + setTemplates((prev) => [ + ...prev, + { id: Date.now(), title: modalTitle, type: modalType, content: modalContent } + ]); + } + + closeDialog(); + toast.current.show({ + severity: 'success', + summary: __('Salvato', 'gepafin'), + detail: __('Template salvato con successo.', 'gepafin') + }); + }; + + const handleRemove = (template) => { + confirmDialog({ + message: __('Sei sicuro di voler eliminare questo template?', 'gepafin'), + header: __('Conferma eliminazione', 'gepafin'), + icon: 'pi pi-exclamation-triangle', + acceptLabel: __('Elimina', 'gepafin'), + rejectLabel: __('Annulla', 'gepafin'), + accept: () => { + setTemplates((prev) => prev.filter((t) => t.id !== template.id)); + toast.current.show({ + severity: 'info', + summary: __('Eliminato', 'gepafin'), + detail: __('Template eliminato.', 'gepafin') + }); + } + }); + }; + + const insertTag = (tag) => { + if (editorRef.current) { + const quill = editorRef.current.getQuill(); + if (quill) { + const range = quill.getSelection(true); + const index = range ? range.index : quill.getLength(); + quill.insertText(index, `{{${tag}}}`); + quill.setSelection(index + tag.length + 4); + return; + } + } + setModalContent((prev) => (prev || '') + `{{${tag}}}`); + }; + + const typeBodyTemplate = (row) => getTypeLabel(row.type); + + const actionsBodyTemplate = (row) => ( +