diff --git a/src/pages/tenant/ViewDocument.tsx b/src/pages/tenant/ViewDocument.tsx index 85a5836..2aa2a99 100644 --- a/src/pages/tenant/ViewDocument.tsx +++ b/src/pages/tenant/ViewDocument.tsx @@ -4,6 +4,7 @@ import { Layout } from "@/components/layout/Layout"; import { DataTable, FormSelect, + FormField, Modal, PrimaryButton, SecondaryButton, @@ -76,7 +77,8 @@ const ViewDocument = (): ReactElement => { >([]); const [actionComment, setActionComment] = useState(""); const [effectiveDate, setEffectiveDate] = useState(""); - const [signatureId, setSignatureId] = useState(""); + const [actionPassword, setActionPassword] = useState(""); + const [actionPin, setActionPin] = useState(""); const [showNewVersionForm, setShowNewVersionForm] = useState(false); const [newVersionContent, setNewVersionContent] = useState(""); const [newVersionContentHtml, setNewVersionContentHtml] = useState(""); @@ -310,7 +312,8 @@ const ViewDocument = (): ReactElement => { setWorkflowDefinitionId(""); setActionComment(""); setEffectiveDate(""); - setSignatureId(""); + setActionPassword(""); + setActionPin(""); setWorkflowOptions([]); setActionErrors({}); }; @@ -356,8 +359,13 @@ const ViewDocument = (): ReactElement => { if (action === "reject" && !actionComment.trim()) { localErrors.comment = "Reason is required for reject"; } - if (action === "effective" && !effectiveDate) { - localErrors.effective_date = "Effective date is required"; + if (action === "effective") { + if (!effectiveDate) { + localErrors.effective_date = "Effective date is required"; + } + if (!actionPassword.trim()) { + localErrors.password = "Password is required for electronic signature"; + } } if (action === "obsolete" && !actionComment.trim()) { localErrors.comment = "Reason is required to obsolete"; @@ -381,10 +389,39 @@ const ViewDocument = (): ReactElement => { await documentService.reject(id, actionComment.trim()); } if (action === "effective") { + const currentVersionObj = versions.find( + (v) => v.version_number === document?.current_version + ) || versions[0]; + const currentVersionId = currentVersionObj?.id; + + if (!currentVersionId) { + showToast.error("Current document version could not be resolved."); + return; + } + + // Generate electronic signature + const signRes = await electronicSignatureService.sign({ + resource_type: "document_version", + resource_id: currentVersionId, + resource_name: `${document?.document_number || "Document"} - Version ${document?.current_version || "1.0"} - Make Effective`, + action: "RELEASE", + meaning: "I authorize the release of this record", + password: actionPassword.trim(), + pin: actionPin.trim() || null, + auth_method: actionPin.trim() ? "password_pin" : "password", + }); + + const finalSignatureId = signRes.data?.id || signRes.data?.signature?.id; + + if (!finalSignatureId) { + showToast.error("Failed to generate electronic signature."); + return; + } + await documentService.makeEffective( id, effectiveDate, - signatureId.trim(), + finalSignatureId, ); } if (action === "obsolete") { @@ -1782,46 +1819,57 @@ const ViewDocument = (): ReactElement => { )} {activeAction === "effective" && ( -
-
- - { - setEffectiveDate(event.target.value); - if (event.target.value) - setActionErrors((prev) => ({ - ...prev, - effective_date: "", - })); - }} - className={`h-10 px-3 w-full border rounded-md text-sm transition-colors ${ - actionErrors.effective_date - ? "border-red-500 bg-red-50/30" - : "border-[rgba(0,0,0,0.08)]" - }`} - /> - {actionErrors.effective_date && ( -

- {actionErrors.effective_date} -

- )} -
-
- - setSignatureId(event.target.value)} - placeholder="Enter signature ID" - className="h-10 px-3 w-full border border-[rgba(0,0,0,0.08)] rounded-md text-sm" - /> +
+ { + setEffectiveDate(event.target.value); + if (event.target.value) + setActionErrors((prev) => ({ + ...prev, + effective_date: "", + })); + }} + error={actionErrors.effective_date} + /> + +
+

+ Electronic Signature Verification +

+

+ Enter your credentials below to electronically sign this document and authorize its release. +

+ +
+ { + setActionPassword(event.target.value); + if (event.target.value) { + setActionErrors((prev) => ({ + ...prev, + password: "", + })); + } + }} + placeholder="Enter password" + error={actionErrors.password} + /> + setActionPin(event.target.value)} + placeholder="Enter PIN (Optional)" + /> +
)}