406 lines
14 KiB
TypeScript
406 lines
14 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
FiDownload,
|
|
FiCheckCircle,
|
|
FiZap,
|
|
FiShield,
|
|
FiClock,
|
|
FiFileText,
|
|
FiX,
|
|
} from 'react-icons/fi';
|
|
import { IoMdArrowRoundBack } from 'react-icons/io';
|
|
import { useParams } from 'react-router-dom';
|
|
import { SignTypeEnum } from '../../utlity/types';
|
|
|
|
const SignCompletionScreen: React.FC = () => {
|
|
const { signType } = useParams();
|
|
const [showDownloadModal, setShowDownloadModal] = useState(false);
|
|
const [animationPhase, setAnimationPhase] = useState(0);
|
|
|
|
|
|
useEffect(() => {
|
|
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);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
// Trigger animation phases sequentially
|
|
const timers = [
|
|
setTimeout(() => setAnimationPhase(1), 200),
|
|
setTimeout(() => setAnimationPhase(2), 800),
|
|
setTimeout(() => setAnimationPhase(3), 1400),
|
|
setTimeout(() => setAnimationPhase(4), 2000),
|
|
];
|
|
|
|
return () => timers.forEach(clearTimeout);
|
|
}, []);
|
|
|
|
const handleDownload = (format: string) => {
|
|
console.log(`Downloading document in ${format} format`);
|
|
const content = `Signed document - ${new Date().toISOString()}`;
|
|
const blob = new Blob([content], { type: 'text/plain' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `signed-document.${format.toLowerCase()}`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen w-screen z-1000 bg-gradient-to-br from-slate-100/50 via-blue-100/50 to-slate-300/50 flex items-center justify-center p-4 overflow-hidden absolute top-0 left-0">
|
|
<style jsx>{`
|
|
:root {
|
|
--primary: #3D74B6;
|
|
--primaryLight: #ffffff;
|
|
--primaryLight2: #6a92c2;
|
|
--primaryLight3: #dae9de;
|
|
--dashBoardBg: #ffffff;
|
|
--mainViewBg: #edeaeb;
|
|
--highlightBg1: #edeaeb;
|
|
--menuTextCol: #98a0a8;
|
|
--menuTextColActive: #3D74B6;
|
|
--menuBgColActive: #edeaeb;
|
|
--menuTextHoverCol: #e7e7e7;
|
|
--greyTextCol: #98a0a8;
|
|
--lightGreyCol: #e1e1e1;
|
|
--compBgCol: #ffffff;
|
|
--avatarBgCol: #3D74B6;
|
|
--avatarTextCol: #ffffff;
|
|
--profileMenuModalBg: #ffffff;
|
|
--profileMenuModalTextCol: #98a0a8;
|
|
--profileMenuModalTextColActive: #2d2d2d;
|
|
--profileMenuModalBgColActive: #edeaeb;
|
|
--sendForSignTextCol: #ffffff;
|
|
--sendForSignBgCol: #d02f56;
|
|
--sendForSignDropDownText: #000000;
|
|
--sendForSignDropDownBg: #ffffff;
|
|
--sendForSignDropDownHover: #e7e7e7;
|
|
--loaderBg: #ffffff;
|
|
--modalBg: #ffffff;
|
|
--hideModalBg: #2d2d2d;
|
|
--processStepOneTextHead: #000000;
|
|
--modalSubmitBG: #1919d7;
|
|
--modalSubmitBGHover: #395ee1;
|
|
}
|
|
|
|
.completion-container {
|
|
animation: fadeInScale 1.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.success-icon {
|
|
animation: successPulse 2s ease-out infinite;
|
|
}
|
|
|
|
.floating-particles {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.particle {
|
|
position: absolute;
|
|
width: 8px;
|
|
height: 8px;
|
|
background: linear-gradient(45deg, var(--primary), var(--primaryLight2));
|
|
border-radius: 50%;
|
|
animation: float 6s ease-in-out infinite;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.particle:nth-child(1) { top: 20%; left: 10%; animation-delay: 1s; }
|
|
.particle:nth-child(2) { top: 60%; left: 20%; animation-delay: 2s; }
|
|
.particle:nth-child(3) { top: 30%; left: 80%; animation-delay: 3s; }
|
|
.particle:nth-child(4) { top: 80%; left: 70%; animation-delay: 2.5s; }
|
|
.particle:nth-child(5) { top: 10%; left: 60%; animation-delay: 1.5s; }
|
|
.particle:nth-child(6) { top: 70%; left: 40%; animation-delay: 3.5s; }
|
|
|
|
.premium-glow {
|
|
box-shadow:
|
|
0 0 0 1px rgba(255, 255, 255, 0.1),
|
|
0 4px 32px rgba(61, 116, 182, 0.15),
|
|
0 16px 64px rgba(61, 116, 182, 0.1),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.premium-card {
|
|
background: linear-gradient(135deg,
|
|
rgba(255, 255, 255, 0.95) 0%,
|
|
rgba(255, 255, 255, 0.9) 100%);
|
|
backdrop-filter: blur(20px);
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.status-badge {
|
|
background: linear-gradient(135deg, #10b981, #059669);
|
|
box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
|
|
}
|
|
|
|
.download-btn-primary {
|
|
background: linear-gradient(135deg, var(--primary), var(--primaryLight2));
|
|
box-shadow: 0 8px 24px rgba(61, 116, 182, 0.3);
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.download-btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 12px 32px rgba(61, 116, 182, 0.4);
|
|
}
|
|
|
|
.download-btn-secondary {
|
|
background: rgba(255, 255, 255, 0.8);
|
|
border: 2px solid rgba(61, 116, 182, 0.2);
|
|
backdrop-filter: blur(10px);
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.download-btn-secondary:hover {
|
|
transform: translateY(-2px);
|
|
background: rgba(255, 255, 255, 0.95);
|
|
border-color: var(--primary);
|
|
}
|
|
|
|
.modal-backdrop {
|
|
background: rgba(0, 0, 0, 0.6);
|
|
backdrop-filter: blur(8px);
|
|
animation: fadeIn 0.3s ease-out;
|
|
}
|
|
|
|
.modal-content {
|
|
animation: modalSlideUp 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
}
|
|
|
|
@keyframes fadeInScale {
|
|
0% {
|
|
opacity: 0;
|
|
transform: scale(0.9) translateY(20px);
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
transform: scale(1) translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes successPulse {
|
|
0%, 100% {
|
|
transform: scale(1);
|
|
box-shadow: 0 0 0 0 var(--primary);
|
|
}
|
|
50% {
|
|
transform: scale(1.05);
|
|
box-shadow: 0 0 0 20px rgba(61, 116, 182, 0); /* var(--primary) with 0 alpha */
|
|
}
|
|
}
|
|
|
|
|
|
@keyframes float {
|
|
0%, 100% {
|
|
transform: translateY(0px) rotate(0deg);
|
|
opacity: 0.6;
|
|
}
|
|
50% {
|
|
transform: translateY(-20px) rotate(180deg);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
@keyframes modalSlideUp {
|
|
0% {
|
|
opacity: 0;
|
|
transform: translateY(50px) scale(0.9);
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
}
|
|
}
|
|
|
|
.fade-in-up {
|
|
animation: fadeInUp 0.8s ease-out forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
.fade-in-up-delay-1 {
|
|
animation: fadeInUp 0.8s ease-out 0.3s forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
.fade-in-up-delay-2 {
|
|
animation: fadeInUp 0.8s ease-out 0.6s forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
.fade-in-up-delay-3 {
|
|
animation: fadeInUp 0.8s ease-out 0.9s forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
@keyframes fadeInUp {
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.fade-in-up,
|
|
.fade-in-up-delay-1,
|
|
.fade-in-up-delay-2,
|
|
.fade-in-up-delay-3 {
|
|
transform: translateY(30px);
|
|
}
|
|
`}</style>
|
|
|
|
{/* Floating Particles Background */}
|
|
<div className="floating-particles">
|
|
<div className="particle"></div>
|
|
<div className="particle"></div>
|
|
<div className="particle"></div>
|
|
<div className="particle"></div>
|
|
<div className="particle"></div>
|
|
<div className="particle"></div>
|
|
</div>
|
|
|
|
{/* Main Completion Screen */}
|
|
<div className="completion-container w-full max-w-[50vw]">
|
|
<div className="premium-card premium-glow rounded-3xl p-8 text-center relative overflow-hidden">
|
|
|
|
{/* Success Icon */}
|
|
<div className="relative mb-4">
|
|
<div className="success-icon inline-flex items-center justify-center w-20 h-20 bg-[var(--primary)] rounded-full mb-6">
|
|
<FiCheckCircle className="w-12 h-12 text-white" />
|
|
</div>
|
|
<FiZap className="absolute top-0 right-1/3 w-6 h-6 text-yellow-400 animate-pulse" />
|
|
<FiZap className="absolute bottom-2 left-1/3 w-4 h-4 text-yellow-400 animate-pulse" style={{ animationDelay: '0.5s' }} />
|
|
</div>
|
|
|
|
{/* Main Success Message */}
|
|
<div className={`mb-2 ${animationPhase >= 1 ? 'fade-in-up' : ''}`}>
|
|
<h1 className="text-xl font-bold text-gray-900 mb-2">
|
|
Signature Complete!
|
|
</h1>
|
|
<p className="text-md text-gray-600 mb-3">
|
|
Your document has been successfully signed.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Action Buttons */}
|
|
<div className='flex justify-between items-center gap-2'>
|
|
<button
|
|
// onClick={() => setShowDownloadModal(true)}
|
|
className="w-full download-btn-secondary text-gray-400 py-2 px-2 rounded-xl font-medium flex items-center justify-center"
|
|
>
|
|
<FiDownload className="w-5 h-5 mr-3" />
|
|
Download Signed Document
|
|
</button>
|
|
{signType == SignTypeEnum.selfSign ? <a
|
|
href="http://localhost:5173/"
|
|
// target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-full download-btn-secondary text-gray-400 py-2 px-2 rounded-xl font-medium flex items-center justify-center"
|
|
>
|
|
{/* <a> */}
|
|
<IoMdArrowRoundBack className="w-5 h-5 mr-3" />
|
|
Back to Sign Made Easy
|
|
{/* </a> */}
|
|
</a> :
|
|
<a
|
|
href="https://signmadeasy.com/"
|
|
// target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-full download-btn-secondary text-gray-400 py-2 px-2 rounded-xl font-medium flex items-center justify-center"
|
|
>
|
|
{/* <a> */}
|
|
<IoMdArrowRoundBack className="w-5 h-5 mr-3" />
|
|
Visit Sign Made Easy
|
|
{/* </a> */}
|
|
</a>
|
|
}
|
|
</div>
|
|
|
|
{/* Additional Info */}
|
|
<div className={`mt-8 pt-3 border-t border-gray-200 border-opacity-50`}>
|
|
<p className="text-sm text-gray-500">
|
|
Your document is signed and saved. Download it or return to Sign Made Easy to continue — navigation is paused until an action is taken.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Premium Download Modal */}
|
|
{/* {showDownloadModal && (
|
|
<div className="fixed inset-0 bg-white/60 backdrop-blur-sm bg-opacity-50 flex items-center justify-center p-4 z-50">
|
|
<div className="modal-content premium-card premium-glow rounded-3xl p-8 w-full max-w-md relative">
|
|
<button
|
|
onClick={() => setShowDownloadModal(false)}
|
|
className="absolute top-6 right-6 p-2 hover:bg-gray-100 rounded-full transition-colors duration-200"
|
|
>
|
|
<FiX className="w-5 h-5 text-gray-500" />
|
|
</button>
|
|
|
|
<div className="text-center mb-4">
|
|
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-full mb-4">
|
|
<FiDownload className="w-8 h-8 text-white" />
|
|
</div>
|
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">Choose Download Format</h2>
|
|
<p className="text-gray-600">Select your preferred file format</p>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
<button
|
|
onClick={() => handleDownload('PDF')}
|
|
className="w-full download-btn-primary text-white py-4 px-6 rounded-xl font-semibold flex items-center justify-center"
|
|
>
|
|
<FiFileText className="w-5 h-5 mr-3" />
|
|
Download as PDF
|
|
<span className="ml-auto text-sm opacity-80">Recommended</span>
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => handleDownload('DOCX')}
|
|
className="w-full download-btn-secondary text-gray-700 py-4 px-6 rounded-xl font-semibold flex items-center justify-center"
|
|
>
|
|
<FiFileText className="w-5 h-5 mr-3" />
|
|
Download as DOCX
|
|
</button>
|
|
</div>
|
|
|
|
<div className="mt-6 pt-6 border-t border-gray-200 border-opacity-50 text-center">
|
|
<p className="text-xs text-gray-500">
|
|
Files are automatically encrypted and timestamped
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)} */}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SignCompletionScreen; |