refactor(campaign): split review and recipient boundaries
This commit is contained in:
191
webui/src/features/campaigns/review/AttachmentLinkingPreview.tsx
Normal file
191
webui/src/features/campaigns/review/AttachmentLinkingPreview.tsx
Normal file
@@ -0,0 +1,191 @@
|
||||
import { useState } from "react";
|
||||
import { Link2, X } from "lucide-react";
|
||||
import { Button, Dialog, i18nMessage } from "@govoplan/core-webui";
|
||||
|
||||
import type {
|
||||
CampaignAttachmentPreviewFile,
|
||||
CampaignAttachmentPreviewResponse
|
||||
} from "../../../api/campaigns";
|
||||
import {
|
||||
attachmentPreviewLinkableFiles,
|
||||
attachmentPreviewMatchedFiles
|
||||
} from "../utils/attachmentPreview";
|
||||
import { WorkflowFact } from "./WorkflowNavigation";
|
||||
|
||||
export default function AttachmentLinkingPreview({
|
||||
preview,
|
||||
loading,
|
||||
error,
|
||||
linking,
|
||||
disabled,
|
||||
onRefresh,
|
||||
onLink
|
||||
}: {
|
||||
preview: CampaignAttachmentPreviewResponse | null;
|
||||
loading: boolean;
|
||||
error: string;
|
||||
linking: boolean;
|
||||
disabled: boolean;
|
||||
onRefresh: () => void;
|
||||
onLink: () => void;
|
||||
}) {
|
||||
const [detailsOpen, setDetailsOpen] = useState(false);
|
||||
const matchedFiles = attachmentPreviewMatchedFiles(preview);
|
||||
const linkableFiles = attachmentPreviewLinkableFiles(preview);
|
||||
const linkedCount =
|
||||
preview?.linked_file_count ??
|
||||
matchedFiles.filter((file) => file.linked_to_campaign !== false).length;
|
||||
const matchedCount = preview?.matched_file_count ?? matchedFiles.length;
|
||||
const unlinkedCount = preview?.unlinked_file_count ?? linkableFiles.length;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="review-flow-data-section attachment-linking-preview">
|
||||
<div className="attachment-linking-header">
|
||||
<div>
|
||||
<h3>i18n:govoplan-campaign.attachment_file_links.0be74fd1</h3>
|
||||
<p className="muted small-note">
|
||||
i18n:govoplan-campaign.preview_includes_already_linked_files_and_access.dfef92af
|
||||
</p>
|
||||
</div>
|
||||
<div className="button-row compact-actions">
|
||||
<Button onClick={onRefresh} disabled={loading || linking}>
|
||||
{loading
|
||||
? "i18n:govoplan-campaign.refreshing.505dddc9"
|
||||
: "i18n:govoplan-campaign.refresh.56e3badc"}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={onLink}
|
||||
disabled={disabled || loading || linking || unlinkedCount === 0}
|
||||
>
|
||||
{linking
|
||||
? "i18n:govoplan-campaign.linking.a5f54e0f"
|
||||
: i18nMessage(
|
||||
unlinkedCount === 1
|
||||
? "i18n:govoplan-campaign.link_value_file.4d4ce740"
|
||||
: "i18n:govoplan-campaign.link_value_files.88b7e6a7",
|
||||
{ value0: unlinkedCount }
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="review-flow-fact-grid">
|
||||
<WorkflowFact
|
||||
label="i18n:govoplan-campaign.matched.1bf3ec5b"
|
||||
value={
|
||||
!loading && matchedFiles.length > 0 ? (
|
||||
<button
|
||||
type="button"
|
||||
className="review-flow-fact-detail-button"
|
||||
aria-haspopup="dialog"
|
||||
aria-expanded={detailsOpen}
|
||||
aria-label={i18nMessage(
|
||||
"i18n:govoplan-campaign.view_all_value_matched_attachment_file_links.81e53951",
|
||||
{ value0: matchedFiles.length }
|
||||
)}
|
||||
onClick={() => setDetailsOpen(true)}
|
||||
>
|
||||
{matchedCount}
|
||||
</button>
|
||||
) : loading ? (
|
||||
"..."
|
||||
) : (
|
||||
matchedCount || "—"
|
||||
)
|
||||
}
|
||||
/>
|
||||
<WorkflowFact
|
||||
label="i18n:govoplan-campaign.linked.a089f600"
|
||||
value={loading ? "..." : linkedCount || "—"}
|
||||
/>
|
||||
<WorkflowFact
|
||||
label="i18n:govoplan-campaign.need_link.fa4ab530"
|
||||
value={loading ? "..." : unlinkedCount || "—"}
|
||||
/>
|
||||
<WorkflowFact
|
||||
label="i18n:govoplan-campaign.shared_source.7d4a1bf2"
|
||||
value={loading ? "..." : preview?.shared_file_count ?? "—"}
|
||||
/>
|
||||
</div>
|
||||
{error && <p className="review-flow-inline-note is-danger">{error}</p>}
|
||||
{!error && unlinkedCount > 0 && (
|
||||
<p className="review-flow-inline-note is-stale">
|
||||
i18n:govoplan-campaign.unlinked_candidate_files_are_not_yet_part_of_the.b8fd5998
|
||||
</p>
|
||||
)}
|
||||
{!error && !loading && matchedFiles.length === 0 && (
|
||||
<p className="muted small-note">
|
||||
i18n:govoplan-campaign.no_managed_files_matched_the_current_attachment_.dba99f5c
|
||||
</p>
|
||||
)}
|
||||
{matchedFiles.length > 0 && <AttachmentLinkingFileList files={matchedFiles} compact />}
|
||||
</div>
|
||||
<Dialog
|
||||
open={detailsOpen}
|
||||
title={i18nMessage(
|
||||
"i18n:govoplan-campaign.attachment_file_links_value.ce230e30",
|
||||
{ value0: matchedFiles.length }
|
||||
)}
|
||||
className="attachment-linking-detail-modal"
|
||||
bodyClassName="attachment-linking-detail-body"
|
||||
onClose={() => setDetailsOpen(false)}
|
||||
footer={
|
||||
<Button variant="primary" onClick={() => setDetailsOpen(false)}>
|
||||
i18n:govoplan-campaign.close.bbfa773e
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<p className="muted small-note">
|
||||
i18n:govoplan-campaign.all_unique_managed_files_matched_by_the_current_.0214c3e5
|
||||
</p>
|
||||
<AttachmentLinkingFileList files={matchedFiles} />
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function AttachmentLinkingFileList({
|
||||
files,
|
||||
compact = false
|
||||
}: {
|
||||
files: CampaignAttachmentPreviewFile[];
|
||||
compact?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<ul
|
||||
className={`attachment-linking-file-list${compact ? " is-compact" : " is-detail"}`}
|
||||
tabIndex={0}
|
||||
aria-label={i18nMessage(
|
||||
files.length === 1
|
||||
? "i18n:govoplan-campaign.value_matched_attachment_file_link.30a84824"
|
||||
: "i18n:govoplan-campaign.value_matched_attachment_file_links.ce509a3a",
|
||||
{ value0: files.length }
|
||||
)}
|
||||
>
|
||||
{files.map((file, index) => {
|
||||
const linked = file.linked_to_campaign !== false;
|
||||
const Icon = linked ? Link2 : X;
|
||||
return (
|
||||
<li
|
||||
key={`${file.id || file.display_path || file.filename}:${index}`}
|
||||
data-linked={linked ? "true" : "false"}
|
||||
>
|
||||
<Icon size={15} strokeWidth={2.2} aria-hidden="true" />
|
||||
<span>
|
||||
<strong>{file.filename || file.display_path}</strong>
|
||||
<small>
|
||||
{linked
|
||||
? "i18n:govoplan-campaign.linked_already_part_of_the_campaign_file_snapsho.d037a6bc"
|
||||
: "i18n:govoplan-campaign.unlinked_candidate_match_potentially_missing_unt.2bae9433"}
|
||||
</small>
|
||||
{file.display_path && file.display_path !== file.filename && (
|
||||
<small className="muted">{file.display_path}</small>
|
||||
)}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user