This commit is contained in:
=bhagwanSingh 2025-07-08 12:23:33 +05:30
commit 8ec313e6d8
20 changed files with 982 additions and 698 deletions

View File

@ -45,7 +45,7 @@ const ProcessStepOne = () => {
// const signingOrder = useSelector((state: RootState) => state.selectedRecipients.signingOrder) // const signingOrder = useSelector((state: RootState) => state.selectedRecipients.signingOrder)
// const user = useSelector((state: RootState) => state.user) // const user = useSelector((state: RootState) => state.user)
const [emailDtls, setEmailDtls] = useState<EmailDtls>({ subject: "Documents for Signature", message: "" }); const [emailDtls, setEmailDtls] = useState<EmailDtls>({ subject: "Documents for Signature", message: "" });
useEffect(() => { useEffect(() => {
@ -112,12 +112,20 @@ const ProcessStepOne = () => {
name: `${recipient.firstName} ${recipient.lastName}` name: `${recipient.firstName} ${recipient.lastName}`
})); }));
dispatch(addRecipientAsync({recipientsData, accountId, transactionId})); dispatch(addRecipientAsync({ recipientsData, accountId, transactionId }));
dispatch(showLoader("Processing Message..."));
await api.put(`/api/accounts/${accountId}/transactions/${transactionId}`, { subject: emailDtls.subject, message: emailDtls.message, status: "CREATED" }).then((res) => {
console.log(res);
})
dispatch(hideLoader());
if (isSendNow) { if (isSendNow) {
dispatch(updateTransactionStatus(TRANSACTION_STATUS_ENUMS.TRANSACTION_SEND_SUCCESS)); dispatch(updateTransactionStatus(TRANSACTION_STATUS_ENUMS.TRANSACTION_SEND_SUCCESS));
setTimeout(() => { setTimeout(() => {
navigate("/"); // navigate("/");
}, 1000); }, 1000);
} else { } else {
setTimeout(() => { setTimeout(() => {

View File

@ -4,13 +4,12 @@ import { RootState } from '../../../store/store'
import api from '../../../config/api'; import api from '../../../config/api';
import RightSideBar from './RightSideBar'; import RightSideBar from './rightSideBar/RightSideBar';
import { DroppedItem } from '../../../utlity/types'; import { DroppedItem } from '../../../utlity/types';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { TRANSACTION_STATUS_ENUMS, updateTransactionStatus } from '../../../store/slices/transactionSlice';
import { hideLoader, showLoader } from '../../../store/slices/loaderSlice';
import { IoMdClose } from 'react-icons/io'; import { IoMdClose } from 'react-icons/io';
import fields from '../../../helper/fieldsListData';
import { fetchRecipients } from '../../../store/slices/selectedRecipientsSlice'; import { fetchRecipients } from '../../../store/slices/selectedRecipientsSlice';
import { fetchDocuments } from '../../../store/slices/documentSlice'; import { fetchDocuments } from '../../../store/slices/documentSlice';
import { FaQuestionCircle } from 'react-icons/fa'; import { FaQuestionCircle } from 'react-icons/fa';
@ -186,7 +185,6 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
// const remove = [] // const remove = []
// console.log(updatedTags, "updatedTags"); // console.log(updatedTags, "updatedTags");
for (const dropPageIds of Object.keys(updatedTags)) { for (const dropPageIds of Object.keys(updatedTags)) {
for (const dropTag of updatedTags[dropPageIds]) { for (const dropTag of updatedTags[dropPageIds]) {
let mask = null let mask = null
@ -202,6 +200,8 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
} }
// } // }
console.log(dropTag, "line 204")
const isDeleted = "isDeleted" in dropTag ? dropTag.isDeleted : false const isDeleted = "isDeleted" in dropTag ? dropTag.isDeleted : false
const updatedTagData = { const updatedTagData = {
@ -229,7 +229,7 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
"textSize": 14.0 "textSize": 14.0
}, },
// "required": (dropTag.type.toUpperCase() !== "SIGNATURE" && dropTag.type.toUpperCase() !== "INITIALS") ? dropTag.required : true, // "required": (dropTag.type.toUpperCase() !== "SIGNATURE" && dropTag.type.toUpperCase() !== "INITIALS") ? dropTag.required : true,
"required": false, "required": "required" in dropTag ? dropTag.required : true,
"update": "update" in dropTag ? dropTag.update : false, "update": "update" in dropTag ? dropTag.update : false,
"readOnly": false, "readOnly": false,
} }
@ -272,9 +272,13 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
// for(const recipient of selectedRecipients) { // for(const recipient of selectedRecipients) {
// const recrecipient // const recrecipient
// } // }
tagsData = groupByRecipientId(tagsData); tagsData = groupByRecipientId(tagsData);
sendTagsToRecipients(tagsData, accountId, transactionId); sendTagsToRecipients(tagsData, accountId, transactionId);
// (async () => {
// const res = await api.put(`/api/accounts/${accountId}/transactions/${transactionId}`, {status: "SENT"})
// console.log(res, "Check123")
// })()
}, [isSend]) }, [isSend])
// Save Tags - END // Save Tags - END
@ -305,6 +309,7 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
// const IconComponent = typeToIconMap[field.type] || <FaQuestionCircle />; // const IconComponent = typeToIconMap[field.type] || <FaQuestionCircle />;
let prepData = { let prepData = {
properties: data.properties,
icon: typeToIconMap[field.label.toUpperCase()] || <FaQuestionCircle />, icon: typeToIconMap[field.label.toUpperCase()] || <FaQuestionCircle />,
type: dragElemData.label, type: dragElemData.label,
subType: (dragElemData.label in droppedTagsDefaultField) ? droppedTagsDefaultField[dragElemData.label] : '', subType: (dragElemData.label in droppedTagsDefaultField) ? droppedTagsDefaultField[dragElemData.label] : '',
@ -514,7 +519,6 @@ const DocumentContainer: React.FC<DocumentContainerProps> = ({ isSend }) => {
})() })()
} }
// const handleAddRadio = (e: React.MouseEvent<HTMLElement>, key: string, index: number) => { // const handleAddRadio = (e: React.MouseEvent<HTMLElement>, key: string, index: number) => {
// // const dataToSet: DroppedItemsObj = { // // const dataToSet: DroppedItemsObj = {
// // ...droppedItems, // // ...droppedItems,

View File

@ -4,9 +4,9 @@ import api from '../../../config/api';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import typeToIconMap from '../../../helper/iconMap'; import typeToIconMap from '../../../helper/iconMap';
import { FaQuestionCircle } from 'react-icons/fa'; import { FaQuestionCircle } from 'react-icons/fa';
import { TagsProperties } from '../../../utlity/types';
const handlePointerDown = (event: React.DragEvent<HTMLDivElement>, label: string, recipientId: number, recipientIndx: number) => { const handlePointerDown = (event: React.DragEvent<HTMLDivElement>, label: string, recipientId: number, recipientIndx: number, tagsProperties: TagsProperties) => {
const dragElemRect = event.currentTarget.getBoundingClientRect(); const dragElemRect = event.currentTarget.getBoundingClientRect();
let width = dragElemRect.width let width = dragElemRect.width
let height = dragElemRect.height let height = dragElemRect.height
@ -27,7 +27,8 @@ const handlePointerDown = (event: React.DragEvent<HTMLDivElement>, label: string
recipientId: recipientId, recipientId: recipientId,
recipientIndx: recipientIndx, recipientIndx: recipientIndx,
width, width,
height height,
properties: tagsProperties
} }
window.dragElemData = JSON.stringify(obj); window.dragElemData = JSON.stringify(obj);
@ -41,7 +42,7 @@ interface FieldListProps {
const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx }) => { const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx }) => {
const [tagsData, setTagsData] = useState([]); const [tagsData, setTagsData] = useState<TagsProperties[]>([]);
const { accountId } = useParams<{ accountId: string }>(); const { accountId } = useParams<{ accountId: string }>();
if (!accountId) { if (!accountId) {
@ -91,7 +92,7 @@ const FieldList: React.FC<FieldListProps> = ({ color, recipientId, recipientIndx
<div <div
draggable={true} draggable={true}
key={index} key={index}
onPointerDown={(e) => handlePointerDown(e, field.type.toLowerCase(), recipientId, recipientIndx)} onPointerDown={(e) => handlePointerDown(e, field.type.toLowerCase(), recipientId, recipientIndx, field)}
className="p-1 flex justify-start items-center gap-2 rounded-sm cursor-grab hover:bg-slate-200 transition-all duration-300"> className="p-1 flex justify-start items-center gap-2 rounded-sm cursor-grab hover:bg-slate-200 transition-all duration-300">
<div <div
className={`p-1 text-sm rounded-sm text-white`} className={`p-1 text-sm rounded-sm text-white`}

View File

@ -1,10 +1,9 @@
import React, { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import NavTwo from './NavTwo'; import NavTwo from './NavTwo';
import LeftSideBar from './LeftSideBar'; import LeftSideBar from './LeftSideBar';
import DocumentContainer from './DocumentContainer'; import DocumentContainer from './DocumentContainer';
import { IoMdClose } from 'react-icons/io'
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { RootState } from '../../../store/store'; import { RootState } from '../../../store/store';
import Loader from '../../dashboard/Loader'; import Loader from '../../dashboard/Loader';
@ -25,28 +24,6 @@ const ProcessStepTwo = () => {
return ( return (
<div className={`min-w-full relative h-screen bg-slate-100 overflow-hidden ${(globalLoader.isLoading) ? 'pointer-events-none' : ''}`}> <div className={`min-w-full relative h-screen bg-slate-100 overflow-hidden ${(globalLoader.isLoading) ? 'pointer-events-none' : ''}`}>
{/* Top Header One */}
{/* <div className='flex items-center shadow-sm pb-3 bg-slate-100'>
<div className='flex w-full justify-center items-center px-4'>
<div className='cursor-default flex justify-center items-center gap-4 border-b-3 relative border-[var(--primary)] py-1 px-4'>
<p className="text-xs tracking-wider">Setup your Document</p>
<div className='absolute bottom-[-7px] w-3 h-3 rounded-full right-[-4px] bg-[var(--primary)] z-50' ></div>
</div>
<div className='cursor-default flex justify-center items-center gap-4 border-b-3 relative border-[var(--primary)] py-1 px-4'>
<p className="text-xs tracking-wider">Prepare</p>
<div className='absolute bottom-[-7px] w-3 h-3 rounded-full right-[-4px] bg-[var(--primary)] z-50' ></div>
</div>
<div className='cursor-default flex justify-center items-center gap-4 border-b-3 relative border-[var(--primaryLight)] py-1 px-4'>
<p className="text-xs tracking-wider">Hooray !</p>
<div className='absolute bottom-[-7px] w-3 h-3 rounded-full right-[-4px] bg-[var(--primaryLight)] z-50' ></div>
</div>
</div>
</div> */}
{/* Top Header One */}
<NavTwo isFields={isFields} setIsFields={setIsFields} isSend={isSend} setIsSend={setIsSend} /> <NavTwo isFields={isFields} setIsFields={setIsFields} isSend={isSend} setIsSend={setIsSend} />
<div className='grid grid-cols-12 gap-1 mt-1 h-[calc(100vh-46px)] overflow-hidden'> <div className='grid grid-cols-12 gap-1 mt-1 h-[calc(100vh-46px)] overflow-hidden'>

View File

@ -1,653 +0,0 @@
import { MdKeyboardArrowDown } from "react-icons/md";
import { DroppedItemsObj } from "./DocumentContainer";
import React, { ReactHTMLElement, useEffect, useState } from "react";
import { RiAsterisk } from "react-icons/ri";
import { GoDotFill } from "react-icons/go";
import { IoClose } from "react-icons/io5";
import { LuAsterisk } from "react-icons/lu";
import { dateFormats, dateTimeFormats, monthFormats, timeFormats, weekFormats, yearFormats } from "../../../utlity/dateTimeUtils";
import { DroppedItem } from "../../../utlity/types";
import { IoMdClose } from "react-icons/io";
import dayjs from "dayjs";
interface DroppedItemProps {
selectedTag: DroppedItem
setDroppedItems: React.Dispatch<React.SetStateAction<DroppedItemsObj>>
selTagKey: string,
selTagIndx: number
}
enum TEXT {
PARAGRAPH = "paragraph",
SINGLE_LINE = "single_line",
PASSWORD = "password",
}
// enum SIGNATURE {
// TYPED = "typed",
// DRAW = "draw",
// UPLOAD = "upload",
// }
// enum INITIALS {
// TYPED = "typed",
// DRAW = "draw",
// UPLOAD = "upload",
// }
export enum TEMPORAL {
DATE = "date",
TIME = "time",
DATE_TIME = "date_time",
// YEAR = "year",
// MONTH = "month",
// WEEK = "week",
}
enum NUMBER {
INTEGER = "integer",
DECIMAL = "decimal",
CURRENCY = "currency"
}
// enum IMAGE {
// STAMP = "stamp",
// LOGO = "logo"
// }
enum SELECT {
SINGLE_SELECT = "single select",
MULTI_SELECT = "multi select"
}
enum MASKTYPE {
ALL = "all",
LAST_FOUR = "last_four",
CREDIT_CARD = "credit_Card",
NATIONAL_INSURANCE = "national_insurance",
SOCIAL_SECURITY = "social_security",
SOCIAL_INSURANCE = "social_insurance"
}
enum MASKCHARACTER {
ASTERISK = "ASTERISK",
DOT = "DOT",
X = "CROSS",
}
const enumMap = {
text: TEXT,
temporal: TEMPORAL,
number: NUMBER,
image: String,
select: SELECT
}
enum DROPDOWNTOGGLE {
TYPE,
MASK_TYPE,
MASK_CHARACTER,
DDMMYY_FORMAT
}
const dateTimeFormatMap = {
"date": dateFormats,
"time": timeFormats,
"date_time": dateTimeFormats,
"year": yearFormats,
"month": monthFormats,
"week": weekFormats
}
const RightSideBar: React.FC<DroppedItemProps> = ({ selectedTag, setDroppedItems, selTagKey, selTagIndx }) => {
console.log(selectedTag, "selectedTag Line 102")
const selectedType = selectedTag.type in enumMap && enumMap[selectedTag.type as keyof typeof enumMap];
const [dropDownToggle, setDropDownToggle] = useState<DROPDOWNTOGGLE | null>(null);
// const [showFormatEg, setShowFormatEg] = useState<boolean>(false);
const [is24Hrs, setIs24Hrs] = useState<boolean>(true);
const [isCurrentTimeStamp, setIsCurrentTimeStamp] = useState<boolean>(true);
// const [selectedOptions, setSelectedOptions] = useState<string[]>([])
const [decimalPlace, setDecimalPlace] = useState<number>(2)
const [selectedOption, setSelectedOption] = useState<string>()
const handlePropertyChange = (changeTo: string, changeWith: string | boolean | number) => {
console.log("Handle Property Change Called", "changeTo", changeTo, "changeWith", changeWith)
if (changeTo === '' || changeWith === '') return
if (changeTo === "subType" && (changeWith === TEMPORAL.DATE || changeWith === TEMPORAL.DATE_TIME || changeWith === TEMPORAL.TIME)) {
// let change: string = changeWith;
// if (change === "DATE TIME") {
// change = "DATE_TIME"
// }
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith || "", format: "", update: "id" in item ? true : false } : item
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
} else if (changeTo === "subType" && typeof changeWith === "string" && changeWith.toLowerCase() === "password") {
console.log("Line 161")
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey])
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith, maskType: "All", maskCharacter: "ASTERISK", update: "id" in item ? true : false } : item
)
: [],
}
));
}
else if (changeTo === "subType" && (changeWith === NUMBER.CURRENCY || changeWith === NUMBER.INTEGER || changeWith === NUMBER.DECIMAL)) {
let decPlace = changeWith !== NUMBER.DECIMAL ? 0 : decimalPlace;
const isCurrency = changeWith === NUMBER.CURRENCY;
// const currencyType = null
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith, decimalPlace: decPlace, isCurrency, update: "id" in item ? true : false } : item
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
} else if (changeTo === "format" && selectedTag.subType === TEMPORAL.DATE_TIME) {
let val = timeFormats[0].format;
if (!is24Hrs) {
val = timeFormats[1].format
}
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith + " " + val, update: "id" in item ? true : false } : item
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
} else {
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith, update: "id" in item ? true : false } : item
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
}
setDropDownToggle(null)
}
// const handleSelectTagOptions = () => {
// if (!selectedOptions.length) return
// setDroppedItems((prev) => (
// {
// ...prev,
// [selTagKey]: Array.isArray(prev[selTagKey])
// ? prev[selTagKey].map((item, i) => {
// if (i === selTagIndx) {
// return { ...item, options: [...selectedOptions] };
// }
// return item;
// })
// : [],
// }
// ));
// }
// useEffect(() => {
// handleSelectTagOptions();
// }, [selectedOptions])
useEffect(() => {
if (selectedTag.subType === TEMPORAL.DATE || selectedTag.subType === TEMPORAL.DATE_TIME || selectedTag.subType === TEMPORAL.TIME) {
if (selectedTag.subType === TEMPORAL.DATE) {
handlePropertyChange("format", dateFormats[0].format)
}
else if (selectedTag.subType === TEMPORAL.DATE_TIME) {
handlePropertyChange("format", dateTimeFormats[0].format)
}
else if (selectedTag.subType === TEMPORAL.TIME) {
handlePropertyChange("format", timeFormats[0].format)
}
}
// else if(selectedTag.subType === TEXT.PASSWORD) {
// handlePropertyChange("format", timeFormats[0].format)
// }
}, [selectedTag.subType])
useEffect(() => {
if (selectedTag.format === timeFormats[1].format && is24Hrs) {
setIs24Hrs(false);
} else if (selectedTag.format === timeFormats[0].format && !is24Hrs) {
setIs24Hrs(true);
}
}, [selectedTag.format])
useEffect(() => {
if (selectedTag.label === "temporal") {
handlePropertyChange("subType", TEMPORAL.DATE);
handlePropertyChange("format", "DD/MM/YY");
}
}, [])
const handleIs24HrsClick = (checked: boolean) => {
if (selectedTag.subType === TEMPORAL.TIME) {
if (!checked) {
handlePropertyChange("format", timeFormats[1].format)
} else {
handlePropertyChange("format", timeFormats[0].format)
}
}
setIs24Hrs(checked)
}
const handleIsCurrentTimeStamp = (checked: boolean) => {
if (selectedTag.type.toLowerCase() === "temporal") {
setIsCurrentTimeStamp(checked)
handlePropertyChange("currentTimeStamp", checked);
}
}
const handleAddSelectOption = () => {
if (selectedOption && selectedOption.length) {
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey])
? prev[selTagKey].map((item, i) => {
if (i === selTagIndx) {
return { ...item, options: item.options ? [...item.options, selectedOption] : [selectedOption], update: "id" in item ? true : false };
}
return item;
})
: [],
}
));
}
}
const handleSelectOptionDel = (indx: number) => {
// setSelectedOptions(prev =>
// prev.filter((_, i) => i !== indx)
// )
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey])
? prev[selTagKey].map((item, i) => {
if (i === selTagIndx) {
return { ...item, options: item.options ? item.options.filter((_, i) => i !== indx) : [] };
}
return item;
})
: [],
}
));
}
const handleDecimalPlace = (e: React.ChangeEvent<HTMLInputElement>) => {
const val = Number(e.target.value)
setDecimalPlace(val)
handlePropertyChange("decimalPlace", val)
}
useEffect(() => {
if ("styles" in selectedTag) {
const fontSize = selectedTag?.styles?.textSize;
const tagHeight = selectedTag?.dimensions?.height - 18;
console.log(fontSize, tagHeight, "Line 323", selectedTag?.styles)
if (selectedTag.subType !== "password" && selectedTag.subType !== "paragraph" && tagHeight > (fontSize + fontSize)) {
console.log("Change subType Called from if")
handlePropertyChange("subType", "paragraph")
} else if (selectedTag.subType !== "password" && selectedTag.subType !== "single_line" && tagHeight <= (fontSize + fontSize)) {
console.log("Change subType Called from elseif")
handlePropertyChange("subType", "single_line")
}
}
}, [selectedTag])
console.log("RightSideBar - selectedTag", selectedTag)
return (
<>
{/* Right Side Bar Start */}
<div className='col-span-2 w-full h-full bg-white text-sm'>
<p className="p-2 font-semibold text-md">Properties</p>
<hr className="text-slate-200" />
<div className="p-3 text-sm text-slate-600 flex flex-col gap-2">
{/* label */}
<div className="flex flex-col">
<label htmlFor="" className="">Label</label>
<input
value={selectedTag.label}
onChange={(e) => handlePropertyChange('label', e.target.value)}
type="text"
className="outline-none border-1 rounded px-2 py-1 border-slate-200" />
</div>
{/* Required */}
{(selectedTag.type !== "signature" && selectedTag.type !== "initials") && <div className="flex justify-between items-center">
<label htmlFor="required" className="text-xs text-slate-600 transitions-all duration-150">Required</label>
<input
id="required"
checked={selectedTag.required ? selectedTag.required : false}
onChange={(e) => handlePropertyChange('required', e.target.checked)}
type="checkbox"
className="outline-none border-1 rounded px-2 py-1 border-slate-200"
/>
</div>}
{/* Use Current TimeStamp */}
{selectedTag.type.toLowerCase() === "temporal" && <div className="flex justify-left items-center gap-1.5 mt-0.5">
<label
className={`text-xs ${isCurrentTimeStamp ? "text-slate-600" : "text-slate-400"} transitions-all duration-150`}
htmlFor="use_current_timestamp"
>
Use Current Timestamp
</label>
<input
checked={isCurrentTimeStamp ? isCurrentTimeStamp : false}
onChange={(e) => handleIsCurrentTimeStamp(e.target.checked)}
id="use_current_timestamp"
type="checkbox"
/>
</div>}
{/* Type | SubType */}
{selectedType && Object.keys(selectedType).length > 0 &&
<div className="flex flex-col">
<label htmlFor="" className="">Type</label>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.TYPE ? null : DROPDOWNTOGGLE.TYPE)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="capitalize cursor-pointer">{selectedTag?.subType ? (selectedTag.subType === "date_time" ? "Date Time" : selectedTag.subType) : selectedType[Object.keys(selectedType)[0] as keyof typeof selectedType]}</p>
<MdKeyboardArrowDown />
</div>
{dropDownToggle === DROPDOWNTOGGLE.TYPE &&
<div className="shadow bg-slate-100 mt-1 border-[1px] border-slate-100 rounded">
{Object.keys(selectedType).map((val, indx) => (
<div
key={indx}
onClick={() => handlePropertyChange("subType", selectedType[val as keyof typeof selectedType])}
className={`capitalize px-2 py-1 hover:bg-slate-200 cursor-pointer`}
>
{selectedType[val as keyof typeof selectedType] === "date_time" ? "Date Time" : selectedType[val as keyof typeof selectedType]}
</div>
))}
</div>
}
</div>
}
{/* Mask Type */}
{
selectedTag?.subType === TEXT.PASSWORD &&
<div>
<label htmlFor="" className="">Mask Type</label>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.MASK_TYPE ? null : DROPDOWNTOGGLE.MASK_TYPE)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="capitalize cursor-pointer">{(selectedTag.maskType && selectedTag.maskType.replace("_", " ")) ? selectedTag.maskType : MASKTYPE.ALL}</p>
<MdKeyboardArrowDown />
</div>
{
dropDownToggle === DROPDOWNTOGGLE.MASK_TYPE &&
<div className="shadow bg-slate-100 mt-1 border-[1px] border-slate-100 rounded">
{(Object.keys(MASKTYPE) as (keyof typeof MASKTYPE)[]).map((val, indx) =>
(
<div
key={indx}
onClick={() => handlePropertyChange("maskType", MASKTYPE[val])}
className="capitalize px-2 py-1 hover:bg-slate-200 cursor-pointer"
>
{(MASKTYPE[val]).replace("_", " ")}
</div>
)
)}
</div>
}
</div>
}
{/* Mask Character - START */}
{
selectedTag?.subType === TEXT.PASSWORD &&
<div>
<label htmlFor="" className="">Mask Character</label>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.MASK_CHARACTER ? null : DROPDOWNTOGGLE.MASK_CHARACTER)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="capitalize cursor-pointer py-1">
{selectedTag?.maskCharacter
?
selectedTag.maskCharacter === MASKCHARACTER.ASTERISK && <LuAsterisk /> ||
selectedTag.maskCharacter === MASKCHARACTER.DOT && <GoDotFill /> ||
selectedTag.maskCharacter === MASKCHARACTER.X && <IoClose />
:
<LuAsterisk />
}
</p>
<MdKeyboardArrowDown />
</div>
{
dropDownToggle === DROPDOWNTOGGLE.MASK_CHARACTER &&
<div className="shadow bg-slate-100 mt-1 border-[1px] border-slate-100 rounded">
{(Object.keys(MASKCHARACTER) as (keyof typeof MASKCHARACTER)[]).map((val, indx) =>
(
<div
key={indx}
onClick={() => handlePropertyChange("maskCharacter", MASKCHARACTER[val])}
className="capitalize p-2 hover:bg-slate-200 cursor-pointer"
>
{
MASKCHARACTER[val] === MASKCHARACTER.ASTERISK &&
<LuAsterisk />
}
{
MASKCHARACTER[val] === MASKCHARACTER.DOT &&
<GoDotFill />
}
{
MASKCHARACTER[val] === MASKCHARACTER.X &&
<IoClose />
}
</div>
)
)}
</div>
}
</div>
}
{/* Mask Character - END */}
{/* TEMPORAL DATE FORMAT - START */}
{
(selectedTag?.subType === TEMPORAL.DATE ||
selectedTag?.subType === TEMPORAL.TIME ||
selectedTag?.subType === TEMPORAL.DATE_TIME) &&
<div>
{/* <div className="flex justify-between">
<label htmlFor="" className="">Formats</label>
<div className="flex justify-center items-center gap-1.5">
<input
checked={showFormatEg ? showFormatEg : false}
onChange={(e) => setShowFormatEg(e.target.checked)}
id="data_time_format"
type="checkbox" />
<label className="text-xs text-slate-400" htmlFor="data_time_format">
Show Example
</label>
</div>
</div> */}
<div className="flex justify-between">
<label htmlFor="" className="">Formats</label>
{(selectedTag.subType === TEMPORAL.DATE_TIME || selectedTag.subType === TEMPORAL.TIME) &&
<div className="flex justify-center items-center gap-1.5">
<input
checked={is24Hrs ? is24Hrs : false}
onChange={(e) => handleIs24HrsClick(e.target.checked)}
id="data_time_format"
type="checkbox" />
<label className={`text-xs ${is24Hrs ? "text-slate-600" : "text-slate-400"} transitions-all duration-150`} htmlFor="data_time_format">
24 Hrs
</label>
</div>
}
</div>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.DDMMYY_FORMAT ? null : DROPDOWNTOGGLE.DDMMYY_FORMAT)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="cursor-pointer py-1">
{selectedTag.format ? selectedTag.format : dateTimeFormatMap['date'][0].format}
{/* {(selectedTag.subType !== TEMPORAL.DATE && selectedTag.subType !== TEMPORAL.TIME) ? (is24Hrs ? " " + timeFormats[0].format : " " + timeFormats[1].format) : ""} */}
</p>
<MdKeyboardArrowDown />
</div>
{
dropDownToggle === DROPDOWNTOGGLE.DDMMYY_FORMAT &&
<div className="shadow bg-slate-100 mt-1 border-[1px] max-h-[200px] overflow-y-auto border-slate-100 rounded">
{dateTimeFormatMap[selectedTag.subType].map((valObj, indx) => {
// let val = showFormatEg ? valObj["example"] : valObj["format"]
let val = valObj["format"]
if (selectedTag.subType === TEMPORAL.DATE_TIME) {
if (is24Hrs) {
val = val + " " + timeFormats[0].format;
} else {
val = val + " " + timeFormats[1].format;
}
}
return (
<div
key={indx}
onClick={() => handlePropertyChange("format", valObj["format"])}
className="px-2 py-1 hover:bg-slate-200 cursor-pointer"
>
{val}
</div>
)
}
)}
</div>
}
{selectedTag.format && <div className="pt-4">
{/* <p>
Example
</p> */}
<p className="text-center">{dayjs().format(selectedTag.format)}</p>
</div>}
</div>
}
{/* TEMPORAL DATE FORMAT - END */}
{/* NUMBER - DECIMAL PLACES */}
{
selectedTag?.subType === NUMBER.DECIMAL &&
<div>
<label htmlFor="" className="">Decimal Places</label>
<input
type="number"
onChange={(e) => handleDecimalPlace(e)}
value={decimalPlace}
className="bg-slate-100 w-full outline-none p-2 rounded" />
</div>
}
{(selectedTag?.subType === "single select" || selectedTag?.subType === "multi select") &&
<>
<div>
<label htmlFor="" className="">Add Options</label>
<input
type="text"
onChange={(e) => setSelectedOption(e.target.value)}
value={selectedOption}
onKeyUp={(e) => {
if (e.code === "Enter") {
// if (selectedOption) {
// setSelectedOptions((prev) => [...prev, selectedOption]);
// setSelectedOption("");
// }
handleAddSelectOption()
}
}}
className="bg-slate-100 w-full outline-none p-2 rounded" />
<div className="h-[150px] mt-1 overflow-hidden overflow-y-auto">
{
selectedTag.options && selectedTag.options.map((val, indx) => (
<div
key={indx}
className="flex justify-between items-center px-2 py-1 my-1 rounded bg-slate-100">
<p>{val}</p>
<IoMdClose
onClick={() =>
// setSelectedOptions(prev =>
// prev.filter((_, i) => i !== indx)
// )
handleSelectOptionDel(indx)
}
className="cursor-pointer text-slate-500 hover:text-slate-600" />
</div>
))
}
</div>
</div>
</>
}
</div>
</div>
{/* Right Side Bar End */}
</>
)
}
export default RightSideBar

View File

@ -0,0 +1,42 @@
import { MdKeyboardArrowDown } from 'react-icons/md';
import { DROPDOWNTOGGLE } from './RightSideBar';
interface CommonAttrDropDownInt {
selectedType: any;
subType: string | undefined;
dropDownToggle: DROPDOWNTOGGLE | null;
setDropDownToggle: React.Dispatch<React.SetStateAction<DROPDOWNTOGGLE | null>>;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number) => void;
}
const CommonAttrDropDown: React.FC<CommonAttrDropDownInt> = ({selectedType, subType, dropDownToggle, setDropDownToggle, handlePropertyChange}) => {
return (
<div className="flex flex-col">
<label htmlFor="" className="">Type</label>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.TYPE ? null : DROPDOWNTOGGLE.TYPE)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="capitalize cursor-pointer">{subType ? (subType === "date_time" ? "Date Time" : subType) : selectedType[Object.keys(selectedType)[0] as keyof typeof selectedType]}</p>
<MdKeyboardArrowDown />
</div>
{dropDownToggle === DROPDOWNTOGGLE.TYPE &&
<div className="shadow bg-slate-100 mt-1 border-[1px] border-slate-100 rounded">
{Object.keys(selectedType).map((val, indx) => (
<div
key={indx}
onClick={() => handlePropertyChange("subType", selectedType[val as keyof typeof selectedType])}
className={`capitalize px-2 py-1 hover:bg-slate-200 cursor-pointer`}
>
{selectedType[val as keyof typeof selectedType] === "date_time" ? "Date Time" : selectedType[val as keyof typeof selectedType]}
</div>
))}
</div>
}
</div>
)
}
export default CommonAttrDropDown

View File

@ -0,0 +1,37 @@
import React, { useState } from 'react'
interface CurrTimeStampAttrInt {
type: string;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number) => void;
}
const CurrTimeStampAttr: React.FC<CurrTimeStampAttrInt> = ({ type, handlePropertyChange}) => {
const [isCurrentTimeStamp, setIsCurrentTimeStamp] = useState<boolean>(true);
const handleIsCurrentTimeStamp = (checked: boolean) => {
if (type.toLowerCase() === "temporal") {
setIsCurrentTimeStamp(checked)
handlePropertyChange("currentTimeStamp", checked);
}
}
return (
<div className="flex justify-left items-center gap-1.5 mt-0.5">
<label
className={`text-xs ${isCurrentTimeStamp ? "text-slate-600" : "text-slate-400"} transitions-all duration-150`}
htmlFor="use_current_timestamp"
>
Use Current Timestamp
</label>
<input
checked={isCurrentTimeStamp ? isCurrentTimeStamp : false}
onChange={(e) => handleIsCurrentTimeStamp(e.target.checked)}
id="use_current_timestamp"
type="checkbox"
/>
</div>
)
}
export default CurrTimeStampAttr

View File

@ -0,0 +1,21 @@
import React from 'react'
interface LabelAttrInt {
label: string;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number) => void;
}
const LabelAttr: React.FC<LabelAttrInt> = ({ label, handlePropertyChange }) => {
return (
<div className="flex flex-col">
<label htmlFor="" className="">Label</label>
<input
value={label}
onChange={(e) => handlePropertyChange('label', e.target.value)}
type="text"
className="outline-none border-1 rounded px-2 py-1 border-slate-200" />
</div>
)
}
export default LabelAttr

View File

@ -0,0 +1,100 @@
import { MdKeyboardArrowDown } from "react-icons/md";
import { DROPDOWNTOGGLE, MASKCHARACTER, MASKTYPE } from "./RightSideBar";
import { LuAsterisk } from "react-icons/lu";
import { GoDotFill } from "react-icons/go";
import { IoClose } from "react-icons/io5";
interface MaskTypePassAttrInt {
maskType: string;
maskCharacter: string;
dropDownToggle: DROPDOWNTOGGLE | null;
setDropDownToggle: React.Dispatch<React.SetStateAction<DROPDOWNTOGGLE | null>>;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number) => void;
}
const MaskTypePassAttr: React.FC<MaskTypePassAttrInt> = ({ maskType, maskCharacter, dropDownToggle, setDropDownToggle, handlePropertyChange }) => {
return (
<>
{/* Mask Type */}
<div>
<label htmlFor="" className="">Mask Type</label>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.MASK_TYPE ? null : DROPDOWNTOGGLE.MASK_TYPE)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="capitalize cursor-pointer">{(maskType && maskType.replace("_", " ")) ? maskType : MASKTYPE.ALL}</p>
<MdKeyboardArrowDown />
</div>
{
dropDownToggle === DROPDOWNTOGGLE.MASK_TYPE &&
<div className="shadow bg-slate-100 mt-1 border-[1px] border-slate-100 rounded">
{(Object.keys(MASKTYPE) as (keyof typeof MASKTYPE)[]).map((val, indx) =>
(
<div
key={indx}
onClick={() => handlePropertyChange("maskType", MASKTYPE[val])}
className="capitalize px-2 py-1 hover:bg-slate-200 cursor-pointer"
>
{(MASKTYPE[val]).replace("_", " ")}
</div>
)
)}
</div>
}
</div>
{/* Mask Character */}
<div>
<label htmlFor="" className="">Mask Character</label>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.MASK_CHARACTER ? null : DROPDOWNTOGGLE.MASK_CHARACTER)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="capitalize cursor-pointer py-1">
{maskCharacter
?
maskCharacter === MASKCHARACTER.ASTERISK && <LuAsterisk /> ||
maskCharacter === MASKCHARACTER.DOT && <GoDotFill /> ||
maskCharacter === MASKCHARACTER.X && <IoClose />
:
<LuAsterisk />
}
</p>
<MdKeyboardArrowDown />
</div>
{
dropDownToggle === DROPDOWNTOGGLE.MASK_CHARACTER &&
<div className="shadow bg-slate-100 mt-1 border-[1px] border-slate-100 rounded">
{(Object.keys(MASKCHARACTER) as (keyof typeof MASKCHARACTER)[]).map((val, indx) =>
(
<div
key={indx}
onClick={() => handlePropertyChange("maskCharacter", MASKCHARACTER[val])}
className="capitalize p-2 hover:bg-slate-200 cursor-pointer"
>
{
MASKCHARACTER[val] === MASKCHARACTER.ASTERISK &&
<LuAsterisk />
}
{
MASKCHARACTER[val] === MASKCHARACTER.DOT &&
<GoDotFill />
}
{
MASKCHARACTER[val] === MASKCHARACTER.X &&
<IoClose />
}
</div>
)
)}
</div>
}
</div>
</>
)
}
export default MaskTypePassAttr

View File

@ -0,0 +1,29 @@
import React from 'react'
interface MaxMinLenAttrIntr {
maxLength: number;
minLength: number;
}
const MaxMinLenAttr : React.FC<MaxMinLenAttrIntr> = ({ maxLength, minLength }) => {
return (
<>
<div>
<label htmlFor="">Max Length</label>
<input
value={minLength ? minLength : 0}
type="number"
className="outline-none border-1 rounded px-2 py-1 border-slate-200" />
</div>
<div className="mt-2">
<label htmlFor="">Min Length</label>
<input
value={maxLength ? maxLength : 255}
type="number"
className="outline-none border-1 rounded px-2 py-1 border-slate-200" />
</div>
</>
)
}
export default MaxMinLenAttr

View File

@ -0,0 +1,88 @@
import React, { useEffect, useState } from 'react'
import { IoCheckmark } from 'react-icons/io5';
import { MdKeyboardArrowDown } from 'react-icons/md';
import { useSelector } from 'react-redux';
import { RootState } from '../../../../store/store';
interface SelectedRecipientsIntr {
id: number;
firstName: string;
lastName: string;
color: string;
}
interface RecipientsAttrConIntr {
selectedRecipientId: number;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number) => void;
}
const RecipientsAttrCon: React.FC<RecipientsAttrConIntr> = ({ selectedRecipientId, handlePropertyChange }) => {
const [selectedRecipient, setSelectedRecipient] = useState(null);
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients);
const [dropDownToggle, setDropDownToggle] = useState(false);
useEffect(() => {
if (selectedRecipients.length) {
const filter = selectedRecipients.filter((obj, indx) => obj.id == selectedRecipientId)
setSelectedRecipient(filter[0]);
}
}, [selectedRecipientId])
if (!selectedRecipient) {
return (
<>
</>
)
}
return (
<>
<div className='relative'
tabIndex={0}
onBlur={() => setDropDownToggle(false)}>
{/* Selected Recipient */}
<div
onClick={() => setDropDownToggle(!dropDownToggle)}
className='flex items-center justify-between gap-2 w-full p-2 text-xs rounded-sm border-1 border-slate-200 cursor-pointer'>
<div className='flex items-center gap-1.5'>
<p className='w-3 h-3 rounded-sm' style={{ background: selectedRecipient.color }}></p>
{/* <FaUserTie className='w-3 h-3 text-2xl mt-[1px]' style={{ color: selectedRecipient.color }} /> */}
<p>{"firstName" in selectedRecipient && selectedRecipient.firstName} {"lastName" in selectedRecipient && selectedRecipient.lastName}</p>
</div>
<MdKeyboardArrowDown />
</div>
<div
className={`absolute w-full shadow-md rounded-md mt-1 px-2 py-1 z-20 bg-white ${dropDownToggle ? '' : 'hidden'}`}>
{selectedRecipients.length && selectedRecipients.map((recipient, indx) => {
return (<div
key={indx}
className='flex items-center justify-between gap-2 w-full p-2 text-xs rounded-sm cursor-pointer hover:bg-slate-100'
onClick={() => {
// handlePropertyChange()
setTimeout(() => {
setDropDownToggle(false);
}, 0)
}}
>
<div className='flex items-center gap-1.5'>
<p className='w-3 h-3 rounded-sm' style={{ background: recipient.color }}></p>
{/* <FaUser className='w-3 h-3 text-2xl mt-[1px]' style={{ color: recipient.color }} /> */}
<p>{recipient.firstName} {recipient.lastName} </p>
</div>
{selectedRecipientId === recipient.id && <IoCheckmark className='text-[var(--primary)]' />}
</div>)
})}
</div>
</div>
</>
)
}
export default RecipientsAttrCon

View File

@ -0,0 +1,23 @@
import React from 'react'
interface RequiredAttrInt {
required: boolean;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number) => void;
}
const RequiredAttr : React.FC<RequiredAttrInt> = ({required, handlePropertyChange}) => {
return (
<div className="flex justify-between items-center">
<label htmlFor="required" className="text-xs text-slate-600 transitions-all duration-150">Required</label>
<input
id="required"
checked={required ? required : false}
onChange={(e) => handlePropertyChange('required', e.target.checked)}
type="checkbox"
className="outline-none border-1 rounded px-2 py-1 border-slate-200"
/>
</div>
)
}
export default RequiredAttr

View File

@ -0,0 +1,367 @@
import { DroppedItemsObj } from "../DocumentContainer";
import React, { useEffect, useState } from "react";
import { dateFormats, dateTimeFormats, timeFormats } from "../../../../utlity/dateTimeFormats";
import { DroppedItem } from "../../../../utlity/types";
import { IoIosArrowDown } from "react-icons/io";
import { TagsTypes } from "../../../../utlity/types";
import LabelAttr from "./LabelAttr";
import RequiredAttr from "./RequiredAttr";
import CurrTimeStampAttr from "./currTimeStampAttr";
import CommonAttrDropDown from "./CommonAttrDropDown";
import MaskTypePassAttr from "./MaskTypePassAttr";
import TemporalDateAttr from "./TemporalDateAttr";
import SelectTagAttr from "./SelectTagAttr";
import MaxMinLenAttr from "./MaxMinLenAttr";
import RecipientsAttrCon from "./RecipientsAttrCon";
export interface DroppedItemProps {
selectedTag: DroppedItem
setDroppedItems: React.Dispatch<React.SetStateAction<DroppedItemsObj>>
selTagKey: string,
selTagIndx: number
}
export enum TEXT {
PARAGRAPH = "paragraph",
SINGLE_LINE = "single_line",
PASSWORD = "password",
}
export enum TEMPORAL {
DATE = "date",
TIME = "time",
DATE_TIME = "date_time",
}
export enum NUMBER {
INTEGER = "integer",
DECIMAL = "decimal",
CURRENCY = "currency"
}
export enum SELECT {
SINGLE_SELECT = "single select",
MULTI_SELECT = "multi select"
}
export enum MASKTYPE {
ALL = "all",
LAST_FOUR = "last_four",
CREDIT_CARD = "credit_Card",
NATIONAL_INSURANCE = "national_insurance",
SOCIAL_SECURITY = "social_security",
SOCIAL_INSURANCE = "social_insurance"
}
export enum MASKCHARACTER {
ASTERISK = "ASTERISK",
DOT = "DOT",
X = "CROSS",
}
export const enumMap = {
text: TEXT,
temporal: TEMPORAL,
number: NUMBER,
image: String,
select: SELECT
}
export enum DROPDOWNTOGGLE {
TYPE,
MASK_TYPE,
MASK_CHARACTER,
DDMMYY_FORMAT
}
const RightSideBar: React.FC<DroppedItemProps> = ({ selectedTag, setDroppedItems, selTagKey, selTagIndx }) => {
const selectedType = selectedTag.type in enumMap && enumMap[selectedTag.type as keyof typeof enumMap];
const [dropDownToggle, setDropDownToggle] = useState<DROPDOWNTOGGLE | null>(null);
const [decimalPlace, setDecimalPlace] = useState<number>(2)
const [styleOpen, setStyleOpen] = useState(false);
const handlePropertyChange = (changeTo: string, changeWith: string | boolean | number, is24Hrs=null) => {
console.log("Handle Property Change Called", "changeTo", changeTo, "changeWith", changeWith)
if (changeTo === '' || changeWith === '') return
if (changeTo === "subType" && (changeWith === TEMPORAL.DATE || changeWith === TEMPORAL.DATE_TIME || changeWith === TEMPORAL.TIME)) {
// let change: string = changeWith;
// if (change === "DATE TIME") {
// change = "DATE_TIME"
// }
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith || "", format: "", update: true } : item
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
} else if (changeTo === "subType" && typeof changeWith === "string" && changeWith.toLowerCase() === "password") {
console.log("Line 161")
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey])
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith, maskType: "All", maskCharacter: "ASTERISK", update: true } : item
)
: [],
}
));
}
else if (changeTo === "subType" && (changeWith === NUMBER.CURRENCY || changeWith === NUMBER.INTEGER || changeWith === NUMBER.DECIMAL)) {
let decPlace = changeWith !== NUMBER.DECIMAL ? 0 : decimalPlace;
const isCurrency = changeWith === NUMBER.CURRENCY;
// const currencyType = null
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith, decimalPlace: decPlace, isCurrency, update: true } : item
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
} else if (changeTo === "format" && selectedTag.subType === TEMPORAL.DATE_TIME) {
let val = timeFormats[0].format;
if (!is24Hrs) {
val = timeFormats[1].format
}
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? 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 {
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey]) // Ensure it's an array
? prev[selTagKey].map((item, i) =>
i === selTagIndx ? { ...item, [changeTo]: changeWith, update: true } : item
)
: [],
}// Provide a fallback in case it's undefined or not an array
));
}
setDropDownToggle(null)
}
useEffect(() => {
if (selectedTag.subType === TEMPORAL.DATE || selectedTag.subType === TEMPORAL.DATE_TIME || selectedTag.subType === TEMPORAL.TIME) {
if (selectedTag.subType === TEMPORAL.DATE) {
handlePropertyChange("format", dateFormats[0].format)
}
else if (selectedTag.subType === TEMPORAL.DATE_TIME) {
handlePropertyChange("format", dateTimeFormats[0].format)
}
else if (selectedTag.subType === TEMPORAL.TIME) {
handlePropertyChange("format", timeFormats[0].format)
}
}
}, [selectedTag.subType])
useEffect(() => {
if (selectedTag.label === "temporal") {
handlePropertyChange("subType", TEMPORAL.DATE);
handlePropertyChange("format", "DD/MM/YY");
}
}, [])
const handleDecimalPlace = (e: React.ChangeEvent<HTMLInputElement>) => {
const val = Number(e.target.value)
setDecimalPlace(val)
handlePropertyChange("decimalPlace", val)
}
useEffect(() => {
if ("styles" in selectedTag) {
const fontSize = selectedTag?.styles?.textSize;
const tagHeight = selectedTag?.dimensions?.height - 18;
if (selectedTag.subType !== TEXT.PASSWORD && selectedTag.subType !== TEXT.PARAGRAPH && tagHeight > (fontSize + fontSize)) {
handlePropertyChange("subType", TEXT.PARAGRAPH)
} else if (selectedTag.subType !== TEXT.PASSWORD && selectedTag.subType !== TEXT.SINGLE_LINE && tagHeight <= (fontSize + fontSize)) {
console.log("Change subType Called from elseif")
handlePropertyChange("subType", TEXT.SINGLE_LINE)
}
}
}, [selectedTag])
return (
<>
{/* Right Side Bar Start */}
<div className='col-span-2 w-full h-full bg-white text-sm'>
<p className="p-2 font-semibold text-md">Properties</p>
<hr className="text-slate-200" />
<div className="p-3 text-sm text-slate-600 flex flex-col gap-2">
{
<RecipientsAttrCon selectedRecipientId={selectedTag.recipientId} handlePropertyChange={handlePropertyChange} />
}
{selectedTag.label &&
<LabelAttr label={selectedTag.label} handlePropertyChange={handlePropertyChange} />}
{(selectedTag.type !== TagsTypes.SIGNATURE && selectedTag.type !== TagsTypes.INITIALS) &&
<RequiredAttr required={selectedTag.required ? selectedTag.required : false} handlePropertyChange={handlePropertyChange} />}
{selectedTag.type.toLowerCase() === TagsTypes.TEMPORAL &&
<CurrTimeStampAttr type={selectedTag.type} handlePropertyChange={handlePropertyChange} />}
{
selectedType && Object.keys(selectedType).length > 0 &&
<CommonAttrDropDown
selectedType={selectedType}
subType={selectedTag.subType}
dropDownToggle={dropDownToggle}
setDropDownToggle={setDropDownToggle}
handlePropertyChange={handlePropertyChange} />
}
{/* Mask Type */}
{
selectedTag?.subType === TEXT.PASSWORD &&
<MaskTypePassAttr
maskType={selectedTag.maskType ? selectedTag.maskType : MASKTYPE.ALL}
maskCharacter={selectedTag.maskCharacter ? selectedTag.maskCharacter : MASKCHARACTER.ASTERISK}
dropDownToggle={dropDownToggle}
setDropDownToggle={setDropDownToggle}
handlePropertyChange={handlePropertyChange} />
}
{/* TEMPORAL DATE FORMAT - START */}
{
(selectedTag?.subType === TEMPORAL.DATE ||
selectedTag?.subType === TEMPORAL.TIME ||
selectedTag?.subType === TEMPORAL.DATE_TIME) &&
<TemporalDateAttr
subType={selectedTag.subType}
format={selectedTag.format}
dropDownToggle={dropDownToggle}
setDropDownToggle={setDropDownToggle}
handlePropertyChange={handlePropertyChange} />
}
{/* TEMPORAL DATE FORMAT - END */}
{/* NUMBER - DECIMAL PLACES */}
{
selectedTag?.subType === NUMBER.DECIMAL &&
<div>
<label htmlFor="" className="">Decimal Places</label>
<input
type="number"
onChange={(e) => handleDecimalPlace(e)}
value={decimalPlace}
className="bg-slate-100 w-full outline-none p-2 rounded" />
</div>
}
{
(selectedTag?.subType === SELECT.SINGLE_SELECT || selectedTag?.subType === SELECT.MULTI_SELECT) &&
<SelectTagAttr
options={selectedTag.options}
selTagKey={selTagKey}
selTagIndx={selTagIndx}
setDroppedItems={setDroppedItems}
handlePropertyChange={handlePropertyChange} />
}
{
selectedTag.type === TagsTypes.TEXT &&
<MaxMinLenAttr maxLength={selectedTag.maxLength} minLength={selectedTag.minLength} />
}
{
<div className="">
<div className="flex items-center justify-between mr-2 cursor-pointer"
onClick={() => setStyleOpen(!styleOpen)}
>
<label
className="block mb-2">Styles</label>
<IoIosArrowDown className={`${styleOpen ? "rotate-[-90deg]" : ""} transition-all`} />
</div>
{
styleOpen && <>
{/* Font */}
<div className="mb-2">
<label className="mr-2">Font</label>
<input
type="text"
placeholder="e.g. Arial"
className="outline-none border-1 rounded px-2 py-1 border-slate-200"
/>
</div>
{/* Text Size */}
<div className="mb-2">
<label className="mr-2">Text Size</label>
<input
// value={}
type="number"
className="outline-none border-1 rounded px-2 py-1 border-slate-200"
/>
</div>
{/* Color */}
<div className="mb-2">
<label className="mr-2">Color</label>
<input
type="color"
className="outline-none border-1 rounded px-2 py-1 border-slate-200 w-10 h-8"
/>
</div>
{/* Toggles for Bold, Italic, Underline */}
<div className="flex gap-4 items-center mt-2">
<label className="flex gap-1 items-center">
<input type="checkbox" />
Bold
</label>
<label className="flex gap-1 items-center">
<input type="checkbox" />
Italic
</label>
<label className="flex gap-1 items-center">
<input type="checkbox" />
Underline
</label>
</div>
</>
}
</div>
}
</div>
</div>
{/* Right Side Bar End */}
</>
)
}
export default RightSideBar

View File

@ -0,0 +1,95 @@
import { useState } from "react";
import { DROPDOWNTOGGLE } from "./RightSideBar";
import { DroppedItemsObj } from "../DocumentContainer";
import { IoMdClose } from "react-icons/io";
interface SelectTagAttrInt {
options: string[] | undefined;
selTagKey: string;
selTagIndx: number;
setDroppedItems: React.Dispatch<React.SetStateAction<DroppedItemsObj>>;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number) => void;
}
const SelectTagAttr: React.FC<SelectTagAttrInt> = ({ options, selTagKey, selTagIndx, setDroppedItems, handlePropertyChange }) => {
const [selectedOption, setSelectedOption] = useState<string>()
const handleAddSelectOption = () => {
if (selectedOption && selectedOption.length) {
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey])
? prev[selTagKey].map((item, i) => {
if (i === selTagIndx) {
return { ...item, options: item.options ? [...item.options, selectedOption] : [selectedOption], update: true };
}
return item;
})
: [],
}
));
}
}
const handleSelectOptionDel = (indx: number) => {
setDroppedItems((prev) => (
{
...prev,
[selTagKey]: Array.isArray(prev[selTagKey])
? prev[selTagKey].map((item, i) => {
if (i === selTagIndx) {
return { ...item, options: item.options ? item.options.filter((_, i) => i !== indx) : [] };
}
return item;
})
: [],
}
));
}
return (
<>
<div>
<label htmlFor="" className="">Add Options</label>
<input
type="text"
onChange={(e) => setSelectedOption(e.target.value)}
value={selectedOption}
onKeyUp={(e) => {
if (e.code === "Enter") {
// if (selectedOption) {
// setSelectedOptions((prev) => [...prev, selectedOption]);
// setSelectedOption("");
// }
handleAddSelectOption()
}
}}
className="bg-slate-100 w-full outline-none p-2 rounded" />
<div className="h-[150px] mt-1 overflow-hidden overflow-y-auto">
{
options && options.map((val, indx) => (
<div
key={indx}
className="flex justify-between items-center px-2 py-1 my-1 rounded bg-slate-100">
<p>{val}</p>
<IoMdClose
onClick={() =>
// setSelectedOptions(prev =>
// prev.filter((_, i) => i !== indx)
// )
handleSelectOptionDel(indx)
}
className="cursor-pointer text-slate-500 hover:text-slate-600" />
</div>
))
}
</div>
</div>
</>
)
}
export default SelectTagAttr

View File

@ -0,0 +1,108 @@
import { useEffect, useState } from "react";
import { dateFormats, dateTimeFormats, monthFormats, timeFormats, weekFormats, yearFormats } from "../../../../utlity/dateTimeFormats";
import { DROPDOWNTOGGLE, TEMPORAL } from "./RightSideBar";
import { MdKeyboardArrowDown } from "react-icons/md";
import dayjs from "dayjs";
const dateTimeFormatMap = {
"date": dateFormats,
"time": timeFormats,
"date_time": dateTimeFormats,
"year": yearFormats,
"month": monthFormats,
"week": weekFormats
}
interface TemporalDateAttrInt {
subType: string;
format: string | undefined;
dropDownToggle: DROPDOWNTOGGLE | null;
setDropDownToggle: React.Dispatch<React.SetStateAction<DROPDOWNTOGGLE | null>>;
handlePropertyChange: (changeTo: string, changeWith: string | boolean | number, is24Hrs: boolean) => void;
}
const TemporalDateAttr: React.FC<TemporalDateAttrInt> = ({ subType, format, dropDownToggle, setDropDownToggle, handlePropertyChange }) => {
const [is24Hrs, setIs24Hrs] = useState<boolean>(true);
const handleIs24HrsClick = (checked: boolean) => {
if (subType === TEMPORAL.TIME) {
if (!checked) {
handlePropertyChange("format", timeFormats[1].format, is24Hrs)
} else {
handlePropertyChange("format", timeFormats[0].format, is24Hrs)
}
}
setIs24Hrs(checked)
}
useEffect(() => {
if (format === timeFormats[1].format && is24Hrs) {
setIs24Hrs(false);
} else if (format === timeFormats[0].format && !is24Hrs) {
setIs24Hrs(true);
}
}, [format])
return (
<div>
<div className="flex justify-between">
<label htmlFor="" className="">Formats</label>
{(subType === TEMPORAL.DATE_TIME || subType === TEMPORAL.TIME) &&
<div className="flex justify-center items-center gap-1.5">
<input
checked={is24Hrs ? is24Hrs : false}
onChange={(e) => handleIs24HrsClick(e.target.checked)}
id="data_time_format"
type="checkbox" />
<label className={`text-xs ${is24Hrs ? "text-slate-600" : "text-slate-400"} transitions-all duration-150`} htmlFor="data_time_format">
24 Hrs
</label>
</div>
}
</div>
<div
onClick={() => setDropDownToggle(dropDownToggle === DROPDOWNTOGGLE.DDMMYY_FORMAT ? null : DROPDOWNTOGGLE.DDMMYY_FORMAT)}
className="flex justify-between items-center border-1 rounded px-2 py-1 border-slate-200">
<p className="cursor-pointer py-1">
{format ? format : dateTimeFormatMap['date'][0].format}
{/* {(subType !== TEMPORAL.DATE && subType !== TEMPORAL.TIME) ? (is24Hrs ? " " + timeFormats[0].format : " " + timeFormats[1].format) : ""} */}
</p>
<MdKeyboardArrowDown />
</div>
{
dropDownToggle === DROPDOWNTOGGLE.DDMMYY_FORMAT &&
<div className="shadow bg-slate-100 mt-1 border-[1px] max-h-[200px] overflow-y-auto border-slate-100 rounded">
{dateTimeFormatMap[subType].map((valObj, indx) => {
// let val = showFormatEg ? valObj["example"] : valObj["format"]
let val = valObj["format"]
if (subType === TEMPORAL.DATE_TIME) {
if (is24Hrs) {
val = val + " " + timeFormats[0].format;
} else {
val = val + " " + timeFormats[1].format;
}
}
return (
<div
key={indx}
onClick={() => handlePropertyChange("format", valObj["format"])}
className="px-2 py-1 hover:bg-slate-200 cursor-pointer"
>
{val}
</div>
)
}
)}
</div>
}
{format && <div className="pt-4">
<p className="text-center">{dayjs().format(format)}</p>
</div>}
</div>
)
}
export default TemporalDateAttr

View File

@ -28,7 +28,8 @@ api.interceptors.response.use(
async error => { async error => {
const originalRequest = error.config; const originalRequest = error.config;
// Prevent multiple refresh attempts // Prevent multiple refresh attempts
if (error.response?.status === 401 || error.response?.status === 500) { // if (error.response?.status === 401 || error.response?.status === 500) {
if (error.response?.status === 401) {
originalRequest._retry = true; originalRequest._retry = true;
try { try {
if (!isRefreshing) { if (!isRefreshing) {

View File

@ -134,7 +134,6 @@ const documentSlice = createSlice({
}) })
.addCase(fetchDocuments.fulfilled, (state, action: PayloadAction<Document[]>) => { .addCase(fetchDocuments.fulfilled, (state, action: PayloadAction<Document[]>) => {
state.loading = false; state.loading = false;
console.log(action.payload, "action.payload")
state.documents = action.payload; state.documents = action.payload;
}) })
.addCase(fetchDocuments.rejected, (state, action) => { .addCase(fetchDocuments.rejected, (state, action) => {

View File

@ -180,10 +180,9 @@ const selectedRecipientsSlice = createSlice({
extraReducers: (builder) => { extraReducers: (builder) => {
builder builder
.addCase(fetchRecipients.pending, (state) => { .addCase(fetchRecipients.pending, (state) => {
console.log("Fetching recipients...");
}) })
.addCase(fetchRecipients.fulfilled, (state, action: PayloadAction<Recipient[]>) => { .addCase(fetchRecipients.fulfilled, (state, action: PayloadAction<Recipient[]>) => {
console.log("Fetched recipients successfully:", action.payload); // console.log("Fetched recipients successfully:", action.payload);
// Assign colors to recipients // Assign colors to recipients
const assignedRecipients = action.payload.map((recipient, index) => ({ const assignedRecipients = action.payload.map((recipient, index) => ({
@ -209,7 +208,7 @@ const selectedRecipientsSlice = createSlice({
.addCase(addRecipientAsync.pending, (state) => { .addCase(addRecipientAsync.pending, (state) => {
console.log("Fetching recipients...");
}) })
.addCase(addRecipientAsync.fulfilled, (state, action: PayloadAction<Recipient>) => { .addCase(addRecipientAsync.fulfilled, (state, action: PayloadAction<Recipient>) => {
console.log("Added recipient successfully:", action.payload); console.log("Added recipient successfully:", action.payload);

View File

@ -79,3 +79,41 @@ export interface AccountData {
role: UserRole; role: UserRole;
status: AccountStatus; status: AccountStatus;
} }
export interface TagsProperties {
"editable": boolean;
"required": boolean;
"navigationOrder": number;
"type": string;
"lastName"?: boolean;
"firstName"?: boolean;
"maxLength"?: number;
"minLength"?: number;
"readOnly"?: boolean;
"multiLine"?: boolean;
"regex"?: string[];
"format"?: string;
"dateFormat"?: string;
"currentTimeStamp"?: boolean;
"decimalPlace"?: number;
"multiSelect"?: boolean;
}
export enum TagsTypes {
TEXT= "text",
SIGNATURE= "signature",
INITIALS= "initials",
TEMPORAL= "temporal",
NUMBER= "number",
IMAGE= "image",
STAMP= "stamp",
CHECKBOX= "checkbox",
SELECT= "select",
FILE= "file",
ATTACHMENT= "attachment",
RADIO= "radio",
EMAIL= "email",
NAME= "name",
COMPANY= "company",
}