/,
);
if (contentMatch) {
return contentMatch[1].trim();
}
return html;
}, []);
// When langData changes (e.g., after refetch), update the body content
useEffect(() => {
if (langData) {
if (langData.is_default) {
// For default templates, extract just the content portion
setEditBody(extractBodyContent(langData.body_html));
} else {
setEditBody(langData.body_html);
}
setEditSubject(langData.subject);
setIsDirty(false);
}
}, [activeLang, langData, extractBodyContent]);
// Save mutation
const saveMutation = useMutation({
mutationFn: () =>
adminEmailTemplatesApi.updateTemplate(detail.notification_type, activeLang, {
subject: editSubject,
body_html: editBody,
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin', 'email-templates'] });
queryClient.invalidateQueries({
queryKey: ['admin', 'email-template', detail.notification_type],
});
setIsDirty(false);
notify.success(t('admin.emailTemplates.saved'));
},
onError: () => {
notify.error(t('common.error'));
},
});
// Reset mutation
const resetMutation = useMutation({
mutationFn: () => adminEmailTemplatesApi.deleteTemplate(detail.notification_type, activeLang),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin', 'email-templates'] });
queryClient.invalidateQueries({
queryKey: ['admin', 'email-template', detail.notification_type],
});
setIsDirty(false);
notify.success(t('admin.emailTemplates.resetted'));
},
onError: () => {
notify.error(t('common.error'));
},
});
// Send test mutation
const testMutation = useMutation({
mutationFn: () =>
adminEmailTemplatesApi.sendTestEmail(detail.notification_type, {
language: activeLang,
}),
onSuccess: (data) => {
notify.success(`${t('admin.emailTemplates.testSent')} → ${data.sent_to}`);
},
onError: () => {
notify.error(t('common.error'));
},
});
const handleSubjectChange = (value: string) => {
setEditSubject(value);
setIsDirty(true);
};
const handleBodyChange = (value: string) => {
setEditBody(value);
setIsDirty(true);
};
const label = detail.label[interfaceLang] || detail.label['en'] || detail.notification_type;
return (
(null);
// Fetch template types list
const { data: typesData, isLoading: typesLoading } = useQuery({
queryKey: ['admin', 'email-templates'],
queryFn: adminEmailTemplatesApi.getTemplateTypes,
});
// Fetch detail for selected type
const { data: detailData, isLoading: detailLoading } = useQuery({
queryKey: ['admin', 'email-template', selectedType],
queryFn: () => adminEmailTemplatesApi.getTemplate(selectedType!),
enabled: !!selectedType,
});
return (
{/* Header */}
{langData && !langData.is_default && (
Custom
)}
{/* Language tabs */}
)}
{/* Body HTML editor */}
{/* Actions */}
);
}
// ============ Main Page ============
export default function AdminEmailTemplates() {
const { t, i18n } = useTranslation();
const currentLang = i18n.language || 'ru';
const [selectedType, setSelectedType] = useState{label}
{detail.description[interfaceLang] || detail.description['en'] || ''}
{Object.keys(detail.languages).map((lang) => {
const isActive = lang === activeLang;
const langInfo = detail.languages[lang];
return (
);
})}
{/* Subject */}
handleSubjectChange(e.target.value)}
className="input"
placeholder={t('admin.emailTemplates.subjectPlaceholder')}
/>
{/* Context variables hint */}
{detail.context_vars.length > 0 && (
{t('admin.emailTemplates.variables')}
{detail.context_vars.map((v) => (
{
navigator.clipboard.writeText(`{${v}}`);
notify.success(`Copied {${v}}`);
}}
>
{`{${v}}`}
))}
{langData && !langData.is_default && (
)}
{/* Page Header */}
{/* Content */}
{selectedType && detailData ? (
setSelectedType(null)}
currentLang={currentLang}
/>
) : (
<>
{/* Template List */}
{typesLoading ? (
)}
);
}
{t('admin.emailTemplates.title')}
{t('admin.emailTemplates.description')}
{[...Array(6)].map((_, i) => (
))}
) : (
{typesData?.items.map((template) => (
setSelectedType(template.type)}
/>
))}
)}
>
)}
{/* Detail loading overlay */}
{selectedType && detailLoading && (