feat: complete campaign wizards and retention reporting

This commit is contained in:
2026-07-31 04:21:34 +02:00
parent e689fdf495
commit fa4eb39e0b
18 changed files with 785 additions and 55 deletions
@@ -1,22 +1,21 @@
import { Card } from "@govoplan/core-webui";
import { MetricCard } from "@govoplan/core-webui";
import { Button } from "@govoplan/core-webui";
export default function ReviewWizard() {
return (
<div className="content-pad workspace-data-page">
<div className="page-heading workspace-heading">
<h1>i18n:govoplan-campaign.review_wizard.3d8bf0aa</h1>
</div>
<div className="metric-grid">
<MetricCard label="i18n:govoplan-campaign.needs_review.33a506cf" value="—" tone="warning" />
<MetricCard label="i18n:govoplan-campaign.missing_attachments.729ad125" value="—" tone="warning" />
<MetricCard label="i18n:govoplan-campaign.ambiguous_matches.dc658a9c" value="—" tone="info" />
<MetricCard label="i18n:govoplan-campaign.blocked.99613c74" value="—" tone="danger" />
</div>
<Card title="i18n:govoplan-campaign.resolution_workflow.708d6c0b">
<p className="muted">i18n:govoplan-campaign.this_wizard_will_guide_users_through_issues_one_.5cb212c3</p>
<Button variant="primary">i18n:govoplan-campaign.start_review.d0bc5cdf</Button>
</Card>
</div>);
import type { ApiSettings, AuthInfo } from "@govoplan/core-webui";
import ReviewSendPage from "../ReviewSendPage";
export default function ReviewWizard({
settings,
auth,
campaignId
}: {
settings: ApiSettings;
auth: AuthInfo;
campaignId: string;
}) {
return (
<ReviewSendPage
settings={settings}
auth={auth}
campaignId={campaignId}
initialStageId="workflow-build-review"
/>
);
}
@@ -1,21 +1,21 @@
import { Card } from "@govoplan/core-webui";
import { Button } from "@govoplan/core-webui";
export default function SendWizard() {
return (
<div className="content-pad workspace-data-page">
<div className="page-heading workspace-heading">
<h1>i18n:govoplan-campaign.send_wizard.3c137422</h1>
</div>
<div className="dashboard-grid">
<Card title="i18n:govoplan-campaign.test_send.03dfff38">
<p className="muted">i18n:govoplan-campaign.send_one_generated_message_to_a_test_address.bc0a4e47</p>
<Button>i18n:govoplan-campaign.open_test_send_dialog.661db713</Button>
</Card>
<Card title="i18n:govoplan-campaign.queue_estimate.5480288a">
<p className="muted">i18n:govoplan-campaign.estimated_duration_will_be_based_on_ready_jobs_a.15b63283</p>
<Button variant="primary">i18n:govoplan-campaign.queue_dry_run.800e1606</Button>
</Card>
</div>
</div>);
import type { ApiSettings, AuthInfo } from "@govoplan/core-webui";
import ReviewSendPage from "../ReviewSendPage";
export default function SendWizard({
settings,
auth,
campaignId
}: {
settings: ApiSettings;
auth: AuthInfo;
campaignId: string;
}) {
return (
<ReviewSendPage
settings={settings}
auth={auth}
campaignId={campaignId}
initialStageId="workflow-send"
/>
);
}
@@ -0,0 +1,55 @@
import { Link } from "react-router";
import {
PageTitle,
WizardDirectory,
usePlatformUiCapabilities,
wizardEntriesForContext,
type ApiSettings,
type AuthInfo,
type WizardDirectoriesUiCapability
} from "@govoplan/core-webui";
import { campaignWizardDirectories } from "./directory";
export default function WizardDirectoryPage({
settings,
auth,
campaignId
}: {
settings: ApiSettings;
auth: AuthInfo;
campaignId: string;
}) {
const contributed = usePlatformUiCapabilities<WizardDirectoriesUiCapability>(
"wizard.directories"
);
const capabilities = contributed.some((capability) =>
capability.directories.some(
(directory) => directory.id === "campaigns.resource"
)
)
? contributed
: [...contributed, campaignWizardDirectories];
const entries = wizardEntriesForContext(capabilities, {
settings,
auth,
contextId: "campaign.resource",
resourceId: campaignId
});
return (
<div className="content-pad workspace-data-page">
<div className="page-heading split workspace-heading">
<PageTitle>i18n:govoplan-campaign.guided_workflows</PageTitle>
<Link className="btn btn-secondary" to="../">
i18n:govoplan-campaign.back_to_overview.ec986cba
</Link>
</div>
<WizardDirectory
entries={entries}
auth={auth}
emptyText="i18n:govoplan-campaign.no_guided_workflows"
/>
</div>
);
}
@@ -0,0 +1,57 @@
import type {
WizardDirectoriesUiCapability,
WizardDirectoryEntry
} from "@govoplan/core-webui";
const campaignRead = ["campaigns:campaign:read"];
export function campaignWizardEntries(
campaignId: string
): WizardDirectoryEntry[] {
const basePath = `/campaigns/${encodeURIComponent(campaignId)}/wizard`;
return [
{
id: "configure",
moduleId: "campaigns",
label: "i18n:govoplan-campaign.create_campaign.59812bbc",
description: "i18n:govoplan-campaign.name_and_scenario.f2bc5241",
to: `${basePath}/create`,
actionLabel: "i18n:govoplan-campaign.open.cf9b7706",
anyOf: campaignRead,
order: 10
},
{
id: "review",
moduleId: "campaigns",
label: "i18n:govoplan-campaign.review_wizard.3d8bf0aa",
description: "i18n:govoplan-campaign.lock_and_validate_the_campaign_then_inspect_bloc.e22b9266",
to: `${basePath}/review`,
actionLabel: "i18n:govoplan-campaign.open.cf9b7706",
anyOf: campaignRead,
order: 20
},
{
id: "send",
moduleId: "campaigns",
label: "i18n:govoplan-campaign.send_wizard.3c137422",
description: "i18n:govoplan-campaign.review_the_final_execution_summary_optionally_ru.6b32b00a",
to: `${basePath}/send`,
actionLabel: "i18n:govoplan-campaign.open.cf9b7706",
anyOf: campaignRead,
order: 30
}
];
}
export const campaignWizardDirectories: WizardDirectoriesUiCapability = {
directories: [
{
id: "campaigns.resource",
moduleId: "campaigns",
contextId: "campaign.resource",
order: 20,
entries: ({ resourceId }) =>
resourceId ? campaignWizardEntries(resourceId) : []
}
]
};