feat(kontakte): Einverständnis für Mails und Mailingliste
Am Kontakt gibt es unter der E-Mail-Adresse das Kästchen "Einverständnis für Mails". Ohne Adresse ist es gesperrt. Der Zeitpunkt wird in `mail_consent_at` mitgeschrieben und im Kontakt angezeigt: bei einer Beschwerde ist nicht die Frage, ob ein Einverständnis vorliegt, sondern seit wann. Beim Widerruf wird er geleert; ein erneutes Speichern verschiebt ihn nicht. Der Knopf "Mailingliste erstellen" in der Kontaktleiste sammelt alle Adressen mit Haken, durch Komma getrennt, mit Zähler am Knopf. Rechts im Feld ein Kopiersymbol (Zwischenablage, mit Fallback für Browser ohne die Schnittstelle) und ein Mailsymbol. Zum Mailsymbol zwei Entscheidungen: - Die Adressen gehen ins BCC, nicht ins An-Feld. Im An-Feld sähe jeder Empfänger die vollständige Kundenliste. - Windows gibt an das Mailprogramm nur rund 2000 Zeichen weiter. Ab 1900 Zeichen ist das Symbol deshalb gesperrt und der Dialog erklärt es - sonst wäre die Empfängerliste unbemerkt abgeschnitten. Nur für richtige Kontakte: Der Vorbereich "Aus Mails" hat das Kästchen nicht, und beim Übernehmen wird der Haken nicht mitgesetzt - dass jemand eine Mail geschrieben hat, ist keine Einwilligung in Werbung. Das Backend weist ein `mail_consent` für Einträge mit `mail_pool = 1` ab. Sichtbar ohne Öffnen: grünes Briefsymbol in der Kachel, Häkchen hinter der Adresse in der Liste. Geprüft im Browser gegen das Stub-Backend: Haken setzen und widerrufen, Zähler, Komma-Liste, Zwischenablage, mailto mit BCC, kein Kästchen im Vorbereich (15 Prüfungen). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9a4266ae7e
commit
41e9f6898f
@@ -46,6 +46,8 @@ interface FormState {
|
||||
avatar: string;
|
||||
owner_id: string;
|
||||
tags: string[];
|
||||
/** Einverstaendnis in Werbemails - Voraussetzung fuer die Mailingliste. */
|
||||
mail_consent: boolean;
|
||||
}
|
||||
|
||||
function toFormState(lead: Lead | null, fallbackOwnerId: number | null): FormState {
|
||||
@@ -70,6 +72,7 @@ function toFormState(lead: Lead | null, fallbackOwnerId: number | null): FormSta
|
||||
avatar: lead?.avatar ?? '',
|
||||
owner_id: String(lead?.owner_id ?? fallbackOwnerId ?? ''),
|
||||
tags: lead?.tags ?? [],
|
||||
mail_consent: lead?.mail_consent ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -303,6 +306,44 @@ export const LeadModal: React.FC<LeadModalProps> = ({
|
||||
<label className={labelClass}>Website</label>
|
||||
<input type="url" value={form.website} onChange={(e) => set('website', e.target.value)} className={inputClass} />
|
||||
</div>
|
||||
|
||||
{/*
|
||||
* Einverstaendnis in Werbemails. Steht bewusst direkt unter der
|
||||
* E-Mail-Adresse und nicht bei den Tags: es gehoert zur Adresse und
|
||||
* entscheidet, ob sie in eine Mailingliste darf.
|
||||
*/}
|
||||
<div className="sm:col-span-2">
|
||||
<label
|
||||
className={`flex cursor-pointer items-start gap-3 rounded-xl border px-4 py-3 transition ${
|
||||
form.mail_consent
|
||||
? 'border-brand-200 bg-brand-50'
|
||||
: 'border-ink-200 bg-surface hover:bg-ink-50'
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={form.mail_consent}
|
||||
onChange={(e) => set('mail_consent', e.target.checked)}
|
||||
disabled={!form.email.trim()}
|
||||
className="mt-0.5 h-4 w-4 shrink-0 rounded border-ink-300 text-brand-500 focus:ring-brand-500/25 disabled:opacity-40"
|
||||
/>
|
||||
<span className="min-w-0">
|
||||
<span className="block text-sm font-bold text-ink-900">Einverständnis für Mails</span>
|
||||
<span className="block text-xs leading-relaxed text-ink-500">
|
||||
{form.email.trim()
|
||||
? 'Diese Adresse darf für Mailings verwendet werden und erscheint in der Mailingliste.'
|
||||
: 'Erst eine E-Mail-Adresse eintragen – ohne Adresse gibt es nichts einzuwilligen.'}
|
||||
{lead?.mail_consent && lead.mail_consent_at && (
|
||||
<>
|
||||
{' '}
|
||||
Erteilt am{' '}
|
||||
{new Date(lead.mail_consent_at.replace(' ', 'T')).toLocaleDateString('de-DE')}.
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user