Refactor campaign recipient and review presentation

This commit is contained in:
2026-07-31 02:48:56 +02:00
parent 5f7503598c
commit e689fdf495
30 changed files with 2175 additions and 1977 deletions
@@ -4,9 +4,11 @@ import { previewCampaignAttachments, type CampaignAttachmentPreviewRule } from "
import { Button } from "@govoplan/core-webui";
import { Card } from "@govoplan/core-webui";
import { FormField } from "@govoplan/core-webui";
import { FieldLabel } from "@govoplan/core-webui";
import { PageTitle } from "@govoplan/core-webui";
import { LoadingFrame } from "@govoplan/core-webui";
import { DismissibleAlert, SegmentedControl, i18nMessage } from "@govoplan/core-webui";
import { WysiwygEditor, type WysiwygEditorHandle } from "@govoplan/core-webui/wysiwyg";
import LockedVersionNotice from "./components/LockedVersionNotice";
import VersionLine from "./components/VersionLine";
import CampaignMessagePreviewOverlay, { type CampaignMessagePreviewAttachment } from "./components/MessagePreviewOverlay";
@@ -35,7 +37,7 @@ export default function TemplateDataPage({ settings, campaignId }: {settings: Ap
const [attachmentPreviewError, setAttachmentPreviewError] = useState("");
const subjectRef = useRef<HTMLInputElement | null>(null);
const textRef = useRef<HTMLTextAreaElement | null>(null);
const htmlRef = useRef<HTMLTextAreaElement | null>(null);
const htmlRef = useRef<WysiwygEditorHandle | null>(null);
const version = data.currentVersion;
const locked = isAuditLockedVersion(version, data.campaign?.current_version_id);
@@ -160,8 +162,12 @@ export default function TemplateDataPage({ settings, campaignId }: {settings: Ap
function insertPlaceholder(namespace: TemplateNamespace, name: string) {
if (locked) return;
const target = activeEditor === "subject" ? "subject" : visibleBodyEditor;
const element = target === "subject" ? subjectRef.current : target === "html" ? htmlRef.current : textRef.current;
const token = `{{${namespace}:${name}}}`;
if (target === "html") {
htmlRef.current?.insertToken({ value: token, label: `${namespace}:${name}` });
return;
}
const element = target === "subject" ? subjectRef.current : textRef.current;
const currentText = getText(template, target);
const start = element?.selectionStart ?? currentText.length;
const end = element?.selectionEnd ?? currentText.length;
@@ -300,16 +306,19 @@ export default function TemplateDataPage({ settings, campaignId }: {settings: Ap
</FormField>
}
{visibleBodyEditor === "html" &&
<FormField label="i18n:govoplan-campaign.html_body.77b5ba37">
<textarea
<div className="form-field">
<FieldLabel className="form-label">i18n:govoplan-campaign.html_body.77b5ba37</FieldLabel>
<WysiwygEditor
ref={htmlRef}
rows={16}
value={getText(template, "html")}
disabled={locked}
ariaLabel="i18n:govoplan-campaign.html_body.77b5ba37"
minHeight={344}
sourceRows={16}
onFocus={() => {setActiveBodyEditor("html");setActiveEditor("html");}}
onChange={(event) => patchTemplateText("html", event.target.value)} />
onChange={(value) => patchTemplateText("html", value)} />
</FormField>
</div>
}
<div className="button-row template-editor-actions">
<Button disabled>i18n:govoplan-campaign.load_from_library.327ada7c</Button>