completion-screen new v1
This commit is contained in:
parent
002c8e6110
commit
cd2b8d3aff
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { FaCheck, FaLock, FaClock, FaEnvelope, FaTimes } from "react-icons/fa";
|
||||
import { FaCheck, FaLock, FaClock, FaEnvelope, FaTimes, FaUserTimes } from "react-icons/fa";
|
||||
import { IoCloseOutline } from "react-icons/io5";
|
||||
|
||||
type Signer = {
|
||||
|
|
@ -48,8 +48,10 @@ const groupByRoutingOrder = (data: Signer[]) => {
|
|||
};
|
||||
|
||||
const getInitials = (name: string) => {
|
||||
if (!name.trim()) return "";
|
||||
return name
|
||||
.split(" ")
|
||||
.filter(n => n)
|
||||
.map((n) => n[0].toUpperCase())
|
||||
.join("");
|
||||
};
|
||||
|
|
@ -63,6 +65,8 @@ const SigningOrderDiagram : React.FC<Signer[]> = (signers) => {
|
|||
.map(Number)
|
||||
.sort((a, b) => a - b);
|
||||
|
||||
console.log("sortedOrders",sortedOrders,grouped)
|
||||
|
||||
const currentProcessingOrder =
|
||||
sortedOrders.find((order) =>
|
||||
grouped[order].some((signer) => !signer.completed)
|
||||
|
|
@ -109,14 +113,14 @@ const SigningOrderDiagram : React.FC<Signer[]> = (signers) => {
|
|||
<div key={signer.id} className="relative">
|
||||
<div
|
||||
className={`w-10 h-10 rounded-full flex items-center justify-center text-white text-sm font-semibold ${bgColor}`}
|
||||
title={signer.name}
|
||||
title={signer?.name}
|
||||
>
|
||||
{getInitials(signer.name)}
|
||||
{(signer?.name !== '' || signer?.roleName) ? getInitials(signer?.name || signer?.roleName) : ""}
|
||||
<span className="absolute bottom-[12px] right-[-12px] p-1 rounded-full bg-white shadow">
|
||||
{icon}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-gray-600 text-center">{signer.name.split(" ")[0]}</p>
|
||||
<p className="mt-1 text-xs text-gray-600 text-center">{(signer?.name?.split(" ")[0] || signer?.roleName)}</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,29 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
FaArrowLeft,
|
||||
FaCheck,
|
||||
FaFileAlt,
|
||||
FaExternalLinkAlt,
|
||||
FaEye,
|
||||
FaEyeSlash,
|
||||
FaRedo,
|
||||
FaImage,
|
||||
FaUsers,
|
||||
FaFileAlt,
|
||||
FaEnvelope,
|
||||
FaClock,
|
||||
FaCog,
|
||||
FaShieldAlt,
|
||||
FaBell,
|
||||
FaDownload,
|
||||
FaShare,
|
||||
FaShieldAlt,
|
||||
FaLock,
|
||||
FaPen,
|
||||
FaCheckCircle
|
||||
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";
|
||||
|
|
@ -21,7 +33,7 @@ import confetti from 'canvas-confetti'
|
|||
import { IoClose } from "react-icons/io5";
|
||||
import { IoMdClose, IoMdHome } from "react-icons/io";
|
||||
import { Bounce, toast } from "react-toastify";
|
||||
import api from "../../../config/api";
|
||||
|
||||
|
||||
type Signer = {
|
||||
id: number;
|
||||
|
|
@ -112,7 +124,7 @@ const SigningOrderDiagram: React.FC<{ signers: Signer[] }> = ({ signers }) => {
|
|||
<div className="bg-white/60 rounded-md shadow-sm border border-gray-100">
|
||||
<div className="p-6">
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-4">Signing Flow</h3>
|
||||
<div className="overflow-x-auto overflow-y-auto h-[69vh] no-scrollbar flex justify-center items-center">
|
||||
<div className="overflow-x-auto overflow-y-auto h-[22vh] no-scrollbar flex justify-center items-center">
|
||||
<div className="flex justify-center items-center gap-4 min-w-max">
|
||||
{/* Mail icon */}
|
||||
<div className="flex flex-col items-center">
|
||||
|
|
@ -163,7 +175,7 @@ const SigningOrderDiagram: React.FC<{ signers: Signer[] }> = ({ signers }) => {
|
|||
</span>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-gray-600 text-center max-w-16 truncate">
|
||||
{signer.name.split(" ")[0]}
|
||||
{signer.name.split(" ")[0] || signer.firstName.split(0,1)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -185,22 +197,7 @@ const SigningOrderDiagram: React.FC<{ signers: Signer[] }> = ({ signers }) => {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Main DocumentCompletionScreen Component
|
||||
const DocumentCompletionScreen = () => {
|
||||
const documentList = [
|
||||
{ title: 'Document 1', pages: 12 },
|
||||
{ title: 'Document 2', pages: 8 },
|
||||
{ title: 'Document 3', pages: 5 },
|
||||
{ title: 'Document 4', pages: 22 },
|
||||
{ title: 'Document 5', pages: 10 },
|
||||
{ title: 'Document 6', pages: 15 },
|
||||
{ title: 'Document 7', pages: 7 },
|
||||
{ title: 'Document 8', pages: 9 },
|
||||
{ title: 'Document 9', pages: 6 },
|
||||
{ title: 'Document 10', pages: 11 },
|
||||
{ title: 'Document 11', pages: 4 }, // Won't be shown due to slice
|
||||
];
|
||||
const DocumentSubmissionOptions = () => {
|
||||
const location = useLocation();
|
||||
const [status, setStatus] = useState(null);
|
||||
console.log("location.pathname", location.pathname, status)
|
||||
|
|
@ -218,6 +215,8 @@ const DocumentCompletionScreen = () => {
|
|||
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(() => {
|
||||
|
|
@ -277,7 +276,10 @@ const DocumentCompletionScreen = () => {
|
|||
// /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);
|
||||
}
|
||||
|
|
@ -336,96 +338,207 @@ const DocumentCompletionScreen = () => {
|
|||
// };
|
||||
// }
|
||||
// }, [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 (
|
||||
<div className="text-center space-y-6">
|
||||
<div className="w-24 h-24 bg-[var(--primary)] rounded-full flex items-center justify-center mx-auto shadow-lg animate-bounce">
|
||||
<FaCheck className="text-white text-3xl" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-gray-800 mb-2">Document Send Successfully!</h3>
|
||||
{selectedDocuments?.map((docs) => (
|
||||
<p className="text-gray-600">Your document "{docs.name}" has been sent for signature.</p>
|
||||
) )}
|
||||
</div>
|
||||
<div className="bg-gray-50 rounded-lg p-4 space-y-2">
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-gray-500">createdBy:</span>
|
||||
<span className="font-medium">{transactionData?.createdBy?.name}</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-gray-500">Email:</span>
|
||||
<span className="font-medium">{transactionData?.createdBy?.email}</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-gray-500">createdAt:</span>
|
||||
<span className="font-medium">{transactionData.createdAt}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
case 'redirect':
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-screen bg-[var(--mainViewBg)]">
|
||||
{/* Top Banner */}
|
||||
<div className='fixed top-0 w-full flex items-center justify-between bg-white shadow z-50 px-4 py-3'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<Link to={"/"}>
|
||||
|
||||
<SigningOrderDiagram signers={selectedRecipients} />
|
||||
</>
|
||||
);
|
||||
case 'public':
|
||||
return (
|
||||
<>
|
||||
<SignersList signers={selectedRecipients} />
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-gray-50 to-blue-50 p-6">
|
||||
<div className={`max-w-6xl mx-auto transition-all duration-700 ${isVisible ? 'translate-y-0 opacity-100' : 'translate-y-8 opacity-0'}`}>
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-center space-x-4 mb-5">
|
||||
<button className="flex items-center space-x-2 text-gray-600 hover:text-[var(--primary)] transition-colors duration-200 group">
|
||||
<IoMdHome
|
||||
className='text-2xl text-slate-500 cursor-pointer hover:text-[var(--primary)] transition'
|
||||
/>
|
||||
</Link>
|
||||
<p className="text-base font-normal text-gray-700 border-l pl-4">🎉 Awesome! The document’s been sent for signature. 🎉</p>
|
||||
</button>
|
||||
<div className="h-8 w-px bg-gray-300"></div>
|
||||
<h1 className="text-2xl font-bold text-gray-800">🎉 Awesome! The document’s been sent for signature. 🎉</h1>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="add-tags-btn-step-one"
|
||||
className='flex items-center gap-3'>
|
||||
{/* <div className='border mb-2 border-gray-500'></div> */}
|
||||
|
||||
<Link to={`/accounts/${accountId}/transactions/${transactionId}`} className="flex items-center gap-2 cursor-pointer text-xs px-4 py-2 ml-3 rounded-sm bg-[var(--primary)]">
|
||||
{/* <FaPen className=" text-white text-md" /> */}
|
||||
<span className="tracking-wide text-white">View Transaction</span>
|
||||
</Link>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3 ">
|
||||
{/* Left Panel - Configuration */}
|
||||
<div className="space-y-6 ">
|
||||
|
||||
{/* <button
|
||||
onClick={() => handleNextClick(false)}
|
||||
className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer"
|
||||
>
|
||||
{signType === SignTypeEnum.selfSign ? "Sign" : "Next"}
|
||||
</button> */}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
{(selectedRecipients.length > 0 && selectedDocuments.length > 0) ?
|
||||
<div className="p-3 mt-[55px]">
|
||||
<div className="max-w-[97vw] mx-auto">
|
||||
{/* Header */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-2">
|
||||
{/* Left Section - Document Details */}
|
||||
<div className="lg:col-span-6 space-y-2">
|
||||
{/* Document Preview Card */}
|
||||
<div className="bg-white/60 rounded-md shadow-sm border border-gray-100 overflow-hidden max-h-[88vh] no-scrollbar overflow-y-auto">
|
||||
<div className="p-3 ">
|
||||
{selectedDocuments?.map((item, index) => (
|
||||
<div key={item.id} className="flex items-start justify-between mb-2 px-2 py-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
||||
{/* <FaFileAlt className="text-blue-600 text-xl" /> */}
|
||||
<img src={item.pages[0].src} alt="document" className="h-10 w-10" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-md font-semibold text-gray-800">
|
||||
Name : {item.name ?? '--'}
|
||||
{/* Action Selection */}
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-200 min-h-[81vh] ">
|
||||
<div className="p-6">
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-4">
|
||||
Choose an action after a signer completes the document.
|
||||
</h3>
|
||||
<div className="text-gray-600 text-sm">
|
||||
Status : {item.status ?? '--'}
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{options.map((option) => {
|
||||
const Icon = option.icon;
|
||||
const isSelected = selectedOption === option.id;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={option.id}
|
||||
onClick={() => 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
|
||||
`}
|
||||
>
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className={`
|
||||
w-12 h-12 rounded-full flex items-center justify-center transition-all duration-200
|
||||
${isSelected
|
||||
? 'bg-[var(--primary)] text-white shadow-lg'
|
||||
: 'bg-white ' + option.iconColor + ' group-hover:scale-110'
|
||||
}
|
||||
`}>
|
||||
<Icon className="text-lg" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center space-x-2">
|
||||
<h4 className={`font-semibold transition-colors duration-200 ${isSelected ? 'text-[var(--primary)]' : 'text-gray-800'
|
||||
}`}>
|
||||
{option.title}
|
||||
</h4>
|
||||
{option.isPremium && (
|
||||
<span className="text-purple-500 text-sm">★</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<p className="text-sm text-gray-600 mt-1">
|
||||
{option.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div><SignersList signers={selectedRecipients} /></div>
|
||||
{/* Selection indicator */}
|
||||
{isSelected && (
|
||||
<div className="absolute top-4 right-4">
|
||||
<div className="w-6 h-6 bg-[var(--primary)] rounded-full flex items-center justify-center">
|
||||
<FaCheck className="text-white text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Section - Signer Components */}
|
||||
<div className="lg:col-span-6 space-y-1.5">
|
||||
{/* Signing Order Diagram */}
|
||||
<SigningOrderDiagram signers={selectedRecipients} />
|
||||
{/* Custom Image Section */}
|
||||
</div>
|
||||
|
||||
{/* Signers List */}
|
||||
{/* Right Panel - Preview */}
|
||||
<div className="space-y-6">
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden sticky top-6">
|
||||
<div className="bg-gradient-to-r from-gray-50 to-blue-50 px-6 py-2 border-b border-gray-200">
|
||||
<h3 className="text-lg font-semibold text-gray-800">Live Preview</h3>
|
||||
<p className="text-sm text-gray-500">See how your users will experience the completion</p>
|
||||
</div>
|
||||
|
||||
<div className="p-3 min-h-[70vh] flex justify-center">
|
||||
<div className="w-full transition-all duration-500 transform">
|
||||
{getPreviewContent()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
: <Loader />}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentCompletionScreen;
|
||||
export default DocumentSubmissionOptions;
|
||||
Loading…
Reference in New Issue