feat: integrate electronic signature verification for document effective action using password and optional PIN
This commit is contained in:
parent
f76bbc6f65
commit
67baf47dbd
@ -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,9 +359,14 @@ const ViewDocument = (): ReactElement => {
|
||||
if (action === "reject" && !actionComment.trim()) {
|
||||
localErrors.comment = "Reason is required for reject";
|
||||
}
|
||||
if (action === "effective" && !effectiveDate) {
|
||||
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,12 +1819,10 @@ const ViewDocument = (): ReactElement => {
|
||||
</div>
|
||||
)}
|
||||
{activeAction === "effective" && (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="text-[13px] font-medium text-[#0e1b2a] mb-2 block">
|
||||
Effective Date <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
<div className="space-y-4">
|
||||
<FormField
|
||||
label="Effective Date"
|
||||
required
|
||||
type="date"
|
||||
value={effectiveDate}
|
||||
onChange={(event) => {
|
||||
@ -1798,30 +1833,43 @@ const ViewDocument = (): ReactElement => {
|
||||
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)]"
|
||||
}`}
|
||||
error={actionErrors.effective_date}
|
||||
/>
|
||||
{actionErrors.effective_date && (
|
||||
<p className="text-[11px] text-red-500 mt-1 font-medium italic">
|
||||
{actionErrors.effective_date}
|
||||
|
||||
<div className="border-t border-[rgba(0,0,0,0.08)] pt-3">
|
||||
<p className="text-xs font-semibold text-gray-500 mb-2 uppercase tracking-wider">
|
||||
Electronic Signature Verification
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-[13px] font-medium text-[#0e1b2a] mb-2 block">
|
||||
Signature ID{" "}
|
||||
<span className="text-gray-400 font-normal">(Optional)</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={signatureId}
|
||||
onChange={(event) => 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"
|
||||
<p className="text-[11px] text-gray-400 mb-4">
|
||||
Enter your credentials below to electronically sign this document and authorize its release.
|
||||
</p>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<FormField
|
||||
label="Account Password"
|
||||
required
|
||||
type="password"
|
||||
value={actionPassword}
|
||||
onChange={(event) => {
|
||||
setActionPassword(event.target.value);
|
||||
if (event.target.value) {
|
||||
setActionErrors((prev) => ({
|
||||
...prev,
|
||||
password: "",
|
||||
}));
|
||||
}
|
||||
}}
|
||||
placeholder="Enter password"
|
||||
error={actionErrors.password}
|
||||
/>
|
||||
<FormField
|
||||
label="Signature PIN"
|
||||
type="password"
|
||||
value={actionPin}
|
||||
onChange={(event) => setActionPin(event.target.value)}
|
||||
placeholder="Enter PIN (Optional)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user