DrawSignature
This commit is contained in:
parent
1215433e16
commit
faa4839fef
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
// import { X, Upload, Edit3, Image, Cloud, HardDrive, Droplets } from 'lucide-react';
|
// import { X, Upload, Edit3, Image, Cloud, HardDrive, Droplets } from 'lucide-react';
|
||||||
import { AiOutlineClose, AiOutlineUpload, AiOutlineEdit } from 'react-icons/ai';
|
import { AiOutlineClose, AiOutlineUpload, AiOutlineEdit } from 'react-icons/ai';
|
||||||
import { MdImage, MdCloudUpload, MdStorage } from 'react-icons/md';
|
import { MdImage, MdCloudUpload } from 'react-icons/md';
|
||||||
import api from '../../../config/api';
|
import api from '../../../config/api';
|
||||||
|
import DrawSignatureCanvas from './DrawSignatureCanvas';
|
||||||
|
|
||||||
|
|
||||||
interface AddSignatureModalProps {
|
interface AddSignatureModalProps {
|
||||||
|
|
@ -28,6 +29,17 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({ setShowAddSignatu
|
||||||
const [fullName, setFullName] = useState('');
|
const [fullName, setFullName] = useState('');
|
||||||
const [initials, setInitials] = useState('');
|
const [initials, setInitials] = useState('');
|
||||||
|
|
||||||
|
const [signatures, setSignatures] = useState<{
|
||||||
|
fullSignature: string | null;
|
||||||
|
initials: string | null;
|
||||||
|
}>({ fullSignature: null, initials: null });
|
||||||
|
|
||||||
|
const handleSignatureChange = (data: { fullSignature: string | null; initials: string | null }) => {
|
||||||
|
setSignatures(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Sample signature options for the CHOOSE tab
|
// Sample signature options for the CHOOSE tab
|
||||||
const signatureOptions = [
|
const signatureOptions = [
|
||||||
{ id: 1, name: 'print', initials: 'LA', style: 'print' },
|
{ id: 1, name: 'print', initials: 'LA', style: 'print' },
|
||||||
|
|
@ -39,6 +51,8 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({ setShowAddSignatu
|
||||||
];
|
];
|
||||||
|
|
||||||
const [selectedSignature, setSelectedSignature] = useState<number>(1);
|
const [selectedSignature, setSelectedSignature] = useState<number>(1);
|
||||||
|
console.log(selectedSignature);
|
||||||
|
|
||||||
|
|
||||||
// Store the actual file
|
// Store the actual file
|
||||||
const [file1, setFile1] = useState<File | null>(null);
|
const [file1, setFile1] = useState<File | null>(null);
|
||||||
|
|
@ -90,6 +104,38 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({ setShowAddSignatu
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!signatures.fullSignature || !signatures.initials) {
|
||||||
|
alert('Please provide both signature and initials');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: Posting the base64 data
|
||||||
|
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
signatureType: "DRAW",
|
||||||
|
// "signatureId": 0, this work on only the put req.
|
||||||
|
signatureBase64: signatures.fullSignature,
|
||||||
|
initialsBase64: signatures.initials,
|
||||||
|
firstName: user.firstName,
|
||||||
|
lastName: user.lastName,
|
||||||
|
font: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('Submitting Signature:', payload);
|
||||||
|
let res = await api.post(`/api/user/signatures`,payload)
|
||||||
|
console.log("handleSubmit", res)
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching user details:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fetch('/api/signature', { method: 'POST', body: JSON.stringify(payload) })
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
switch (activeTab) {
|
switch (activeTab) {
|
||||||
|
|
@ -149,51 +195,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({ setShowAddSignatu
|
||||||
|
|
||||||
case 'draw':
|
case 'draw':
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col">
|
<DrawSignatureCanvas onSignatureChange={handleSignatureChange} />
|
||||||
<div className="mb-6">
|
|
||||||
<h2 className="text-xl font-semibold text-gray-900 mb-2">Draw Signature</h2>
|
|
||||||
<p className="text-sm text-gray-600">Create your signature by drawing directly on the canvas</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-1 flex flex-col">
|
|
||||||
<div className="grid grid-cols-12 gap-6 mb-6">
|
|
||||||
{/* Draw area 1 */}
|
|
||||||
<div className="col-span-8">
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">Full Signature</label>
|
|
||||||
<div className="border-2 border-dashed border-gray-300 rounded-lg h-48 flex items-center justify-center bg-gray-50 hover:bg-gray-100 cursor-pointer transition-colors">
|
|
||||||
<div className="text-center">
|
|
||||||
{/* <Edit3 className="mx-auto h-12 w-12 text-gray-400 mb-3" /> */}
|
|
||||||
<p className="text-sm text-gray-500">Click and drag to draw your signature</p>
|
|
||||||
<p className="text-xs text-gray-400 mt-1">Use mouse or touch to create your signature</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* Draw area 2 */}
|
|
||||||
<div className="col-span-4">
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">Initials</label>
|
|
||||||
<div className="border-2 border-dashed border-gray-300 rounded-lg h-48 flex items-center justify-center bg-gray-50 hover:bg-gray-100 cursor-pointer transition-colors">
|
|
||||||
<div className="text-center">
|
|
||||||
{/* <Edit3 className="mx-auto h-8 w-8 text-gray-400 mb-2" /> */}
|
|
||||||
<p className="text-xs text-gray-500">Draw initials</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex gap-3">
|
|
||||||
<button className="px-4 py-2 text-sm border border-gray-300 rounded-md hover:bg-gray-50 transition-colors flex items-center gap-2">
|
|
||||||
{/* <X className="w-4 h-4" /> */}
|
|
||||||
Clear
|
|
||||||
</button>
|
|
||||||
<button className="px-4 py-2 text-sm border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
|
|
||||||
Undo
|
|
||||||
</button>
|
|
||||||
<button className="px-4 py-2 text-sm border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
|
|
||||||
Redo
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
case 'upload':
|
case 'upload':
|
||||||
|
|
@ -264,7 +266,10 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({ setShowAddSignatu
|
||||||
try {
|
try {
|
||||||
let res = await api.get(`/api/user/details`)
|
let res = await api.get(`/api/user/details`)
|
||||||
console.log("getuser", res)
|
console.log("getuser", res)
|
||||||
setUser(res?.data)
|
let currUser = res?.data
|
||||||
|
setUser(currUser)
|
||||||
|
setFullName(currUser.firstName + " " + currUser.lastName)
|
||||||
|
setInitials(currUser.firstName.slice(0, 1) + currUser.lastName.slice(0, 1))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching user details:", error);
|
console.error("Error fetching user details:", error);
|
||||||
}
|
}
|
||||||
|
|
@ -368,7 +373,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({ setShowAddSignatu
|
||||||
>
|
>
|
||||||
CANCEL
|
CANCEL
|
||||||
</button>
|
</button>
|
||||||
<button className="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700 transition-colors">
|
<button className="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700 transition-colors" onClick={handleSubmit}>
|
||||||
CREATE SIGNATURE
|
CREATE SIGNATURE
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
onSignatureChange: (data: { fullSignature: string | null; initials: string | null }) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DrawSignatureCanvas: React.FC<Props> = ({ onSignatureChange }) => {
|
||||||
|
const canvasRef1 = useRef<HTMLCanvasElement>(null);
|
||||||
|
const canvasRef2 = useRef<HTMLCanvasElement>(null);
|
||||||
|
const [isDrawing, setIsDrawing] = useState(false);
|
||||||
|
const [paths1, setPaths1] = useState<Array<Array<{ x: number; y: number }>>>([]);
|
||||||
|
const [paths2, setPaths2] = useState<Array<Array<{ x: number; y: number }>>>([]);
|
||||||
|
const [currentPath, setCurrentPath] = useState<Array<{ x: number; y: number }>>([]);
|
||||||
|
const [activeCanvas, setActiveCanvas] = useState<'full' | 'initials' | null>(null);
|
||||||
|
|
||||||
|
const handleMouseDown = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
|
setIsDrawing(true);
|
||||||
|
const rect = e.currentTarget.getBoundingClientRect();
|
||||||
|
const point = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
||||||
|
setCurrentPath([point]);
|
||||||
|
setActiveCanvas(e.currentTarget === canvasRef1.current ? 'full' : 'initials');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseMove = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
|
if (!isDrawing) return;
|
||||||
|
const rect = e.currentTarget.getBoundingClientRect();
|
||||||
|
const point = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
||||||
|
const newPath = [...currentPath, point]; // <- Build new path
|
||||||
|
setCurrentPath(newPath); // <- Save for next event
|
||||||
|
drawPath(e.currentTarget as HTMLCanvasElement, newPath); // <- Draw current
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportCanvasAsImage = (canvas: HTMLCanvasElement | null): string | null => {
|
||||||
|
if (!canvas) return null;
|
||||||
|
return canvas.toDataURL('image/png');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
setIsDrawing(false);
|
||||||
|
if (currentPath.length === 0 || !activeCanvas) return;
|
||||||
|
|
||||||
|
if (activeCanvas === 'full') {
|
||||||
|
const newPaths = [...paths1, currentPath];
|
||||||
|
setPaths1(newPaths);
|
||||||
|
const fullSignature = exportCanvasAsImage(canvasRef1.current);
|
||||||
|
onSignatureChange({ fullSignature, initials: exportCanvasAsImage(canvasRef2.current) });
|
||||||
|
} else {
|
||||||
|
const newPaths = [...paths2, currentPath];
|
||||||
|
setPaths2(newPaths);
|
||||||
|
const initials = exportCanvasAsImage(canvasRef2.current);
|
||||||
|
onSignatureChange({ fullSignature: exportCanvasAsImage(canvasRef1.current), initials });
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentPath([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const drawPath = (canvas: HTMLCanvasElement | null, path: Array<{ x: number; y: number }>) => {
|
||||||
|
if (!canvas) return;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const allPaths =
|
||||||
|
canvas === canvasRef1.current ? [...paths1, path] : [...paths2, path];
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
ctx.lineCap = 'round';
|
||||||
|
|
||||||
|
allPaths.forEach((p) => {
|
||||||
|
if (p.length < 2) return;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(p[0].x, p[0].y);
|
||||||
|
for (let i = 1; i < p.length; i++) {
|
||||||
|
ctx.lineTo(p[i].x, p[i].y);
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const clearCanvas = () => {
|
||||||
|
if (canvasRef1.current) {
|
||||||
|
const ctx1 = canvasRef1.current.getContext('2d');
|
||||||
|
ctx1?.clearRect(0, 0, canvasRef1.current.width, canvasRef1.current.height);
|
||||||
|
}
|
||||||
|
if (canvasRef2.current) {
|
||||||
|
const ctx2 = canvasRef2.current.getContext('2d');
|
||||||
|
ctx2?.clearRect(0, 0, canvasRef2.current.width, canvasRef2.current.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPaths1([]);
|
||||||
|
setPaths2([]);
|
||||||
|
onSignatureChange({ fullSignature: null, initials: null });
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full flex flex-col">
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900 mb-2">Draw Signature</h2>
|
||||||
|
<p className="text-sm text-gray-600">Create your signature by drawing directly on the canvas</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 flex flex-col">
|
||||||
|
<div className="grid grid-cols-12 gap-6 mb-2">
|
||||||
|
{/* Full Signature Canvas */}
|
||||||
|
<div className="col-span-8">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">Full Signature</label>
|
||||||
|
<div className="border-2 border-dashed border-gray-300 rounded-lg bg-gray-50 hover:bg-gray-100 transition-colors">
|
||||||
|
<canvas
|
||||||
|
ref={canvasRef1}
|
||||||
|
className="w-full h-48 cursor-crosshair"
|
||||||
|
width={canvasRef1.current?.clientWidth || 600} // use real width
|
||||||
|
height={canvasRef1.current?.clientHeight || 180}
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
onMouseMove={handleMouseMove}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
onMouseLeave={handleMouseUp}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Initials Canvas */}
|
||||||
|
<div className="col-span-4">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">Initials</label>
|
||||||
|
<div className="border-2 border-dashed border-gray-300 rounded-lg bg-gray-50 hover:bg-gray-100 transition-colors">
|
||||||
|
<canvas
|
||||||
|
ref={canvasRef2}
|
||||||
|
width={canvasRef2.current?.clientWidth || 300}
|
||||||
|
height={canvasRef2.current?.clientHeight || 180}
|
||||||
|
className="w-full h-48 cursor-crosshair"
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
onMouseMove={handleMouseMove}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
onMouseLeave={handleMouseUp}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Controls */}
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<button
|
||||||
|
className="px-4 py-2 text-sm border border-gray-300 rounded-md hover:bg-gray-50 transition-colors"
|
||||||
|
onClick={clearCanvas}
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DrawSignatureCanvas;
|
||||||
|
|
@ -1,35 +1,29 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { FiEdit3, FiTrash2, FiPlus, FiMoreVertical } from 'react-icons/fi';
|
import { FiEdit3, FiTrash2, FiPlus, FiMoreVertical } from 'react-icons/fi';
|
||||||
import AddSignatureModal from './AddSignatureModal';
|
import AddSignatureModal from './AddSignatureModal';
|
||||||
|
import api from '../../../config/api';
|
||||||
|
|
||||||
interface Signature {
|
interface Signature {
|
||||||
id: string;
|
id: string;
|
||||||
signature: string;
|
email: string;
|
||||||
initial: string;
|
signatureType: string;
|
||||||
createdAt: 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 SignatureManager: React.FC = () => {
|
||||||
const [signatures, setSignatures] = useState<Signature[]>([
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
signature: 'https://www.signwell.com/assets/vip-signatures/muhammad-ali-signature-3f9237f6fc48c3a04ba083117948e16ee7968aae521ae4ccebdfb8f22596ad22.svg',
|
const [signatures, setSignatures] = useState<Signature[]>([]);
|
||||||
initial: 'AB',
|
|
||||||
createdAt: 'dca3e646-62cd-4cc...'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
signature: '∼∼⌒∼∼⌒∼',
|
|
||||||
initial: 'AB',
|
|
||||||
createdAt: 'dca3e646-62cd-4cc...'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
signature: 'Digital Signature',
|
|
||||||
initial: 'DS',
|
|
||||||
createdAt: 'dca3e646-62cd-4cc...'
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
|
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
|
||||||
const [showAddSignature, setShowAddSignature] = useState<boolean>(false)
|
const [showAddSignature, setShowAddSignature] = useState<boolean>(false)
|
||||||
|
|
@ -48,6 +42,21 @@ const SignatureManager: React.FC = () => {
|
||||||
setActiveDropdown(activeDropdown === id ? null : id);
|
setActiveDropdown(activeDropdown === id ? null : id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAllSignatures = async () => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getAllSignatures()
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-white p-3 rounded-md px-4 mb-6">
|
<div className="min-h-screen bg-white p-3 rounded-md px-4 mb-6">
|
||||||
<div className="max-w-[84vw] mx-auto">
|
<div className="max-w-[84vw] mx-auto">
|
||||||
|
|
@ -95,7 +104,7 @@ const SignatureManager: React.FC = () => {
|
||||||
{/* Signature Image */}
|
{/* Signature Image */}
|
||||||
<div className="bg-white rounded-lg p-1 flex items-center justify-center ">
|
<div className="bg-white rounded-lg p-1 flex items-center justify-center ">
|
||||||
<img
|
<img
|
||||||
src="https://www.signwell.com/assets/vip-signatures/muhammad-ali-signature-3f9237f6fc48c3a04ba083117948e16ee7968aae521ae4ccebdfb8f22596ad22.svg"
|
src={`data:image/png;base64,${signature.signatureBlob}`}
|
||||||
className="h-[50px] w-[250px] object-contain"
|
className="h-[50px] w-[250px] object-contain"
|
||||||
alt="Signature"
|
alt="Signature"
|
||||||
/>
|
/>
|
||||||
|
|
@ -103,7 +112,7 @@ const SignatureManager: React.FC = () => {
|
||||||
|
|
||||||
{/* Signature ID */}
|
{/* Signature ID */}
|
||||||
<div className="text-xs text-gray-500 truncate">
|
<div className="text-xs text-gray-500 truncate">
|
||||||
{signature.createdAt}
|
{signature.signatureHash}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -120,7 +129,7 @@ const SignatureManager: React.FC = () => {
|
||||||
{/* Signature Image */}
|
{/* Signature Image */}
|
||||||
<div className="bg-white rounded-lg p-1 flex items-center justify-center ">
|
<div className="bg-white rounded-lg p-1 flex items-center justify-center ">
|
||||||
<img
|
<img
|
||||||
src="https://www.signwell.com/assets/vip-signatures/muhammad-ali-signature-3f9237f6fc48c3a04ba083117948e16ee7968aae521ae4ccebdfb8f22596ad22.svg"
|
src={`data:image/png;base64,${signature.initialsBlob}`}
|
||||||
className="h-[50px] object-contain"
|
className="h-[50px] object-contain"
|
||||||
alt="DS Signature"
|
alt="DS Signature"
|
||||||
/>
|
/>
|
||||||
|
|
@ -174,10 +183,6 @@ const SignatureManager: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-xl font-semibold text-gray-700 mb-2">No signatures yet</h3>
|
<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>
|
<p className="text-gray-500 mb-6">Create your first signature to get started.</p>
|
||||||
<button className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-semibold flex items-center gap-2 mx-auto transition-all duration-200">
|
|
||||||
<FiPlus className="w-5 h-5" />
|
|
||||||
ADD SIGNATURE
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue