Merge branch

This commit is contained in:
=bhagwanSingh 2025-09-01 15:52:17 +05:30
commit cdbada638b
6 changed files with 523 additions and 508 deletions

View File

@ -1,5 +1,5 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import "../styles/style.css"; // import "../styles/style.css";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useLocation } from "react-router-dom";
import LoginForm from "./LoginForm"; import LoginForm from "./LoginForm";
import RegisterForm from "./RegisterForm"; import RegisterForm from "./RegisterForm";
@ -37,7 +37,7 @@ function UserAuthUI() {
return ( return (
<div className="max-h-screen bg-white flex"> <div className="max-h-screen bg-white flex">
{/* Left Side - Branding */} {/* Left Side - Branding */}
<div className="hidden lg:flex lg:w-1/2 bg-[var(--primary)] text-white p-12"> <div className="hidden lg:flex lg:w-1/2 bg-[var(--primary)] text-white p-12 lg:h-[100vh]">
<div className="flex flex-col items-center justify-center text-center w-full h-full gap-6"> <div className="flex flex-col items-center justify-center text-center w-full h-full gap-6">
{/* Logos */} {/* Logos */}
<div className="flex flex-col items-center gap-2 space-y-3"> <div className="flex flex-col items-center gap-2 space-y-3">

View File

@ -267,7 +267,7 @@ const ProcessStepOne = () => {
} }
} else { } else {
if(!accountId || !transactionId) return; if (!accountId || !transactionId) return;
dispatch(addRecipientAsync({ recipientsData: recipientsDataTemp, accountId, transactionId })); dispatch(addRecipientAsync({ recipientsData: recipientsDataTemp, accountId, transactionId }));
} }
dispatch(showLoader("Processing Message...")); dispatch(showLoader("Processing Message..."));
@ -345,49 +345,59 @@ const ProcessStepOne = () => {
<div className={`relative w-full h-screen bg-[var(--mainViewBg)] ${globalLoader.isLoading ? 'pointer-events-none overflow-hidden' : ''}`}> <div className={`relative w-full h-screen bg-[var(--mainViewBg)] ${globalLoader.isLoading ? 'pointer-events-none overflow-hidden' : ''}`}>
{/* Top Navigation - Fixed */} {/* Top Navigation - Fixed */}
<div className='fixed top-0 left-0 right-0 w-full flex items-center justify-between bg-white shadow z-50 px-4 py-3'> <div className='fixed top-0 left-0 right-0 w-full bg-white shadow z-50 px-4 py-1.5 lg:py-3'>
<div className='flex items-center gap-2'> <div className='flex flex-col sm:flex-row sm:items-center sm:justify-between gap-1 flex-wrap'>
{/* Left Section */}
<div className='flex sm:flex-row items-start sm:items-center gap-2 sm:gap-4 w-full sm:w-auto'>
<IoMdClose <IoMdClose
onClick={handleClose} onClick={handleClose}
className='text-2xl text-slate-500 cursor-pointer hover:text-[var(--primary)] transition' className='text-2xl text-slate-500 cursor-pointer hover:text-[var(--primary)] transition self-start sm:self-auto'
/> />
<p className="text-base font-normal text-gray-700 border-l pl-4 relative">
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES ? <p className="text-base font-normal text-gray-700 border-l pl-4 relative w-full sm:w-auto">
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES ? (
<> <>
<input <input
value={templateName} value={templateName}
onChange={handleChange} onChange={handleChange}
className="w-full px-4 py-1.5 border-2 border-dashed rounded-md text-sm focus:outline-none transition border-gray-300 focus:ring-2 focus:border-dashed focus:ring-[var(--primary)]" className="w-full sm:w-[250px] px-4 py-1.5 border-2 border-dashed rounded-md text-sm focus:outline-none transition border-gray-300 focus:ring-2 focus:border-dashed focus:ring-[var(--primary)]"
/> />
{!isTyping && ( {!isTyping && (
<RiPencilFill className="absolute top-2.5 right-2 text-[17px]" /> <RiPencilFill className="absolute top-2.5 right-2 text-[17px]" />
)} )}
</> : </>
) : (
"Add Recipient and Message" "Add Recipient and Message"
} )}
</p> </p>
</div> </div>
{/* Right Section */}
<div <div
id="add-tags-btn-step-one" id="add-tags-btn-step-one"
className='flex items-center gap-3'> className='flex sm:flex-row items-stretch sm:items-center gap-2 sm:gap-3 w-full sm:w-auto '>
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && <button {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && (
<button
onClick={() => handleNextClick(true)} onClick={() => handleNextClick(true)}
className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer" className="text-sm w-full sm:w-auto px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer"
> >
Save & Close Save & Close
</button>} </button>
)}
<button <button
onClick={() => handleNextClick(false)} onClick={() => handleNextClick(false)}
className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer" className="text-sm w-full sm:w-auto px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition cursor-pointer"
> >
{signType === SignTypeEnum.selfSign ? "Sign" : "Next"} {signType === SignTypeEnum.selfSign ? "Sign" : "Next"}
</button> </button>
</div>
</div>
</div>
</div>
</div>
{/* Main Content - Scrollable */} {/* Main Content - Scrollable */}
<div className="h-screen pt-[80px] overflow-y-auto no-scrollbar"> <div className="h-screen pt-[80px] overflow-y-auto no-scrollbar">

View File

@ -369,15 +369,14 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
ref={formRef} ref={formRef}
onSubmit={handleRecipientAdd} onSubmit={handleRecipientAdd}
id="add-recipient-step-one" id="add-recipient-step-one"
className="w-full bg-white border border-gray-200 rounded-lg shadow-sm px-6 py-4 space-y-3 relative" className="w-full bg-white border border-gray-200 rounded-lg shadow-sm px-3 sm:px-4 lg:px-6 py-3 sm:py-4 space-y-3 sm:space-y-4 relative"
> >
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && ( {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && (
<div className="space-y-1"> <div className="space-y-2 sm:space-y-3">
{/* Top Row: Role Input + Settings */} {/* Role Name and Permissions Section - Responsive Layout */}
<div className="flex justify-between items-center"> <div className="flex flex-col lg:flex-row lg:justify-between lg:items-start gap-3 lg:gap-4">
{/* Role Name Input */} {/* Role Name Input */}
{/* Role Name Input */} <div className="w-full lg:w-64 xl:w-80">
<div className="w-64">
<input <input
type="text" type="text"
value={recipient.roleName} value={recipient.roleName}
@ -394,32 +393,12 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
)} )}
</div> </div>
{/* Permissions Section */}
{/* Settings + Permissions */} <div className="flex items-center justify-start lg:justify-end">
<div className="flex items-center"> <div className="flex sm:flex-row items-start sm:items-center gap-2 sm:gap-3">
<div className="flex justify-between w-full">
{/* Permission Status Text - Always Visible */}
<div className="max-h-10 opacity-100 me-3 overflow-hidden">
<div className="text-sm text-gray-600 pt-0.5">
{/* {recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Full permissions granted"}
{recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "Edit permission granted"}
{!recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Delete permission granted"}
{!recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "No permissions granted"} */}
Permissions granted :
</div>
</div>
{/* Permission Controls - Always Visible */}
<div className="max-w-80 opacity-100 overflow-visible">
<div className="flex items-center space-x-3 pr-1.5">
{/* Edit Permission */} {/* Edit Permission */}
<div className="relative group"> <div className="relative group">
<label <label className="flex items-center gap-1 text-xs sm:text-sm text-gray-700">
className={`relative flex items-center justify-center w-12 h-7 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToEdit
? 'bg-blue-100 border-blue-500 shadow-md'
: 'bg-white border-gray-300 hover:border-blue-400 text-gray-400'
}`}
>
<input <input
type="checkbox" type="checkbox"
checked={recipient.allowSenderToEdit} checked={recipient.allowSenderToEdit}
@ -428,30 +407,15 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
} }
onFocus={() => setOpenContactModal(true)} onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
className="absolute w-full h-full opacity-0 cursor-pointer" className='accent-blue-500 w-3 h-3 sm:w-4 sm:h-4'
/> />
<FiEdit <span className="whitespace-nowrap">Allow Edit</span>
className={`w-2.5 h-2.5 pointer-events-none transition-all duration-300 ${recipient.allowSenderToEdit ? 'text-blue-600' : 'text-gray-400'
}`}
/><span className="ms-0.5 text-[12px]">Edit</span>
</label> </label>
{/* Tooltip */}
<div className="absolute bottom-0 -translate-y-full left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-20">
<div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
Edit Permission
<div className="absolute bottom-[-5px] left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-800"></div>
</div>
</div>
</div> </div>
{/* Delete Permission */} {/* Delete Permission */}
<div className="relative group"> <div className="relative group">
<label <label className="flex items-center gap-1 text-xs sm:text-sm text-gray-700">
className={`relative flex items-center justify-center w-15 h-7 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToDelete
? 'bg-red-100 border-red-500 shadow-md'
: 'bg-white border-gray-300 hover:border-red-400 text-gray-400'
}`}
>
<input <input
type="checkbox" type="checkbox"
checked={recipient.allowSenderToDelete} checked={recipient.allowSenderToDelete}
@ -460,58 +424,44 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
} }
onFocus={() => setOpenContactModal(true)} onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
className="absolute w-full h-full opacity-0 cursor-pointer" className="accent-red-500 w-3 h-3 sm:w-4 sm:h-4"
/> />
<FiTrash <span className="whitespace-nowrap">Allow Delete</span>
className={`w-3 h-3 pointer-events-none transition-all duration-300 ${recipient.allowSenderToDelete ? 'text-red-600' : 'text-gray-400'
}`}
/><span className="ms-0.5 text-[12px]">Delete</span>
</label> </label>
{/* Tooltip */}
<div className="absolute bottom-0 -translate-y-full left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-20">
<div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
Delete Permission
<div className="absolute bottom-[-5px] left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-800"></div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div>
</div>
)} )}
{/* Name Inputs */} {/* Name and Email Inputs - Responsive Grid */}
<div className="grid grid-cols-12 gap-4 mt-3"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4 mt-3">
<div className="col-span-4"> {/* First Name */}
<div className="w-full">
<input <input
type="text" type="text"
onFocus={() => handleFocus("firstName")} onFocus={() => handleFocus("firstName")}
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
value={recipient.firstName} value={recipient.firstName}
placeholder="First Name" placeholder="First Name"
className={`w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition className={`w-full px-3 sm:px-4 py-2 border rounded-md text-sm focus:outline-none transition
${errors.firstName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} ${errors.firstName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`}
onChange={(e) => { onChange={(e) => {
setRecipients({ ...recipient, firstName: e.target.value }); setRecipients({ ...recipient, firstName: e.target.value });
// setErrors((prev) => ({ ...prev, firstName: false }));
}} }}
/> />
</div> </div>
{/* {errors.firstName && (
<p className="text-red-500 text-xs mt-1">First Name is required</p> {/* Last Name */}
)} */} <div className="w-full">
<div className="col-span-4">
<input <input
type="text" type="text"
onFocus={() => handleFocus("lastName")} onFocus={() => handleFocus("lastName")}
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
value={recipient.lastName} value={recipient.lastName}
placeholder="Last Name" placeholder="Last Name"
className={` w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition className={`w-full px-3 sm:px-4 py-2 border rounded-md text-sm focus:outline-none transition
${errors.lastName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} ${errors.lastName ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`}
onChange={(e) => { onChange={(e) => {
setRecipients({ ...recipient, lastName: e.target.value }); setRecipients({ ...recipient, lastName: e.target.value });
@ -522,14 +472,16 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
<p className="text-red-500 text-xs mt-1">Last Name is required</p> <p className="text-red-500 text-xs mt-1">Last Name is required</p>
)} )}
</div> </div>
<div className="col-span-4">
{/* Email - Full width on small screens, shares row on larger */}
<div className="w-full sm:col-span-2 lg:col-span-1">
<input <input
type="email" type="email"
onFocus={() => handleFocus("email")} onFocus={() => handleFocus("email")}
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
value={recipient.email} value={recipient.email}
placeholder="Recipient Email" placeholder="Recipient Email"
className={`w-full px-4 py-2 border rounded-md text-sm focus:outline-none transition className={`w-full px-3 sm:px-4 py-2 border rounded-md text-sm focus:outline-none transition
${errors.email ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`} ${errors.email ? 'border-red-500 ring-2 ring-red-300' : 'border-gray-300 focus:ring-2 focus:ring-[var(--primary)]'}`}
onChange={(e) => { onChange={(e) => {
setRecipients({ ...recipient, email: e.target.value }); setRecipients({ ...recipient, email: e.target.value });
@ -542,8 +494,9 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
</div> </div>
</div> </div>
{/* Host Fields for In-Person Signers */}
{recipient.type === recipientType.INPERSONSIGNER && <div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> {recipient.type === recipientType.INPERSONSIGNER && (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<input <input
required={transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES} required={transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES}
type="text" type="text"
@ -551,7 +504,7 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
value={recipient.hostName} value={recipient.hostName}
placeholder="Host Name" placeholder="Host Name"
className="w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition" className="w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
onChange={(e) => setRecipients({ ...recipient, hostName: e.target.value })} onChange={(e) => setRecipients({ ...recipient, hostName: e.target.value })}
/> />
<input <input
@ -561,14 +514,15 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
value={recipient.hostEmail} value={recipient.hostEmail}
placeholder="Host Email" placeholder="Host Email"
className="w-full px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition" className="w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition"
onChange={(e) => setRecipients({ ...recipient, hostEmail: e.target.value })} onChange={(e) => setRecipients({ ...recipient, hostEmail: e.target.value })}
/> />
</div>} </div>
)}
{/* Contact Modal */} {/* Contact Modal - Responsive Positioning */}
{openContactModal && contactData.contacts.length > 0 && ( {openContactModal && contactData.contacts.length > 0 && (
<div className="absolute z-50 mt-1 w-2/3 max-h-[50vh] bg-white shadow-lg rounded-md p-3 border border-gray-100 overflow-y-auto no-scrollbar"> <div className="absolute z-50 mt-1 w-full sm:w-2/3 lg:w-1/2 xl:w-2/3 max-h-[40vh] sm:max-h-[50vh] bg-white shadow-lg rounded-md p-2 sm:p-3 border border-gray-100 overflow-y-auto no-scrollbar">
<ContactModal <ContactModal
contactData={contactData} contactData={contactData}
inpFirstName={recipient.firstName} inpFirstName={recipient.firstName}
@ -583,36 +537,41 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
</div> </div>
)} )}
{/* Signing Options and Add Button - Responsive Layout */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
{/* Signing options + Add button in one line */} {/* Recipient Type Radio Options */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4"> <div className="flex flex-col sm:flex-row sm:flex-wrap gap-2 sm:gap-4 lg:gap-6">
<div className="flex flex-wrap gap-6">
{[ {[
{ label: "Signer", value: recipientType.SIGNER }, { label: "Signer", value: recipientType.SIGNER },
{ label: "In Person Signer", value: recipientType.INPERSONSIGNER }, { label: "In Person Signer", value: recipientType.INPERSONSIGNER },
{ label: "CC", value: recipientType.CC }, { label: "CC", value: recipientType.CC },
].map((option) => ( ].map((option) => (
<label key={option.value} className="flex items-center gap-2 text-gray-700 text-sm cursor-pointer"> <label key={option.value} className="flex items-center gap-2 text-gray-700 text-xs sm:text-sm cursor-pointer">
<input <input
type="radio" type="radio"
name="recipient-type" name="recipient-type"
value={option.value} value={option.value}
checked={recipient.type === option.value} checked={recipient.type === option.value}
onClick={(e) => setRecipients({ ...recipient, type: e.target.value })} onClick={(e) => setRecipients({ ...recipient, type: e.target.value })}
className="accent-[var(--primary)] cursor-pointer" className="accent-[var(--primary)] cursor-pointer w-3 h-3 sm:w-4 sm:h-4"
/> />
{option.label} <span className="whitespace-nowrap">{option.label}</span>
</label> </label>
))} ))}
</div> </div>
{!showCard && <button {/* Add/Edit Button */}
{!showCard && (
<button
type="submit" type="submit"
className="inline-flex items-center gap-2 bg-[var(--primary)] hover:bg-[var(--primaryLight2)] text-white text-sm font-semibold px-5 py-2 rounded-md transition" className="inline-flex items-center justify-center gap-2 bg-[var(--primary)] hover:bg-[var(--primaryLight2)] text-white text-xs sm:text-sm font-semibold px-4 sm:px-5 py-2 rounded-md transition w-full sm:w-auto min-w-fit"
> >
<FaPlus size={14} /> {editCase === "Edit" ? "Edit Recipient" : "Add Recipient"} <FaPlus size={12} className="sm:w-3.5 sm:h-3.5" />
</button>} <span className="whitespace-nowrap">
{editCase === "Edit" ? "Edit Recipient" : "Add Recipient"}
</span>
</button>
)}
</div> </div>
</form> </form>
</div> </div>

View File

@ -130,19 +130,15 @@ const RecipientCards = ({
) => { ) => {
const identifier = getRecipientIdentifier(recipient); const identifier = getRecipientIdentifier(recipient);
const currentValue = getCurrentValue(recipient, fieldName); const currentValue = getCurrentValue(recipient, fieldName);
const isEditing = editingField?.recipientId === identifier && editingField?.fieldName === fieldName;
const showValue = hasValue(recipient, fieldName);
const error = errors[identifier]?.[fieldName]; const error = errors[identifier]?.[fieldName];
const editable = isEditable(recipient); const editable = isEditable(recipient);
if (isEditing && editable) {
return ( return (
<div className="relative"> <div className="relative inline-block w-full sm:mx-1 lg:mx-3">
<input <input
type={type} type={type}
value={currentValue || ""} value={currentValue || ""}
placeholder={placeholder} placeholder={placeholder}
autoFocus
onFocus={() => handleFieldFocus(identifier, fieldName)} onFocus={() => handleFieldFocus(identifier, fieldName)}
onBlur={(e) => handleFieldBlur(recipient, fieldName, e.target.value)} onBlur={(e) => handleFieldBlur(recipient, fieldName, e.target.value)}
onChange={(e) => handleFieldChange(recipient, fieldName, e.target.value)} onChange={(e) => handleFieldChange(recipient, fieldName, e.target.value)}
@ -151,28 +147,12 @@ const RecipientCards = ({
e.currentTarget.blur(); e.currentTarget.blur();
} }
}} }}
className={`w-full px-3 py-1 border ${error ? "border-red-500 placeholder-red-500 text-xs" : "border-gray-300" disabled={!editable}
} rounded-lg text-sm focus:outline-none focus:ring-0 focus:ring-gray-300 ${className}`} className={`w-full px-2 sm:px-3 lg:px-4 py-1.5 sm:py-2 font-normal border focus:outline-none focus:ring-2 focus:ring-[var(--primary)] transition ${error ? "border-red-500 placeholder-red-500 text-xs" : "border-gray-300"} rounded-lg text-xs sm:text-sm ${className} ${!editable ? "bg-gray-100 cursor-not-allowed" : ""}`}
title={editable ? "Edit field" : "Editing disabled"}
/> />
{/* {error && (
<span className="text-red-500 text-xs absolute left-0">{`${placeholder} is required`}</span>
)} */}
</div> </div>
); );
}
return (
<span
onClick={editable ? () => handleFieldFocus(identifier, fieldName) : undefined}
className={`${editable
? "cursor-pointer hover:bg-gray-100 rounded px-1 transition-colors"
: "cursor-not-allowed"
} ${showValue ? "text-gray-800" : "text-gray-400 italic"} ${className}`}
title={editable ? "Click to edit" : "Editing disabled"}
>
{showValue ? currentValue : placeholder}
</span>
);
}; };
const handleOrderChange = (id: string, value: number) => { const handleOrderChange = (id: string, value: number) => {
@ -240,12 +220,12 @@ const RecipientCards = ({
{recipients.length > 0 ? ( {recipients.length > 0 ? (
<> <>
{recipients.length > 1 && ( {recipients.length > 1 && (
<div className="flex items-center justify-between px-4 py-2 border-b border-gray-300"> <div className="flex sm:flex-row sm:items-center justify-between px-3 sm:px-4 py-2 border-b border-gray-300 gap-2">
<h3 className="text-sm font-semibold text-gray-700"> <h3 className="text-sm font-semibold text-gray-700">
Recipients ({recipients.length}) Recipients ({recipients.length})
</h3> </h3>
<label <label
className="flex items-center gap-2 cursor-pointer select-none" className="flex items-center gap-2 cursor-pointer select-none justify-center sm:justify-end"
onClick={() => setSigningOrderModal({ ...signingOrderModal, open: true })} onClick={() => setSigningOrderModal({ ...signingOrderModal, open: true })}
> >
<span className="text-xs font-medium text-gray-600">Signing Order</span> <span className="text-xs font-medium text-gray-600">Signing Order</span>
@ -254,18 +234,20 @@ const RecipientCards = ({
</div> </div>
)} )}
<div className="flex flex-col divide-y divide-gray-200"> <div className="flex flex-col divide-y divide-gray-200 max-h-[47vh] overflow-y-auto custom-scrollbar">
{recipients.map((recipient, idx) => ( {recipients.map((recipient, idx) => (
<div <div
key={recipient.email + idx} key={recipient.email + idx}
className={`flex items-center justify-between px-4 py-3 hover:bg-gray-50 transition-colors ${(recipient.uuid || recipient.id) === editRecipientCurrentEmail className={`flex flex-col lg:flex-row lg:items-center justify-between px-2 sm:px-3 lg:px-2 py-3 hover:bg-gray-50 transition-colors gap-3 lg:gap-0 ${(recipient.uuid || recipient.id) === editRecipientCurrentEmail
? "bg-neutral-100 opacity-40" ? "bg-neutral-100 opacity-40"
: "" : ""
}`} }`}
> >
<div className="flex items-center gap-3 min-w-0"> {/* Main Content Section */}
<div className="flex items-start sm:items-center gap-2 sm:gap-3 min-w-0 flex-1">
{/* Order Number */}
{recipients.length > 1 ? ( {recipients.length > 1 ? (
<div className="relative"> <div className="relative flex-shrink-0">
<input <input
type="number" type="number"
value={recipient.routingOrder || 1} value={recipient.routingOrder || 1}
@ -276,7 +258,7 @@ const RecipientCards = ({
Number(e.target.value) Number(e.target.value)
) )
} }
className="w-10 h-6 text-center rounded text-sm text-gray-600 focus:outline-none focus:ring-[var(--primary)] border border-dashed border-gray-400 bg-slate-100" className="w-8 sm:w-10 h-6 text-center rounded text-sm text-gray-600 focus:outline-none focus:ring-[var(--primary)] border border-dashed border-gray-400 bg-slate-100"
/> />
</div> </div>
) : ( ) : (
@ -291,25 +273,34 @@ const RecipientCards = ({
Number(e.target.value) Number(e.target.value)
) )
} }
className="w-8 text-center rounded text-sm text-gray-700 border-none focus:outline-none focus:ring-[var(--primary)]" className="w-6 sm:w-8 text-center rounded text-sm text-gray-700 border-none focus:outline-none focus:ring-[var(--primary)] flex-shrink-0"
/> />
)} )}
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-[var(--primary)] text-white flex items-center justify-center font-semibold text-xs select-none">
{/* Avatar */}
<div className="flex-shrink-0 w-7 h-7 sm:w-8 sm:h-8 rounded-full bg-[var(--primary)] text-white flex items-center justify-center font-semibold text-xs select-none">
{getInitials(`${recipient.firstName} ${recipient.lastName || ""}`)} {getInitials(`${recipient.firstName} ${recipient.lastName || ""}`)}
</div> </div>
<div className="min-w-0">
<p className="font-semibold text-gray-800 truncate text-xs flex items-center gap-0.5"> {/* Form Fields Section */}
{renderEditableField(recipient, "firstName", "First Name")} <div className="min-w-0 flex-1">
{renderEditableField(recipient, "lastName", "Last Name")} {/* Role Name and Permissions Row */}
<div className="flex flex-col lg:flex-row lg:items-center gap-2 mb-2">
<div className="flex-1 lg:w-1/2">
<p className="font-semibold text-gray-800 text-xs">
{renderEditableField(recipient, "roleName", "Role name")}
</p>
</div>
{/* Permissions - Mobile: Below role, Desktop: Right side */}
<div className="lg:w-1/2 lg:flex lg:items-center lg:justify-end">
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && ( {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && (
<span className="flex items-center gap-2"> <div className="flex ps-2.5 sm:flex-row items-start sm:items-center gap-2 sm:gap-4">
<span className="text-gray-400 ">| Permissions granted :</span> <label className="flex items-center gap-1 text-xs sm:text-sm text-gray-700">
<FiEdit <input
className={`cursor-pointer h-3 w-3 ${recipient.allowSenderToEdit type="checkbox"
? "text-blue-500" checked={recipient.allowSenderToEdit}
: "text-gray-400" onChange={() =>
} hover:text-blue-800`}
onClick={() =>
dispatch( dispatch(
updateRecipient({ updateRecipient({
...recipient, ...recipient,
@ -318,13 +309,16 @@ const RecipientCards = ({
}) })
) )
} }
className="accent-blue-500 w-3 h-3 sm:w-4 sm:h-4"
/> />
<ImBin <span className="whitespace-nowrap">Allow Edit</span>
className={`cursor-pointer h-3 w-3 ${recipient.allowSenderToDelete </label>
? "text-red-500"
: "text-gray-400" <label className="flex items-center gap-1 text-xs sm:text-sm text-gray-700">
} hover:text-red-700`} <input
onClick={() => type="checkbox"
checked={recipient.allowSenderToDelete}
onChange={() =>
dispatch( dispatch(
updateRecipient({ updateRecipient({
...recipient, ...recipient,
@ -333,61 +327,71 @@ const RecipientCards = ({
}) })
) )
} }
className="accent-red-500 w-3 h-3 sm:w-4 sm:h-4"
/> />
</span> <span className="whitespace-nowrap">Allow Delete</span>
</label>
</div>
)} )}
</div>
</div>
{/* Name and Email Fields */}
<div className="mb-2">
{/* Mobile: Stack vertically, Tablet+: Side by side */}
<div className="flex flex-col sm:flex-row gap-1 sm:gap-2">
<div className="flex flex-col sm:flex-row gap-1 sm:gap-2 sm:flex-1">
<div className="w-full sm:w-1/2">
<p className="font-semibold text-gray-800 text-xs">
{renderEditableField(recipient, "firstName", "First Name")}
</p> </p>
<p className="text-xs text-gray-500 truncate flex items-center gap-1"> </div>
{renderEditableField(recipient, "email", "Recipient Email", "", "email")} | <div className="w-full sm:w-1/2">
<span <p className="font-semibold text-gray-800 text-xs">
onClick={ {renderEditableField(recipient, "lastName", "Last Name")}
isEditable(recipient) </p>
? () => handleFieldFocus(getRecipientIdentifier(recipient), "type") </div>
: undefined </div>
} <div className="w-full sm:flex-1">
className={`${isEditable(recipient) <p className="font-semibold text-gray-800 text-xs">
? "cursor-pointer hover:bg-gray-100" {renderEditableField(recipient, "email", "Recipient Email", "", "email")}
: "cursor-not-allowed" </p>
} rounded px-1 transition-colors`} </div>
> </div>
{recipient.type} </div>
</span>
{(hasValue(recipient, "roleName") || {/* Host Fields (for In-Person Signers) */}
transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) && (
<span>
{" | Role: "}
{renderEditableField(recipient, "roleName", "Role name")}
</span>
)}
{recipient.type === recipientType.INPERSONSIGNER && ( {recipient.type === recipientType.INPERSONSIGNER && (
<> <div className="mb-2">
<span className="flex items-center"> <div className="flex flex-col sm:flex-row gap-1 sm:gap-2">
<span>{" | Host Name: "}</span> <div className="w-full sm:w-1/2">
<p className="font-semibold text-gray-800 text-xs">
{renderEditableField(recipient, "hostName", "Host Name")} {renderEditableField(recipient, "hostName", "Host Name")}
<span>{" | Host Email: "}</span>
{renderEditableField(recipient, "hostEmail", "Host Email", "", "email")}
</span>
</>
)}
</p> </p>
{editingField?.recipientId === getRecipientIdentifier(recipient) && </div>
editingField?.fieldName === "type" && <div className="w-full sm:w-1/2">
isEditable(recipient) && ( <p className="font-semibold text-gray-800 text-xs">
<div className="flex items-center gap-2 mt-1"> {renderEditableField(recipient, "hostEmail", "Host Email", "", "email")}
</p>
</div>
</div>
</div>
)}
{/* Recipient Type Radio Buttons */}
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2 my-1.5 mx-1 sm:mx-2">
<label className="flex items-center gap-1"> <label className="flex items-center gap-1">
<input <input
type="radio" type="radio"
name={`recipient-type-${getRecipientIdentifier(recipient)}`} name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.SIGNER} value={recipientType.SIGNER}
checked={recipient.type === recipientType.SIGNER} checked={recipient.type === recipientType.SIGNER}
onChange={() => onChange={() => handleTypeChange(recipient, recipientType.SIGNER)}
handleTypeChange(recipient, recipientType.SIGNER)
}
onBlur={() => setEditingField(null)} onBlur={() => setEditingField(null)}
className="accent-[var(--primary)]" className="accent-[var(--primary)] w-3 h-3"
disabled={!isEditable(recipient)} disabled={!isEditable(recipient)}
/> />
<span className="text-xs">Signer</span> <span className="text-xs sm:text-sm">Signer</span>
</label> </label>
<label className="flex items-center gap-1"> <label className="flex items-center gap-1">
<input <input
@ -395,14 +399,12 @@ const RecipientCards = ({
name={`recipient-type-${getRecipientIdentifier(recipient)}`} name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.INPERSONSIGNER} value={recipientType.INPERSONSIGNER}
checked={recipient.type === recipientType.INPERSONSIGNER} checked={recipient.type === recipientType.INPERSONSIGNER}
onChange={() => onChange={() => handleTypeChange(recipient, recipientType.INPERSONSIGNER)}
handleTypeChange(recipient, recipientType.INPERSONSIGNER)
}
onBlur={() => setEditingField(null)} onBlur={() => setEditingField(null)}
className="accent-[var(--primary)]" className="accent-[var(--primary)] w-3 h-3"
disabled={!isEditable(recipient)} disabled={!isEditable(recipient)}
/> />
<span className="text-xs">In Person Signer</span> <span className="text-xs sm:text-sm whitespace-nowrap">In Person Signer</span>
</label> </label>
<label className="flex items-center gap-1"> <label className="flex items-center gap-1">
<input <input
@ -410,21 +412,20 @@ const RecipientCards = ({
name={`recipient-type-${getRecipientIdentifier(recipient)}`} name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.CC} value={recipientType.CC}
checked={recipient.type === recipientType.CC} checked={recipient.type === recipientType.CC}
onChange={() => onChange={() => handleTypeChange(recipient, recipientType.CC)}
handleTypeChange(recipient, recipientType.CC)
}
onBlur={() => setEditingField(null)} onBlur={() => setEditingField(null)}
className="accent-[var(--primary)]" className="accent-[var(--primary)] w-3 h-3"
disabled={!isEditable(recipient)} disabled={!isEditable(recipient)}
/> />
<span className="text-xs">CC</span> <span className="text-xs sm:text-sm">CC</span>
</label> </label>
</div> </div>
)}
</div> </div>
</div> </div>
{/* Action Buttons */}
{signType !== "self-sign" && ( {signType !== "self-sign" && (
<div className="flex justify-between gap-2 items-center"> <div className="flex justify-end lg:justify-center gap-2 items-center lg:ml-2">
<button <button
type="button" type="button"
title="Remove recipient" title="Remove recipient"
@ -435,9 +436,9 @@ const RecipientCards = ({
? false ? false
: !recipient.newOne && !recipient.allowSenderToDelete : !recipient.newOne && !recipient.allowSenderToDelete
} }
className="text-gray-400 hover:text-red-600 transition-colors cursor-pointer disabled:opacity-50" className="text-gray-400 hover:text-red-600 transition-colors cursor-pointer disabled:opacity-50 p-1"
> >
<ImBin size={16} /> <ImBin size={14} className="sm:w-4 sm:h-4" />
</button> </button>
</div> </div>
)} )}
@ -446,26 +447,29 @@ const RecipientCards = ({
</div> </div>
</> </>
) : ( ) : (
<div className="p-6 text-center text-gray-500 font-medium text-sm"> <div className="p-4 sm:p-6 text-center text-gray-500 font-medium text-sm">
No Recipients Added No Recipients Added
</div> </div>
)} )}
{/* Responsive Modal */}
{signingOrderModal.open && ( {signingOrderModal.open && (
<div className="fixed top-0 left-0 inset-0 z-50 bg-black/50 backdrop-blur-sm flex justify-center items-center"> <div className="fixed top-0 left-0 inset-0 z-50 bg-black/50 backdrop-blur-sm flex justify-center items-center p-4">
<div className="flex-col relative justify-center items-center max-w-[80%] max-h-[60vh] h-full overflow-auto"> <div className="flex-col relative justify-center items-center w-full max-w-xs sm:max-w-md md:max-w-lg lg:max-w-2xl xl:max-w-4xl max-h-[80vh] sm:max-h-[70vh] lg:max-h-[60vh] h-full overflow-auto">
<div className="p-2 rounded-t-lg text-white flex justify-between items-center bg-[var(--primary)]"> <div className="p-3 sm:p-4 rounded-t-lg text-white flex justify-between items-center bg-[var(--primary)]">
<p className="font-semibold">Signing Order</p> <p className="font-semibold text-sm sm:text-base">Signing Order</p>
<div <div
onClick={() => setSigningOrderModal({ ...signingOrderModal, open: false })} onClick={() => setSigningOrderModal({ ...signingOrderModal, open: false })}
className="text-xl cursor-pointer hover:text-gray-200 transition-all" className="text-xl sm:text-2xl cursor-pointer hover:text-gray-200 transition-all p-1"
> >
<IoCloseOutline /> <IoCloseOutline />
</div> </div>
</div> </div>
<div className="bg-white rounded-b-lg">
<SigningOrderDiagram signers={recipients} /> <SigningOrderDiagram signers={recipients} />
</div> </div>
</div> </div>
</div>
)} )}
</div> </div>
); );

View File

@ -90,15 +90,26 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
// Get proper Tailwind class names for upload card span // Get proper Tailwind class names for upload card span
const getUploadCardSpanClass = () => { const getUploadCardSpanClass = () => {
switch (docCount) { if (docCount === 0) {
case 0: return 'col-span-5'; // Full width when no docs // Upload card takes all columns only when no docs
case 1: return 'col-span-4'; // 4 cols for upload, 1 for doc return "col-span-1 sm:col-span-2 md:col-span-3 lg:col-span-4 xl:col-span-5";
case 2: return 'col-span-3'; // 3 cols for upload, 2 for docs
case 3: return 'col-span-2'; // 2 cols for upload, 3 for docs
case 4: return 'col-span-1'; // 1 col for upload, 4 for docs
default: return 'col-span-1'; // 1 col for upload, rest for docs
} }
};
switch (docCount) {
case 1:
return "col-span-1 sm:col-span-1 md:col-span-2 lg:col-span-3 xl:col-span-4";
case 2:
return "col-span-1 sm:col-span-1 md:col-span-1 lg:col-span-2 xl:col-span-3";
case 3:
return "col-span-1 sm:col-span-1 md:col-span-1 lg:col-span-1 xl:col-span-2";
case 4:
return "col-span-1"; // balanced
default:
return "col-span-1";
}
};
// Calculate how many documents should be in the first row // Calculate how many documents should be in the first row
const getFirstRowDocCount = () => { const getFirstRowDocCount = () => {
@ -113,9 +124,12 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
return ( return (
<> <>
{/* Upload Card First */} {/* Upload Card First */}
<div className='space-y-3'> <div className="space-y-3">
<div id='upload-doc-step-one' className="grid grid-cols-5 gap-2"> <div
{/* Upload Document Card - Always First */} id="upload-doc-step-one"
className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-5 gap-2"
>
{/* Upload Document Card */}
<div <div
onClick={() => setModalOpen(true)} onClick={() => setModalOpen(true)}
className={`${getUploadCardSpanClass()} cursor-pointer h-[170px] flex flex-col items-center justify-center border-2 border-dashed border-gray-300 rounded-xl bg-white hover:bg-gray-50 transition shadow-sm hover:shadow-md`} className={`${getUploadCardSpanClass()} cursor-pointer h-[170px] flex flex-col items-center justify-center border-2 border-dashed border-gray-300 rounded-xl bg-white hover:bg-gray-50 transition shadow-sm hover:shadow-md`}
@ -126,13 +140,10 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
{/* First Row Documents */} {/* First Row Documents */}
<ReactSortable <ReactSortable
className="contents" // Use 'contents' to make children participate in parent grid className="contents"
list={documents.slice(0, firstRowDocCount).map(doc => ({ ...doc }))} list={documents.slice(0, firstRowDocCount).map((doc) => ({ ...doc }))}
setList={(newState) => { setList={(newState) => {
const updatedDocs = [ const updatedDocs = [...newState, ...documents.slice(firstRowDocCount)];
...newState,
...documents.slice(firstRowDocCount)
];
dispatch(setDocuments(updatedDocs)); dispatch(setDocuments(updatedDocs));
}} }}
handle=".drag-handle" handle=".drag-handle"
@ -141,12 +152,13 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
disabled={false} disabled={false}
> >
{documents.slice(0, firstRowDocCount).map((doc) => ( {documents.slice(0, firstRowDocCount).map((doc) => (
<div key={doc.id} className="col-span-1"> <div key={doc.id} className="col-span-1 mx-auto">
<DocumentCard <DocumentCard
id={doc.id} id={doc.id}
name={doc.name} name={doc.name}
isCompleted={ isCompleted={
("isCompleted" in doc || ("status" in doc && doc.status === "UPLOADED")) "isCompleted" in doc ||
("status" in doc && doc.status === "UPLOADED")
? true ? true
: false : false
} }
@ -157,15 +169,15 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
</ReactSortable> </ReactSortable>
</div> </div>
{/* Additional Rows - Remaining Documents (5th, 6th, 7th, etc.) */} {/* Additional Rows */}
{remainingDocs > 0 && ( {remainingDocs > 0 && (
<ReactSortable <ReactSortable
className="grid grid-cols-5 gap-2" className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 xl:grid-cols-5 gap-2"
list={documents.slice(firstRowDocCount).map(doc => ({ ...doc }))} list={documents.slice(firstRowDocCount).map((doc) => ({ ...doc }))}
setList={(newState) => { setList={(newState) => {
const updatedDocs = [ const updatedDocs = [
...documents.slice(0, firstRowDocCount), ...documents.slice(0, firstRowDocCount),
...newState ...newState,
]; ];
dispatch(setDocuments(updatedDocs)); dispatch(setDocuments(updatedDocs));
}} }}
@ -175,12 +187,13 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
disabled={false} disabled={false}
> >
{documents.slice(firstRowDocCount).map((doc) => ( {documents.slice(firstRowDocCount).map((doc) => (
<div key={doc.id} className="col-span-1"> <div key={doc.id} className="col-span-1 mx-auto">
<DocumentCard <DocumentCard
id={doc.id} id={doc.id}
name={doc.name} name={doc.name}
isCompleted={ isCompleted={
("isCompleted" in doc || ("status" in doc && doc.status === "UPLOADED")) "isCompleted" in doc ||
("status" in doc && doc.status === "UPLOADED")
? true ? true
: false : false
} }
@ -191,11 +204,10 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
</ReactSortable> </ReactSortable>
)} )}
{/* Modal */} {/* Modal */}
{isModalOpen && ( {isModalOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-100/60 backdrop-blur-sm px-4"> <div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-100/60 backdrop-blur-sm px-2 sm:px-4">
<div className="bg-white w-full max-w-5xl h-[500px] rounded-xl shadow-lg flex overflow-hidden relative"> <div className="bg-white w-full h-full sm:max-w-5xl sm:h-[500px] rounded-xl shadow-lg flex flex-col sm:flex-row overflow-hidden relative">
{/* Close Button */} {/* Close Button */}
<button <button
className="absolute top-2 right-2 text-gray-500 hover:text-red-500 transition text-xl bg-white rounded-full p-2" className="absolute top-2 right-2 text-gray-500 hover:text-red-500 transition text-xl bg-white rounded-full p-2"
@ -205,13 +217,13 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
</button> </button>
{/* Sidebar Tabs */} {/* Sidebar Tabs */}
<div className="w-1/4 bg-gray-100 p-4 flex flex-col gap-2 border-r border-gray-200"> <div className="w-full sm:w-1/4 bg-gray-100 p-4 flex flex-row sm:flex-col gap-2 border-b sm:border-b-0 sm:border-r border-gray-200 overflow-x-auto sm:overflow-hidden">
{tabs.map(tab => ( {tabs.map((tab) => (
<button <button
key={tab.name} key={tab.name}
className={`flex items-center gap-2 p-3 rounded-md text-sm font-medium transition ${activeTab === tab.name className={`flex items-center gap-2 p-3 rounded-md text-sm font-medium transition whitespace-nowrap ${activeTab === tab.name
? 'bg-white shadow text-[var(--primary)]' ? "bg-white shadow text-[var(--primary)]"
: 'hover:bg-gray-200 text-gray-600' : "hover:bg-gray-200 text-gray-600"
}`} }`}
onClick={() => setActiveTab(tab.name)} onClick={() => setActiveTab(tab.name)}
> >
@ -221,8 +233,8 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
</div> </div>
{/* Modal Content */} {/* Modal Content */}
<div className="w-3/4 p-6 overflow-y-auto"> <div className="w-full sm:w-3/4 p-4 sm:p-6 overflow-y-auto">
{activeTab === 'Upload' && ( {activeTab === "Upload" && (
<div <div
onClick={() => fileInputRef.current?.click()} onClick={() => fileInputRef.current?.click()}
onDragOver={(e) => e.preventDefault()} onDragOver={(e) => e.preventDefault()}
@ -230,7 +242,9 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
className="flex flex-col items-center justify-center h-full border-2 border-dashed border-gray-300 rounded-xl p-6 text-center cursor-pointer hover:bg-gray-50" className="flex flex-col items-center justify-center h-full border-2 border-dashed border-gray-300 rounded-xl p-6 text-center cursor-pointer hover:bg-gray-50"
> >
<FaCloudUploadAlt className="text-5xl text-[var(--primary)] mb-4" /> <FaCloudUploadAlt className="text-5xl text-[var(--primary)] mb-4" />
<p className="text-sm text-gray-500 mb-2">Drag & drop files here or</p> <p className="text-sm text-gray-500 mb-2">
Drag & drop files here or
</p>
<button className="px-5 py-2 text-sm bg-[var(--primary)] text-white rounded-md hover:scale-103 cursor-pointer transition-all"> <button className="px-5 py-2 text-sm bg-[var(--primary)] text-white rounded-md hover:scale-103 cursor-pointer transition-all">
Browse Files Browse Files
</button> </button>
@ -244,7 +258,7 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
/> />
</div> </div>
)} )}
{activeTab !== 'Upload' && ( {activeTab !== "Upload" && (
<div className="flex items-center justify-center h-full text-gray-400 text-sm"> <div className="flex items-center justify-center h-full text-gray-400 text-sm">
<p>{activeTab} integration coming soon...</p> <p>{activeTab} integration coming soon...</p>
</div> </div>
@ -253,10 +267,10 @@ const SelectedDocuments = ({ transactionTemplateToggle }) => {
</div> </div>
</div> </div>
)} )}
</div> </div>
</> </>
); );
}; };

View File

@ -140,6 +140,34 @@ canvas {
} }
} }
/* Custom scrollbar size via CSS */
@layer utilities {
.custom-scrollbar {
scrollbar-width: thin; /* For Firefox */
scrollbar-color: rgba(120, 120, 120, 0.4) transparent;
}
.custom-scrollbar::-webkit-scrollbar {
width: 1px;
height: 1px;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: rgba(120, 120, 120, 0.4);
border-radius: 9999px; /* fully rounded */
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background-color: rgba(120, 120, 120, 0.6); /* slightly darker on hover */
}
.custom-scrollbar::-webkit-scrollbar-track {
background-color: transparent;
}
}
/* Chrome, Safari, Edge, Opera */ /* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button, input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button { input::-webkit-inner-spin-button {