Files
govoplan-campaign/webui/src/features/campaigns/review/reviewProgress.ts
T
zemion c51fc180fb
Module Package Release / publish-packages (push) Successful in 12s
Release govoplan-campaign v0.1.28: stabilize saving, review and delivery recovery
2026-09-08 01:32:26 +02:00

74 lines
2.7 KiB
TypeScript

export type BuildReviewProgressInput = {
blocking: number;
individualRequired: number;
individualReviewed: number;
groupRequired: number;
reviewComplete: boolean;
};
export type BuildReviewProgress = {
blocking: number;
individualRequired: number;
individualReviewed: number;
individualRemaining: number;
groupRequired: number;
groupReviewed: number;
groupRemaining: number;
required: number;
reviewed: number;
remaining: number;
};
function count(value: number): number {
return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;
}
export function calculateBuildReviewProgress(input: BuildReviewProgressInput): BuildReviewProgress {
const blocking = count(input.blocking);
const individualRequired = count(input.individualRequired);
const groupRequired = count(input.groupRequired);
const individualReviewed = input.reviewComplete
? individualRequired
: Math.min(individualRequired, count(input.individualReviewed));
const groupReviewed = input.reviewComplete ? groupRequired : 0;
const individualRemaining = individualRequired - individualReviewed;
const groupRemaining = groupRequired - groupReviewed;
return {
blocking,
individualRequired,
individualReviewed,
individualRemaining,
groupRequired,
groupReviewed,
groupRemaining,
required: individualRequired + groupRequired,
reviewed: individualReviewed + groupReviewed,
remaining: individualRemaining + groupRemaining
};
}
/** Summary match counts describe inputs; they are not fresh review gates. */
export function attachmentDeliveryPreflight(input: {
migrationRequired: boolean;
hasBuild: boolean;
reviewLoaded: boolean;
blocking: number;
remaining: number;
inspectionComplete: boolean;
missing: number;
ambiguous: number;
}): { state: "ready" | "warning" | "blocked" | "info"; detail: string } {
if (input.migrationRequired) return { state: "blocked", detail: "i18n:govoplan-campaign.attachment_checks_await_mail_migration" };
if (!input.hasBuild) return { state: "info", detail: "i18n:govoplan-campaign.attachment_preflight_build_first" };
if (!input.reviewLoaded) return { state: "info", detail: "i18n:govoplan-campaign.attachment_preflight_loading" };
if (input.blocking > 0) return { state: "blocked", detail: "i18n:govoplan-campaign.attachment_preflight_blocked" };
if (input.inspectionComplete || input.remaining === 0) {
return { state: "ready", detail: "i18n:govoplan-campaign.attachment_preflight_satisfied" };
}
if (input.missing + input.ambiguous > 0) {
return { state: "warning", detail: "i18n:govoplan-campaign.attachment_preflight_review" };
}
return { state: "info", detail: "i18n:govoplan-campaign.attachment_preflight_pending" };
}