jai #8
|
|
@ -41,7 +41,7 @@ const App = () => {
|
|||
<Route path="/accounts/:accountId/transactions" element={<Account />} />
|
||||
<Route path="/transactions" element={<Account />} />
|
||||
<Route path="/accounts/:accountId/transactions/:transactionId" element={<TransactionView />} />
|
||||
<Route path="/transactions/:filterParam" element={<Transactions />} />
|
||||
{/* <Route path="/transactions/:filterParam" element={<Transactions />} /> */}
|
||||
<Route path="/templates" element={<Templates />} />
|
||||
{/* </Route> */}
|
||||
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ const CommonNav: React.FC<AccountNavProps> = () => {
|
|||
<header className="w-full px-6 py-2 flex justify-between items-center bg-white border-b rounded-sm border-gray-200">
|
||||
<nav className="text-md font-medium text-gray-800 capitalize flex items-center flex-wrap">
|
||||
{pathnames.length === 0 ? (
|
||||
<span className="text-gray-900 font-semibold">Dashboard</span>
|
||||
<span className="text-gray-900 font-semibold">Home</span>
|
||||
) : (
|
||||
pathnames.map((segment, index) => {
|
||||
const label = labelMap[segment] || formatSegment(segment);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {
|
|||
FaFilter,
|
||||
FaCalendarAlt
|
||||
} from 'react-icons/fa';
|
||||
import TransactionDataTable from "./TransactionDataTable";
|
||||
|
||||
interface Transaction {
|
||||
id: number;
|
||||
|
|
@ -28,12 +29,6 @@ interface Transaction {
|
|||
expireAfter: number | null;
|
||||
}
|
||||
|
||||
const formatDate = (timestamp: number) => {
|
||||
return new Date(timestamp * 1000).toLocaleString();
|
||||
};
|
||||
|
||||
|
||||
|
||||
const Account = () => {
|
||||
const mapApiDataToCards = (data: any): CardData[] => {
|
||||
return [
|
||||
|
|
@ -115,12 +110,9 @@ const Account = () => {
|
|||
JSON.parse(sessionStorage.getItem('activeAccountId') || 'null')
|
||||
);
|
||||
|
||||
const [currentEmailId, setCurrentEmailId] = useState<string | null>('null');
|
||||
|
||||
console.log("activeAccountId Trans.", activeAccountId)
|
||||
// const { accountId } = useParams<{ accountId: string }>();
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [selectedTransactions, setSelectedTransactions] = useState<number[]>([]);
|
||||
const [accountsData, setAccountsData] = useState([])
|
||||
const [inviteLoading, setInviteLoading] = useState(false);
|
||||
const [cards, setCards] = useState<CardData[]>([]);
|
||||
|
|
@ -143,12 +135,6 @@ const Account = () => {
|
|||
// getUserDetails()
|
||||
// }, [])
|
||||
|
||||
useEffect(() => {
|
||||
const userDetails = JSON.parse(sessionStorage.getItem('userDetails'));
|
||||
setCurrentEmailId(userDetails?.email)
|
||||
}, []);
|
||||
|
||||
|
||||
// Listen for sessionStorage changes
|
||||
useEffect(() => {
|
||||
const handleStorageChange = (e: StorageEvent) => {
|
||||
|
|
@ -195,20 +181,9 @@ const Account = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const fetchTransactions = async () => {
|
||||
console.log("fetchTransactions")
|
||||
try {
|
||||
const response = await api(`/api/accounts/${activeAccountId}/transactions`);
|
||||
setTransactions(response.data || []);
|
||||
} catch (error) {
|
||||
console.error("Error fetching transactions:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (activeAccountId) {
|
||||
getDashboardData()
|
||||
fetchTransactions();
|
||||
}
|
||||
}, [activeAccountId]);
|
||||
|
||||
|
|
@ -276,68 +251,9 @@ const Account = () => {
|
|||
<>
|
||||
<Cards type="transactions" onOpenModal={handleOpenModal} cards={cards}
|
||||
isLoading={isLoading} />
|
||||
{transactions.length > 0 && (
|
||||
<div className="overflow-x-auto py-2">
|
||||
<table className="min-w-full text-sm border border-gray-200 rounded bg-white shadow-sm">
|
||||
<thead className="bg-gray-100 text-gray-700 uppercase text-xs tracking-wider">
|
||||
<tr>
|
||||
<th className="px-4 py-3 text-left"></th>
|
||||
<th className="px-4 py-3 text-center">Name</th>
|
||||
<th className="px-4 py-3 text-center">Status</th>
|
||||
<th className="px-4 py-3 text-center">Active</th>
|
||||
<th className="px-4 py-3 text-center">Last Change</th>
|
||||
<th className="px-4 py-3 text-center">Expire After (days)</th>
|
||||
<th className="px-4 py-3 text-center">Sign</th>
|
||||
<th className="px-4 py-3 text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{transactions.map((tx) => {
|
||||
const lastModifiedAt = new Date(tx.lastModifiedAt, "DD/MM/YYYY");
|
||||
return (
|
||||
<tr
|
||||
key={tx.id}
|
||||
onClick={() => handleTransactionClick(tx.id)}
|
||||
className="hover:bg-gray-50 cursor-pointer"
|
||||
>
|
||||
<td className="px-4 py-3">
|
||||
<div className="w-5 h-5 rounded border border-slate-300 flex justify-center items-center">
|
||||
{selectedTransactions.includes(tx.id) && (
|
||||
<FaCheck className="text-purple-600 text-sm" />
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
{tx.subject || "Untitled"}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
<span className="px-2 py-0.5 rounded-xl text-xs font-medium bg-blue-100 text-blue-700">
|
||||
{tx.status}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
{tx.active ? "Yes" : "No"}
|
||||
</td>
|
||||
|
||||
<td className="px-4 py-3 text-center">
|
||||
{formatDate(tx.lastModifiedAt)}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
{tx.expireAfter ?? "-"}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center ">
|
||||
{tx?.createdBy?.email === currentEmailId ? <button className="px-2 py-0.5 rounded-xl text-xs font-medium bg-green-100 text-green-700 cursor-pointer">Sign now</button> : "-"}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
<PiDotsThreeOutlineVerticalFill className="text-lg text-slate-300 hover:text-black mx-auto" />
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
<TransactionDataTable />
|
||||
|
||||
{isModalOpen && <AddInviteModal onClose={() => setIsModalOpen(false)} onInvite={handleInvite} inviteLoading={inviteLoading}
|
||||
accountOptions={accountsData} />}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { PiDotsThreeOutlineVerticalFill } from 'react-icons/pi';
|
||||
import api from '../../config/api';
|
||||
import { Transaction } from '../transactions/Transactions';
|
||||
|
||||
|
||||
|
||||
const formatDate = (timestamp: number) => {
|
||||
return new Date(timestamp * 1000).toLocaleString();
|
||||
};
|
||||
|
||||
const TransactionDataTable = () => {
|
||||
const [currentEmailId, setCurrentEmailId] = useState<string | null>('null');
|
||||
const [selectedTransactions, setSelectedTransactions] = useState<number[]>([]);
|
||||
const [activeAccountId, setActiveAccountId] = useState<string | null>(
|
||||
JSON.parse(sessionStorage.getItem('activeAccountId') || 'null')
|
||||
);
|
||||
|
||||
const fetchTransactions = async () => {
|
||||
console.log("fetchTransactions")
|
||||
try {
|
||||
const response = await api(`/api/accounts/${activeAccountId}/transactions`);
|
||||
setTransactions(response.data || []);
|
||||
} catch (error) {
|
||||
console.error("Error fetching transactions:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeAccountId) {
|
||||
fetchTransactions();
|
||||
}
|
||||
}, [activeAccountId]);
|
||||
|
||||
useEffect(() => {
|
||||
const userDetails = JSON.parse(sessionStorage.getItem('userDetails'));
|
||||
setCurrentEmailId(userDetails?.email)
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{transactions.length > 0 && (
|
||||
<div className="overflow-x-auto py-2">
|
||||
<table className="min-w-full text-sm border border-gray-200 rounded bg-white shadow-sm">
|
||||
<thead className="bg-gray-100 text-gray-700 uppercase text-xs tracking-wider">
|
||||
<tr>
|
||||
<th className="px-4 py-3 text-left"></th>
|
||||
<th className="px-4 py-3 text-center">Name</th>
|
||||
<th className="px-4 py-3 text-center">Status</th>
|
||||
<th className="px-4 py-3 text-center">Active</th>
|
||||
<th className="px-4 py-3 text-center">Last Change</th>
|
||||
<th className="px-4 py-3 text-center">Expire After (days)</th>
|
||||
<th className="px-4 py-3 text-center">Sign</th>
|
||||
<th className="px-4 py-3 text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{transactions.map((tx) => {
|
||||
const lastModifiedAt = new Date(tx.lastModifiedAt, "DD/MM/YYYY");
|
||||
return (
|
||||
<tr
|
||||
key={tx.id}
|
||||
onClick={() => handleTransactionClick(tx.id)}
|
||||
className="hover:bg-gray-50 cursor-pointer"
|
||||
>
|
||||
<td className="px-4 py-3">
|
||||
<div className="w-5 h-5 rounded border border-slate-300 flex justify-center items-center">
|
||||
{selectedTransactions.includes(tx.id) && (
|
||||
<FaCheck className="text-purple-600 text-sm" />
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
{tx.subject || "Untitled"}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
<span className="px-2 py-0.5 rounded-xl text-xs font-medium bg-blue-100 text-blue-700">
|
||||
{tx.status}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
{tx.active ? "Yes" : "No"}
|
||||
</td>
|
||||
|
||||
<td className="px-4 py-3 text-center">
|
||||
{formatDate(tx.lastModifiedAt)}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
{tx.expireAfter ?? "-"}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center ">
|
||||
{tx?.createdBy?.email === currentEmailId ? <button className="px-2 py-0.5 rounded-xl text-xs font-medium bg-green-100 text-green-700 cursor-pointer">Sign now</button> : "-"}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
<PiDotsThreeOutlineVerticalFill className="text-lg text-slate-300 hover:text-black mx-auto" />
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TransactionDataTable
|
||||
|
|
@ -303,7 +303,7 @@ const SignDocument = () => {
|
|||
console.log(res, "Line 288")
|
||||
|
||||
setSelectedDocuments(res.data.documents)
|
||||
setRecipient(res.data.recipient)
|
||||
setRecipient(res.data.details)
|
||||
setDroppedItems(res.data.tagJsons)
|
||||
setTransaction(res.data.transaction)
|
||||
setRecSignStatus(res.data.status)
|
||||
|
|
@ -810,6 +810,10 @@ const SignDocument = () => {
|
|||
</div>
|
||||
|
||||
|
||||
<p className="text-xs text-slate-600">Hi! {recipient && recipient.firstName} {recipient && recipient.lastName}</p>
|
||||
|
||||
|
||||
|
||||
{/* Right Side - STARTS */}
|
||||
<div className='flex justify-center items-center'>
|
||||
|
||||
|
|
@ -846,15 +850,15 @@ const SignDocument = () => {
|
|||
{(!transparentTags && !hideTags) ? <button
|
||||
// onClick={() => handleFormSubmitBtnClick()}
|
||||
className='flex items-center gap-2 cursor-pointer text-xs px-4 py-2 ml-3 rounded-sm bg-[var(--primary)] outline-none'>
|
||||
<p
|
||||
className='tracking-wide text-white'>Sign</p>
|
||||
<p className='tracking-wide text-white'>
|
||||
Sign
|
||||
</p>
|
||||
<FaSignature className='text-white text-md' />
|
||||
</button>
|
||||
:
|
||||
<p className="text-xs">Signed Successfully</p>
|
||||
}
|
||||
|
||||
<p>{recipient && recipient.firstName} {recipient && recipient.lastName}</p>
|
||||
|
||||
</div>
|
||||
{/* Right Side - ENDS */}
|
||||
|
|
@ -1274,7 +1278,13 @@ const SignDocument = () => {
|
|||
|
||||
|
||||
<div style={{ display: `${openSign ? 'block' : 'none'}` }}>
|
||||
<SignCon recipientId={recipientId as string} setOpenSign={setOpenSign} saved={saved} setSaved={setSaved} signTagId={signTagId}/>
|
||||
{recipient &&
|
||||
<SignCon
|
||||
recipient={recipient}
|
||||
recipientId={recipientId as string}
|
||||
setOpenSign={setOpenSign} saved={saved}
|
||||
setSaved={setSaved}
|
||||
signTagId={signTagId} />}
|
||||
</div>
|
||||
|
||||
<div style={{ display: `${stamp.open ? 'block' : 'none'}` }}>
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ const SendForSign: React.FC<Props> = ({ showSideBar }) => {
|
|||
.then(res => {
|
||||
if (res.status === 200 || res.status === 201) {
|
||||
dispatch(updateTransactionStatus(TRANSACTION_STATUS_ENUMS.TRANSACTION_INITIATED));
|
||||
dispatch(setTransactionId(res.data));
|
||||
let navigateUrl = `/process-step-one/${defaultAccountId}/${res.data}`;
|
||||
if (signType === SignTypeEnum.selfSign) navigateUrl = `/process-step-one/${defaultAccountId}/${res.data}/self_sign`;
|
||||
dispatch(setTransactionId(res.data.id));
|
||||
let navigateUrl = `/process-step-one/${defaultAccountId}/${res.data.id}`;
|
||||
if (signType === SignTypeEnum.selfSign) navigateUrl = `/process-step-one/${defaultAccountId}/${res.data.id}/self_sign`;
|
||||
setTimeout(() => navigate(navigateUrl), 0)
|
||||
}
|
||||
})
|
||||
|
|
@ -81,18 +81,25 @@ const SendForSign: React.FC<Props> = ({ showSideBar }) => {
|
|||
ref={dropDownRef}
|
||||
onBlur={() => setSendForSignDropdown(false)}
|
||||
>
|
||||
<div className={`flex justify-between items-center gap-2 cursor-pointer bg-[var(--primary)] rounded text-[var(--sendForSignTextCol)] ${showSideBar ? "" : "pt-[0.4rem] pr-[0.6rem] pb-[0.4rem] pl-[0.2rem]"}`}
|
||||
onClick={() => setSendForSignDropdown(!sendForSignDropdown)}>
|
||||
<div className={`w-full`}>
|
||||
<div
|
||||
className={`flex justify-between items-center gap-2 cursor-pointer bg-[var(--primary)] rounded text-[var(--sendForSignTextCol)] ${showSideBar ? "" : "pt-[0.4rem] pr-[0.6rem] pb-[0.4rem] pl-[0.2rem]"}`}>
|
||||
<div
|
||||
onClick={() => handleStartSectionClick(SignTypeEnum.multipleSign)}
|
||||
className={`w-full`}>
|
||||
{
|
||||
showSideBar ?
|
||||
<p className='text-center text-sm'>Send for signature</p>
|
||||
<p
|
||||
className='text-center text-sm'>Send for signature</p>
|
||||
:
|
||||
<IoIosSend className={`pl-2 text-3xl`} />
|
||||
}
|
||||
</div>
|
||||
{showSideBar && <p className='border-l-1 border-[var(--sendForSignTextCol)] px-2 py-2'>
|
||||
<IoMdArrowDropdown className={`text-2xl ${sendForSignDropdown ? 'rotate-180' : ''} transition-all duration-150`} />
|
||||
{showSideBar &&
|
||||
<p
|
||||
className='border-l-1 border-[var(--sendForSignTextCol)] px-2 py-2'>
|
||||
<IoMdArrowDropdown
|
||||
onClick={() => setSendForSignDropdown(!sendForSignDropdown)}
|
||||
className={`text-2xl ${sendForSignDropdown ? 'rotate-180' : ''} transition-all duration-150`} />
|
||||
</p>}
|
||||
</div>
|
||||
|
||||
|
|
@ -100,12 +107,14 @@ const SendForSign: React.FC<Props> = ({ showSideBar }) => {
|
|||
{
|
||||
sendForSignDropdown &&
|
||||
<div className={`w-[300px] rounded absolute z-40 bg-[var(--sendForSignDropDownBg)] shadow-lg top-[54px] text-left outline-none`}>
|
||||
<div className='py-3 px-8 leading-6 rounded-t-sm hover:bg-[var(--sendForSignDropDownHover)] cursor-pointer' onClick={() => handleStartSectionClick(SignTypeEnum.selfSign)}>
|
||||
<div className='py-3 px-8 leading-6 rounded-t-sm hover:bg-[var(--sendForSignDropDownHover)] cursor-pointer'
|
||||
onClick={() => handleStartSectionClick(SignTypeEnum.selfSign)}>
|
||||
<p>Self Sign</p>
|
||||
<p className='text-[var(--greyTextCol)] text-sm'>You're the only signer.</p>
|
||||
</div>
|
||||
<div className='w-full h-[1px] opacity-30 bg-[var(--greyTextCol)]'></div>
|
||||
<div className='py-3 px-8 leading-6 rounded-b-sm hover:bg-[var(--sendForSignDropDownHover)] cursor-pointer' onClick={() => handleStartSectionClick(SignTypeEnum.multipleSign)}>
|
||||
<div className='py-3 px-8 leading-6 rounded-b-sm hover:bg-[var(--sendForSignDropDownHover)] cursor-pointer'
|
||||
onClick={() => handleStartSectionClick(SignTypeEnum.multipleSign)}>
|
||||
<p>Send for Sign</p>
|
||||
<p className='text-[var(--greyTextCol)] text-sm'>You and other need to sign.</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
import { useRef, useState } from 'react';
|
||||
import { FiUpload } from 'react-icons/fi'
|
||||
import { uploadDocuments } from '../../store/slices/documentSlice';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { RootState } from '../../store/store';
|
||||
import api from '../../config/api';
|
||||
|
||||
const StartNow = () => {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
|
||||
const userData = useSelector((state: RootState) => state.user);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleUpload = async (filesToUpload: File[]) => {
|
||||
|
||||
const accountId = userData.account?.id;
|
||||
const transactionRes = await api.post(`/api/accounts/${userData.account?.id}/transactions`);
|
||||
const transactionId = transactionRes.data.id
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", filesToUpload[0]);
|
||||
|
||||
dispatch(uploadDocuments({ formData, accountId, transactionId }))
|
||||
.unwrap()
|
||||
.then((res) => {
|
||||
// toast.dismiss();
|
||||
setFiles([]);
|
||||
navigate(`/process-step-one/${accountId}/${transactionId}`);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Upload failed", err);
|
||||
});
|
||||
};
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const selectedFiles = e.target.files ? Array.from(e.target.files) : [];
|
||||
if (selectedFiles.length > 0) {
|
||||
setFiles((prev) => [...prev, ...selectedFiles]);
|
||||
handleUpload(selectedFiles);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
className="group cursor-pointer border-slate-300 rounded-lg bg-white/60 transition-all duration-200 p-4 flex flex-col items-center justify-center gap-2 text-center shadow-sm hover:shadow-md">
|
||||
{/* Upload icon with subtle animation */}
|
||||
<div className="p-2 text-blue-600 group-hover:text-blue-700 transition-colors">
|
||||
<FiUpload className="text-lg" />
|
||||
</div>
|
||||
|
||||
{/* Compact text */}
|
||||
<p className="text-xs text-gray-600">
|
||||
<span className="text-blue-600 font-medium">Click to upload</span> or drag and drop
|
||||
</p>
|
||||
|
||||
<button
|
||||
className="mt-1 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 px-3 py-1 rounded shadow-xs transition-colors duration-150 focus:outline-none focus:ring-1 focus:ring-blue-400"
|
||||
>
|
||||
Start Now
|
||||
</button>
|
||||
|
||||
<p className="text-[0.65rem] text-gray-400 mt-0.5">
|
||||
PDF, JPG, PNG (max. 10MB)
|
||||
</p>
|
||||
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
className="hidden"
|
||||
onChange={handleFileChange}
|
||||
accept=".pdf,.doc,.docx,.jpg,.png,.jpeg,.txt"
|
||||
multiple
|
||||
/>
|
||||
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default StartNow
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
import axios from 'axios';
|
||||
import React, { ReactNode, useEffect } from 'react';
|
||||
import React, { ReactNode, useEffect, useState } from 'react';
|
||||
import { FiUpload, FiEdit, FiFolder, FiArrowRight } from 'react-icons/fi';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { AppDispatch, RootState } from '../../store/store';
|
||||
import api from '../../config/api';
|
||||
import { setTransactionId, TRANSACTION_STATUS_ENUMS, updateTransactionStatus } from '../../store/slices/transactionSlice';
|
||||
import { Transaction, TransactionResponse } from '../transactions/Transactions';
|
||||
import TransactionsTable from '../transactions/TransactionsTable';
|
||||
import TransactionDataTable from '../accounts/TransactionDataTable';
|
||||
import StartNow from './StartNow';
|
||||
|
||||
|
||||
export interface StartCard {
|
||||
|
|
@ -17,13 +21,13 @@ export interface StartCard {
|
|||
}
|
||||
|
||||
const cards = [
|
||||
{
|
||||
icon: <FiUpload className="w-5 h-5 text-blue-700" />,
|
||||
title: 'Start a Workflow',
|
||||
description: 'Begin by uploading a document and tagging fields.',
|
||||
buttonText: 'Start Now',
|
||||
bg: 'bg-white/60',
|
||||
},
|
||||
// {
|
||||
// icon: <FiUpload className="w-5 h-5 text-blue-700" />,
|
||||
// title: 'Start a Workflow',
|
||||
// description: 'Begin by uploading a document and tagging fields.',
|
||||
// buttonText: 'Start Now',
|
||||
// bg: 'bg-white/60',
|
||||
// },
|
||||
{
|
||||
icon: <FiEdit className="w-5 h-5 text-green-700" />,
|
||||
title: 'Sign an Agreement',
|
||||
|
|
@ -76,15 +80,19 @@ const StartSection = () => {
|
|||
// }, [])
|
||||
|
||||
return (
|
||||
<section className="px-4 py-3 w-full">
|
||||
<section className="px-4 pt-2 pb-3 w-full">
|
||||
<h2 className="text-lg font-semibold text-gray-800 mb-2">Get Started</h2>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
|
||||
<StartNow />
|
||||
|
||||
<div className='col-span-2 grid grid-cols-2 justify-between gap-4'>
|
||||
{cards.map((card, index) => (
|
||||
<div
|
||||
onClick={() => handleStartSectionClick(card)}
|
||||
key={index}
|
||||
className={`${card.bg} cursor-pointer relative border border-gray-200 rounded-xl p-4 shadow-sm hover:shadow-md transition-all h-full flex flex-col justify-between min-h-[220px]`}
|
||||
className={`${card.bg} w-full max-h-max cursor-pointer relative border border-gray-200 rounded-xl p-4 shadow-sm hover:shadow-md transition-all flex flex-col justify-between`}
|
||||
>
|
||||
{/* Icon + Text */}
|
||||
<div className="flex flex-col gap-3">
|
||||
|
|
@ -111,6 +119,17 @@ const StartSection = () => {
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<section className='pt-2 pb-3'>
|
||||
<h2 className="mt-3 text-lg font-semibold text-gray-800 mb-2">Recent Activities</h2>
|
||||
<section>
|
||||
<TransactionDataTable />
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -55,14 +55,31 @@ const ProcessStepOne = () => {
|
|||
const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
|
||||
const selectedRecipients = useSelector((state: RootState) => state.selectedRecipients.recipients)
|
||||
const userData = useSelector((state: RootState) => state.user)
|
||||
// const userData = useSelector((state: RootState) => state.user)
|
||||
|
||||
const [transactionDetails, setTransactionDetails] = useState<any>([]);
|
||||
|
||||
console.log("selectedRecipients", selectedRecipients)
|
||||
|
||||
useEffect(() => {
|
||||
<<<<<<< HEAD
|
||||
// Fetching Transaction Details - START
|
||||
(async () => {
|
||||
try {
|
||||
const res = await api.get(`/api/accounts/${accountId}/transactions/${transactionId}`);
|
||||
setTransactionDetails(res.data)
|
||||
} catch (e) {
|
||||
console.log("Error - transactions details")
|
||||
}
|
||||
})()
|
||||
// Fetching Transaction Details - END
|
||||
|
||||
=======
|
||||
(async () => {
|
||||
const res = await api.get(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`)
|
||||
console.log(res.data);
|
||||
})()
|
||||
>>>>>>> origin/main
|
||||
|
||||
selectedRecipients.length === 0 && dispatch(fetchRecipients({ accountId, transactionId }));
|
||||
selectedDocuments.length === 0 && dispatch(fetchDocuments({ accountId, transactionId }));
|
||||
|
|
@ -165,6 +182,7 @@ const ProcessStepOne = () => {
|
|||
}));
|
||||
|
||||
let recipientsDataTemp = recipientsData;
|
||||
let recipientId = null;
|
||||
|
||||
if (signType === SignTypeEnum.selfSign) {
|
||||
recipientsDataTemp = [{
|
||||
|
|
@ -189,9 +207,18 @@ const ProcessStepOne = () => {
|
|||
name: `${userData.firstName} ${userData.lastName}`,
|
||||
roleName: ""
|
||||
}]
|
||||
|
||||
try {
|
||||
const basePath = `/api/accounts/${accountId}/transactions/${transactionId}/recipients`;
|
||||
const res = await api.post(basePath, recipientsDataTemp)
|
||||
recipientId = res.data[0].id;
|
||||
} catch (error) {
|
||||
console.log("Error Creating Self Sign Recipient", error.message)
|
||||
}
|
||||
|
||||
} else {
|
||||
dispatch(addRecipientAsync({ recipientsData: recipientsDataTemp, accountId, transactionId }));
|
||||
}
|
||||
dispatch(showLoader("Processing Message..."));
|
||||
|
||||
console.log(`1/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`)
|
||||
|
|
@ -213,12 +240,24 @@ const ProcessStepOne = () => {
|
|||
dispatch(resetDocuments())
|
||||
dispatch(resetRecipients())
|
||||
dispatch(hideLoader());
|
||||
if (transactionTemplateToggle === 'templates') {
|
||||
if (transactionTemplateToggle === TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES) {
|
||||
console.log(`/process-step-two/${accountId}/template/${transactionId}`)
|
||||
navigate(`/process-step-two/${accountId}/template/${transactionId}`)
|
||||
} else {
|
||||
if (signType === SignTypeEnum.selfSign) {
|
||||
(async () => {
|
||||
try {
|
||||
const res = await api.put(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}`, { status: "SENT" })
|
||||
console.log(res, "Check123");
|
||||
navigate(`/sign/${recipientId}`);
|
||||
} catch (err) {
|
||||
console.log("Error Transaction Sent", err.message);
|
||||
}
|
||||
})()
|
||||
} else {
|
||||
navigate(`/process-step-two/${accountId}/${transactionId}`);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
|
@ -270,15 +309,6 @@ const ProcessStepOne = () => {
|
|||
</div>
|
||||
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className="flex items-center" >
|
||||
<input
|
||||
checked={signType === SignTypeEnum.selfSign}
|
||||
onChange={(e) => handleSelfSignCb(e)}
|
||||
id="default-checkbox" type="checkbox" value="" className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm outline-none"
|
||||
/>
|
||||
|
||||
<label htmlFor="default-checkbox" className="ms-2 text-sm text-slate-600">SELF SIGN</label>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleNextClick(false)}
|
||||
className="text-sm px-4 py-2 rounded bg-[var(--primary)] text-white shadow hover:bg-[var(--primaryLight2)] transition"
|
||||
|
|
@ -298,17 +328,32 @@ const ProcessStepOne = () => {
|
|||
</section>
|
||||
|
||||
{/* Recipients */}
|
||||
<section className="mt-8">
|
||||
|
||||
{
|
||||
transactionTemplateToggle !== TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES &&
|
||||
<div className="flex justify-between items-center">
|
||||
<h2 className="text-lg font-medium mb-4 pt-6 border-t text-[var(--processStepOneTextHead)]">Signers</h2>
|
||||
<div className="flex items-center mr-2">
|
||||
<input
|
||||
checked={signType === SignTypeEnum.selfSign}
|
||||
onChange={(e) => handleSelfSignCb(e)}
|
||||
id="default-checkbox" type="checkbox" value="" className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm outline-none"
|
||||
/>
|
||||
<label htmlFor="default-checkbox" className="ms-2 text-sm text-slate-600">SELF SIGN</label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
signType !== SignTypeEnum.selfSign &&
|
||||
< section className="mt-8">
|
||||
<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">
|
||||
<RecipientCards transactionTemplateToggle={transactionTemplateToggle} setEditRecipient={setEditRecipient} setEditCase={setEditCase}/>
|
||||
{/* {signType !== "self-sign" && <RecipientAddCard />} */}
|
||||
<RecipientAddCard transactionTemplateToggle={transactionTemplateToggle} editRecipient={editRecipient} editCase={editCase} setEditRecipient={setEditRecipient} setEditCase={setEditCase}/>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
</section>
|
||||
|
||||
{/* Email */}
|
||||
<section className="mt-8">
|
||||
|
|
|
|||
|
|
@ -59,6 +59,15 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
|
|||
|
||||
const handleRemoveRecipient = (recipient) => {
|
||||
if (!accountId || !transactionId) return;
|
||||
<<<<<<< HEAD
|
||||
// dispatch(removeSelectedRecipient(recipient))
|
||||
dispatch(removeRecipientAsync([{
|
||||
recipientId: recipient.id,
|
||||
email: recipient.email,
|
||||
accountId: accountId,
|
||||
transactionId: transactionId,
|
||||
}]))
|
||||
=======
|
||||
if (recipient.uuid) {
|
||||
dispatch(removeSelectedRecipient(recipient))
|
||||
} else {
|
||||
|
|
@ -69,6 +78,7 @@ const RecipientCards = ({ setEditRecipient, setEditCase, transactionTemplateTogg
|
|||
transactionId: transactionId,
|
||||
}))
|
||||
}
|
||||
>>>>>>> origin/main
|
||||
if (recipients.length === 2) {
|
||||
let leftRecipient = recipients.filter((obj) => {
|
||||
if ("id" in obj && "id" in recipient) {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,24 @@ const SelectedDocuments = ({transactionTemplateToggle}) => {
|
|||
{ name: 'Dropbox', icon: <FaDropbox /> },
|
||||
];
|
||||
|
||||
const handleUpload = (filesToUpload: File[]) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", filesToUpload[0])
|
||||
console.log(formData, "Line 59")
|
||||
// filesToUpload.forEach((file) => formData.append("document", file));
|
||||
|
||||
dispatch(uploadDocuments({ formData, accountId, transactionId }))
|
||||
.unwrap()
|
||||
.then((res) => {
|
||||
toast.dismiss();
|
||||
setFiles([]);
|
||||
setModalOpen(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Upload failed", err);
|
||||
});
|
||||
};
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const selectedFiles = e.target.files ? Array.from(e.target.files) : [];
|
||||
if (selectedFiles.length > 0) {
|
||||
|
|
@ -66,40 +84,6 @@ const SelectedDocuments = ({transactionTemplateToggle}) => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleUpload = (filesToUpload: File[]) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", filesToUpload[0])
|
||||
console.log(formData, "Line 59")
|
||||
// filesToUpload.forEach((file) => formData.append("document", file));
|
||||
|
||||
dispatch(uploadDocuments({ formData, accountId, transactionId }))
|
||||
.unwrap()
|
||||
.then((res) => {
|
||||
toast.dismiss();
|
||||
// toast.info("📄 Documents uploaded!", {
|
||||
// position: "bottom-right",
|
||||
// autoClose: 5000,
|
||||
// hideProgressBar: false,
|
||||
// closeOnClick: false,
|
||||
// pauseOnHover: true,
|
||||
// draggable: true,
|
||||
// progress: undefined,
|
||||
// theme: "light",
|
||||
// transition: Bounce,
|
||||
// });
|
||||
|
||||
// Update selected documents after upload
|
||||
// dispatch(setSelectedDocuments([...documents, ...res]));
|
||||
|
||||
// debugger;
|
||||
setFiles([]);
|
||||
setModalOpen(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Upload failed", err);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Upload Card First */}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ interface SelectStyle {
|
|||
}
|
||||
|
||||
const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
||||
recipient,
|
||||
setOpenSign,
|
||||
recipientId,
|
||||
saved,
|
||||
|
|
@ -86,7 +87,7 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
|||
signTagId
|
||||
}) => {
|
||||
|
||||
console.log("savedModal", saved)
|
||||
console.log("savedModal", recipient)
|
||||
const [activeTab, setActiveTab] = useState<'TYPED' | 'DRAW' | 'UPLOAD' | 'SAVED'>('TYPED');
|
||||
const [fullName, setFullName] = useState('');
|
||||
const [initials, setInitials] = useState('');
|
||||
|
|
@ -506,17 +507,16 @@ const AddSignatureModal: React.FC<AddSignatureModalProps> = ({
|
|||
|
||||
const getUserDetails = async () => {
|
||||
try {
|
||||
let res = await axios.get(`/api/user/details`, {
|
||||
headers: {
|
||||
"ngrok-skip-browser-warning": "69420",
|
||||
}
|
||||
});
|
||||
console.log("getuser", res);
|
||||
let currUser = res?.data;
|
||||
setUser(currUser);
|
||||
|
||||
setFullName(currUser.firstName + " " + currUser.lastName);
|
||||
setInitials(currUser.firstName.slice(0, 1) + currUser.lastName.slice(0, 1));
|
||||
// let res = await axios.get(`/api/user/details`, {
|
||||
// headers: {
|
||||
// "ngrok-skip-browser-warning": "69420",
|
||||
// }
|
||||
// });
|
||||
// console.log("getuser", res);
|
||||
// let currUser = res?.data;
|
||||
setUser(recipient);
|
||||
setFullName(recipient.firstName + " " + recipient.lastName);
|
||||
setInitials(recipient.firstName.slice(0, 1) + recipient.lastName.slice(0, 1));
|
||||
} catch (error) {
|
||||
console.error("Error fetching user details:", error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
|
|||
import { useParams } from 'react-router-dom';
|
||||
import TransactionTopNav from './TransactionTopNav';
|
||||
import api from '../../config/api';
|
||||
import TransactionsTable from './TransactionsTable';
|
||||
|
||||
interface Document {
|
||||
documentId: string;
|
||||
|
|
@ -19,7 +20,7 @@ interface Recipient {
|
|||
signedDateTime?: string;
|
||||
}
|
||||
|
||||
interface Transaction {
|
||||
export interface Transaction {
|
||||
transactionId: string;
|
||||
name: string;
|
||||
createAt: string;
|
||||
|
|
@ -30,7 +31,7 @@ interface Transaction {
|
|||
recipients: Recipient[];
|
||||
}
|
||||
|
||||
interface TransactionResponse {
|
||||
export interface TransactionResponse {
|
||||
content: Transaction[];
|
||||
pageNumber: number;
|
||||
totalPages: number;
|
||||
|
|
@ -53,70 +54,7 @@ const Transactions = () => {
|
|||
<div>
|
||||
{filterParam && <TransactionTopNav filterType={filterParam} />}
|
||||
{/* <h2 className="text-cl font-semibold text-gray-800 mb-2.5">Transactions</h2> */}
|
||||
|
||||
{
|
||||
|
||||
transactionData.length > 0 ?
|
||||
<div className="overflow-x-auto bg-white shadow-md rounded-lg border border-gray-200">
|
||||
<table className="min-w-full text-sm text-gray-700">
|
||||
<thead className="bg-gray-100 text-left text-xs uppercase tracking-wider text-gray-600">
|
||||
<tr>
|
||||
<th className="px-6 py-3">Name</th>
|
||||
<th className="px-6 py-3">Created At</th>
|
||||
<th className="px-6 py-3">Status</th>
|
||||
<th className="px-6 py-3">Documents</th>
|
||||
<th className="px-6 py-3">Recipients</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{transactionData.map((tx) => (
|
||||
<tr key={tx.transactionId} className="border-t hover:bg-gray-50 transition duration-150">
|
||||
<td className="px-6 py-4 font-medium text-gray-800">
|
||||
{tx.name?.trim() || 'N/A'}
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
{new Date(tx.createAt).toLocaleString()}
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<span className="inline-block px-2 py-1 text-xs font-semibold rounded bg-blue-100 text-blue-800">
|
||||
{tx.status}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
{tx.documents.map((doc) => (
|
||||
<li key={doc.documentId}>{doc.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</td>
|
||||
<td className="px-6 py-4 space-y-2">
|
||||
{tx.recipients.map((rec) => (
|
||||
<div key={rec.id} className="text-sm">
|
||||
<div className="font-semibold">
|
||||
{rec.firstName} {rec.lastName}
|
||||
</div>
|
||||
<div className="text-gray-600">Status: {rec.status}</div>
|
||||
{rec.signedDateTime && (
|
||||
<div className="text-green-600">
|
||||
Signed: {new Date(rec.signedDateTime).toLocaleString()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div> :
|
||||
<div className='flex justify-center items-center mt-6 text-slate-400 gap-2'>
|
||||
<hr className='w-full border-dashed' />
|
||||
<p className='whitespace-nowrap text-sm'>No Data Found</p>
|
||||
<hr className='w-full border-dashed' />
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
{/* <TransactionsTable transactionData={transactionData} /> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
import { Transaction } from './Transactions'
|
||||
|
||||
interface TransactionsTableInterface {
|
||||
transactionData: Transaction[]
|
||||
}
|
||||
|
||||
const TransactionsTable : React.FC<TransactionsTableInterface>= ({transactionData}) => {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
|
||||
transactionData.length > 0 ?
|
||||
<div className="overflow-x-auto bg-white shadow-md rounded-lg border border-gray-200">
|
||||
<table className="min-w-full text-sm text-gray-700">
|
||||
<thead className="bg-gray-100 text-left text-xs uppercase tracking-wider text-gray-600">
|
||||
<tr>
|
||||
<th className="px-6 py-3">Name</th>
|
||||
<th className="px-6 py-3">Created At</th>
|
||||
<th className="px-6 py-3">Status</th>
|
||||
<th className="px-6 py-3">Documents</th>
|
||||
<th className="px-6 py-3">Recipients</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{transactionData.map((tx) => (
|
||||
<tr key={tx.transactionId} className="border-t hover:bg-gray-50 transition duration-150">
|
||||
<td className="px-6 py-4 font-medium text-gray-800">
|
||||
{tx.name?.trim() || 'N/A'}
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
{new Date(tx.createAt).toLocaleString()}
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<span className="inline-block px-2 py-1 text-xs font-semibold rounded bg-blue-100 text-blue-800">
|
||||
{tx.status}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
{tx.documents.map((doc) => (
|
||||
<li key={doc.documentId}>{doc.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</td>
|
||||
<td className="px-6 py-4 space-y-2">
|
||||
{tx.recipients.map((rec) => (
|
||||
<div key={rec.id} className="text-sm">
|
||||
<div className="font-semibold">
|
||||
{rec.firstName} {rec.lastName}
|
||||
</div>
|
||||
<div className="text-gray-600">Status: {rec.status}</div>
|
||||
{rec.signedDateTime && (
|
||||
<div className="text-green-600">
|
||||
Signed: {new Date(rec.signedDateTime).toLocaleString()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div> :
|
||||
<div className='flex justify-center items-center mt-6 text-slate-400 gap-2'>
|
||||
<hr className='w-full border-dashed' />
|
||||
<p className='whitespace-nowrap text-sm'>No Data Found</p>
|
||||
<hr className='w-full border-dashed' />
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TransactionsTable
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--primary: #41644A;
|
||||
--primary: #3D74B6;
|
||||
--primaryLight: #ffffff;
|
||||
--primaryLight2: #4b7455;
|
||||
--primaryLight2: #6a92c2;
|
||||
--primaryLight3: #dae9de;
|
||||
--dashBoardBg: #ffffff;
|
||||
--mainViewBg: #edeaeb;
|
||||
--highlightBg1: #edeaeb;
|
||||
--menuTextCol: #98a0a8;
|
||||
--menuTextColActive: #41644A;
|
||||
--menuTextColActive: #3D74B6;
|
||||
--menuBgColActive: #edeaeb;
|
||||
--menuTextHoverCol: #e7e7e7;
|
||||
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
--lightGreyCol: #e1e1e1;
|
||||
--compBgCol: #ffffff;
|
||||
|
||||
--avatarBgCol: #41644A;
|
||||
--avatarBgCol: #3D74B6;
|
||||
--avatarTextCol: #ffffff;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -240,8 +240,6 @@ export const uploadDocuments = createAsyncThunk<
|
|||
|
||||
console.log(`/api/accounts/${accountId}/${toggle}/${transactionId}/documents`)
|
||||
|
||||
|
||||
|
||||
const response = await api.post(
|
||||
`/api/accounts/${accountId}/${toggle}/${transactionId}/documents`,
|
||||
formData,
|
||||
|
|
|
|||
Loading…
Reference in New Issue