step-1-form-edit-ui-input-field
This commit is contained in:
parent
d9f8cd58b0
commit
2eaa1ed3e1
5
.env
5
.env
|
|
@ -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://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"
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import "../styles/style.css";
|
||||
// import "../styles/style.css";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import LoginForm from "./LoginForm";
|
||||
import RegisterForm from "./RegisterForm";
|
||||
|
|
@ -37,7 +37,7 @@ function UserAuthUI() {
|
|||
return (
|
||||
<div className="max-h-screen bg-white flex">
|
||||
{/* 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">
|
||||
{/* Logos */}
|
||||
<div className="flex flex-col items-center gap-2 space-y-3">
|
||||
|
|
|
|||
|
|
@ -399,27 +399,13 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
|
|||
<div className="flex items-center">
|
||||
<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 */}
|
||||
<div className="relative group">
|
||||
<label
|
||||
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'
|
||||
}`}
|
||||
>
|
||||
<label className="flex items-center gap-1 text-sm text-gray-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={recipient.allowSenderToEdit}
|
||||
|
|
@ -428,30 +414,17 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
|
|||
}
|
||||
onFocus={() => setOpenContactModal(true)}
|
||||
onBlur={handleContactModalBlur}
|
||||
className="absolute w-full h-full opacity-0 cursor-pointer"
|
||||
className='accent-blue-500'
|
||||
/>
|
||||
<FiEdit
|
||||
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>
|
||||
Allow Edit
|
||||
</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>
|
||||
|
||||
{/* Delete Permission */}
|
||||
<div className="relative group">
|
||||
<label
|
||||
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'
|
||||
}`}
|
||||
>
|
||||
<label className="flex items-center gap-1 text-sm text-gray-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={recipient.allowSenderToDelete}
|
||||
|
|
@ -460,20 +433,17 @@ const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase,
|
|||
}
|
||||
onFocus={() => setOpenContactModal(true)}
|
||||
onBlur={handleContactModalBlur}
|
||||
className="absolute w-full h-full opacity-0 cursor-pointer"
|
||||
className="accent-red-500"
|
||||
/>
|
||||
<FiTrash
|
||||
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>
|
||||
Allow Delete
|
||||
</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="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>
|
||||
|
|
|
|||
|
|
@ -130,48 +130,28 @@ const RecipientCards = ({
|
|||
) => {
|
||||
const identifier = getRecipientIdentifier(recipient);
|
||||
const currentValue = getCurrentValue(recipient, fieldName);
|
||||
const isEditing = editingField?.recipientId === identifier && editingField?.fieldName === fieldName;
|
||||
const showValue = hasValue(recipient, fieldName);
|
||||
const error = errors[identifier]?.[fieldName];
|
||||
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 (
|
||||
<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>
|
||||
<div className="relative inline-block mx-3">
|
||||
<input
|
||||
type={type}
|
||||
value={currentValue || ""}
|
||||
placeholder={placeholder}
|
||||
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();
|
||||
}
|
||||
}}
|
||||
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 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) => (
|
||||
<div
|
||||
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
|
||||
? "bg-neutral-100 opacity-40"
|
||||
: ""
|
||||
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"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
|
|
@ -298,133 +278,122 @@ const RecipientCards = ({
|
|||
{getInitials(`${recipient.firstName} ${recipient.lastName || ""}`)}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="font-semibold text-gray-800 truncate text-xs flex items-center gap-0.5">
|
||||
{renderEditableField(recipient, "firstName", "First Name")}
|
||||
{renderEditableField(recipient, "lastName", "Last Name")}
|
||||
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && (
|
||||
<span className="flex items-center gap-2">
|
||||
<span className="text-gray-400 ">| Permissions granted :</span>
|
||||
<FiEdit
|
||||
className={`cursor-pointer h-3 w-3 ${recipient.allowSenderToEdit
|
||||
? "text-blue-500"
|
||||
: "text-gray-400"
|
||||
} hover:text-blue-800`}
|
||||
onClick={() =>
|
||||
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"
|
||||
} hover:text-red-700`}
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
updateRecipient({
|
||||
...recipient,
|
||||
allowSenderToDelete: !recipient.allowSenderToDelete,
|
||||
uuid: getRecipientIdentifier(recipient),
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 truncate flex items-center gap-1">
|
||||
{renderEditableField(recipient, "email", "Recipient Email", "", "email")} |
|
||||
<span
|
||||
onClick={
|
||||
isEditable(recipient)
|
||||
? () => handleFieldFocus(getRecipientIdentifier(recipient), "type")
|
||||
: undefined
|
||||
}
|
||||
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>
|
||||
<div className="grid grid-cols-12 gap-2 mb-2">
|
||||
<div className="col-span-6">
|
||||
<p className="font-semibold text-gray-800 text-xs">
|
||||
{renderEditableField(recipient, "roleName", "Role name")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="col-span-6 flex items-center justify-end ">
|
||||
{transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES && (
|
||||
<div className="flex items-center gap-4">
|
||||
{/* <span className="text-sm text-gray-600">Permissions granted:</span> */}
|
||||
|
||||
<label className="flex items-center gap-1 text-sm text-gray-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={recipient.allowSenderToEdit}
|
||||
onChange={() =>
|
||||
dispatch(
|
||||
updateRecipient({
|
||||
...recipient,
|
||||
allowSenderToEdit: !recipient.allowSenderToEdit,
|
||||
uuid: getRecipientIdentifier(recipient),
|
||||
})
|
||||
)
|
||||
}
|
||||
className="accent-blue-500"
|
||||
/>
|
||||
Allow Edit
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-1 text-sm text-gray-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={recipient.allowSenderToDelete}
|
||||
onChange={() =>
|
||||
dispatch(
|
||||
updateRecipient({
|
||||
...recipient,
|
||||
allowSenderToDelete: !recipient.allowSenderToDelete,
|
||||
uuid: getRecipientIdentifier(recipient),
|
||||
})
|
||||
)
|
||||
}
|
||||
className="accent-red-500"
|
||||
/>
|
||||
Allow Delete
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{recipient.type === recipientType.INPERSONSIGNER && (
|
||||
<>
|
||||
<span className="flex items-center">
|
||||
<span>{" | Host Name: "}</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<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")}
|
||||
<span>{" | Host Email: "}</span>
|
||||
{renderEditableField(recipient, "hostEmail", "Host Email", "", "email")}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</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>
|
||||
</p>
|
||||
</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>
|
||||
|
||||
{signType !== "self-sign" && (
|
||||
<div className="flex justify-between gap-2 items-center">
|
||||
<div className="flex justify-end gap-2 items-center">
|
||||
<button
|
||||
type="button"
|
||||
title="Remove recipient"
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
|
|
|
|||
Loading…
Reference in New Issue