import React, { useState, useEffect } from 'react';
import {
FaArrowLeft,
FaCheck,
FaExternalLinkAlt,
FaEye,
FaEyeSlash,
FaRedo,
FaImage,
FaUsers,
FaFileAlt,
FaEnvelope,
FaCog,
FaShieldAlt,
FaBell,
FaDownload,
FaShare,
FaEdit,
FaSave,
FaClock,
FaLock
} from 'react-icons/fa';
import { RootState } from '../../../store/store';
import api from '../../../config/api';
import { fetchRecipients } from "../../../store/slices/selectedRecipientsSlice";
import { fetchDocuments } from "../../../store/slices/documentSlice";
import { useDispatch, useSelector } from "react-redux";
import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
import Loader from "../../dashboard/Loader";
import confetti from 'canvas-confetti'
import { IoClose } from "react-icons/io5";
import { IoMdClose, IoMdHome } from "react-icons/io";
import { Bounce, toast } from "react-toastify";
type Signer = {
id: number;
name: string;
email: string;
routingOrder: number;
completed: boolean;
};
// Signers List Component
const SignersList: React.FC<{ signers: Signer[] }> = ({ signers }) => {
return (
//
Signature Status
{signers.filter(s => s.completed).length} of {signers.length} signed
{signers.map((signer) => (
{signer.name.length > 2 ? signer.name.split(" ").map(n => n[0].toUpperCase()).join("") : signer.email.split("").map(n => n[0].toUpperCase()).join("")}
{signer.name}
{signer.email}
Order: {signer.routingOrder}
{signer.completed ? (
Signed
) : (
Pending
)}
))}
//
);
};
// Fixed Signing Order Diagram Component
const SigningOrderDiagram: React.FC<{ signers: Signer[] }> = ({ signers }) => {
const groupByRoutingOrder = (data: Signer[]) => {
const grouped: Record = {};
data.forEach((signer) => {
if (!grouped[signer.routingOrder]) {
grouped[signer.routingOrder] = [];
}
grouped[signer.routingOrder].push(signer);
});
return grouped;
};
const getInitials = (name: string) => {
return name
.split(" ")
.map((n) => n[0].toUpperCase())
.join("");
};
const grouped = groupByRoutingOrder(signers);
const sortedOrders = Object.keys(grouped)
.map(Number)
.sort((a, b) => a - b);
const currentProcessingOrder =
sortedOrders.find((order) =>
grouped[order].some((signer) => !signer.completed)
) || -1;
return (
//
Signing Flow
{/* Mail icon */}
{/* Dotted line */}
{/* Signers by routing order */}
{sortedOrders.map((order, index) => (
Step {order}
{grouped[order].map((signer) => {
let bgColor = "";
let icon = null;
if (signer.completed) {
bgColor = "bg-[var(--primary)]";
icon =
;
} else if (order === currentProcessingOrder) {
bgColor = "bg-yellow-500";
icon =
;
} else {
bgColor = "bg-gray-400";
icon =
;
}
return (
{getInitials(signer.name)}
{icon}
{signer.name.split(" ")[0] || signer.firstName.split(0, 1)}
);
})}
{index < sortedOrders.length - 1 && (
)}
))}
//
);
};
const DocumentSubmissionOptions = () => {
const location = useLocation();
const [status, setStatus] = useState(null);
console.log("location.pathname", location.pathname, status)
const { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>();
const [showConfetti, setShowConfetti] = React.useState(true)
if (!accountId || !transactionId) {
window.location.href = "/";
return null;
}
// const transactionId = useSelector((state: RootState) => state.transaction.transactionId)
const navigate = useNavigate();
const dispatch = useDispatch();
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients);
// const selectedDocuments = useSelector((state: RootState) => state.selectedDocuments.selectedDocuments)
const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
console.log('Line 218', selectedDocuments)
const [transactionData, setTransactionData] = useState({})
useEffect(() => {
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId }));
}, [])
useEffect(() => {
// toast.dismiss();
// toast.success("Your document has been successfully sent for signature.", {
// position: "top-center",
// autoClose: 1500,
// hideProgressBar: false,
// closeOnClick: false,
// pauseOnHover: true,
// draggable: true,
// progress: undefined,
// theme: "light",
// transition: Bounce,
// });
if (showConfetti) {
const duration = 3000;
const end = Date.now() + duration;
const interval = setInterval(() => {
if (Date.now() > end) {
clearInterval(interval);
return;
}
confetti({
particleCount: 5, // fewer particles per burst for smoothness
angle: 90, // falling straight down
spread: 30, // slight spread
startVelocity: 8, // gentle falling speed
origin: {
x: Math.random(), // random horizontal position across the top
y: 0,
},
scalar: 1,
zIndex: 9999,
});
}, 50); // fire every 50ms for continuous effect
return () => clearInterval(interval);
}
}, [showConfetti]);
console.log("History length:", window.history.length);
// Step 1: Fetch transaction status
useEffect(() => {
const fetchTransaction = async () => {
// /api/accounts/{accountId}/transactions/{trxId}
try {
const res = await api.get(`/api/accounts/${accountId}/transactions/${transactionId}`);
if (res?.data) {
setStatus(res?.data?.status);
setTransactionData(res?.data)
}
} catch (error) {
console.error("Failed to fetch transaction:", error);
}
};
if (accountId && transactionId) {
fetchTransaction();
}
}, [accountId, transactionId]);
// Step 2: Prevent browser back when status === 'SENT'
useEffect(() => {
if (status === "SENT") {
const currentPath = window.location.pathname;
const handlePopState = (event) => {
// Show warning
alert("Back navigation is blocked on this screen.");
// Push the current URL back to prevent navigating away
window.history.pushState(null, "", currentPath);
};
// Push extra states to build history buffer
for (let i = 0; i < 50; i++) {
window.history.pushState(null, "", currentPath);
}
// Add popstate listener
window.addEventListener("popstate", handlePopState);
// Cleanup on unmount
return () => {
window.removeEventListener("popstate", handlePopState);
};
}
}, [status]);
// useEffect(() => {
// if (status === 'SENT') {
// // Step 1: Push a dummy state to trap the user
// window.history.pushState(null, '', window.location.href);
// // Step 2: Intercept back button
// const handlePopState = (event) => {
// // Push the same dummy state again to block back
// window.history.pushState(null, '', window.location.href);
// };
// window.addEventListener('popstate', handlePopState);
// return () => {
// window.removeEventListener('popstate', handlePopState);
// };
// }
// }, [status]);
const [selectedOption, setSelectedOption] = useState('success');
const [isVisible, setIsVisible] = useState(false);
const [previewData, setPreviewData] = useState({
documentName: "Contract Agreement.pdf",
submissionCount: 1,
signerName: "Sumit Kumar",
signerEmail: "sumit.kumar@hicglobalsolutions.com",
submissionTime: new Date().toLocaleString()
});
useEffect(() => {
setIsVisible(true);
}, []);
const options = [
{
id: 'success',
icon: FaCheck,
title: 'Success screen',
description: 'Display confirmation message after successful document submission',
color: 'bg-green-50 border-green-200 hover:bg-green-100',
iconColor: 'text-green-600',
isPremium: false
},
{
id: 'redirect',
icon: FaExternalLinkAlt,
title: 'Signing Flow',
description: 'Navigate user to view their transaction details',
color: 'bg-blue-50 border-blue-200 hover:bg-blue-100',
iconColor: 'text-blue-600',
isPremium: true
},
{
id: 'public',
icon: FaEye,
title: 'Signature status',
description: 'Show transaction status on public dashboard',
color: 'bg-purple-50 border-purple-200 hover:bg-purple-100',
iconColor: 'text-purple-600',
isPremium: true
},
];
const getPreviewContent = () => {
switch (selectedOption) {
case 'success':
return (
Document Send Successfully!
{selectedDocuments?.map((docs) => (
Your document "{docs.name}" has been sent for signature.
))}
createdBy:
{transactionData?.createdBy?.name}
Email:
{transactionData?.createdBy?.email}
createdAt:
{transactionData.createdAt}
);
case 'redirect':
return (
<>
>
);
case 'public':
return (
<>
>
);
default:
return null;
}
};
return (
🎉 Awesome! The document’s been sent for signature. 🎉
{/* Header */}
{/*
Choose an action after a signer completes the document.
{options.map((option) => {
const Icon = option.icon;
const isSelected = selectedOption === option.id;
return (
setSelectedOption(option.id)}
className={`
relative cursor-pointer p-4 rounded-xl border-2 transition-all duration-200 group
${isSelected
? 'border-[var(--primary)] bg-blue-50 shadow-md scale-[1.02]'
: option.color + ' border-2'
}
hover:shadow-md hover:scale-[1.01] transform
`}
>
{option.title}
{option.isPremium && (
★
)}
{option.description}
{isSelected && (
)}
);
})}
Live Preview
See how your users will experience the completion
*/}
Document Send Successfully!
);
};
export default DocumentSubmissionOptions;