import { useState } from "react"; import type { ApiSettings, AuthInfo } from "../../types"; import { Button } from "@govoplan/core-webui"; import { Card } from "@govoplan/core-webui"; import { FormField } from "@govoplan/core-webui"; import { DismissibleAlert } from "@govoplan/core-webui"; import { PageTitle } from "@govoplan/core-webui"; import { LoadingFrame } from "@govoplan/core-webui"; import { PolicyRow } from "@govoplan/core-webui"; import { PolicyTable } from "@govoplan/core-webui"; import LockedVersionNotice from "./components/LockedVersionNotice"; import CampaignAccessCard from "./components/CampaignAccessCard"; import VersionLine from "./components/VersionLine"; import { ToggleSwitch } from "@govoplan/core-webui"; import { hasScope } from "@govoplan/core-webui"; import { RetentionPolicyEditor } from "../privacy/RetentionPolicyManagement"; import { useCampaignWorkspaceData } from "./hooks/useCampaignWorkspaceData"; import { useCampaignDraftEditor } from "./hooks/useCampaignDraftEditor"; import { asRecord, isAuditLockedVersion } from "./utils/campaignView"; import { cloneJson, getBool, getNumber, getText, updateNested } from "./utils/draftEditor"; const behaviorOptions = ["block", "ask", "drop", "continue", "warn"]; type EditorState = Record; type SettingsView = "settings" | "policy"; type GlobalSettingsPageProps = { settings: ApiSettings; auth: AuthInfo; campaignId: string; view?: SettingsView; }; export default function GlobalSettingsPage({ settings, auth, campaignId, view = "settings" }: GlobalSettingsPageProps) { const { data, loading, error, reload, setError } = useCampaignWorkspaceData(settings, campaignId); const [editorState, setEditorState] = useState({}); const isPolicyView = view === "policy"; const version = data.currentVersion; const locked = isAuditLockedVersion(version, data.campaign?.current_version_id); const { draft, displayDraft, dirty, saveState, localError, patch, markDirty, saveDraft } = useCampaignDraftEditor({ settings, campaignId, version, locked, reload, setError, currentStep: isPolicyView ? "policies" : "global-settings", unsavedTitle: isPolicyView ? "i18n:govoplan-campaign.unsaved_campaign_policy_changes.181f3426" : "i18n:govoplan-campaign.unsaved_campaign_settings.0555d713", unsavedMessage: isPolicyView ? "i18n:govoplan-campaign.campaign_policies_have_unsaved_changes_save_them.7b07827f" : "i18n:govoplan-campaign.campaign_settings_have_unsaved_changes_save_them.c1c5f65f", extraPayload: () => ({ editor_state: editorState }), onLoaded: (loadedVersion) => setEditorState(cloneJson(loadedVersion.editor_state ?? {})), onSaved: (savedVersion) => setEditorState(cloneJson(savedVersion.editor_state ?? editorState)) }); const validationPolicy = asRecord(displayDraft.validation_policy); const attachments = asRecord(displayDraft.attachments); const delivery = asRecord(displayDraft.delivery); const rateLimit = asRecord(delivery.rate_limit); const retry = asRecord(delivery.retry); const statusTracking = asRecord(displayDraft.status_tracking); const optIns = asRecord(editorState.opt_ins); const canReadRetentionPolicy = hasScope(auth, "admin:policies:read"); const canWriteRetentionPolicy = hasScope(auth, "admin:policies:write"); const pageTitle = isPolicyView ? "i18n:govoplan-campaign.campaign_policies.0b5de1f5" : "i18n:govoplan-campaign.campaign_settings.efffec26"; function patchEditor(path: string[], value: unknown) { if (locked) return; setEditorState((current) => updateNested(current, path, value)); markDirty(); } return (
{pageTitle}
{error && {error}} {localError && {localError}} {locked && } {isPolicyView ? <> {canReadRetentionPolicy && }
patch(["validation_policy", "missing_required_attachment"], value)} />} effective={behaviorSummary(getText(validationPolicy, "missing_required_attachment", "ask"))} /> patch(["validation_policy", "missing_optional_attachment"], value)} />} effective={behaviorSummary(getText(validationPolicy, "missing_optional_attachment", "warn"))} /> patch(["validation_policy", "ambiguous_attachment_match"], value)} />} effective={behaviorSummary(getText(validationPolicy, "ambiguous_attachment_match", "ask"))} /> patch(["validation_policy", "unsent_attachment_files"], value)} />} effective={behaviorSummary(getText(validationPolicy, "unsent_attachment_files", "warn"))} /> patch(["validation_policy", "missing_email"], value)} options={["block", "drop"]} />} effective={behaviorSummary(getText(validationPolicy, "missing_email", "block"))} /> patch(["validation_policy", "template_error"], value)} options={["block", "drop"]} />} effective={behaviorSummary(getText(validationPolicy, "template_error", "block"))} /> patch(["validation_policy", "ignore_empty_fields"], checked)} />} effective={getBool(validationPolicy, "ignore_empty_fields") ? "i18n:govoplan-campaign.missing_values_render_as_empty_text.0a6bce45" : "i18n:govoplan-campaign.missing_values_remain_visible_and_can_trigger_te.31464ee2"} /> patch(["attachments", "missing_behavior"], value)} />} effective={behaviorSummary(getText(attachments, "missing_behavior", "ask"))} /> patch(["attachments", "ambiguous_behavior"], value)} />} effective={behaviorSummary(getText(attachments, "ambiguous_behavior", "ask"))} /> patch(["attachments", "send_without_attachments"], checked)} />} effective={getBool(attachments, "send_without_attachments", true) ? "i18n:govoplan-campaign.messages_may_be_sent_when_attachment_rules_allow.e6bf1aed" : "i18n:govoplan-campaign.missing_attachment_coverage_blocks_sending.05ff02a1"} />
: <> {data.campaign && }
patch(["delivery", "rate_limit", "messages_per_minute"], Number(event.target.value || 1))} /> patch(["delivery", "rate_limit", "concurrency"], Number(event.target.value || 1))} /> patch(["delivery", "retry", "max_attempts"], Number(event.target.value || 1))} /> patch(["status_tracking", "enabled"], checked)} />
patchEditor(["opt_ins", "campaign_address_suggestions"], checked)} /> patchEditor(["opt_ins", "remember_used_addresses"], checked)} /> patchEditor(["opt_ins", "inline_guidance"], checked)} />

i18n:govoplan-campaign.these_opt_ins_are_stored_in_the_draft_editor_met.dc6ffbfd

}
); } function PolicySelectControl({ value, disabled, onChange, options = behaviorOptions }: {value: string;disabled?: boolean;onChange: (value: string) => void;options?: string[];}) { return ( ); } function behaviorSummary(value: string): string { if (value === "block") return "i18n:govoplan-campaign.blocks_the_affected_message.0157342a"; if (value === "ask") return "i18n:govoplan-campaign.marks_the_message_for_review.d63beb24"; if (value === "drop") return "i18n:govoplan-campaign.excludes_the_affected_message.73be963f"; if (value === "continue") return "i18n:govoplan-campaign.continues_without_a_review_issue.99ab0684"; if (value === "warn") return "i18n:govoplan-campaign.keeps_sending_possible_with_a_warning.66c84a54"; return "i18n:govoplan-campaign.uses_the_configured_behavior.ea6e82a3"; }