From f2b17edb13aaf194cb9e49da8f663d2b28c8d6cb Mon Sep 17 00:00:00 2001 From: =bhagwanSingh <=bhagwan.r@hicglobalsolutions.com> Date: Fri, 10 Oct 2025 11:41:07 +0530 Subject: [PATCH] 10-10 --- src/components/client/SignDocument.tsx | 2 + src/components/client/TagsCon.tsx | 26 +- .../setting/Signature/AddSignatureModal.tsx | 126 +++--- src/components/signature/ClientSignCon.tsx | 362 ++++-------------- src/config/api.tsx | 16 +- src/config/axiosInstance.tsx | 11 +- 6 files changed, 190 insertions(+), 353 deletions(-) diff --git a/src/components/client/SignDocument.tsx b/src/components/client/SignDocument.tsx index 7c7707c..821aaf8 100644 --- a/src/components/client/SignDocument.tsx +++ b/src/components/client/SignDocument.tsx @@ -90,6 +90,7 @@ export enum SaveTypeEnum { DRAW = "DRAW", TYPE = "TEXT", UPLOAD = "IMAGE", + SELECT = "SELECT", } export interface SaveType { signatureId: string | null @@ -98,6 +99,7 @@ export interface SaveType { signature: string | null; initial: string | null; isDefaultAndClicked?: boolean; + font?: string; } interface TagsSubmitDataObj { tags: TagSubmitData[]; diff --git a/src/components/client/TagsCon.tsx b/src/components/client/TagsCon.tsx index 898ad82..70a3a55 100644 --- a/src/components/client/TagsCon.tsx +++ b/src/components/client/TagsCon.tsx @@ -629,8 +629,8 @@ const TagsCon: React.FC = ({ ) )) ? ( - ) : saved.saveType === "SELECT" ? ( - <>{saved.fullName} + ) : saved && saved.saveType !== null && saved.saveType === "SELECT" ? ( + <>{saved.signature} ) : ( = ({ ) )) ? - : - + : saved && saved.saveType !== null && saved.saveType === "SELECT" ? ( + <>{saved.initial} + ) : + () } } diff --git a/src/components/setting/Signature/AddSignatureModal.tsx b/src/components/setting/Signature/AddSignatureModal.tsx index 9b75e0d..948baf1 100644 --- a/src/components/setting/Signature/AddSignatureModal.tsx +++ b/src/components/setting/Signature/AddSignatureModal.tsx @@ -65,21 +65,29 @@ const AddSignatureModal: React.FC = ({ initials: string | null; }>({ fullSignature: null, initials: null }); - const signatureOptions = [ - { id: 1, name: 'print', initials: 'LA', style: 'print' }, - { id: 2, name: 'cursive', initials: 'LA', style: 'cursive' }, - { id: 3, name: 'script', initials: 'LA', style: 'script' }, - { id: 4, name: 'elegant', initials: 'LA', style: 'elegant' }, - { id: 5, name: 'modern', initials: 'LA', style: 'modern' }, - { id: 6, name: 'classic', initials: 'LA', style: 'classic' }, - ]; + // const signatureOptions = [ + // { id: 1, name: 'print', initials: 'LA', style: 'print' }, + // { id: 2, name: 'cursive', initials: 'LA', style: 'cursive' }, + // { id: 3, name: 'script', initials: 'LA', style: 'script' }, + // { id: 4, name: 'elegant', initials: 'LA', style: 'elegant' }, + // { id: 5, name: 'modern', initials: 'LA', style: 'modern' }, + // { id: 6, name: 'classic', initials: 'LA', style: 'classic' }, + // ]; const [checked, setChecked] = useState(false); const toggleCheckbox = () => setChecked(!checked); + + const fontsMap = [ + { style: "'Great Vibes', cursive", label: "Elegant Script", acronym: "f1" }, + { style: "'Pacifico', cursive", label: "Casual Handwritten", acronym: "f2" }, + { style: "'Dancing Script', cursive", label: "Smooth Flow", acronym: "f3" }, + { style: "'Playfair Display', serif", label: "Classic Serif", acronym: "f4" }, + ] + const [selectedSignature, setSelectedSignature] = useState( - signatureOptions.length > 0 ? { id: signatureOptions[0].id, style: signatureOptions[0].style } : { id: 0, style: "" } + fontsMap.length > 0 ? { id: fontsMap[0].acronym, style: fontsMap[0].style } : { id: "f1", style: "" } ); // Store the actual file @@ -216,9 +224,10 @@ const AddSignatureModal: React.FC = ({ // Base payload const payload = { signatureType: activeTab, - firstName: fullName.split(' ')[0] || user.firstName, - lastName: fullName.split(' ')[1] || user.lastName, - font: selectedSignature.style, + initials: activeTab === "SELECT" ? initials : "", + firstName: fullName.split(' ').length > 1 ? fullName.split(' ')[0] : "", + lastName: fullName.split(' ').length > 1 ? fullName.split(' ')[1] : fullName.split(' ')[0], + font: activeTab === "SELECT" ? selectedSignature.id : "", default: checked }; @@ -292,41 +301,68 @@ const AddSignatureModal: React.FC = ({ switch (activeTab) { case 'SELECT': return ( - <> - {/* Form Inputs - Fixed */} -
-

Confirm your name and choose signature style. *Are required fields.

-
-
- - setFullName(e.target.value)} - placeholder="Enter full name" - className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none" - /> -
-
- - setInitials(e.target.value)} - placeholder="Enter initials" - className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none" - /> -
-
+
+

+ Confirm your name and choose signature style. *Are required fields. +

+
+
+ + { + setFullName(e.target.value) + setInitials(e.target.value.trim().split(' ').length > 1 ? e.target.value.split(' ')[0][0] + "" + e.target.value.split(' ')[1][0] : e.target.value.split(' ')[0][0]) + }} + placeholder="Enter full name" + className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none" + /> +
+
+ + setInitials(e.target.value)} + placeholder="Enter initials" + className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none" + /> +
- + + {/* Signature Style Options */} +
+ {fontsMap.map((opt) => ( +
setSelectedSignature({ id: opt.acronym, style: opt.style })} + className={`cursor-pointer border border-slate-200 rounded-xl p-4 text-center bg-white transition + ${selectedSignature.id === opt.acronym + ? "ring-2 ring-[var(--mainPrimaryBtn)]" + : "hover:shadow-md"}`} + > +
+ {fullName || "Full Name"} +
+
+ {initials || "AB"} +
+

{opt.label}

+
+ ))} +
+
); case 'DRAW': diff --git a/src/components/signature/ClientSignCon.tsx b/src/components/signature/ClientSignCon.tsx index 79451a2..82f1743 100644 --- a/src/components/signature/ClientSignCon.tsx +++ b/src/components/signature/ClientSignCon.tsx @@ -75,10 +75,18 @@ interface UserData { } interface SelectStyle { - id: number, + id: number | string, style: string } +const fontsMap = [ + { style: "'Great Vibes', cursive", label: "Elegant Script", acronym: "f1" }, + { style: "'Pacifico', cursive", label: "Casual Handwritten", acronym: "f2" }, + { style: "'Dancing Script', cursive", label: "Smooth Flow", acronym: "f3" }, + { style: "'Playfair Display', serif", label: "Classic Serif", acronym: "f4" }, +] + + const ClientSignCon: React.FC = ({ recipient, setOpenSign, @@ -228,26 +236,9 @@ const ClientSignCon: React.FC = ({ const handleSubmit = async () => { setIsSubmitting(true); - // if (!signatures.fullSignature || !signatures.initials) { - // alert('Please provide both signature and initials'); - // setIsSubmitting(false); - // return; - // } if ((activeTab === 'DRAW' || activeTab === 'UPLOAD') && (!signatures.fullSignature || !signatures.initials)) { - // alert('Please provide both signature and initials'); - // toast.error('Please provide both signature and initials in draw and upload case', { - // position: "top-center", - // autoClose: 2000, - // hideProgressBar: false, - // closeOnClick: false, - // pauseOnHover: true, - // draggable: true, - // progress: undefined, - // theme: "light", - // transition: Bounce, - // }); setIsSubmitting(false); return; } @@ -257,12 +248,12 @@ const ClientSignCon: React.FC = ({ tagId: signTagId, // signatureId: signatureId, type: activeTab, - firstName: fullName.split(' ')[0] || user.firstName, - lastName: fullName.split(' ')[1] || user.lastName, - initials: "", + firstName: fullName.split(' ').length > 1 ? fullName.split(' ')[0] : "", + lastName: fullName.split(' ').length > 1 ? fullName.split(' ')[1] : fullName.split(' ')[0], + initials: initials, initialsBase64: signatures.initials, signatureBase64: signatures.fullSignature, - font: selectedSignature.style + font: activeTab === "SELECT" ? selectedSignature.id : "" }; if (activeTab !== 'SELECT') { @@ -270,48 +261,30 @@ const ClientSignCon: React.FC = ({ payload.initialsBase64 = signatures.initials; } - // if (isEditMode && editingSignature) { - // // Update existing signature - // const updatePayload = { - // ...payload, - // signatureId: editingSignature.id - // }; - // res = await axios.put(`${import.meta.env.VITE_BASE_URI}/api/v1/user/signatures`, updatePayload); - // console.log("handleUpdate", res); + let res = null + if (activeTab === 'SAVED') { + res = await axios.get(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures/${selectedSignature.id}`) + } else if (activeTab === 'SELECT') { - // toast.success("Signature Updated Successfully", { - // position: "top-center", - // autoClose: 500, - // hideProgressBar: false, - // closeOnClick: false, - // pauseOnHover: true, - // draggable: true, - // progress: undefined, - // theme: "light", - // transition: Bounce, - // }); - // } else { - // Create new signature - let res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures`, - payload, - { - headers: { - "ngrok-skip-browser-warning": "69420" - } - }); + payload.signatureBase64 = "" + payload.initialsBase64 = "" - // toast.success("Signature Created Successfully", { - // position: "top-center", - // autoClose: 500, - // hideProgressBar: false, - // closeOnClick: false, - // pauseOnHover: true, - // draggable: true, - // progress: undefined, - // theme: "light", - // transition: Bounce, - // }); - // } + res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures`, + payload, + { + headers: { + "ngrok-skip-browser-warning": "69420" + } + }); + } else { + res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures`, + payload, + { + headers: { + "ngrok-skip-browser-warning": "69420" + } + }); + } if (res?.data) { setSignatures({ @@ -322,231 +295,20 @@ const ClientSignCon: React.FC = ({ signatureId: res.data.id ?? null, saveType: res.data.signatureType ?? null, save: true, - signature: res.data.signatureBlob ?? null, - initial: res.data.initialsBlob ?? null, + signature: res.data.signatureType === "SELECT" ? payload.firstName : (res.data.signatureBlob ?? null), + initial: res.data.signatureType === "SELECT" ? payload.initials : (res.data.initialsBlob ?? null), + font: res.data.signatureType === "SELECT" ? selectedSignature.style : "" }); setOpenSign(false); } } catch (error) { console.error("Error submitting signature:", error); - // toast.error(isEditMode ? "Failed to update signature" : "Failed to create signature", { - // position: "top-center", - // autoClose: 2000, - // hideProgressBar: false, - // closeOnClick: false, - // pauseOnHover: true, - // draggable: true, - // progress: undefined, - // theme: "light", - // transition: Bounce, - // }); } finally { setIsSubmitting(false); } }; - // const renderContent = () => { - // switch (activeTab) { - // case 'SELECT': - // return ( - //
- //
- //

Choose Signature Style

- //

Select from pre-designed signature styles

- //
- - //
- //
- // {signatureOptions.map((option) => ( - //
- // setSelectedSignature({ id: option.id, style: option.style })} - // className="w-4 h-4 text-blue-600 focus:ring-blue-500" - // /> - //
- //
- //
Signed by:
- //
- // {fullName || option.name} - //
- //
- // dca3e646-62cd-4cc... - //
- //
- //
- //
DS
- //
- // {initials || option.initials} - //
- //
- //
- //
- // ))} - //
- //
- //
- // ); - - // case 'DRAW': - // return ( - // - // ); - - // case 'UPLOAD': - // return ( - //
- //
- //

Upload Signature

- //
- //
- //
- //
- // {/* Upload 1 */} - //
- // - // - // handleImageChange(e, setFile1, setPreview1, "fullSignature")} - // /> - //
- - // {/* Upload 2 */} - //
- // - // - // handleImageChange(e, setFile2, setPreview2, "initials")} - // /> - //
- //
- //
- //
- //
- // ); - // case 'SAVED': - // return ( - //
- //
- //

Saved Signature's

- // {/*

Select from pre-designed signature styles

*/} - //
- - //
- //
- // {preSaveSignatures.map((signature) => ( - //
- // {/* Signature Column */} - //
- //
- //
- // Signed by: - //
- - // {/* Signature Image or Fallback Text */} - //
- // {signature?.signatureBlob ? ( - // Signature - // ) : ( - //
No Signature
- // )} - //
- - // {/* Name */} - //
- // {signature?.signatureHash ?? ' '} - //
- //
- //
- - // {/* Initial Column */} - //
- //
- //
- // Initials - //
- - // {/* Initials Image */} - //
- // {signature?.initialsBlob ? ( - // Initials - // ) : ( - //
No Initials
- // )} - //
- - // {/* Optional initials hash or font */} - //
- // {signature?.initialsHash || " "} - //
- //
- //
- //
- // ))} - - //
- //
- //
- // ); - - // default: - // return null; - // } - // }; - - const renderSignatureText = (type, font, firstName, lastName, mode = 'name') => { if (type !== 'SELECT') return null; @@ -579,10 +341,12 @@ const ClientSignCon: React.FC = ({ case 'SELECT': return (
-

Confirm your name and choose signature style. *Are required fields.

+

+ Confirm your name and choose signature style. *Are required fields. +

-
-
+
+
-
+
setInitials(e.target.value)} + // onChange={(e) => setInitials(e.target.value)} placeholder="Enter initials" className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none" />
+ {/* Signature Style Options */} +
+ {fontsMap.map((opt) => ( +
setSelectedSignature({ id: opt.acronym, style: opt.style })} + className={`cursor-pointer border border-slate-200 rounded-xl p-4 text-center bg-white transition + ${selectedSignature.id === opt.acronym + ? "ring-2 ring-[var(--mainPrimaryBtn)]" + : "hover:shadow-md"}`} + > +
+ {fullName || "Full Name"} +
+
+ {initials || "AB"} +
+

{opt.label}

+
+ ))} +
); + case 'DRAW': return (
@@ -716,12 +508,12 @@ const ClientSignCon: React.FC = ({ {/* Horizontal Scrollable List */}
- {preSaveSignatures.map((signature) => ( + {preSaveSignatures.map((signature: Signature) => (
setSelectedSignature(signature?.id)} + onClick={() => setSelectedSignature({ id: Number(signature?.id), style: "" })} className={`cursor-pointer bg-white rounded-xl border p-4 w-full flex justify-between items-start transition-shadow duration-200 gap-3 - ${selectedSignature === signature?.id ? 'border-blue-500 shadow-lg' : 'border-gray-200'} + ${selectedSignature.id === Number(signature?.id) ? 'border-blue-500 shadow-lg' : 'border-gray-200'} `} style={{ minWidth: '220px' }} // each card width > diff --git a/src/config/api.tsx b/src/config/api.tsx index ef4c4b9..35b5564 100644 --- a/src/config/api.tsx +++ b/src/config/api.tsx @@ -49,12 +49,7 @@ api.interceptors.response.use( if (window.location.pathname === "/login" || window.location.pathname === "/register") { window.location.href = "/"; } - - if (typeof response.data === 'string' && response.data.toLowerCase().includes('')) { - // Likely a full HTML page, handle accordinglys - window.location.href = response.request.responseURL; - } - + if (response && (response.status === 301 || response.status === 302)) { const redirectUrl = response.headers["location"]; if (redirectUrl) { @@ -62,6 +57,13 @@ api.interceptors.response.use( } } + if (typeof response.data === 'string' && response.data.toLowerCase().includes('')) { + // Likely a full HTML page, handle accordinglys + if("responseURL" in response.request && response.request.responseURL !== null && response.request.responseURL !== "" && response.request.responseURL !== undefined) { + window.location.href = response.request.responseURL; + } + } + return response; }, async error => { @@ -81,7 +83,7 @@ api.interceptors.response.use( // Prevent multiple refresh attempts // if (error.response?.status === 401 || error.response?.status === 500) { - if (error.response?.status === 401 && !originalRequest._retry) { + if (error.response?.status === 401 && error.response?.status === 502 && !originalRequest._retry) { originalRequest._retry = true; try { if (!isRefreshing) { diff --git a/src/config/axiosInstance.tsx b/src/config/axiosInstance.tsx index 091f83e..afd724d 100644 --- a/src/config/axiosInstance.tsx +++ b/src/config/axiosInstance.tsx @@ -17,10 +17,6 @@ const axiosInstance: AxiosInstance = axios.create({ axiosInstance.interceptors.response.use( (response) => { - if (typeof response.data === 'string' && response.data.toLowerCase().includes('')) { - // Likely a full HTML page, handle accordingly - window.location.href = response.request.responseURL; - } if (response && (response.status === 301 || response.status === 302)) { const redirectUrl = response.headers["location"]; @@ -29,6 +25,13 @@ axiosInstance.interceptors.response.use( } } + if (typeof response.data === 'string' && response.data.toLowerCase().includes('')) { + // Likely a full HTML page, handle accordingly + if ("responseURL" in response.request && response.request.responseURL !== null && response.request.responseURL !== "" && response.request.responseURL !== undefined) { + window.location.href = response.request.responseURL; + } + } + // Otherwise just continue as normal return response; },