Redirect Solved 09-10

This commit is contained in:
=bhagwanSingh 2025-10-09 16:30:58 +05:30
parent b3beb64265
commit a7b7be491e
4 changed files with 88 additions and 69 deletions

View File

@ -488,7 +488,7 @@ const ProcessStepOne = () => {
transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES &&
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className=" text-lg font-medium mb-4 pt-6 text-[var(--processStepOneTextHead)]">Signers</h2> <h2 className=" text-lg font-medium mb-4 pt-6 text-[var(--processStepOneTextHead)]">Signers</h2>
<div className="flex items-center mr-3"> {/* <div className="flex items-center mr-3">
<input <input
checked={signType === SignTypeEnum.selfSign} checked={signType === SignTypeEnum.selfSign}
onChange={(e) => handleSelfSignCb(e)} onChange={(e) => handleSelfSignCb(e)}
@ -496,7 +496,7 @@ const ProcessStepOne = () => {
/> />
<label htmlFor="default-checkbox" className="ms-2 text-sm flex gap-1 text-slate-600"> <label htmlFor="default-checkbox" className="ms-2 text-sm flex gap-1 text-slate-600">
I AM THE ONLY SIGNER</label> I AM THE ONLY SIGNER</label>
</div> </div> */}
</div> </div>
} }

View File

@ -164,18 +164,21 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
if (res.data.length) { if (res.data.length) {
const defaultVal = res.data.filter((obj, indx) => "default" in obj && obj.default); const defaultVal = res.data.filter((obj, indx) => "default" in obj && obj.default);
const { id, initialsBlob, signatureBlob } = defaultVal[0]; if (defaultVal.length > 0) {
const { id, initialsBlob, signatureBlob } = defaultVal[0];
if (initialsBlob && signatureBlob) { if (initialsBlob && signatureBlob) {
setSaved({ setSaved({
signatureId: id, signatureId: id,
saveType: SaveTypeEnum.DRAW, saveType: SaveTypeEnum.DRAW,
save: true, save: true,
signature: signatureBlob, signature: signatureBlob,
initial: initialsBlob, initial: initialsBlob,
isDefaultAndClicked: true isDefaultAndClicked: true
}); });
}
} }
} }
setPreSaveSignatures(preSavedSignatures) setPreSaveSignatures(preSavedSignatures)
} }
@ -705,28 +708,31 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
return ( return (
<div className="h-full flex flex-col"> <div className="h-full flex flex-col">
{/* Header */} {/* Header */}
<div className="mb-6 px-4 sm:px-6"> <div className="my-4 px-4 sm:px-6">
<h2 className="text-2xl font-semibold text-gray-900 mb-2">Saved Signatures</h2> <h2 className="text-2xl font-semibold text-gray-900 mb-1">Saved Signatures</h2>
<p className="text-sm text-gray-600">Select from your pre-saved signatures</p> <p className="text-sm text-gray-600">Select from your pre-saved signatures</p>
</div> </div>
{/* Signatures List */} {/* Horizontal Scrollable List */}
<div className="flex-1 overflow-y-auto px-2 sm:px-6"> <div className="flex-1 overflow-x-auto px-2 sm:px-6">
<div className="space-y-4"> <div className="flex flex-col space-x-4 max-h-[40vh] gap-2">
{preSaveSignatures.map((signature) => ( {preSaveSignatures.map((signature) => (
<div <div
key={signature?.id} key={signature?.id}
className="flex flex-col md:flex-row md:space-x-4 bg-white rounded-xl border border-gray-200 p-4 hover:shadow-lg transition-shadow duration-200" onClick={() => setSelectedSignature(signature?.id)}
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'}
`}
style={{ minWidth: '220px' }} // each card width
> >
{/* Full Signature */} {/* Signature */}
<div className="flex-1 flex flex-col space-y-2 border-l-4 border-blue-500 rounded-l-xl pl-4 md:pl-6 py-2"> <div className="w-[60%] flex flex-col">
<span className="text-sm font-medium text-gray-600">Signed by:</span> <span className="text-sm font-medium text-gray-600 mb-1">Signed by:</span>
<div className="w-full bg-gray-50 rounded-lg p-2 flex items-center justify-center min-h-[60px]">
<div className="bg-gray-50 rounded-lg p-2 flex items-center justify-center min-h-[50px]">
{signature?.signatureType !== 'SELECT' && signature?.signatureBlob ? ( {signature?.signatureType !== 'SELECT' && signature?.signatureBlob ? (
<img <img
src={`data:${signature?.signatureMimeType};base64,${signature?.signatureBlob}`} src={`data:${signature?.signatureMimeType};base64,${signature?.signatureBlob}`}
className="max-h-[60px] w-full object-contain" className="w-full h-12 object-contain"
alt={`${signature?.firstName ?? ''} ${signature?.lastName ?? ''} signature`} alt={`${signature?.firstName ?? ''} ${signature?.lastName ?? ''} signature`}
/> />
) : ( ) : (
@ -739,19 +745,17 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
) )
)} )}
</div> </div>
{/* <span className="text-xs text-gray-500 truncate mt-1 text-center w-full">{signature?.signatureHash ?? ' '}</span> */}
<span className="text-xs text-gray-500 truncate">{signature?.signatureHash ?? ' '}</span>
</div> </div>
{/* Initials */} {/* Initials */}
<div className="flex-1 flex flex-col space-y-2 border-l-4 border-green-500 rounded-l-xl pl-4 md:pl-6 py-2 mt-4 md:mt-0"> <div className="w-[40%] flex flex-col">
<span className="text-sm font-medium text-gray-600">Initials</span> <span className="text-sm font-medium text-gray-600 mb-1">Initials</span>
<div className="bg-gray-50 rounded-lg p-1 flex items-center justify-center min-h-[40px]">
<div className="bg-gray-50 rounded-lg p-2 flex items-center justify-center min-h-[50px]">
{signature?.signatureType !== 'SELECT' && signature?.initialsBlob ? ( {signature?.signatureType !== 'SELECT' && signature?.initialsBlob ? (
<img <img
src={`data:${signature?.initialsMimeType};base64,${signature?.initialsBlob}`} src={`data:${signature?.initialsMimeType};base64,${signature?.initialsBlob}`}
className="max-h-[60px] w-full object-contain" className="w-full h-10 object-contain"
alt={`${signature?.firstName ?? ''} ${signature?.lastName ?? ''} initials`} alt={`${signature?.firstName ?? ''} ${signature?.lastName ?? ''} initials`}
/> />
) : ( ) : (
@ -764,8 +768,7 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
) )
)} )}
</div> </div>
{/* <span className="text-xs text-gray-500 truncate mt-1 text-center w-full">{signature?.initialsHash ?? ' '}</span> */}
<span className="text-xs text-gray-500 truncate">{signature?.initialsHash ?? ' '}</span>
</div> </div>
</div> </div>
))} ))}
@ -775,6 +778,7 @@ const ClientSignCon: React.FC<ClientSignConProps> = ({
); );
default: default:
return null; return null;
} }

View File

@ -3,7 +3,7 @@ import axios from "axios";
const api = axios.create({ const api = axios.create({
baseURL: import.meta.env.VITE_BASE_URI, baseURL: import.meta.env.VITE_BASE_URI,
maxRedirects: 5, maxRedirects: 10,
withCredentials: true, withCredentials: true,
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -49,6 +49,19 @@ 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)) {
const redirectUrl = response.headers["location"];
if (redirectUrl) {
window.location.href = redirectUrl;
}
}
return response; return response;
}, },
async error => { async error => {
@ -58,12 +71,13 @@ api.interceptors.response.use(
// const res = error.response; // const res = error.response;
// 🔹 Handle 301/302 manually // 🔹 Handle 301/302 manually
// if (res && (res.status === 301 || res.status === 302)) {
// const redirectUrl = res.headers["location"]; if (error && (error.status === 301 || error.status === 302)) {
// if (redirectUrl) { const redirectUrl = error.headers["location"];
// window.location.href = redirectUrl; if (redirectUrl) {
// } window.location.href = redirectUrl;
// } }
}
// 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) {

View File

@ -2,45 +2,46 @@
import axios, { AxiosInstance } from "axios"; import axios, { AxiosInstance } from "axios";
const defaultHeaders = { const defaultHeaders = {
"Content-Type": "application/json", "Content-Type": "application/json",
"ngrok-skip-browser-warning": "69420", "ngrok-skip-browser-warning": "69420",
}; };
const axiosInstance: AxiosInstance = axios.create({ const axiosInstance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_BASE_URI, baseURL: import.meta.env.VITE_BASE_URI,
withCredentials: true, withCredentials: true,
headers: defaultHeaders, headers: defaultHeaders,
validateStatus: (status) => status >= 200 && status < 400, validateStatus: (status) => status >= 200 && status < 400,
}); });
axiosInstance.interceptors.response.use( axiosInstance.interceptors.response.use(
(response) => { (response) => {
// ✅ Handle backend "soft redirects"
if (response?.data?.redirect) {
const redirectUrl = response.data.redirect;
// Use location.replace to avoid back button returning to invalid page if (typeof response.data === 'string' && response.data.toLowerCase().includes('<!doctype html>')) {
window.location.replace(redirectUrl); // Likely a full HTML page, handle accordingly
// OR window.location.href = redirectUrl; if you want history entry window.location.href = response.request.responseURL;
}
// Optionally return a rejected promise to stop normal handling if (response && (response.status === 301 || response.status === 302)) {
return Promise.reject({ redirected: true }); const redirectUrl = response.headers["location"];
if (redirectUrl) {
window.location.href = redirectUrl;
}
}
// Otherwise just continue as normal
return response;
},
(error) => {
// Optionally handle backend 302 or 3xx here (if returned as error)
if (error.response?.status === 302 && error.response?.headers?.location) {
window.location.replace(error.response.headers.location);
return Promise.reject({ redirected: true });
}
// Pass through all other errors
return Promise.reject(error);
} }
// Otherwise just continue as normal
return response;
},
(error) => {
// Optionally handle backend 302 or 3xx here (if returned as error)
if (error.response?.status === 302 && error.response?.headers?.location) {
window.location.replace(error.response.headers.location);
return Promise.reject({ redirected: true });
}
// Pass through all other errors
return Promise.reject(error);
}
); );
export default axiosInstance; export default axiosInstance;