10-10
This commit is contained in:
parent
a7b7be491e
commit
f2b17edb13
|
|
@ -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[];
|
||||||
|
|
|
||||||
|
|
@ -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,8 +669,10 @@ 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></>
|
||||||
|
) :
|
||||||
|
(<img
|
||||||
style={{
|
style={{
|
||||||
width: `${item.dimensions.width}px`,
|
width: `${item.dimensions.width}px`,
|
||||||
height: `${item.dimensions.height}px`,
|
height: `${item.dimensions.height}px`,
|
||||||
|
|
@ -678,7 +680,7 @@ const TagsCon: React.FC<TagsConProps> = ({
|
||||||
className="w-[100%] h-full"
|
className="w-[100%] h-full"
|
||||||
// src={saved.initial as string}
|
// src={saved.initial as string}
|
||||||
src={`data:image/png;base64,${saved.initial}`}
|
src={`data:image/png;base64,${saved.initial}`}
|
||||||
/>
|
/>)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,12 +301,13 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
switch (activeTab) {
|
switch (activeTab) {
|
||||||
case 'SELECT':
|
case 'SELECT':
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{/* Form Inputs - Fixed */}
|
|
||||||
<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'>
|
||||||
<div className="grid grid-cols-2 gap-3">
|
Confirm your name and choose signature style. *Are required fields.
|
||||||
<div className='w-full'>
|
</h2>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-2 gap-3 mb-6">
|
||||||
|
<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>
|
||||||
|
|
@ -305,28 +315,54 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||||
<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='w-full'>
|
<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
|
||||||
|
disabled
|
||||||
type="text"
|
type="text"
|
||||||
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':
|
||||||
|
|
|
||||||
|
|
@ -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,
|
res = await axios.post(`${import.meta.env.VITE_BASE_URI}/api/v1/sign/${recipientId}/signatures`,
|
||||||
// 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,
|
payload,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"ngrok-skip-browser-warning": "69420"
|
"ngrok-skip-browser-warning": "69420"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
// 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,
|
}
|
||||||
// theme: "light",
|
|
||||||
// transition: Bounce,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
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
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,6 @@ api.interceptors.response.use(
|
||||||
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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue