This commit is contained in:
=bhagwanSingh 2025-10-10 11:41:07 +05:30
parent a7b7be491e
commit f2b17edb13
6 changed files with 190 additions and 353 deletions

View File

@ -90,6 +90,7 @@ export enum SaveTypeEnum {
DRAW = "DRAW", DRAW = "DRAW",
TYPE = "TEXT", TYPE = "TEXT",
UPLOAD = "IMAGE", UPLOAD = "IMAGE",
SELECT = "SELECT",
} }
export interface SaveType { export interface SaveType {
signatureId: string | null signatureId: string | null
@ -98,6 +99,7 @@ export interface SaveType {
signature: string | null; signature: string | null;
initial: string | null; initial: string | null;
isDefaultAndClicked?: boolean; isDefaultAndClicked?: boolean;
font?: string;
} }
interface TagsSubmitDataObj { interface TagsSubmitDataObj {
tags: TagSubmitData[]; tags: TagSubmitData[];

View File

@ -629,8 +629,8 @@ const TagsCon: React.FC<TagsConProps> = ({
) )
)) ? ( )) ? (
<FaSignature className="text-lg text-slate-600" /> <FaSignature className="text-lg text-slate-600" />
) : saved.saveType === "SELECT" ? ( ) : saved && saved.saveType !== null && saved.saveType === "SELECT" ? (
<>{saved.fullName}</> <><span style={{ fontFamily: saved?.font, fontSize: "18px" }}>{saved.signature}</span></>
) : ( ) : (
<img <img
style={{ style={{
@ -669,16 +669,18 @@ const TagsCon: React.FC<TagsConProps> = ({
) )
)) ? )) ?
<TbSignature className="text-lg text-slate-600" /> <TbSignature className="text-lg text-slate-600" />
: : saved && saved.saveType !== null && saved.saveType === "SELECT" ? (
<img <><span style={{ fontFamily: saved?.font }}>{saved.initial}</span></>
style={{ ) :
width: `${item.dimensions.width}px`, (<img
height: `${item.dimensions.height}px`, style={{
}} width: `${item.dimensions.width}px`,
className="w-[100%] h-full" height: `${item.dimensions.height}px`,
// src={saved.initial as string} }}
src={`data:image/png;base64,${saved.initial}`} className="w-[100%] h-full"
/> // src={saved.initial as string}
src={`data:image/png;base64,${saved.initial}`}
/>)
} }
</div> </div>
} }

View File

@ -65,21 +65,29 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
initials: string | null; initials: string | null;
}>({ fullSignature: null, initials: null }); }>({ fullSignature: null, initials: null });
const signatureOptions = [ // const signatureOptions = [
{ id: 1, name: 'print', initials: 'LA', style: 'print' }, // { id: 1, name: 'print', initials: 'LA', style: 'print' },
{ id: 2, name: 'cursive', initials: 'LA', style: 'cursive' }, // { id: 2, name: 'cursive', initials: 'LA', style: 'cursive' },
{ id: 3, name: 'script', initials: 'LA', style: 'script' }, // { id: 3, name: 'script', initials: 'LA', style: 'script' },
{ id: 4, name: 'elegant', initials: 'LA', style: 'elegant' }, // { id: 4, name: 'elegant', initials: 'LA', style: 'elegant' },
{ id: 5, name: 'modern', initials: 'LA', style: 'modern' }, // { id: 5, name: 'modern', initials: 'LA', style: 'modern' },
{ id: 6, name: 'classic', initials: 'LA', style: 'classic' }, // { id: 6, name: 'classic', initials: 'LA', style: 'classic' },
]; // ];
const [checked, setChecked] = useState(false); const [checked, setChecked] = useState(false);
const toggleCheckbox = () => setChecked(!checked); 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<SelectStyle>( const [selectedSignature, setSelectedSignature] = useState<SelectStyle>(
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 // Store the actual file
@ -216,9 +224,10 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
// Base payload // Base payload
const payload = { const payload = {
signatureType: activeTab, signatureType: activeTab,
firstName: fullName.split(' ')[0] || user.firstName, initials: activeTab === "SELECT" ? initials : "",
lastName: fullName.split(' ')[1] || user.lastName, firstName: fullName.split(' ').length > 1 ? fullName.split(' ')[0] : "",
font: selectedSignature.style, lastName: fullName.split(' ').length > 1 ? fullName.split(' ')[1] : fullName.split(' ')[0],
font: activeTab === "SELECT" ? selectedSignature.id : "",
default: checked default: checked
}; };
@ -292,41 +301,68 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
switch (activeTab) { switch (activeTab) {
case 'SELECT': case 'SELECT':
return ( return (
<> <div className="px-4 lg:px-6 py-4 flex-shrink-0">
{/* Form Inputs - Fixed */} <h2 className='mt-4 mb-5 text-sm'>
<div className="px-4 lg:px-6 py-4 flex-shrink-0"> Confirm your name and choose signature style. *Are required fields.
<h2 className='mt-4 mb-5 text-sm'>Confirm your name and choose signature style. *Are required fields.</h2> </h2>
<div className="grid grid-cols-2 gap-3">
<div className='w-full'>
<label className="block text-sm font-medium mb-2">
Full Name
<span className='text-red-600'> *</span>
</label>
<input
type="text"
value={fullName}
onChange={(e) => 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"
/>
</div>
<div className='w-full'>
<label className="block text-sm font-medium mb-2">
Initials
<span className='text-red-600'> *</span>
</label>
<input
type="text"
value={initials}
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"
/>
</div>
</div>
<div className="grid grid-cols-2 gap-3 mb-6">
<div>
<label className="block text-sm font-medium mb-2">
Full Name
<span className='text-red-600'> *</span>
</label>
<input
type="text"
value={fullName}
onChange={(e) => {
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"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Initials
<span className='text-red-600'> *</span>
</label>
<input
disabled
type="text"
value={initials}
// 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"
/>
</div>
</div> </div>
</>
{/* Signature Style Options */}
<div className="grid grid-cols-2 gap-4">
{fontsMap.map((opt) => (
<div
key={opt.acronym}
onClick={() => 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"}`}
>
<div style={{ fontFamily: opt.style, fontSize: "1.75rem" }}>
{fullName || "Full Name"}
</div>
<div
style={{ fontFamily: opt.style, fontSize: "1.25rem", opacity: 0.7 }}
>
{initials || "AB"}
</div>
<p className="text-xs mt-2 text-gray-500">{opt.label}</p>
</div>
))}
</div>
</div>
); );
case 'DRAW': case 'DRAW':

View File

@ -75,10 +75,18 @@ interface UserData {
} }
interface SelectStyle { interface SelectStyle {
id: number, id: number | string,
style: 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<ClientSignConProps> = ({ const ClientSignCon: React.FC<ClientSignConProps> = ({
recipient, recipient,
setOpenSign, setOpenSign,
@ -228,26 +236,9 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
const handleSubmit = async () => { const handleSubmit = async () => {
setIsSubmitting(true); setIsSubmitting(true);
// if (!signatures.fullSignature || !signatures.initials) {
// alert('Please provide both signature and initials');
// setIsSubmitting(false);
// return;
// }
if ((activeTab === 'DRAW' || activeTab === 'UPLOAD') && if ((activeTab === 'DRAW' || activeTab === 'UPLOAD') &&
(!signatures.fullSignature || !signatures.initials)) { (!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); setIsSubmitting(false);
return; return;
} }
@ -257,12 +248,12 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
tagId: signTagId, tagId: signTagId,
// signatureId: signatureId, // signatureId: signatureId,
type: activeTab, type: activeTab,
firstName: fullName.split(' ')[0] || user.firstName, firstName: fullName.split(' ').length > 1 ? fullName.split(' ')[0] : "",
lastName: fullName.split(' ')[1] || user.lastName, lastName: fullName.split(' ').length > 1 ? fullName.split(' ')[1] : fullName.split(' ')[0],
initials: "", initials: initials,
initialsBase64: signatures.initials, initialsBase64: signatures.initials,
signatureBase64: signatures.fullSignature, signatureBase64: signatures.fullSignature,
font: selectedSignature.style font: activeTab === "SELECT" ? selectedSignature.id : ""
}; };
if (activeTab !== 'SELECT') { if (activeTab !== 'SELECT') {
@ -270,48 +261,30 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
payload.initialsBase64 = signatures.initials; payload.initialsBase64 = signatures.initials;
} }
// if (isEditMode && editingSignature) { let res = null
// // Update existing signature if (activeTab === 'SAVED') {
// const updatePayload = { res = await axios.get(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures/${selectedSignature.id}`)
// ...payload, } else if (activeTab === 'SELECT') {
// signatureId: editingSignature.id
// };
// res = await axios.put(`${import.meta.env.VITE_BASE_URI}/api/v1/user/signatures`, updatePayload);
// console.log("handleUpdate", res);
// toast.success("Signature Updated Successfully", { payload.signatureBase64 = ""
// position: "top-center", payload.initialsBase64 = ""
// 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"
}
});
// toast.success("Signature Created Successfully", { res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures`,
// position: "top-center", payload,
// autoClose: 500, {
// hideProgressBar: false, headers: {
// closeOnClick: false, "ngrok-skip-browser-warning": "69420"
// pauseOnHover: true, }
// draggable: true, });
// progress: undefined, } else {
// theme: "light", res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures`,
// transition: Bounce, payload,
// }); {
// } headers: {
"ngrok-skip-browser-warning": "69420"
}
});
}
if (res?.data) { if (res?.data) {
setSignatures({ setSignatures({
@ -322,231 +295,20 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
signatureId: res.data.id ?? null, signatureId: res.data.id ?? null,
saveType: res.data.signatureType ?? null, saveType: res.data.signatureType ?? null,
save: true, save: true,
signature: res.data.signatureBlob ?? null, signature: res.data.signatureType === "SELECT" ? payload.firstName : (res.data.signatureBlob ?? null),
initial: res.data.initialsBlob ?? null, initial: res.data.signatureType === "SELECT" ? payload.initials : (res.data.initialsBlob ?? null),
font: res.data.signatureType === "SELECT" ? selectedSignature.style : ""
}); });
setOpenSign(false); setOpenSign(false);
} }
} catch (error) { } catch (error) {
console.error("Error submitting signature:", 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 { } finally {
setIsSubmitting(false); setIsSubmitting(false);
} }
}; };
// const renderContent = () => {
// switch (activeTab) {
// case 'SELECT':
// return (
// <div className="h-full flex flex-col ">
// <div className="mb-6">
// <h2 className="text-xl font-semibold text-gray-900 mb-2">Choose Signature Style</h2>
// <p className="text-sm text-gray-600">Select from pre-designed signature styles</p>
// </div>
// <div className="flex-1 overflow-y-auto">
// <div className="space-y-4">
// {signatureOptions.map((option) => (
// <div key={option.id} className="flex items-center space-x-4 px-2 py-1 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors">
// <input
// type="radio"
// id={`signature-${option.id}`}
// name="signature"
// checked={selectedSignature.id === option.id}
// onChange={() => setSelectedSignature({ id: option.id, style: option.style })}
// className="w-4 h-4 text-blue-600 focus:ring-blue-500"
// />
// <div className="flex-1 grid grid-cols-2 gap-2">
// <div className=" border-gray-300 rounded-lg px-2 py-1 bg-white ">
// <div className="text-xs text-gray-500 mb-2">Signed by:</div>
// <div className={`text-lg ${option.style === 'cursive' ? 'font-serif italic' :
// option.style === 'script' ? 'font-mono' :
// option.style === 'elegant' ? 'font-serif' :
// option.style === 'modern' ? 'font-sans tracking-wide' :
// 'font-sans'
// }`}>
// {fullName || option.name}
// </div>
// <div className="text-xs text-gray-400 mt-2">
// dca3e646-62cd-4cc...
// </div>
// </div>
// <div className=" rounded-lg px-2 py-2 bg-white ">
// <div className="text-xs text-gray-500 mb-2">DS</div>
// <div className={`text-2xl ${option.style === 'cursive' ? 'font-serif italic' :
// option.style === 'script' ? 'font-mono' :
// option.style === 'elegant' ? 'font-serif' :
// option.style === 'modern' ? 'font-sans tracking-wide' :
// 'font-sans'
// }`}>
// {initials || option.initials}
// </div>
// </div>
// </div>
// </div>
// ))}
// </div>
// </div>
// </div>
// );
// case 'DRAW':
// return (
// <DrawSignatureCanvas
// onSignatureChange={handleSignatureChange}
// // initialSignatures={isEditMode ? signatures : undefined}
// />
// );
// case 'UPLOAD':
// return (
// <div className="h-full flex flex-col">
// <div className="mb-6">
// <h2 className="text-xl font-semibold text-gray-900 mb-2">Upload Signature</h2>
// </div>
// <div className="flex-1 overflow-y-auto">
// <div>
// <div className="grid grid-cols-12 gap-6">
// {/* Upload 1 */}
// <div className="col-span-8">
// <label className="block text-sm font-medium text-gray-700 mb-2">Full Signature</label>
// <label htmlFor="upload1" className=" border-2 border-dashed border-gray-300 rounded-lg h-62 flex items-center justify-center bg-gray-50 hover:bg-gray-100 cursor-pointer transition-colors">
// {preview1 ? (
// <img src={preview1} alt="Signature Preview" className="max-h-44 object-contain" />
// ) : (
// <div className="text-center">
// <MdCloudUpload className="mx-auto h-12 w-12 text-gray-400 mb-3" />
// <p className="text-sm text-gray-500 mb-1">Click to upload or drag and drop</p>
// <p className="text-xs text-gray-400">PNG, JPG, GIF up to 10MB</p>
// </div>
// )}
// </label>
// <input
// id="upload1"
// type="file"
// accept="image/*"
// className="hidden"
// onChange={(e) => handleImageChange(e, setFile1, setPreview1, "fullSignature")}
// />
// </div>
// {/* Upload 2 */}
// <div className="col-span-4">
// <label className="block text-sm font-medium text-gray-700 mb-2">Initials</label>
// <label htmlFor="upload2" className=" border-2 border-dashed border-gray-300 rounded-lg h-62 flex items-center justify-center bg-gray-50 hover:bg-gray-100 cursor-pointer transition-colors">
// {preview2 ? (
// <img src={preview2} alt="Initials Preview" className="max-h-44 object-contain" />
// ) : (
// <div className="text-center">
// <MdCloudUpload className="mx-auto h-8 w-8 text-gray-400 mb-2" />
// <p className="text-xs text-gray-500">Upload initials</p>
// </div>
// )}
// </label>
// <input
// id="upload2"
// type="file"
// accept="image/*"
// className="hidden"
// onChange={(e) => handleImageChange(e, setFile2, setPreview2, "initials")}
// />
// </div>
// </div>
// </div>
// </div>
// </div>
// );
// case 'SAVED':
// return (
// <div className="h-full flex flex-col ">
// <div className="mb-6">
// <h2 className="text-xl font-semibold text-gray-900 mb-2">Saved Signature's</h2>
// {/* <p className="text-sm text-gray-600">Select from pre-designed signature styles</p> */}
// </div>
// <div className="flex-1 overflow-y-auto">
// <div className="space-y-4">
// {preSaveSignatures.map((signature) => (
// <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">
// <div className="text-sm text-gray-600 font-medium mb-1">
// Signed by:
// </div>
// {/* Signature Image or Fallback Text */}
// <div className="bg-white rounded-lg p-1 flex items-center justify-center">
// {signature?.signatureBlob ? (
// <img
// src={`data:${signature?.signatureMimeType || "image/png"};base64,${signature?.signatureBlob}`}
// className="h-[50px] w-[250px] object-contain"
// alt="Signature"
// />
// ) : (
// <div className="text-gray-400 italic text-sm">No Signature</div>
// )}
// </div>
// {/* Name */}
// <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">
// <div className="text-sm text-gray-600 font-medium mb-1">
// Initials
// </div>
// {/* Initials Image */}
// <div className="bg-white rounded-lg p-1 flex items-center justify-center">
// {signature?.initialsBlob ? (
// <img
// src={`data:image/png;base64,${signature?.initialsBlob}`}
// className="h-[50px] object-contain"
// alt="Initials"
// />
// ) : (
// <div className="text-gray-400 italic text-sm">No Initials</div>
// )}
// </div>
// {/* Optional initials hash or font */}
// <div className="text-xs text-gray-500 truncate">
// {signature?.initialsHash || " "}
// </div>
// </div>
// </div>
// </div>
// ))}
// </div>
// </div>
// </div>
// );
// default:
// return null;
// }
// };
const renderSignatureText = (type, font, firstName, lastName, mode = 'name') => { const renderSignatureText = (type, font, firstName, lastName, mode = 'name') => {
if (type !== 'SELECT') return null; if (type !== 'SELECT') return null;
@ -579,10 +341,12 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
case 'SELECT': case 'SELECT':
return ( return (
<div className="px-4 lg:px-6 py-4 flex-shrink-0"> <div className="px-4 lg:px-6 py-4 flex-shrink-0">
<h2 className='mt-4 mb-5 text-sm'>Confirm your name and choose signature style. *Are required fields.</h2> <h2 className='mt-4 mb-5 text-sm'>
Confirm your name and choose signature style. *Are required fields.
</h2>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3 mb-6">
<div className=''> <div>
<label className="block text-sm font-medium mb-2"> <label className="block text-sm font-medium mb-2">
Full Name Full Name
<span className='text-red-600'> *</span> <span className='text-red-600'> *</span>
@ -590,29 +354,57 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
<input <input
type="text" type="text"
value={fullName} value={fullName}
onChange={(e) => setFullName(e.target.value)} onChange={(e) => {
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" placeholder="Enter full name"
className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none" className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none"
/> />
</div> </div>
<div className=''> <div>
<label className="block text-sm font-medium mb-2"> <label className="block text-sm font-medium mb-2">
Initials Initials
<span className='text-red-600'> *</span> <span className='text-red-600'> *</span>
</label> </label>
<input <input
type="text" type="text"
disabled
value={initials} value={initials}
onChange={(e) => setInitials(e.target.value)} // onChange={(e) => setInitials(e.target.value)}
placeholder="Enter initials" placeholder="Enter initials"
className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none" className="w-full px-3 py-2 text-sm border border-gray-200 rounded-md outline-none"
/> />
</div> </div>
</div> </div>
{/* Signature Style Options */}
<div className="grid grid-cols-2 gap-4">
{fontsMap.map((opt) => (
<div
key={opt.acronym}
onClick={() => 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"}`}
>
<div style={{ fontFamily: opt.style, fontSize: "1.75rem" }}>
{fullName || "Full Name"}
</div>
<div
style={{ fontFamily: opt.style, fontSize: "1.25rem", opacity: 0.7 }}
>
{initials || "AB"}
</div>
<p className="text-xs mt-2 text-gray-500">{opt.label}</p>
</div>
))}
</div>
</div> </div>
); );
case 'DRAW': case 'DRAW':
return ( return (
<div className="h-full"> <div className="h-full">
@ -716,12 +508,12 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
{/* Horizontal Scrollable List */} {/* Horizontal Scrollable List */}
<div className="flex-1 overflow-x-auto px-2 sm:px-6"> <div className="flex-1 overflow-x-auto px-2 sm:px-6">
<div className="flex flex-col space-x-4 max-h-[40vh] gap-2"> <div className="flex flex-col space-x-4 max-h-[40vh] gap-2">
{preSaveSignatures.map((signature) => ( {preSaveSignatures.map((signature: Signature) => (
<div <div
key={signature?.id} key={signature?.id}
onClick={() => 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 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 style={{ minWidth: '220px' }} // each card width
> >

View File

@ -49,12 +49,7 @@ api.interceptors.response.use(
if (window.location.pathname === "/login" || window.location.pathname === "/register") { if (window.location.pathname === "/login" || window.location.pathname === "/register") {
window.location.href = "/"; window.location.href = "/";
} }
if (typeof response.data === 'string' && response.data.toLowerCase().includes('<!doctype html>')) {
// Likely a full HTML page, handle accordinglys
window.location.href = response.request.responseURL;
}
if (response && (response.status === 301 || response.status === 302)) { if (response && (response.status === 301 || response.status === 302)) {
const redirectUrl = response.headers["location"]; const redirectUrl = response.headers["location"];
if (redirectUrl) { if (redirectUrl) {
@ -62,6 +57,13 @@ api.interceptors.response.use(
} }
} }
if (typeof response.data === 'string' && response.data.toLowerCase().includes('<!doctype html>')) {
// 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; return response;
}, },
async error => { async error => {
@ -81,7 +83,7 @@ api.interceptors.response.use(
// Prevent multiple refresh attempts // Prevent multiple refresh attempts
// if (error.response?.status === 401 || error.response?.status === 500) { // 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; originalRequest._retry = true;
try { try {
if (!isRefreshing) { if (!isRefreshing) {

View File

@ -17,10 +17,6 @@ const axiosInstance: AxiosInstance = axios.create({
axiosInstance.interceptors.response.use( axiosInstance.interceptors.response.use(
(response) => { (response) => {
if (typeof response.data === 'string' && response.data.toLowerCase().includes('<!doctype html>')) {
// Likely a full HTML page, handle accordingly
window.location.href = response.request.responseURL;
}
if (response && (response.status === 301 || response.status === 302)) { if (response && (response.status === 301 || response.status === 302)) {
const redirectUrl = response.headers["location"]; const redirectUrl = response.headers["location"];
@ -29,6 +25,13 @@ axiosInstance.interceptors.response.use(
} }
} }
if (typeof response.data === 'string' && response.data.toLowerCase().includes('<!doctype html>')) {
// 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 // Otherwise just continue as normal
return response; return response;
}, },