192 lines
6.7 KiB
TypeScript
192 lines
6.7 KiB
TypeScript
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>
|
|
);
|
|
}
|