Email de test : récapitulatif de planning compilé
L'email de test reprend le modèle en cours d'édition, balises remplies avec le planning d'un bénévole au choix (premier avec un créneau par défaut), option lien de connexion sans vrai jeton, sujet « [Test] … » — même fonction de rendu que l'envoi réel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
461742eb78
commit
440466ccf9
@@ -1,11 +1,12 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useSendPlanningNotification, useSendTestEmail } from '@/api/hooks';
|
||||
import { useSendPlanningNotification, useSendTestEmail, useVolunteers } from '@/api/hooks';
|
||||
import type { TestEmailResult } from '@/api/schema';
|
||||
import { ErrorNote } from '@/components/state';
|
||||
import { Btn, FieldLabel, HelpTip, Panel, PanelHeader } from '@/components/ui';
|
||||
import { t } from '@/i18n';
|
||||
import { cx } from '@/lib/cx';
|
||||
import { volunteerName } from '@/lib/volunteer';
|
||||
|
||||
const MAIL_VARIABLES = [
|
||||
'{prenom}',
|
||||
@@ -102,7 +103,7 @@ export function ConfigMail() {
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<TestEmailPanel />
|
||||
<TestEmailPanel subject={subject} body={body} />
|
||||
|
||||
<Panel shadow="lg">
|
||||
<PanelHeader hatched>{t('config.mail.previewTitle')}</PanelHeader>
|
||||
@@ -128,19 +129,34 @@ const RESULT_TONE: Record<TestEmailResult['status'], string> = {
|
||||
rejected: 'bg-orange',
|
||||
};
|
||||
|
||||
/** Envoie un email de test à l'adresse saisie et affiche le résultat réel
|
||||
* du serveur SMTP (envoyé, envoi désactivé, connexion ou message refusé). */
|
||||
function TestEmailPanel() {
|
||||
/** Envoie à l'adresse saisie le récapitulatif **tel que les bénévoles le
|
||||
* recevront** (le modèle en cours d'édition, variables remplies avec les
|
||||
* données d'un bénévole) et affiche le résultat réel du serveur SMTP. */
|
||||
function TestEmailPanel({ subject, body }: { subject: string; body: string }) {
|
||||
const [email, setEmail] = useState('');
|
||||
// '' = choix automatique (premier bénévole qui a un créneau).
|
||||
const [volunteerId, setVolunteerId] = useState('');
|
||||
const [withLink, setWithLink] = useState(false);
|
||||
const volunteers = useVolunteers();
|
||||
const test = useSendTestEmail();
|
||||
const result = test.data;
|
||||
const options = [...(volunteers.data ?? [])].sort((a, b) =>
|
||||
volunteerName(a).localeCompare(volunteerName(b), 'fr'),
|
||||
);
|
||||
return (
|
||||
<Panel shadow="lg">
|
||||
<PanelHeader>{t('config.mail.test.title')}</PanelHeader>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (email.trim()) test.mutate(email.trim());
|
||||
if (!email.trim()) return;
|
||||
test.mutate({
|
||||
email: email.trim(),
|
||||
subject,
|
||||
// Même corps que le bouton « avec lien de connexion » si coché.
|
||||
body: withLink ? withLoginLink(body) : body,
|
||||
volunteer_id: volunteerId || null,
|
||||
});
|
||||
}}
|
||||
className="flex flex-col gap-3 p-[13px]"
|
||||
>
|
||||
@@ -155,6 +171,25 @@ function TestEmailPanel() {
|
||||
className="w-full border-2 border-ink bg-cream p-[9px] font-mono text-[12px]"
|
||||
/>
|
||||
</label>
|
||||
<label className="block">
|
||||
<FieldLabel>{t('config.mail.test.example')}</FieldLabel>
|
||||
<select
|
||||
value={volunteerId}
|
||||
onChange={(e) => setVolunteerId(e.target.value)}
|
||||
className="w-full border-2 border-ink bg-cream p-[8px] font-display text-[12.5px] font-bold"
|
||||
>
|
||||
<option value="">{t('config.mail.test.exampleAuto')}</option>
|
||||
{options.map((v) => (
|
||||
<option key={v.id} value={v.id}>
|
||||
{volunteerName(v)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="flex cursor-pointer items-center gap-2 font-display text-[12px] font-bold">
|
||||
<input type="checkbox" checked={withLink} onChange={(e) => setWithLink(e.target.checked)} />
|
||||
{t('config.mail.test.withLink')}
|
||||
</label>
|
||||
<Btn type="submit" disabled={!email.trim() || test.isPending}>
|
||||
{test.isPending ? t('config.mail.test.sending') : t('config.mail.test.send')}
|
||||
</Btn>
|
||||
@@ -163,6 +198,11 @@ function TestEmailPanel() {
|
||||
<div className="font-display text-[12px] font-extrabold leading-snug">
|
||||
{t(`config.mail.test.result.${result.status}`)}
|
||||
</div>
|
||||
<div className="mt-1 font-mono text-[10.5px] leading-snug">
|
||||
{result.example_volunteer_id
|
||||
? t('config.mail.test.filledWith', { name: result.example_volunteer_name || t('volunteer.unnamed') })
|
||||
: t('config.mail.test.filledWithExample')}
|
||||
</div>
|
||||
{result.detail ? (
|
||||
<div className="mt-1 break-words font-mono text-[10.5px] leading-snug">
|
||||
{t('config.mail.test.serverSaid', { detail: result.detail })}
|
||||
|
||||
Reference in New Issue
Block a user