step-1-form-edit-ui-input-field

This commit is contained in:
JaiPandey425 2025-08-29 15:27:42 +05:30
parent d9f8cd58b0
commit 2eaa1ed3e1
5 changed files with 173 additions and 205 deletions

5
.env
View File

@ -1,3 +1,4 @@
VITE_BASE_URI="https://officially-powerful-goat.ngrok-free.app" # VITE_BASE_URI="https://officially-powerful-goat.ngrok-free.app"
# VITE_BASE_URI="https://python-amused-adder.ngrok-free.app" # VITE_BASE_URI="https://python-amused-adder.ngrok-free.app"
# VITE_BASE_URI="https://concrete-gladly-mullet.ngrok-free.app" # VITE_BASE_URI="https://concrete-gladly-mullet.ngrok-free.app"
VITE_BASE_URI="https://wired-terminally-muskrat.ngrok-free.app"

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

@ -399,27 +399,13 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
<div className="flex items-center"> <div className="flex items-center">
<div className="flex justify-between w-full"> <div className="flex justify-between w-full">
{/* Permission Status Text - Always Visible */} {/* 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 */} {/* Permission Controls - Always Visible */}
<div className="max-w-80 opacity-100 overflow-visible"> <div className="max-w-80 opacity-100 overflow-visible">
<div className="flex items-center space-x-3 pr-1.5"> <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-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 +414,17 @@ 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'
/> />
<FiEdit Allow Edit
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 */} {/* 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-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,20 +433,17 @@ 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"
/> />
<FiTrash Allow Delete
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 */} {/* 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="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"> <div className="bg-gray-800 text-white text-xs rounded-lg py-2 px-3 whitespace-nowrap">
Delete Permission 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 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>

View File

@ -130,48 +130,28 @@ 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 (
<div className="relative">
<input
type={type}
value={currentValue || ""}
placeholder={placeholder}
autoFocus
onFocus={() => handleFieldFocus(identifier, fieldName)}
onBlur={(e) => handleFieldBlur(recipient, fieldName, e.target.value)}
onChange={(e) => handleFieldChange(recipient, fieldName, e.target.value)}
onKeyPress={(e) => {
if (e.key === "Enter") {
e.currentTarget.blur();
}
}}
className={`w-full px-3 py-1 border ${error ? "border-red-500 placeholder-red-500 text-xs" : "border-gray-300"
} rounded-lg text-sm focus:outline-none focus:ring-0 focus:ring-gray-300 ${className}`}
/>
{/* {error && (
<span className="text-red-500 text-xs absolute left-0">{`${placeholder} is required`}</span>
)} */}
</div>
);
}
return ( return (
<span <div className="relative inline-block mx-3">
onClick={editable ? () => handleFieldFocus(identifier, fieldName) : undefined} <input
className={`${editable type={type}
? "cursor-pointer hover:bg-gray-100 rounded px-1 transition-colors" value={currentValue || ""}
: "cursor-not-allowed" placeholder={placeholder}
} ${showValue ? "text-gray-800" : "text-gray-400 italic"} ${className}`} onFocus={() => handleFieldFocus(identifier, fieldName)}
title={editable ? "Click to edit" : "Editing disabled"} onBlur={(e) => handleFieldBlur(recipient, fieldName, e.target.value)}
> onChange={(e) => handleFieldChange(recipient, fieldName, e.target.value)}
{showValue ? currentValue : placeholder} onKeyPress={(e) => {
</span> if (e.key === "Enter") {
e.currentTarget.blur();
}
}}
disabled={!editable}
className={`w-full px-4 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-sm ${className} ${!editable ? "bg-gray-100 cursor-not-allowed" : ""}`}
title={editable ? "Edit field" : "Editing disabled"}
/>
</div>
); );
}; };
@ -254,13 +234,13 @@ 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 items-center justify-between px-2 py-3 hover:bg-gray-50 transition-colors ${(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"> <div className="flex items-center gap-3 min-w-0">
@ -298,133 +278,122 @@ const RecipientCards = ({
{getInitials(`${recipient.firstName} ${recipient.lastName || ""}`)} {getInitials(`${recipient.firstName} ${recipient.lastName || ""}`)}
</div> </div>
<div className="min-w-0"> <div className="min-w-0">
<p className="font-semibold text-gray-800 truncate text-xs flex items-center gap-0.5"> <div className="grid grid-cols-12 gap-2 mb-2">
{renderEditableField(recipient, "firstName", "First Name")} <div className="col-span-6">
{renderEditableField(recipient, "lastName", "Last Name")} <p className="font-semibold text-gray-800 text-xs">
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && ( {renderEditableField(recipient, "roleName", "Role name")}
<span className="flex items-center gap-2"> </p>
<span className="text-gray-400 ">| Permissions granted :</span> </div>
<FiEdit <div className="col-span-6 flex items-center justify-end ">
className={`cursor-pointer h-3 w-3 ${recipient.allowSenderToEdit {transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && (
? "text-blue-500" <div className="flex items-center gap-4">
: "text-gray-400" {/* <span className="text-sm text-gray-600">Permissions granted:</span> */}
} hover:text-blue-800`}
onClick={() => <label className="flex items-center gap-1 text-sm text-gray-700">
dispatch( <input
updateRecipient({ type="checkbox"
...recipient, checked={recipient.allowSenderToEdit}
allowSenderToEdit: !recipient.allowSenderToEdit, onChange={() =>
uuid: getRecipientIdentifier(recipient), dispatch(
}) updateRecipient({
) ...recipient,
} allowSenderToEdit: !recipient.allowSenderToEdit,
/> uuid: getRecipientIdentifier(recipient),
<ImBin })
className={`cursor-pointer h-3 w-3 ${recipient.allowSenderToDelete )
? "text-red-500" }
: "text-gray-400" className="accent-blue-500"
} hover:text-red-700`} />
onClick={() => Allow Edit
dispatch( </label>
updateRecipient({
...recipient, <label className="flex items-center gap-1 text-sm text-gray-700">
allowSenderToDelete: !recipient.allowSenderToDelete, <input
uuid: getRecipientIdentifier(recipient), type="checkbox"
}) checked={recipient.allowSenderToDelete}
) onChange={() =>
} dispatch(
/> updateRecipient({
</span> ...recipient,
)} allowSenderToDelete: !recipient.allowSenderToDelete,
</p> uuid: getRecipientIdentifier(recipient),
<p className="text-xs text-gray-500 truncate flex items-center gap-1"> })
{renderEditableField(recipient, "email", "Recipient Email", "", "email")} | )
<span }
onClick={ className="accent-red-500"
isEditable(recipient) />
? () => handleFieldFocus(getRecipientIdentifier(recipient), "type") Allow Delete
: undefined </label>
} </div>
className={`${isEditable(recipient)
? "cursor-pointer hover:bg-gray-100"
: "cursor-not-allowed"
} rounded px-1 transition-colors`}
>
{recipient.type}
</span>
{(hasValue(recipient, "roleName") ||
transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) && (
<span>
{" | Role: "}
{renderEditableField(recipient, "roleName", "Role name")}
</span>
)} )}
{recipient.type === recipientType.INPERSONSIGNER && (
<> </div>
<span className="flex items-center"> </div>
<span>{" | Host Name: "}</span> <div className="grid grid-cols-12 gap-2 mb-2">
<div className="col-span-12">
<p className="font-semibold text-gray-800 text-xs flex items-center gap-1">
{renderEditableField(recipient, "firstName", "First Name")}
{renderEditableField(recipient, "lastName", "Last Name")}
{renderEditableField(recipient, "email", "Recipient Email", "", "email")}
</p>
</div>
</div>
{recipient.type === recipientType.INPERSONSIGNER && (
<div className="grid grid-cols-12 gap-2">
<div className="col-span-12">
<p className="font-semibold text-gray-800 text-xs flex items-center gap-1">
{renderEditableField(recipient, "hostName", "Host Name")} {renderEditableField(recipient, "hostName", "Host Name")}
<span>{" | Host Email: "}</span>
{renderEditableField(recipient, "hostEmail", "Host Email", "", "email")} {renderEditableField(recipient, "hostEmail", "Host Email", "", "email")}
</span> </p>
</>
)}
</p>
{editingField?.recipientId === getRecipientIdentifier(recipient) &&
editingField?.fieldName === "type" &&
isEditable(recipient) && (
<div className="flex items-center gap-2 mt-1">
<label className="flex items-center gap-1">
<input
type="radio"
name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.SIGNER}
checked={recipient.type === recipientType.SIGNER}
onChange={() =>
handleTypeChange(recipient, recipientType.SIGNER)
}
onBlur={() => setEditingField(null)}
className="accent-[var(--primary)]"
disabled={!isEditable(recipient)}
/>
<span className="text-xs">Signer</span>
</label>
<label className="flex items-center gap-1">
<input
type="radio"
name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.INPERSONSIGNER}
checked={recipient.type === recipientType.INPERSONSIGNER}
onChange={() =>
handleTypeChange(recipient, recipientType.INPERSONSIGNER)
}
onBlur={() => setEditingField(null)}
className="accent-[var(--primary)]"
disabled={!isEditable(recipient)}
/>
<span className="text-xs">In Person Signer</span>
</label>
<label className="flex items-center gap-1">
<input
type="radio"
name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.CC}
checked={recipient.type === recipientType.CC}
onChange={() =>
handleTypeChange(recipient, recipientType.CC)
}
onBlur={() => setEditingField(null)}
className="accent-[var(--primary)]"
disabled={!isEditable(recipient)}
/>
<span className="text-xs">CC</span>
</label>
</div> </div>
)} </div>
)}
<div className="flex items-center gap-2 my-1.5 mx-2">
<label className="flex items-center gap-1">
<input
type="radio"
name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.SIGNER}
checked={recipient.type === recipientType.SIGNER}
onChange={() => handleTypeChange(recipient, recipientType.SIGNER)}
onBlur={() => setEditingField(null)}
className="accent-[var(--primary)] w-3 h-3"
disabled={!isEditable(recipient)}
/>
<span className="text-sm">Signer</span>
</label>
<label className="flex items-center gap-1">
<input
type="radio"
name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.INPERSONSIGNER}
checked={recipient.type === recipientType.INPERSONSIGNER}
onChange={() => handleTypeChange(recipient, recipientType.INPERSONSIGNER)}
onBlur={() => setEditingField(null)}
className="accent-[var(--primary)] w-3 h-3"
disabled={!isEditable(recipient)}
/>
<span className="text-sm">In Person Signer</span>
</label>
<label className="flex items-center gap-1">
<input
type="radio"
name={`recipient-type-${getRecipientIdentifier(recipient)}`}
value={recipientType.CC}
checked={recipient.type === recipientType.CC}
onChange={() => handleTypeChange(recipient, recipientType.CC)}
onBlur={() => setEditingField(null)}
className="accent-[var(--primary)] w-3 h-3"
disabled={!isEditable(recipient)}
/>
<span className="text-sm">CC</span>
</label>
</div>
</div> </div>
</div> </div>
{signType !== "self-sign" && ( {signType !== "self-sign" && (
<div className="flex justify-between gap-2 items-center"> <div className="flex justify-end gap-2 items-center">
<button <button
type="button" type="button"
title="Remove recipient" title="Remove recipient"

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 {