From 93112f89ebc3f59a31654cbddcea381bd64f5655 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Sun, 4 May 2025 11:22:33 -0700 Subject: [PATCH] Add policy download pdf file Signed-off-by: Bryan Frimin --- .../organizations/policies/ShowPolicyView.tsx | 190 ++++++++++++++- .../ShowPolicyViewQuery.graphql.ts | 216 +++++++++++------- 2 files changed, 323 insertions(+), 83 deletions(-) diff --git a/apps/console/src/pages/organizations/policies/ShowPolicyView.tsx b/apps/console/src/pages/organizations/policies/ShowPolicyView.tsx index bd52bfe2e..ade1ca54b 100644 --- a/apps/console/src/pages/organizations/policies/ShowPolicyView.tsx +++ b/apps/console/src/pages/organizations/policies/ShowPolicyView.tsx @@ -1,4 +1,4 @@ -import { Suspense, useEffect, useState, useCallback, ReactNode } from "react"; +import { Suspense, useEffect, useState, useCallback, ReactNode, useRef } from "react"; import { useParams, Link, useNavigate } from "react-router"; import { graphql, @@ -6,6 +6,7 @@ import { usePreloadedQuery, useQueryLoader, useMutation, + useFragment, } from "react-relay"; import { Clock, @@ -43,9 +44,18 @@ import { import { SignaturesModal } from "./SignaturesModal"; import { VersionHistoryModal } from "./VersionHistoryModal"; import rehypeRaw from "rehype-raw"; +import { createRoot } from "react-dom/client"; +import { policyVersionsFragment } from "./SignaturesModal"; +import type { SignaturesModal_policyVersions$key } from "./__generated__/SignaturesModal_policyVersions.graphql"; const policyViewQuery = graphql` - query ShowPolicyViewQuery($policyId: ID!) { + query ShowPolicyViewQuery($policyId: ID!, $organizationId: ID!) { + organization: node(id: $organizationId) { + ... on Organization { + name + } + } + node(id: $policyId) { id ... on Policy { @@ -131,6 +141,7 @@ function ShowPolicyContent({ ); const policy = data.node; const { organizationId } = useParams(); + const navigate = useNavigate(); const { toast } = useToast(); const [queryRef2, loadQuery] = @@ -139,6 +150,7 @@ function ShowPolicyContent({ const [isDeleting, setIsDeleting] = useState(false); const [isVersionHistoryOpen, setIsVersionHistoryOpen] = useState(false); const [isSignaturesModalOpen, setIsSignaturesModalOpen] = useState(false); + const printContentRef = useRef(null); const [publishDraft, isPublishInFlight] = useMutation(publishPolicyVersionMutation); @@ -294,11 +306,179 @@ function ShowPolicyContent({ return format(date, "MMM d, yyyy"); }; + // Get policy signatures data + const policyData = useFragment( + policyVersionsFragment, + policy as unknown as SignaturesModal_policyVersions$key + ); + + // Handle PDF download + const handlePrintPDF = useCallback(() => { + // Create a new window for printing + const printWindow = window.open('', '_blank'); + if (!printWindow) { + toast({ + title: "Error", + description: "Unable to open print window. Please check your browser settings.", + variant: "destructive", + }); + return; + } + + // Get version nodes and signatures from the fragment data we have + const versionNodes = policyData?.policyVersions?.edges?.map(edge => edge.node) || []; + const currentVersion = versionNodes.find(v => v.version === latestVersionNode?.version); + const signatures = currentVersion?.signatures?.edges?.map(edge => edge.node) || []; + + // Create temporary div to render and capture markdown + const tempDiv = document.createElement('div'); + const root = createRoot(tempDiv); + + // Render the markdown content to HTML + root.render( + + {latestVersionNode?.content || 'No content available'} + + ); + + // Give React a moment to render the content + setTimeout(() => { + const renderedMarkdown = tempDiv.innerHTML; + + // Prepare signatures HTML + let signaturesHtml = '

No signatures yet

'; + if (signatures.length > 0) { + signaturesHtml = ` + + + + + + + + + + ${signatures.map(sig => ` + + + + + + `).join('')} + +
NameStatusDate
${sig.signedBy?.fullName || 'Unknown'}${sig.state === 'SIGNED' ? 'Signed' : 'Pending'}${sig.signedAt ? formatDate(sig.signedAt) : 'Not yet signed'}
+ `; + } + + // Create the print document content with the policy document data + printWindow.document.write(` + + + + ${policy.title || 'Policy Document'} + + + +
+

${policy.title || 'Policy Document'}

+ +
+
+ ${renderedMarkdown} +
+ + + + `); + + // Trigger print + printWindow.document.close(); + printWindow.focus(); + + // Use setTimeout to give the browser time to load any resources + setTimeout(() => { + printWindow.print(); + // Optional: close the window after printing + // printWindow.close(); + }, 500); + + // Clean up + root.unmount(); + }, 100); + + }, [policy, latestVersionNode, formatDate, toast, policyData, data.organization.name!]); + return ( + +