In App Navigation

This commit is contained in:
Bhagwan Singh 2026-05-22 18:22:41 +05:30
parent dcb1934cfa
commit f6e0b3b8af
7 changed files with 346 additions and 51 deletions

View File

@ -225,12 +225,11 @@ const StartNow = () => {
</button> </button>
<button <button
onClick={() => navigate("/templates")}
className="w-full text-left px-4 py-2.5 text-xs hover:bg-slate-50 border-t border-slate-100 cursor-pointer flex gap-2 items-center" className="w-full text-left px-4 py-2.5 text-xs hover:bg-slate-50 border-t border-slate-100 cursor-pointer flex gap-2 items-center"
> >
<HiTemplate className='text-[var(--primary)]' /> <HiTemplate className='text-[var(--primary)]' />
<span <span>Use a Template</span>
onClick={() => navigate("/templates")}
>Use a Template</span>
</button> </button>
</div> </div>
</div> </div>

View File

@ -17,6 +17,12 @@ import Loader from '../../dashboard/Loader';
import { hideLoader, showLoader } from '../../../store/slices/loaderSlice'; import { hideLoader, showLoader } from '../../../store/slices/loaderSlice';
import DroppedItemsTagsCon from './DroppedItemsTagsCon'; import DroppedItemsTagsCon from './DroppedItemsTagsCon';
import DocumentPages from './documentPages/DocumentPages'; import DocumentPages from './documentPages/DocumentPages';
import {
initializeDroppedItems,
setDroppedItems,
clearTransactionTags,
incrementCounter,
} from '../../../store/slices/documentTagsSlice';
export interface DroppedItemsObj { export interface DroppedItemsObj {
[key: string]: DroppedItem[] [key: string]: DroppedItem[]
@ -87,12 +93,16 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
const tagUndoRef = useRef<DroppedItem[] | []>([]); const tagUndoRef = useRef<DroppedItem[] | []>([]);
const imageRefs = useRef<{ [key: string]: HTMLImageElement | null }>({}); const imageRefs = useRef<{ [key: string]: HTMLImageElement | null }>({});
const [imageSizes, setImageSizes] = useState<Record<string, { width: number; height: number }>>({});
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients); const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients);
// const selectedDocuments = useSelector((state: RootState) => state.selectedDocuments.selectedDocuments) // const selectedDocuments = useSelector((state: RootState) => state.selectedDocuments.selectedDocuments)
const selectedDocuments = useSelector((state: RootState) => state.documents.documents) const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
const [droppedItems, setDroppedItems] = useState<DroppedItemsObj>({}); // Redux state for dropped items
const transactionKey = `${accountId}_${transactionId}`;
const droppedItems = useSelector((state: RootState) => state.documentTags.items[transactionKey] || {});
const droppedItemsCounter = useSelector((state: RootState) => state.documentTags.counter[transactionKey] || 0);
interface HotKeysObj { interface HotKeysObj {
isActive: boolean; isActive: boolean;
@ -143,7 +153,11 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
} }
} }
setDroppedItems(recTags) // Dispatch to Redux instead of local state
dispatch(initializeDroppedItems({
transactionKey,
items: recTags
}));
// Handle your response here // Handle your response here
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -157,7 +171,6 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
}, [selectedRecipients, isPreview]); }, [selectedRecipients, isPreview]);
// FETCHING TAG - END // FETCHING TAG - END
const [droppedItemsCounter, setDroppedItemsCounter] = useState<number>(1);
const [selectedTag, setSelectedTag] = useState<{ key: string, index: number } | null>(null); const [selectedTag, setSelectedTag] = useState<{ key: string, index: number } | null>(null);
// NAVIGATING to Dashboard if Transaction is not created - START // NAVIGATING to Dashboard if Transaction is not created - START
@ -197,13 +210,17 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
if ("update" in tag && tag.update) { if ("update" in tag && tag.update) {
updateTags.push(tag) updateTags.push(tag)
} }
if (updateTags.length && "update" in updateTags[updateTags.length - 1]) { if (updateTags.length) {
delete updateTags[updateTags.length - 1].update const lastTag = updateTags[updateTags.length - 1];
delete updateTags[updateTags.length - 1].icon if ("update" in lastTag || "icon" in lastTag) {
// Create new object without update and icon properties
const { update, icon, ...cleanTag } = lastTag as any;
updateTags[updateTags.length - 1] = cleanTag;
}
} }
} }
updatedData[recipientId] = updateTags.filter((tag, indx) => !tag.isDeleted); updatedData[recipientId] = updateTags.filter((tag) => !tag.isDeleted);
} }
const requests = Object.entries(updatedData) const requests = Object.entries(updatedData)
@ -224,13 +241,18 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
try { try {
const responses = await Promise.all(requests); const responses = await Promise.all(requests);
// Dispatch Redux action instead of local state
const droppedItemsUpdateFalse = Object.fromEntries( const droppedItemsUpdateFalse = Object.fromEntries(
Object.entries(droppedItems).map(([recipientId, tags]) => { Object.entries(droppedItems).map(([recipientId, tags]) => {
return [recipientId, tags.map(tag => ({ ...tag, update: false }))]; return [recipientId, tags.map(tag => ({ ...tag, update: false }))];
}) })
) )
setDroppedItems(droppedItemsUpdateFalse); dispatch(setDroppedItems({
transactionKey,
items: droppedItemsUpdateFalse
}));
return responses; return responses;
} catch (error) { } catch (error) {
console.error("Error submitting recipient tags:", error); console.error("Error submitting recipient tags:", error);
@ -302,10 +324,11 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
// HANDLE DROP - START // HANDLE DROP - START
const handleDrop = (event: React.DragEvent<HTMLDivElement>, docId: string, documentId: number, pageIndex: number, originalWidth: number, originalHeight: number) => { const handleDrop = (event: React.DragEvent<HTMLDivElement>, docId: string, documentId: number, pageIndex: number, originalWidth: number, originalHeight: number) => {
event.preventDefault(); event.preventDefault();
const imageElement = document.getElementById(`${docId}-${pageIndex}`) as HTMLImageElement; const pageRefKey = `${docId}_${pageIndex}`;
const imageElement = imageRefs.current[pageRefKey] || document.getElementById(`${docId}-${pageIndex}`) as HTMLImageElement;
const currentWidth = imageElement.offsetWidth; const currentWidth = imageElement?.offsetWidth || originalWidth;
const currentHeight = imageElement.offsetHeight; const currentHeight = imageElement?.offsetHeight || originalHeight;
const scaleX = currentWidth / originalWidth; // 350 / 700 = 0.5 const scaleX = currentWidth / originalWidth; // 350 / 700 = 0.5
const scaleY = currentHeight / originalHeight; // 225 / 450 = 0.5 const scaleY = currentHeight / originalHeight; // 225 / 450 = 0.5
@ -371,10 +394,10 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
label: dragElemData.label, label: dragElemData.label,
// subType: (dragElemData.label in droppedTagsDefaultField) ? droppedTagsDefaultField[dragElemData.label] : '', // subType: (dragElemData.label in droppedTagsDefaultField) ? droppedTagsDefaultField[dragElemData.label] : '',
dimensions: { dimensions: {
left: x, left: x / scaleX,
top: y, top: y / scaleY,
width: dragElemData.width, width: dragElemData.width / scaleX,
height: dragElemData.height, height: dragElemData.height / scaleY,
}, },
styles: null, styles: null,
documentId: docId, documentId: docId,
@ -409,8 +432,11 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
prepData], prepData],
} }
setDroppedItems(dataToSet); dispatch(setDroppedItems({
setDroppedItemsCounter((prev) => prev + 1); transactionKey,
items: dataToSet
}));
dispatch(incrementCounter(transactionKey));
// setTimeout(() => { // setTimeout(() => {
// const tagIndex = key in droppedItems ? droppedItems[key].length : 0; // const tagIndex = key in droppedItems ? droppedItems[key].length : 0;
@ -440,9 +466,12 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
console.log("copiedTags", copiedTags) console.log("copiedTags", copiedTags)
console.log("updatedKey", updatedKey) console.log("updatedKey", updatedKey)
setDroppedItems(prevState => ({ dispatch(setDroppedItems({
...prevState, transactionKey,
items: {
...droppedItems,
[selectedDoc.key]: updatedKey [selectedDoc.key]: updatedKey
}
})); }));
// Handle Ctrl+V // Handle Ctrl+V
@ -566,7 +595,21 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
// className={`w-[${(page.width / 2)}px] h-[${(page.height / 2)}px] sm:w-[${page.width}px] sm:h-[${page.height}px]`} // className={`w-[${(page.width / 2)}px] h-[${(page.height / 2)}px] sm:w-[${page.width}px] sm:h-[${page.height}px]`}
id={`${doc.id}-${page.index}`} id={`${doc.id}-${page.index}`}
className={`w-[${page.width / 2}px] h-[${page.height / 2}px] sm:w-[${page.width}px] sm:h-[${page.height}px]`} className={`w-[${page.width / 2}px] h-[${page.height / 2}px] sm:w-[${page.width}px] sm:h-[${page.height}px]`}
ref={(el) => (imageRefs.current[page.index] = el)} ref={(el) => {
const pageRefKey = `${doc.id}_${page.index}`;
imageRefs.current[pageRefKey] = el;
}}
onLoad={(event) => {
const pageRefKey = `${doc.id}_${page.index}`;
const el = event.currentTarget;
setImageSizes((prev) => ({
...prev,
[pageRefKey]: {
width: el.offsetWidth,
height: el.offsetHeight,
},
}));
}}
draggable="false" draggable="false"
width={page.width} width={page.width}
height={page.height} height={page.height}
@ -579,19 +622,28 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
<DroppedItemsTagsCon <DroppedItemsTagsCon
pageWidth={page.width} pageWidth={page.width}
pageHeight={page.height} pageHeight={page.height}
renderedWidth={imageRefs.current[page.index]?.offsetWidth || 0} renderedWidth={imageSizes[key]?.width || imageRefs.current[key]?.offsetWidth || 0}
renderedHeight={imageRefs.current[page.index]?.offsetHeight || 0} renderedHeight={imageSizes[key]?.height || imageRefs.current[key]?.offsetHeight || 0}
ref={childRef} ref={childRef}
droppedItems={droppedItems} droppedItems={droppedItems}
pageIdkey={key} pageIdkey={key}
selectedTag={selectedTag} selectedTag={selectedTag}
selectedRecipients={selectedRecipients} selectedRecipients={selectedRecipients}
setSelectedTag={setSelectedTag} setSelectedTag={setSelectedTag}
setDroppedItems={setDroppedItems} setDroppedItems={(updateFn: any) => {
const newItems = typeof updateFn === 'function'
? updateFn(droppedItems)
: updateFn;
dispatch(setDroppedItems({
transactionKey,
items: newItems
}));
}}
accountId={accountId} accountId={accountId}
transactionId={transactionId} transactionId={transactionId}
transactionTemplateToggle={transactionTemplateToggle} transactionTemplateToggle={transactionTemplateToggle}
tagUndoRef={tagUndoRef} tagUndoRef={tagUndoRef}
transactionKey={transactionKey}
/> />
{/* Side details of documents Pages and document Name - START */} {/* Side details of documents Pages and document Name - START */}
@ -625,7 +677,15 @@ const DocumentContainer = forwardRef<DocumentContainerRef, DocumentContainerProp
{selectedTag && selectedTag != null && "key" in selectedTag && "index" in selectedTag && droppedItems[selectedTag.key] && droppedItems[selectedTag.key][selectedTag.index] && <TagProperties {selectedTag && selectedTag != null && "key" in selectedTag && "index" in selectedTag && droppedItems[selectedTag.key] && droppedItems[selectedTag.key][selectedTag.index] && <TagProperties
droppedItems={droppedItems} droppedItems={droppedItems}
selectedTag={droppedItems[selectedTag.key][selectedTag.index]} selectedTag={droppedItems[selectedTag.key][selectedTag.index]}
setDroppedItems={setDroppedItems} setDroppedItems={(updateFn: any) => {
const newItems = typeof updateFn === 'function'
? updateFn(droppedItems)
: updateFn;
dispatch(setDroppedItems({
transactionKey,
items: newItems
}));
}}
selTagKey={selectedTag.key} selTagKey={selectedTag.key}
selTagIndx={selectedTag.index} selTagIndx={selectedTag.index}
signClient={false} signClient={false}

View File

@ -9,6 +9,8 @@
// -- handleAddGroupItemClicked // -- handleAddGroupItemClicked
import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'
import { useDispatch } from 'react-redux'
import type { AppDispatch } from '../../../store/store'
import { DroppedItemsObj } from './DocumentContainer'; import { DroppedItemsObj } from './DocumentContainer';
import typeToIconMap from '../../../helper/iconMap'; import typeToIconMap from '../../../helper/iconMap';
import { IoMdClose } from 'react-icons/io'; import { IoMdClose } from 'react-icons/io';
@ -17,6 +19,7 @@ import { FaQuestionCircle } from 'react-icons/fa';
import api from '../../../config/api'; import api from '../../../config/api';
import { Recipient } from '../../../store/slices/selectedRecipientsSlice'; import { Recipient } from '../../../store/slices/selectedRecipientsSlice';
import { DroppedItem } from '../../../utlity/types'; import { DroppedItem } from '../../../utlity/types';
import { setDroppedItems as setDroppedItemsAction } from '../../../store/slices/documentTagsSlice';
interface DroppedItemsTagsConProps { interface DroppedItemsTagsConProps {
pageWidth: number, pageWidth: number,
@ -28,11 +31,12 @@ interface DroppedItemsTagsConProps {
selectedTag: { key: string; index: number } | null; selectedTag: { key: string; index: number } | null;
selectedRecipients: Recipient[]; selectedRecipients: Recipient[];
setSelectedTag: React.Dispatch<React.SetStateAction<{ key: string; index: number } | null>>; setSelectedTag: React.Dispatch<React.SetStateAction<{ key: string; index: number } | null>>;
setDroppedItems: React.Dispatch<React.SetStateAction<DroppedItemsObj>>; setDroppedItems: (updateFn: ((prevState: DroppedItemsObj) => DroppedItemsObj) | DroppedItemsObj) => void;
accountId: string; accountId: string;
transactionId: string; transactionId: string;
transactionTemplateToggle: string; transactionTemplateToggle: string;
tagUndoRef: React.MutableRefObject<DroppedItem[]>; tagUndoRef: React.MutableRefObject<DroppedItem[]>;
transactionKey: string;
} }
// 👶 Child component with forwardRef // 👶 Child component with forwardRef
@ -50,9 +54,12 @@ const DroppedItemsTagsCon = forwardRef(({
accountId, accountId,
transactionId, transactionId,
transactionTemplateToggle, transactionTemplateToggle,
tagUndoRef tagUndoRef,
transactionKey
}: DroppedItemsTagsConProps, ref) => { }: DroppedItemsTagsConProps, ref) => {
const dispatch = useDispatch();
const positionRef = useRef<{ left: number; top: number }>({ left: 0, top: 0 }); const positionRef = useRef<{ left: number; top: number }>({ left: 0, top: 0 });
const handleTagClick = (key: string, index: number) => { const handleTagClick = (key: string, index: number) => {
@ -388,11 +395,17 @@ const DroppedItemsTagsCon = forwardRef(({
// check pageIndex match // check pageIndex match
const isSamePage = currentPageIndex == tagDocumentUpdate.pageIndex; const isSamePage = currentPageIndex == tagDocumentUpdate.pageIndex;
const scaleX = renderedWidth && pageWidth ? renderedWidth / pageWidth : 1;
const scaleY = renderedHeight && pageHeight ? renderedHeight / pageHeight : 1;
// same document + same page // same document + same page
if (isSameDocument && isSamePage) { if (isSameDocument && isSamePage) {
left = Math.max(0, Math.min(left, conScrollWidth - elementRect.width)); left = Math.max(0, Math.min(left, conScrollWidth - elementRect.width));
top = Math.max(0, Math.min(top, conScrollHeight - elementRect.height)); top = Math.max(0, Math.min(top, conScrollHeight - elementRect.height));
const normalizedLeft = left / scaleX;
const normalizedTop = top / scaleY;
return { return {
...prevState, ...prevState,
[key]: Array.isArray(prevState[key]) [key]: Array.isArray(prevState[key])
@ -406,8 +419,8 @@ const DroppedItemsTagsCon = forwardRef(({
tagDocumentUpdate.pageIndex, tagDocumentUpdate.pageIndex,
dimensions: { dimensions: {
...item.dimensions, ...item.dimensions,
left, left: normalizedLeft,
top, top: normalizedTop,
}, },
update: true, update: true,
} }
@ -561,9 +574,12 @@ const DroppedItemsTagsCon = forwardRef(({
borderPositions.forEach(position => { borderPositions.forEach(position => {
const borderElement = document.querySelector(`[border-group='${groupId}'][border-pos='${position}']`); const borderElement = document.querySelector(`[border-group='${groupId}'][border-pos='${position}']`);
if (borderElement && borderElement.parentNode) { if (borderElement) {
borderElement.remove?.();
if (!borderElement.remove && borderElement.parentNode && borderElement.parentNode.contains(borderElement)) {
borderElement.parentNode.removeChild(borderElement); borderElement.parentNode.removeChild(borderElement);
} }
}
}); });
}; };
@ -790,8 +806,8 @@ const DroppedItemsTagsCon = forwardRef(({
const IconComponent = typeToIconMap[type] || <FaQuestionCircle />; const IconComponent = typeToIconMap[type] || <FaQuestionCircle />;
const selectedRecipient = selectedRecipients.filter((obj, indx) => obj.id == item.recipientId); const selectedRecipient = selectedRecipients.filter((obj, indx) => obj.id == item.recipientId);
const scaleX = renderedWidth / Math.round(pageWidth); const scaleX = renderedWidth && pageWidth ? renderedWidth / pageWidth : 1;
const scaleY = renderedHeight / Math.round(pageHeight); const scaleY = renderedHeight && pageHeight ? renderedHeight / pageHeight : 1;
return ( return (
<React.Fragment key={index}> <React.Fragment key={index}>

View File

@ -254,11 +254,18 @@ const NavTwo: React.FC<NavTwoProps> = ({
{/* Left Side */} {/* Left Side */}
<div className='flex justify-start items-center gap-2'> <div className='flex justify-start items-center gap-2'>
<div> {/* <div>
<Link to={"/"}> <Link to={"/"}>
<img width={120} src="/sme-colored.png" alt="Sign Made Easy" /> <img width={120} src="/sme-colored.png" alt="Sign Made Easy" />
</Link> </Link>
</div> </div> */}
{/* <div>
<Link to={"/"}>
<img width={120} src="/sme-colored.png" alt="Sign Made Easy" />
</Link>
</div> */}
<div <div
@ -467,8 +474,9 @@ const NavTwo: React.FC<NavTwoProps> = ({
{editRecipientsModal && accountId && transactionId && <> {editRecipientsModal && accountId && transactionId && <>
<div className="w-full h-full absolute top-0 left-0 z-[1000] flex justify-center items-center"> <div className="w-full h-[100vh] absolute top-0 left-0 z-[1000] flex justify-center items-center">
<div className="w-full h-full bg-slate-100 opacity-85 blur-2xl absolute top-0 left-0"></div> {/* <div className="w-full h-full bg-slate-100 opacity-40 blur-2xl absolute top-0 left-0"></div> */}
<div className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50" />
<div className="z-50 bg-white p-4 rounded-sm shadow-md"> <div className="z-50 bg-white p-4 rounded-sm shadow-md">
<RecipientsCon <RecipientsCon
transactionTemplateToggle={transactionTemplateToggle} transactionTemplateToggle={transactionTemplateToggle}
@ -482,8 +490,9 @@ const NavTwo: React.FC<NavTwoProps> = ({
</>} </>}
{messageModal && accountId && transactionId && <> {messageModal && accountId && transactionId && <>
<div className="w-full h-full absolute top-0 left-0 z-[1000] flex justify-center items-center"> <div className="w-full h-[100vh] absolute top-0 left-0 z-[1000] flex justify-center items-center">
<div className="w-full h-full bg-slate-100 opacity-85 blur-2xl absolute top-0 left-0"></div> {/* <div className="w-full h-full bg-slate-100 opacity-40 blur-2xl absolute top-0 left-0"></div> */}
<div className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50" />
<div className="z-50 bg-white p-4 rounded-sm shadow-md"> <div className="z-50 bg-white p-4 rounded-sm shadow-md">
<MessageCon <MessageCon
transactionTemplateToggle={transactionTemplateToggle} transactionTemplateToggle={transactionTemplateToggle}

View File

@ -0,0 +1,218 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
// Define the interface matching DocumentContainer.tsx usage
export interface DroppedItem {
id?: string;
icon?: any;
label?: string;
type: string;
subType?: string;
dimensions: {
left: number;
top: number;
width: number;
height: number;
};
styles?: any;
documentId: string;
pageIndex: number;
recipientId: string | number;
recipientIndx?: number;
required?: boolean;
update?: boolean;
isDeleted?: boolean;
group?: string;
isGroupExist?: boolean;
currentTimeStamp?: boolean;
decimalPlace?: number;
isCurrency?: boolean;
maskType?: string;
maskCharacter?: string;
format?: string;
regex?: string[];
[key: string]: any; // Allow other properties
}
export interface DroppedItemsObj {
[key: string]: DroppedItem[];
}
export interface DocumentTagsState {
items: {
[transactionKey: string]: DroppedItemsObj; // Key: `${accountId}_${transactionId}`
};
counter: {
[transactionKey: string]: number;
};
isLoading: {
[transactionKey: string]: boolean;
};
}
const initialState: DocumentTagsState = {
items: {},
counter: {},
isLoading: {},
};
const documentTagsSlice = createSlice({
name: 'documentTags',
initialState,
reducers: {
/**
* Initialize or replace all dropped items for a transaction
* Used when fetching tags from API
*/
initializeDroppedItems: (
state,
action: PayloadAction<{
transactionKey: string;
items: DroppedItemsObj;
}>
) => {
const { transactionKey, items } = action.payload;
state.items[transactionKey] = items;
state.isLoading[transactionKey] = false;
},
/**
* Set all dropped items (replaces existing)
* Used when user adds/modifies tags in current session
*/
setDroppedItems: (
state,
action: PayloadAction<{
transactionKey: string;
items: DroppedItemsObj;
}>
) => {
const { transactionKey, items } = action.payload;
state.items[transactionKey] = items;
},
/**
* Add a dropped item to specific page
*/
addDroppedItem: (
state,
action: PayloadAction<{
transactionKey: string;
pageKey: string;
item: DroppedItem;
}>
) => {
const { transactionKey, pageKey, item } = action.payload;
if (!state.items[transactionKey]) {
state.items[transactionKey] = {};
}
if (!state.items[transactionKey][pageKey]) {
state.items[transactionKey][pageKey] = [];
}
state.items[transactionKey][pageKey].push(item);
state.counter[transactionKey] = (state.counter[transactionKey] || 0) + 1;
},
/**
* Update dropped items for a specific page
*/
updatePageItems: (
state,
action: PayloadAction<{
transactionKey: string;
pageKey: string;
items: DroppedItem[];
}>
) => {
const { transactionKey, pageKey, items } = action.payload;
if (!state.items[transactionKey]) {
state.items[transactionKey] = {};
}
state.items[transactionKey][pageKey] = items;
},
/**
* Remove an item by index from a page
*/
removeDroppedItem: (
state,
action: PayloadAction<{
transactionKey: string;
pageKey: string;
index: number;
}>
) => {
const { transactionKey, pageKey, index } = action.payload;
if (state.items[transactionKey]?.[pageKey]) {
state.items[transactionKey][pageKey].splice(index, 1);
}
},
/**
* Update a specific item by index
*/
updateDroppedItem: (
state,
action: PayloadAction<{
transactionKey: string;
pageKey: string;
index: number;
updates: Partial<DroppedItem>;
}>
) => {
const { transactionKey, pageKey, index, updates } = action.payload;
if (state.items[transactionKey]?.[pageKey]?.[index]) {
state.items[transactionKey][pageKey][index] = {
...state.items[transactionKey][pageKey][index],
...updates,
};
}
},
/**
* Clear all tags for a specific transaction
*/
clearTransactionTags: (state, action: PayloadAction<string>) => {
const transactionKey = action.payload;
delete state.items[transactionKey];
delete state.counter[transactionKey];
delete state.isLoading[transactionKey];
},
/**
* Increment counter for a transaction
*/
incrementCounter: (state, action: PayloadAction<string>) => {
const transactionKey = action.payload;
state.counter[transactionKey] = (state.counter[transactionKey] || 0) + 1;
},
/**
* Set loading state
*/
setLoading: (
state,
action: PayloadAction<{
transactionKey: string;
isLoading: boolean;
}>
) => {
const { transactionKey, isLoading } = action.payload;
state.isLoading[transactionKey] = isLoading;
},
},
});
export const {
initializeDroppedItems,
setDroppedItems,
addDroppedItem,
updatePageItems,
removeDroppedItem,
updateDroppedItem,
clearTransactionTags,
incrementCounter,
setLoading,
} = documentTagsSlice.actions;
export default documentTagsSlice.reducer;

View File

@ -2,7 +2,6 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
/* TYPES */ /* TYPES */
export interface Position { export interface Position {
top: number; top: number;
left: number; left: number;
@ -43,8 +42,6 @@ export interface Tag {
/* PAYLOAD TYPES */ /* PAYLOAD TYPES */
interface AddTagPayload { interface AddTagPayload {
recipientId: string; recipientId: string;
tag: Tag; tag: Tag;
@ -99,7 +96,6 @@ const localTagsSlice = createSlice({
reducers: { reducers: {
/* ------------------------------ ADD TAG ----------------------------- */ /* ------------------------------ ADD TAG ----------------------------- */
addTag: (state, action: PayloadAction<AddTagPayload>) => { addTag: (state, action: PayloadAction<AddTagPayload>) => {
const { recipientId, tag } = action.payload; const { recipientId, tag } = action.payload;
@ -111,7 +107,6 @@ const localTagsSlice = createSlice({
}, },
/* ---------------------------- UPDATE TAG ---------------------------- */ /* ---------------------------- UPDATE TAG ---------------------------- */
updateTag: (state, action: PayloadAction<UpdateTagPayload>) => { updateTag: (state, action: PayloadAction<UpdateTagPayload>) => {
const { recipientId, tagId, updatedData } = action.payload; const { recipientId, tagId, updatedData } = action.payload;
@ -125,7 +120,6 @@ const localTagsSlice = createSlice({
}, },
/* ---------------------------- REMOVE TAG ---------------------------- */ /* ---------------------------- REMOVE TAG ---------------------------- */
removeTag: (state, action: PayloadAction<RemoveTagPayload>) => { removeTag: (state, action: PayloadAction<RemoveTagPayload>) => {
const { recipientId, tagId } = action.payload; const { recipientId, tagId } = action.payload;
@ -140,7 +134,6 @@ const localTagsSlice = createSlice({
}, },
/* ------------------------- REPLACE ALL TAGS ------------------------- */ /* ------------------------- REPLACE ALL TAGS ------------------------- */
replaceRecipientTags: ( replaceRecipientTags: (
state, state,
action: PayloadAction<ReplaceRecipientTagsPayload> action: PayloadAction<ReplaceRecipientTagsPayload>
@ -155,7 +148,6 @@ const localTagsSlice = createSlice({
}, },
/* -------------------------- CLEAR RECIPIENT ------------------------- */ /* -------------------------- CLEAR RECIPIENT ------------------------- */
clearRecipientTags: ( clearRecipientTags: (
state, state,
action: PayloadAction<string> action: PayloadAction<string>
@ -164,7 +156,6 @@ const localTagsSlice = createSlice({
}, },
/* ----------------------------- CLEAR ALL ---------------------------- */ /* ----------------------------- CLEAR ALL ---------------------------- */
clearTags: () => { clearTags: () => {
return initialState; return initialState;
}, },

View File

@ -72,6 +72,7 @@ import documentReducer from "./slices/documentSlice";
import tagsReducer from "./slices/tagsSlice"; import tagsReducer from "./slices/tagsSlice";
import transactionReducer from "./slices/transactionSlice"; import transactionReducer from "./slices/transactionSlice";
import signatureReducer from "./slices/signatureSlice"; import signatureReducer from "./slices/signatureSlice";
import documentTagsReducer from "./slices/documentTagsSlice";
const rootReducer = combineReducers({ const rootReducer = combineReducers({
user: userReducer, user: userReducer,
@ -83,6 +84,7 @@ const rootReducer = combineReducers({
tags: tagsReducer, tags: tagsReducer,
transaction: transactionReducer, transaction: transactionReducer,
signature: signatureReducer, signature: signatureReducer,
documentTags: documentTagsReducer,
}); });
export const store = configureStore({ export const store = configureStore({