SME-Web/src/components/setting/Signature/Signature.tsx

260 lines
14 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { FiEdit3, FiTrash2, FiPlus, FiMoreVertical } from 'react-icons/fi';
import AddSignatureModal from './AddSignatureModal';
import api from '../../../config/api';
import { Bounce, toast } from "react-toastify";
import { FaSpinner } from 'react-icons/fa';
interface Signature {
id: string;
email: string;
signatureType: string;
lastName: string;
firstName: string
font: string;
initialsBlob: string;
initialsStampedBlob: string;
initialsHash: string;
signatureHash: string;
signatureBlob: string;
signatureStampedBlob: string;
default: boolean
}
const SignatureManager: React.FC = () => {
const [loading, setLoading] = useState<boolean>(false)
const [signatures, setSignatures] = useState<Signature[]>([]);
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
const [showAddSignature, setShowAddSignature] = useState<boolean>(false);
const [editingSignature, setEditingSignature] = useState<Signature | null>(null);
const getAllSignatures = async () => {
setLoading(true)
try {
let res = await api.get("/api/user/signatures")
console.log("getAllSignatures", res.data)
let signatureData = res?.data
setSignatures(signatureData)
} catch (error) {
console.log("getAllSignatures", error)
} finally {
setLoading(false)
}
}
useEffect(() => {
getAllSignatures()
}, [])
const handleEdit = (id: string) => {
console.log('Edit signature:', id);
let editSignature = signatures.find((item) => item.id === id);
console.log("editSignature", editSignature);
if (editSignature) {
setEditingSignature(editSignature);
setShowAddSignature(true);
}
setActiveDropdown(null);
};
const handleDelete = async (id: string) => {
if (!id) return;
setLoading(true)
try {
let res = await api.delete(`/api/user/signatures/${id}`)
console.log(res.data)
toast.success("Signature Delete Successfull", {
position: "top-center",
autoClose: 500,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
transition: Bounce,
});
await getAllSignatures();
} catch (error) {
console.log("delete signature", error)
} finally {
setActiveDropdown(null);
setLoading(false)
}
};
const toggleDropdown = (id: string) => {
setActiveDropdown(activeDropdown === id ? null : id);
};
const handleAddNew = () => {
setEditingSignature(null);
setShowAddSignature(true);
};
const handleModalClose = () => {
setShowAddSignature(false);
setEditingSignature(null);
};
return (
<>
{loading ? <div className=' flex items-center justify-center'>
<div className="p-12 text-center mt-8">
<div className="text-gray-400 mb-4">
<FaSpinner className="w-20 h-20 mx-auto animate-spin" />
</div>
<h3 className="text-xl font-semibold text-gray-700 mb-2">Loading...</h3>
</div>
</div> :
<div className="min-h-screen bg-white p-3 rounded-md px-4 mb-6">
<div className="max-w-[84vw] mx-auto">
<>
{/* Header */}
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-[17px] font-medium text-gray-500 mb-2">Signatures</h1>
<p className="text-gray-300 text-sm">Add or update your name and signature styles.</p>
</div>
<button className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-semibold text-sm text-[14px] flex items-center cursor-pointer transition-all duration-200 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5" onClick={handleAddNew}>
<FiPlus className="" />
ADD
</button>
</div>
{/* Table Card */}
<div className="bg-white rounded-md shadow-md overflow-hidden border border-gray-100">
{/* Table Header */}
<div className="bg-gray-50 border-b border-gray-200">
<div className="grid grid-cols-12 gap-4 px-6 py-4">
<div className="col-span-5">
<h3 className="text-sm font-semibold text-gray-700 uppercase tracking-wider">Signature</h3>
</div>
<div className="col-span-5">
<h3 className="text-sm font-semibold text-gray-700 uppercase tracking-wider">Initial</h3>
</div>
<div className="col-span-2">
<h3 className="text-sm font-semibold text-gray-700 uppercase tracking-wider text-right">Actions</h3>
</div>
</div>
</div>
{/* Table Body */}
<div className="divide-y divide-gray-100">
{signatures.map((signature, index) => (
<div key={signature.id} className="grid grid-cols-12 gap-4 px-6 py-9 hover:bg-gray-50 transition-colors duration-150">
{/* Signature Column */}
<div className="col-span-5">
<div className="flex flex-col space-y-2 relative ps-6 border-l-3 border-blue-600 rounded-bl-2xl rounded-tl-2xl">
{/* Label */}
<div className="text-sm text-gray-600 font-medium mb-1">
Signed by:
</div>
{/* Signature Image */}
<div className="bg-white rounded-lg p-1 flex items-center justify-center ">
<img
src={`data:image/png;base64,${signature.signatureBlob}`}
className="h-[50px] w-[250px] object-contain"
alt="Signature"
/>
</div>
{/* Signature ID */}
<div className="text-xs text-gray-500 truncate">
{signature.signatureHash}
</div>
</div>
</div>
{/* Initial Column */}
<div className="col-span-5">
<div className="flex flex-col space-y-2 relative ps-6 border-l-3 border-green-600 rounded-bl-2xl rounded-tl-2xl">
{/* Label */}
<div className="text-sm text-gray-600 font-medium mb-1">
DS
</div>
{/* Signature Image */}
<div className="bg-white rounded-lg p-1 flex items-center justify-center ">
<img
src={`data:image/png;base64,${signature.initialsBlob}`}
className="h-[50px] object-contain"
alt="DS Signature"
/>
</div>
</div>
</div>
{/* Actions Column */}
<div className="col-span-2 flex justify-between items-start pt-9 ps-8 ">
<div className="relative ">
<button
onClick={() => toggleDropdown(signature.id)}
className="bg-gray-100 hover:bg-gray-200 text-gray-700 px-1.5 py-1.5 text-[13px] rounded-lg font-semibold flex items-center transition-all duration-200 border border-gray-300 "
>
ACTIONS
<FiMoreVertical />
</button>
{/* Dropdown Menu */}
{activeDropdown === signature.id && (
<div className="absolute right-0 mt-0.5 w-28 bg-white rounded-lg shadow-xl border border-gray-200 z-10 py-1">
<button
onClick={() => handleEdit(signature.id)}
className="w-full px-4 py-1 text-left text-gray-500 hover:bg-blue-50 hover:text-blue-700 flex items-center gap-3 text-sm transition-colors duration-150"
>
<FiEdit3 />
Edit
</button>
<button
onClick={() => handleDelete(signature.id)}
className="w-full px-4 py-1 text-left text-gray-500 hover:bg-red-50 hover:text-red-700 flex items-center gap-3 text-sm transition-colors duration-150"
>
<FiTrash2 />
Delete
</button>
</div>
)}
</div>
</div>
</div>
))}
</div>
</div>
{/* Empty State (if no signatures) */}
{signatures.length === 0 && (
<div className="bg-white rounded-xl shadow-lg p-12 text-center mt-8">
<div className="text-gray-400 mb-4">
<FiEdit3 className="w-16 h-16 mx-auto" />
</div>
<h3 className="text-xl font-semibold text-gray-700 mb-2">No signatures yet</h3>
<p className="text-gray-500 mb-6">Create your first signature to get started.</p>
</div>
)}
</>
</div>
{/* Click outside to close dropdown */}
{activeDropdown && (
<div
className="fixed inset-0 z-0"
onClick={() => setActiveDropdown(null)}
/>
)}
{showAddSignature && (
<AddSignatureModal
setShowAddSignature={handleModalClose}
getAllSignatures={getAllSignatures}
editingSignature={editingSignature}
/>
)}
</div>
}</>
);
};
export default SignatureManager;