From faa4839fef72670f9685dbbde9516868a5ba7172 Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Thu, 3 Jul 2025 11:33:55 +0530 Subject: [PATCH] DrawSignature --- .../setting/Signature/AddSignatureModal.tsx | 157 ++++++++--------- .../setting/Signature/DrawSignatureCanvas.tsx | 158 ++++++++++++++++++ .../setting/Signature/Signature.tsx | 73 ++++---- 3 files changed, 278 insertions(+), 110 deletions(-) create mode 100644 src/components/setting/Signature/DrawSignatureCanvas.tsx diff --git a/src/components/setting/Signature/AddSignatureModal.tsx b/src/components/setting/Signature/AddSignatureModal.tsx index a6ef255..7612baf 100644 --- a/src/components/setting/Signature/AddSignatureModal.tsx +++ b/src/components/setting/Signature/AddSignatureModal.tsx @@ -1,26 +1,27 @@ import React, { useEffect, useState } from 'react'; // import { X, Upload, Edit3, Image, Cloud, HardDrive, Droplets } from 'lucide-react'; 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 DrawSignatureCanvas from './DrawSignatureCanvas'; interface AddSignatureModalProps { setShowAddSignature?: (value: boolean) => void; } interface Account { - id: number; - isDefault: boolean; - name: string; + id: number; + isDefault: boolean; + name: string; } interface UserData { - id: string; - firstName: string; - lastName: string; - email: string; - language: string; - account: Account; + id: string; + firstName: string; + lastName: string; + email: string; + language: string; + account: Account; } const AddSignatureModal: React.FC = ({ setShowAddSignature }) => { @@ -28,6 +29,17 @@ const AddSignatureModal: React.FC = ({ setShowAddSignatu const [fullName, setFullName] = 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 const signatureOptions = [ { id: 1, name: 'print', initials: 'LA', style: 'print' }, @@ -39,6 +51,8 @@ const AddSignatureModal: React.FC = ({ setShowAddSignatu ]; const [selectedSignature, setSelectedSignature] = useState(1); + console.log(selectedSignature); + // Store the actual file const [file1, setFile1] = useState(null); @@ -56,11 +70,11 @@ const AddSignatureModal: React.FC = ({ setShowAddSignatu email: "", language: "", account: { - id: 0, - isDefault: false, - name: "", + id: 0, + isDefault: false, + name: "", }, - }); + }); // Navigation items const navigationItems = [ @@ -90,6 +104,38 @@ const AddSignatureModal: React.FC = ({ 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 = () => { switch (activeTab) { @@ -149,51 +195,7 @@ const AddSignatureModal: React.FC = ({ setShowAddSignatu case 'draw': return ( -
-
-

Draw Signature

-

Create your signature by drawing directly on the canvas

-
- -
-
- {/* Draw area 1 */} -
- -
-
- {/* */} -

Click and drag to draw your signature

-

Use mouse or touch to create your signature

-
-
-
- {/* Draw area 2 */} -
- -
-
- {/* */} -

Draw initials

-
-
-
-
- -
- - - -
-
-
+ ); case 'upload': @@ -261,19 +263,22 @@ const AddSignatureModal: React.FC = ({ setShowAddSignatu }; const getUserDetails = async () => { - try { - let res = await api.get(`/api/user/details`) - console.log("getuser", res) - setUser(res?.data) - } catch (error) { - console.error("Error fetching user details:", error); + try { + let res = await api.get(`/api/user/details`) + console.log("getuser", res) + let currUser = res?.data + setUser(currUser) + setFullName(currUser.firstName + " " + currUser.lastName) + setInitials(currUser.firstName.slice(0, 1) + currUser.lastName.slice(0, 1)) + } catch (error) { + console.error("Error fetching user details:", error); + } } - } - useEffect(() => { - getUserDetails() - }, []) - + useEffect(() => { + getUserDetails() + }, []) + return (
@@ -352,11 +357,11 @@ const AddSignatureModal: React.FC = ({ setShowAddSignatu {/* Content */}
+ onClick={() => setShowAddSignature?.(false)} + className="absolute top-2 right-3 p-2 hover:bg-gray-100 rounded-full transition-colors z-20" + > + + {renderContent()}
@@ -368,7 +373,7 @@ const AddSignatureModal: React.FC = ({ setShowAddSignatu > CANCEL -
diff --git a/src/components/setting/Signature/DrawSignatureCanvas.tsx b/src/components/setting/Signature/DrawSignatureCanvas.tsx new file mode 100644 index 0000000..1ba50d5 --- /dev/null +++ b/src/components/setting/Signature/DrawSignatureCanvas.tsx @@ -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 = ({ onSignatureChange }) => { + const canvasRef1 = useRef(null); + const canvasRef2 = useRef(null); + const [isDrawing, setIsDrawing] = useState(false); + const [paths1, setPaths1] = useState>>([]); + const [paths2, setPaths2] = useState>>([]); + const [currentPath, setCurrentPath] = useState>([]); + const [activeCanvas, setActiveCanvas] = useState<'full' | 'initials' | null>(null); + + const handleMouseDown = (e: React.MouseEvent) => { + 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) => { + 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 ( +
+
+

Draw Signature

+

Create your signature by drawing directly on the canvas

+
+ +
+
+ {/* Full Signature Canvas */} +
+ +
+ +
+
+ + {/* Initials Canvas */} +
+ +
+ +
+
+
+ + {/* Controls */} +
+ +
+
+
+ ); +}; + +export default DrawSignatureCanvas; diff --git a/src/components/setting/Signature/Signature.tsx b/src/components/setting/Signature/Signature.tsx index 2d3aafe..a175ff6 100644 --- a/src/components/setting/Signature/Signature.tsx +++ b/src/components/setting/Signature/Signature.tsx @@ -1,38 +1,32 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { FiEdit3, FiTrash2, FiPlus, FiMoreVertical } from 'react-icons/fi'; import AddSignatureModal from './AddSignatureModal'; +import api from '../../../config/api'; interface Signature { id: string; - signature: string; - initial: string; - createdAt: 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 [signatures, setSignatures] = useState([ - { - id: '1', - signature: 'https://www.signwell.com/assets/vip-signatures/muhammad-ali-signature-3f9237f6fc48c3a04ba083117948e16ee7968aae521ae4ccebdfb8f22596ad22.svg', - 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 [signatures, setSignatures] = useState([]); const [activeDropdown, setActiveDropdown] = useState(null); - const [showAddSignature , setShowAddSignature] = useState(false) + const [showAddSignature, setShowAddSignature] = useState(false) const handleEdit = (id: string) => { console.log('Edit signature:', id); @@ -48,6 +42,21 @@ const SignatureManager: React.FC = () => { 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 (
@@ -57,7 +66,7 @@ const SignatureManager: React.FC = () => {

Signatures

Add or update your name and signature styles.

- @@ -95,7 +104,7 @@ const SignatureManager: React.FC = () => { {/* Signature Image */}
Signature @@ -103,7 +112,7 @@ const SignatureManager: React.FC = () => { {/* Signature ID */}
- {signature.createdAt} + {signature.signatureHash}
@@ -120,7 +129,7 @@ const SignatureManager: React.FC = () => { {/* Signature Image */}
DS Signature @@ -174,10 +183,6 @@ const SignatureManager: React.FC = () => {

No signatures yet

Create your first signature to get started.

-
)} @@ -191,7 +196,7 @@ const SignatureManager: React.FC = () => { )} {showAddSignature && ( - + )} );