jai #7

Merged
jaipandey merged 2 commits from jai into main 2025-07-25 14:30:19 +00:00
12 changed files with 409 additions and 116 deletions

View File

@ -300,7 +300,7 @@ const CommonNav: React.FC<AccountNavProps> = () => {
aria-expanded={open} aria-expanded={open}
aria-haspopup="true" aria-haspopup="true"
> >
<div className="w-8 h-8 rounded-full overflow-hidden bg-gradient-to-br from-green-500 to-blue-600 flex items-center justify-center text-white font-semibold text-sm shadow-md"> <div className="w-8 h-8 rounded-full overflow-hidden bg-[var(--primaryLight2)] flex items-center justify-center text-white font-semibold text-sm shadow-md">
{user ? ( {user ? (
<span className="w-full h-full object-cover p-1.5 font-bold"> <span className="w-full h-full object-cover p-1.5 font-bold">
{(user?.name?.slice(0, 2)).toUpperCase()} {(user?.name?.slice(0, 2)).toUpperCase()}

View File

@ -39,6 +39,11 @@ const ProcessStepOne = () => {
dispatch(toggleToTemplates()); dispatch(toggleToTemplates());
} }
const [editCase , setEditCase] = useState<string>("")
const [editRecipient , setEditRecipient] = useState({})
// if (!accountId || !transactionId) { // if (!accountId || !transactionId) {
// window.location.href = "/"; // window.location.href = "/";
// return null; // return null;
@ -54,6 +59,11 @@ const ProcessStepOne = () => {
console.log("selectedRecipients", selectedRecipients) console.log("selectedRecipients", selectedRecipients)
useEffect(() => { useEffect(() => {
(async () => {
const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`)
console.log(res.data);
})()
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId })); selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId })); selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId }));
}, []) }, [])
@ -149,7 +159,9 @@ const ProcessStepOne = () => {
accessCodeDelivery: true, accessCodeDelivery: true,
language: "en", language: "en",
name: `${recipient.firstName} ${recipient.lastName}`, name: `${recipient.firstName} ${recipient.lastName}`,
roleName: recipient.roleName roleName: recipient.roleName,
allowSenderToEdit: recipient.allowSenderToEdit ,
allowSenderToDelete: recipient.allowSenderToDelete,
})); }));
let recipientsDataTemp = recipientsData; let recipientsDataTemp = recipientsData;
@ -291,9 +303,9 @@ const ProcessStepOne = () => {
< section className="mt-8"> < section className="mt-8">
<h2 className="text-lg font-medium mb-4 pt-6 border-t text-[var(--processStepOneTextHead)]">Signers</h2> <h2 className="text-lg font-medium mb-4 pt-6 border-t text-[var(--processStepOneTextHead)]">Signers</h2>
<div className="flex flex-col gap-4 align-start"> <div className="flex flex-col gap-4 align-start">
<RecipientCards /> <RecipientCards transactionTemplateToggle={transactionTemplateToggle} setEditRecipient={setEditRecipient} setEditCase={setEditCase}/>
{/* {signType !== "self-sign" && <RecipientAddCard />} */} {/* {signType !== "self-sign" && <RecipientAddCard />} */}
<RecipientAddCard transactionTemplateToggle={transactionTemplateToggle} /> <RecipientAddCard transactionTemplateToggle={transactionTemplateToggle} editRecipient={editRecipient} editCase={editCase} setEditRecipient={setEditRecipient} setEditCase={setEditCase}/>
</div> </div>
</section> </section>
} }

View File

@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { FaPlus } from "react-icons/fa"; import { FaPlus } from "react-icons/fa";
import { addRecipient, Recipient, recipientType } from "../../../store/slices/selectedRecipientsSlice"; import { addRecipient, Recipient, recipientType, updateRecipient } from "../../../store/slices/selectedRecipientsSlice";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { AppDispatch } from "../../../store/store"; import { AppDispatch } from "../../../store/store";
import api from "../../../config/api"; import api from "../../../config/api";
@ -8,6 +8,8 @@ import ContactModal from "./ContactModal";
import useDebouncedEffect from "../../../utlity/useDebounce"; import useDebouncedEffect from "../../../utlity/useDebounce";
import { IoIosSettings } from "react-icons/io"; import { IoIosSettings } from "react-icons/io";
import { FiEdit, FiTrash } from "react-icons/fi"; import { FiEdit, FiTrash } from "react-icons/fi";
import { v4 as uuidv4 } from 'uuid';
interface ContactType { interface ContactType {
id: string; id: string;
@ -21,7 +23,8 @@ export interface ContactTypeObj {
contacts: ContactType[]; contacts: ContactType[];
} }
const RecipientAddCard = ({ transactionTemplateToggle }) => {
const RecipientAddCard = ({ transactionTemplateToggle, editRecipient, editCase ,setEditRecipient, setEditCase }) => {
const [contactData, setContactData] = useState<ContactTypeObj>({ type: "", contacts: [] }); const [contactData, setContactData] = useState<ContactTypeObj>({ type: "", contacts: [] });
const [openContactModal, setOpenContactModal] = useState(false); const [openContactModal, setOpenContactModal] = useState(false);
@ -29,29 +32,79 @@ const RecipientAddCard = ({ transactionTemplateToggle }) => {
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const formRef = useRef<HTMLFormElement | null>(null); const formRef = useRef<HTMLFormElement | null>(null);
const [recipient, setRecipients] = useState<Recipient>({ firstName: "", lastName: "", email: "", hostName: "", hostEmail: "", roleName: "", type: recipientType.SIGNER, allowSenderToEdit: Boolean, allowSenderToRemove: Boolean }); const [recipient, setRecipients] = useState<Recipient>({ uuid:null, newOne:false, firstName: "", lastName: "", email: "", hostName: "", hostEmail: "", roleName: "", type: recipientType.SIGNER, allowSenderToEdit: false, allowSenderToDelete: false });
const [showAdvanceSettings, setShowAdvanceSettings] = useState(false) const [showAdvanceSettings, setShowAdvanceSettings] = useState(false)
console.log(recipient) console.log(recipient)
useEffect(() => {
if (editCase === "Edit" && editRecipient) {
setRecipients({
// id:editRecipient.id,
firstName: editRecipient.firstName || "",
lastName: editRecipient.lastName || "",
email: editRecipient.email || "",
hostName: editRecipient.hostName || "",
hostEmail: editRecipient.hostEmail || "",
roleName: editRecipient.roleName || "",
type: editRecipient.type || recipientType.SIGNER,
allowSenderToEdit: editRecipient.allowSenderToEdit ?? false,
allowSenderToDelete: editRecipient.allowSenderToDelete ?? false,
uuid: String(editRecipient?.id ?? editRecipient?.uuid ?? ''),
newOne:editRecipient.newOne ?? false
});
}
}, [editCase, editRecipient]);
const handleRecipientAdd = (e: React.FormEvent<HTMLFormElement>) => { const handleRecipientAdd = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
if (recipient.lastName === "" || recipient.email === "" || !recipient.type) return; console.log("recipientrecipient",recipient)
// Validate Email Format if (!recipient.lastName || !recipient.email || !recipient.type) return;
// ✅ Email format validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(recipient.email)) { if (!emailRegex.test(recipient.email)) {
console.log("Invalid email format"); console.log("Invalid email format");
return; return;
} }
// Validation Ends
dispatch(addRecipient(recipient)); if (editCase === 'Edit') {
setRecipients({ firstName: "", lastName: "", email: "", hostName: "", hostEmail: "", roleName: "", type: recipientType.SIGNER, allowSenderToEdit: false, allowSenderToRemove: false }); dispatch(updateRecipient(recipient));
formRef.current?.reset(); } else {
dispatch(addRecipient({
...recipient,
uuid:uuidv4(),
newOne:true
}));
} }
// ✅ Reset state and form
setRecipients({
firstName: "",
lastName: "",
email: "",
hostName: "",
hostEmail: "",
roleName: "",
type: recipientType.SIGNER,
allowSenderToEdit: false,
allowSenderToDelete: false,
uuid:"",
newOne:false
});
// setRecipients(null),
setEditCase("")
formRef.current?.reset();
};
// useEffect(() => { // useEffect(() => {
// if (!recipient.firstName.length) return; // if (!recipient.firstName.length) return;
@ -133,10 +186,10 @@ const RecipientAddCard = ({ transactionTemplateToggle }) => {
} overflow-hidden`} } overflow-hidden`}
> >
<div className="text-sm text-gray-600"> <div className="text-sm text-gray-600">
{recipient.allowSenderToEdit && recipient.allowSenderToRemove && "Full permissions granted"} {recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Full permissions granted"}
{recipient.allowSenderToEdit && !recipient.allowSenderToRemove && "Edit permission granted"} {recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "Edit permission granted"}
{!recipient.allowSenderToEdit && recipient.allowSenderToRemove && "Delete permission granted"} {!recipient.allowSenderToEdit && recipient.allowSenderToDelete && "Delete permission granted"}
{!recipient.allowSenderToEdit && !recipient.allowSenderToRemove && "No permissions granted"} {!recipient.allowSenderToEdit && !recipient.allowSenderToDelete && "No permissions granted"}
</div> </div>
</div> </div>
{/* Animated Permission Controls */} {/* Animated Permission Controls */}
@ -178,23 +231,23 @@ const RecipientAddCard = ({ transactionTemplateToggle }) => {
{/* Delete Permission */} {/* Delete Permission */}
<div className="relative group"> <div className="relative group">
<label <label
className={`relative flex items-center justify-center w-6 h-6 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToRemove className={`relative flex items-center justify-center w-6 h-6 border-2 rounded-lg cursor-pointer transition-all duration-300 transform hover:scale-105 ${recipient.allowSenderToDelete
? 'bg-red-100 border-red-500 shadow-lg' ? 'bg-red-100 border-red-500 shadow-lg'
: 'bg-white border-gray-300 hover:border-red-400' : 'bg-white border-gray-300 hover:border-red-400'
}`} }`}
> >
<input <input
type="checkbox" type="checkbox"
checked={recipient.allowSenderToRemove} checked={recipient.allowSenderToDelete}
onChange={(e) => onChange={(e) =>
setRecipients({ ...recipient, allowSenderToRemove: e.target.checked }) setRecipients({ ...recipient, allowSenderToDelete: e.target.checked })
} }
onFocus={() => setOpenContactModal(true)} onFocus={() => setOpenContactModal(true)}
onBlur={handleContactModalBlur} onBlur={handleContactModalBlur}
className="absolute w-full h-full opacity-0 cursor-pointer" className="absolute w-full h-full opacity-0 cursor-pointer"
/> />
<FiTrash <FiTrash
className={`w-3 h-3 pointer-events-none transition-all duration-300 ${recipient.allowSenderToRemove ? 'text-red-600' : 'text-gray-400' className={`w-3 h-3 pointer-events-none transition-all duration-300 ${recipient.allowSenderToDelete ? 'text-red-600' : 'text-gray-400'
}`} }`}
/> />
</label> </label>
@ -332,7 +385,7 @@ const RecipientAddCard = ({ transactionTemplateToggle }) => {
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 gap-2 bg-[var(--primary)] hover:bg-[var(--primaryLight2)] text-white text-sm font-semibold px-5 py-2 rounded-md transition"
> >
<FaPlus size={14} /> Add Recipient <FaPlus size={14} /> {editCase === "Edit" ? "Edit Recipient" : "Add Recipient"}
</button> </button>
</div> </div>
</form> </form>

View File

@ -13,6 +13,7 @@ import { useState } from "react";
import SigningOrderDiagram from "../../../SigningOrderDiagram "; import SigningOrderDiagram from "../../../SigningOrderDiagram ";
import { IoCloseOutline } from "react-icons/io5"; import { IoCloseOutline } from "react-icons/io5";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { FiEdit } from "react-icons/fi";
const getInitials = (name: string) => { const getInitials = (name: string) => {
if (!name) return ""; if (!name) return "";
@ -23,7 +24,13 @@ const getInitials = (name: string) => {
.toUpperCase(); .toUpperCase();
}; };
const RecipientCards = () => { type CardsData = {
setEditRecipient: (recipient: any) => void; // Replace `any` with the actual type if known
setEditCase: (string: any) => void;
transactionTemplateToggle: string
};
const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateToggle }: CardsData) => {
const templateId = useParams<{ templateId: string }>().templateId; const templateId = useParams<{ templateId: string }>().templateId;
let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>(); let { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>();
@ -34,7 +41,7 @@ const RecipientCards = () => {
} }
const recipients = useSelector((state: RootState) => state.selectedRecipients.recipients); const recipients = useSelector((state: RootState) => state.selectedRecipients.recipients);
console.log("recipients.length",recipients) console.log("recipients.length", recipients)
// const signingOrder = useSelector((state: RootState) => state.selectedRecipients.signingOrder); // const signingOrder = useSelector((state: RootState) => state.selectedRecipients.signingOrder);
const signType = useSelector((state: RootState) => state.selectedDocuments.signType); const signType = useSelector((state: RootState) => state.selectedDocuments.signType);
@ -44,15 +51,24 @@ const RecipientCards = () => {
dispatch(updateRecipientOrder({ id, routingOrder: value })); dispatch(updateRecipientOrder({ id, routingOrder: value }));
}; };
const handleEditRecipient = (recipient) => {
// alert(JSON.stringify(recipient))
setEditCase('Edit')
setEditRecipient(recipient)
}
const handleRemoveRecipient = (recipient) => { const handleRemoveRecipient = (recipient) => {
if (!accountId || !transactionId) return; if (!accountId || !transactionId) return;
// dispatch(removeSelectedRecipient(recipient)) if (recipient.uuid) {
dispatch(removeSelectedRecipient(recipient))
} else {
dispatch(removeRecipientAsync({ dispatch(removeRecipientAsync({
recipientId: recipient.id, recipientId: recipient.id,
email: recipient.email, email: recipient.email,
accountId: accountId, accountId: accountId,
transactionId: transactionId, transactionId: transactionId,
})) }))
}
if (recipients.length === 2) { if (recipients.length === 2) {
let leftRecipient = recipients.filter((obj) => { let leftRecipient = recipients.filter((obj) => {
if ("id" in obj && "id" in recipient) { if ("id" in obj && "id" in recipient) {
@ -144,14 +160,45 @@ const RecipientCards = () => {
</div> </div>
{signType !== "self-sign" && ( {signType !== "self-sign" && (
<div className="flex justify-between gap-2 items-center">
{/* Edit Button */}
<button <button
type="button" type="button"
title="Edit recipient"
aria-label={`Edit recipient ${recipient.firstName}`}
onClick={() => handleEditRecipient(recipient)}
disabled={
// For templates: always enabled (never disabled)
['templates'].includes(transactionTemplateToggle)
? false
: // For transactions: disabled if not newOne AND not allowed to edit
(!recipient.newOne && !recipient.allowSenderToEdit)
}
className="text-gray-400 hover:text-blue-600 transition-colors cursor-pointer disabled:opacity-50"
>
<FiEdit size={16} />
</button>
{/* Delete Button */}
<button
type="button"
title="Remove recipient"
aria-label={`Remove recipient ${recipient.firstName}`} aria-label={`Remove recipient ${recipient.firstName}`}
onClick={() => handleRemoveRecipient(recipient)} onClick={() => handleRemoveRecipient(recipient)}
className="text-gray-400 hover:text-red-600 transition-colors" disabled={
// For templates: always enabled (never disabled)
['templates'].includes(transactionTemplateToggle)
? false
: // For transactions: disabled if not newOne AND not allowed to delete
(!recipient.newOne && !recipient.allowSenderToDelete)
}
className="text-gray-400 hover:text-red-600 transition-colors cursor-pointer disabled:opacity-50"
> >
<ImBin size={16} /> <ImBin size={16} />
</button> </button>
</div>
)} )}
</div> </div>
))} ))}

View File

@ -999,6 +999,7 @@ const handleGroupBorderPosition = (groupElements: NodeListOf<HTMLElement>, conta
// NEW DIRECTIONAL MOVEMENT HANDLER - START // NEW DIRECTIONAL MOVEMENT HANDLER - START
const handleDirectionalMove = (direction: 'up' | 'down' | 'left' | 'right', stepSize: number = 5) => { const handleDirectionalMove = (direction: 'up' | 'down' | 'left' | 'right', stepSize: number = 5) => {
if (!selectedTag) return; if (!selectedTag) return;
@ -1037,11 +1038,44 @@ const handleGroupBorderPosition = (groupElements: NodeListOf<HTMLElement>, conta
}); });
}; };
// Create a wrapper that matches DirectionalControls' expected signature
const directionalControlsHandler = (direction: 'up' | 'down' | 'left' | 'right') => { const directionalControlsHandler = (direction: 'up' | 'down' | 'left' | 'right') => {
handleDirectionalMove(direction, 5); // Use default stepSize of 5 handleDirectionalMove(direction, 5); // Use default stepSize of 5
}; };
// Add this new handler function to your parent component
const handleDirectPositionChange = (newLeft: number, newTop: number) => {
console.log("handleDirectPositionChange",newLeft,newTop)
if (!selectedTag) return;
const { key, index } = selectedTag;
const currentItem = droppedItems[key]?.[index];
if (!currentItem) return;
// Ensure values are not negative
const clampedLeft = Math.max(0, newLeft);
const clampedTop = Math.max(0, newTop);
setDroppedItems({
...droppedItems,
[key]: Array.isArray(droppedItems[key])
? droppedItems[key].map((item, i) =>
i === index
? {
...item,
dimensions: {
...item.dimensions,
left: clampedLeft,
top: clampedTop
},
update: true
}
: item
)
: [],
});
};
return ( return (
<> <>
{/* Center Doc Container - START */} {/* Center Doc Container - START */}
@ -1201,6 +1235,7 @@ const handleGroupBorderPosition = (groupElements: NodeListOf<HTMLElement>, conta
{selectedTag && <RightSideBar selectedTag={droppedItems[selectedTag.key][selectedTag.index]} setDroppedItems={setDroppedItems} selTagKey={selectedTag.key} selTagIndx={selectedTag.index} DirectionalControlsProps={{ {selectedTag && <RightSideBar selectedTag={droppedItems[selectedTag.key][selectedTag.index]} setDroppedItems={setDroppedItems} selTagKey={selectedTag.key} selTagIndx={selectedTag.index} DirectionalControlsProps={{
onMove: directionalControlsHandler, onMove: directionalControlsHandler,
onPositionChange: handleDirectPositionChange,
disabled: false, disabled: false,
stepSize: 5, stepSize: 5,
className: '' className: ''

View File

@ -1,8 +1,9 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { FaArrowUp, FaArrowDown, FaArrowLeft, FaArrowRight, FaRegCircle } from 'react-icons/fa'; import { FaArrowUp, FaArrowDown, FaArrowLeft, FaArrowRight } from 'react-icons/fa';
interface DirectionalControlsProps { interface DirectionalControlsProps {
onMove: (direction: 'up' | 'down' | 'left' | 'right', stepSize?: number) => void; onMove: (direction: 'up' | 'down' | 'left' | 'right', stepSize?: number) => void;
onPositionChange?: (left: number, top: number) => void;
disabled?: boolean; disabled?: boolean;
stepSize?: number; stepSize?: number;
className?: string; className?: string;
@ -16,23 +17,67 @@ interface DirectionalControlsProps {
const DirectionalControls: React.FC<DirectionalControlsProps> = ({ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
onMove, onMove,
onPositionChange,
disabled = false, disabled = false,
stepSize = 1, stepSize = 1,
className = '', className = '',
selectedType, selectedType,
}) => { }) => {
const onMoveRef = useRef(onMove); const onMoveRef = useRef(onMove);
const [leftValue, setLeftValue] = useState('');
const [topValue, setTopValue] = useState('');
useEffect(() => { useEffect(() => {
onMoveRef.current = onMove; onMoveRef.current = onMove;
}, [onMove]); }, [onMove]);
useEffect(() => {
const { top = 0, left = 0 } = selectedType || {};
setLeftValue(Math.round(left).toString());
setTopValue(Math.round(top).toString());
}, [selectedType]);
const handleMove = (direction: 'up' | 'down' | 'left' | 'right') => { const handleMove = (direction: 'up' | 'down' | 'left' | 'right') => {
if (!disabled) { if (!disabled) {
onMoveRef.current(direction, stepSize); onMoveRef.current(direction, stepSize);
} }
}; };
const handlePositionInputChange = (type: 'left' | 'top', value: string) => {
if (type === 'left') {
setLeftValue(value);
} else {
setTopValue(value);
}
};
const handlePositionInputBlur = (type: 'left' | 'top') => {
if (!onPositionChange) return;
const numericValue = parseFloat(type === 'left' ? leftValue : topValue);
if (isNaN(numericValue)) {
const { top = 0, left = 0 } = selectedType || {};
if (type === 'left') {
setLeftValue(Math.round(left).toString());
} else {
setTopValue(Math.round(top).toString());
}
return;
}
const { top = 0, left = 0 } = selectedType || {};
const newLeft = type === 'left' ? numericValue : left;
const newTop = type === 'top' ? numericValue : top;
onPositionChange(newLeft, newTop);
};
const handleKeyPress = (e: React.KeyboardEvent, type: 'left' | 'top') => {
if (e.key === 'Enter') {
handlePositionInputBlur(type);
}
};
useEffect(() => { useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => { const handleKeyDown = (event: KeyboardEvent) => {
if (disabled) return; if (disabled) return;
@ -66,55 +111,111 @@ const DirectionalControls: React.FC<DirectionalControlsProps> = ({
${disabled ${disabled
? 'bg-gray-100 text-gray-400 cursor-not-allowed' ? 'bg-gray-100 text-gray-400 cursor-not-allowed'
: 'bg-white text-gray-600 hover:bg-blue-100 active:bg-blue-200 cursor-pointer'} : 'bg-white text-gray-600 hover:bg-blue-100 active:bg-blue-200 cursor-pointer'}
flex items-center justify-center w-6 h-6 flex items-center justify-center w-6 h-6 `;
`;
const inputClass = `
w-12 h-6 text-[10px] text-center border rounded px-1 bg-white
${disabled
? 'bg-gray-100 text-gray-400 cursor-not-allowed border-gray-300'
: 'text-gray-600 border-gray-300 focus:border-blue-400 focus:outline-none'}
`;
const { top = 0, left = 0, width = 0, height = 0 } = selectedType || {}; const { top = 0, left = 0, width = 0, height = 0 } = selectedType || {};
const right = left + width;
const bottom = top + height;
return ( return (
<div className={`grid grid-cols-3 grid-rows-1 text-[10px] text-gray-700 ${className}`}> <div className={`flex flex-col items-center space-y-4 text-[10px] text-gray-700 ${className}`}>
{/* Top Row */} {/* Top Button */}
<div></div> <div className="flex justify-center me-4">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<button onClick={() => handleMove('up')} disabled={disabled} className={buttonClass} title="Move up" type="button"> <button
onClick={() => handleMove('up')}
disabled={disabled}
className={buttonClass}
title="Move up"
type="button"
>
<FaArrowUp size={12} /> <FaArrowUp size={12} />
</button> </button>
<span className="mt-1">Top: {Math.round(top)}px</span> <span className="mt-1">Top</span>
</div>
</div> </div>
<div></div>
{/* Middle Row */} {/* Middle Row: Left - Center (Inputs) - Right */}
<div className="flex flex-col items-center justify-center"> <div className="flex items-center space-x-1">
<button onClick={() => handleMove('left')} disabled={disabled} className={buttonClass} title="Move left" type="button"> {/* Left Button */}
<div className="flex flex-col items-center">
<button
onClick={() => handleMove('left')}
disabled={disabled}
className={buttonClass}
title="Move left"
type="button"
>
<FaArrowLeft size={12} /> <FaArrowLeft size={12} />
</button> </button>
<span className="mt-1">Left: {Math.round(left)}px</span> <span className="mt-1">Left</span>
</div> </div>
<div className="w-8 h-8 flex items-center justify-center text-xs text-gray-400 ps-5"><FaRegCircle/></div> {/* Center Panel */}
<div className="relative flex items-center justify-center bg-white rounded-lg px-1 py-2 w-24">
{/* Floating dimensions tooltip */}
<div className="absolute -top-2 left-1/2 -translate-x-1/2 px-2 py-[1px] text-[10px] font-mono text-black z-10 rounded-sm flex items-center gap-[2px]">
<input
type="number"
value={leftValue}
onChange={(e) => handlePositionInputChange('left', e.target.value)}
onBlur={() => handlePositionInputBlur('left')}
onKeyPress={(e) => handleKeyPress(e, 'left')}
disabled={disabled}
className="w-[40px] h-[16px] text-[10px] text-center border-none focus:outline-none text-black font-mono"
/>
<span className="mx-[1px]">×</span>
<input
type="number"
value={topValue}
onChange={(e) => handlePositionInputChange('top', e.target.value)}
onBlur={() => handlePositionInputBlur('top')}
onKeyPress={(e) => handleKeyPress(e, 'top')}
disabled={disabled}
className="w-[40px] h-[16px] text-[10px] text-center border-none focus:outline-none text-black font-mono"
/>
</div>
</div>
<div className="flex flex-col items-center justify-center">
<button onClick={() => handleMove('right')} disabled={disabled} className={buttonClass} title="Move right" type="button"> {/* Right Button */}
<div className="flex flex-col items-center">
<button
onClick={() => handleMove('right')}
disabled={disabled}
className={buttonClass}
title="Move right"
type="button"
>
<FaArrowRight size={12} /> <FaArrowRight size={12} />
</button> </button>
{/* <span className="mt-1">Right: {Math.round(right)}px</span> */} <span className="mt-1">Right</span>
</div>
</div> </div>
{/* Bottom Row */} {/* Bottom Button */}
<div></div> <div className="flex justify-center me-4">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<button onClick={() => handleMove('down')} disabled={disabled} className={buttonClass} title="Move down" type="button"> <button
onClick={() => handleMove('down')}
disabled={disabled}
className={buttonClass}
title="Move down"
type="button"
>
<FaArrowDown size={12} /> <FaArrowDown size={12} />
</button> </button>
{/* <span className="mt-1">Bottom: {Math.round(bottom)}px</span> */} <span className="mt-1">Bottom</span>
</div>
</div> </div>
<div></div>
</div> </div>
); );
}; };
export default DirectionalControls; export default DirectionalControls;

View File

@ -180,16 +180,26 @@ const RightSideBar: React.FC<DroppedItemProps> = ({ selectedTag, setDroppedItems
if (!is24Hrs) { if (!is24Hrs) {
val = timeFormats[1].format val = timeFormats[1].format
} }
setDroppedItems((prev) => ( console.log("val", val)
{
setDroppedItems((prev) => {
const updatedArray = Array.isArray(prev[selTagKey])
? prev[selTagKey].map((item, i) => {
if (i === selTagIndx) {
const updatedItem = { ...item, [changeTo]: changeWith + " " + val, update: true };
console.log('Updating item at index', i, 'with:', updatedItem);
return updatedItem;
}
return item;
})
: [];
return {
...prev, ...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array [selTagKey]: updatedArray,
? prev[selTagKey].map((item, i) => };
i === selTagIndx ? { ...item, [changeTo]: changeWith + " " + val, update: true } : item });
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
} else { } else {
setDroppedItems((prev) => { setDroppedItems((prev) => {
@ -397,7 +407,7 @@ const RightSideBar: React.FC<DroppedItemProps> = ({ selectedTag, setDroppedItems
{ {(selectedTag.type.toLowerCase() !== TagsTypes.SIGNATURE && selectedTag.type.toLowerCase() !== TagsTypes.INITIALS) &&
<div className=""> <div className="">
<div className="flex items-center justify-between mr-2 cursor-pointer" <div className="flex items-center justify-between mr-2 cursor-pointer"
onClick={() => setStyleOpen(!styleOpen)} onClick={() => setStyleOpen(!styleOpen)}

View File

@ -86,6 +86,7 @@ const TemporalDateAttr: React.FC<TemporalDateAttrInt> = ({ subType, format, drop
val = val + " " + timeFormats[1].format; val = val + " " + timeFormats[1].format;
} }
} }
console.log('line 89' , val )
return ( return (
<div <div
key={indx} key={indx}

View File

@ -55,7 +55,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
getAllSignatures, getAllSignatures,
editingSignature editingSignature
}) => { }) => {
const [activeTab, setActiveTab] = useState<'TYPE' | 'DRAW' | 'UPLOAD' | 'SELECT'>('TYPE'); const [activeTab, setActiveTab] = useState<'TYPE' | 'DRAW' | 'UPLOAD' >('TYPE');
const [fullName, setFullName] = useState(''); const [fullName, setFullName] = useState('');
const [initials, setInitials] = useState(''); const [initials, setInitials] = useState('');
const [isSubmitting, setIsSubmitting] = useState<boolean>(false); const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
@ -110,7 +110,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
{ id: 'TYPE', label: 'TYPE', icon: <GrCheckboxSelected className="w-4 h-4" /> }, { id: 'TYPE', label: 'TYPE', icon: <GrCheckboxSelected className="w-4 h-4" /> },
{ id: 'DRAW', label: 'DRAW', icon: <AiOutlineEdit className="w-5 h-5" /> }, { id: 'DRAW', label: 'DRAW', icon: <AiOutlineEdit className="w-5 h-5" /> },
{ id: 'UPLOAD', label: 'UPLOAD', icon: <AiOutlineUpload className="w-5 h-5" /> }, { id: 'UPLOAD', label: 'UPLOAD', icon: <AiOutlineUpload className="w-5 h-5" /> },
{ id: 'SELECT', label: 'SELECT', icon: <GrCheckboxSelected className="w-4 h-4" /> }, // { id: 'SELECT', label: 'SELECT', icon: <GrCheckboxSelected className="w-4 h-4" /> },
]; ];
// Initialize form with editing signature data // Initialize form with editing signature data
@ -394,14 +394,14 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
</div> </div>
); );
case 'SELECT': // case 'SELECT':
return ( // return (
<div className="h-full flex flex-col"> // <div className="h-full flex flex-col">
<div className="mb-6"> // <div className="mb-6">
<h2 className="text-xl font-semibold text-gray-900 mb-2">Select Signature</h2> // <h2 className="text-xl font-semibold text-gray-900 mb-2">Select Signature</h2>
</div> // </div>
</div> // </div>
); // );
default: default:
return null; return null;
} }

View File

@ -232,7 +232,7 @@ const SignatureManager: React.FC = () => {
{/* Empty State (if no signatures) */} {/* Empty State (if no signatures) */}
{signatures.length === 0 && ( {signatures.length === 0 && (
<div className="bg-white rounded-xl shadow-lg p-12 text-center mt-8"> <div className=" rounded-xl shadow-lg p-12 text-center mt-8">
<div className="text-gray-400 mb-4"> <div className="text-gray-400 mb-4">
<FiEdit3 className="w-16 h-16 mx-auto" /> <FiEdit3 className="w-16 h-16 mx-auto" />
</div> </div>

View File

@ -149,7 +149,7 @@ const Templates = () => {
<td className="px-4 py-2 text-sm text-center">{item.name || 'Dummy'}</td> <td className="px-4 py-2 text-sm text-center">{item.name || 'Dummy'}</td>
<td className="px-4 py-2 text-sm text-center">{formatDate(item.createdAt)}</td> <td className="px-4 py-2 text-sm text-center">{formatDate(item.createdAt)}</td>
<td className="px-4 py-2 text-sm text-center">{formatDate(item.lastModifiedAt)}</td> <td className="px-4 py-2 text-sm text-center">{formatDate(item.lastModifiedAt)}</td>
<td className="px-4 py-2 text-sm text-center" onClick={() => handleUseClick(item)}><span className="from-green-500 cursor-pointer to-blue-500 bg-gradient-to-br px-3 py-1 rounded-lg text-white font-semibold text-[12px]">Use</span></td> <td className="px-4 py-2 text-sm text-center" onClick={() => handleUseClick(item)}><span className="bg-[var(--lightGreyCol)] cursor-pointer border-gray-300 text-gray-600 hover:bg-gray-100 px-3 py-1 rounded-lg font-semibold text-[12px]">Use</span></td>
{/* Dropdown Trigger + Tooltip */} {/* Dropdown Trigger + Tooltip */}
<td className="px-4 py-2 text-center relative"> <td className="px-4 py-2 text-center relative">
<button <button

View File

@ -351,10 +351,12 @@ export interface Recipient {
hostEmail: string; hostEmail: string;
type: recipientType; type: recipientType;
color?: string; color?: string;
allowSenderToEdit: Boolean; allowSenderToEdit: boolean;
allowSenderToRemove: Boolean; allowSenderToDelete: boolean;
roleName:string roleName: string
provideOwnTags?: boolean; provideOwnTags?: boolean;
uuid?: string;
newOne: boolean;
} }
export interface SelectedRecipientInt { export interface SelectedRecipientInt {
@ -403,6 +405,8 @@ export const addRecipientAsync = createAsyncThunk<
const updateRecipientsData = recipientsData.filter(recipient => recipient.id !== null); const updateRecipientsData = recipientsData.filter(recipient => recipient.id !== null);
const createRecipientsData = recipientsData.filter(recipient => recipient.id == null); const createRecipientsData = recipientsData.filter(recipient => recipient.id == null);
console.log("createRecipientsData", createRecipientsData)
const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`; const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`;
const resUpdate = updateRecipientsData.length const resUpdate = updateRecipientsData.length
@ -518,7 +522,7 @@ const selectedRecipientsSlice = createSlice({
state.signingOrder = action.payload; state.signingOrder = action.payload;
}, },
removeSelectedRecipient: (state, action: PayloadAction<Recipient>) => { removeSelectedRecipient: (state, action: PayloadAction<Recipient>) => {
state.recipients = state.recipients.filter((recipient) => recipient.email !== action.payload.email); state.recipients = state.recipients.filter((recipient) => recipient.uuid !== action.payload.uuid);
}, },
addColorsToRecipient: (state) => { addColorsToRecipient: (state) => {
for (const [index, recipient] of state.recipients.entries()) { for (const [index, recipient] of state.recipients.entries()) {
@ -540,6 +544,35 @@ const selectedRecipientsSlice = createSlice({
} }
} }
}, },
updateRecipient(state, action: PayloadAction<Recipient>) {
const payloadUuid = String(action.payload.uuid);
// First try matching by id
let index = state.recipients.findIndex(
r => String(r.id) === payloadUuid
);
// If not found, try matching by uuid
if (index === -1) {
index = state.recipients.findIndex(
r => String(r.uuid) === payloadUuid
);
}
if (index !== -1) {
// Merge existing recipient with new values
state.recipients[index] = {
...state.recipients[index],
...action.payload
};
} else {
console.warn('Recipient not found with uuid:', payloadUuid);
}
}
,
resetSelRecipient: () => initialState resetSelRecipient: () => initialState
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
@ -602,6 +635,7 @@ export const {
updateRecipientIds, updateRecipientIds,
resetSelRecipient, resetSelRecipient,
updateRecipientOrder, updateRecipientOrder,
updateRecipient,
resetRecipients resetRecipients
} = selectedRecipientsSlice.actions; } = selectedRecipientsSlice.actions;