260 lines
8.9 KiB
TypeScript
260 lines
8.9 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { PiDotsThreeOutlineVerticalFill } from "react-icons/pi";
|
|
import AccountNav from "./AccountNav";
|
|
import api from "../../config/api";
|
|
import { useNavigate, useParams } from "react-router-dom";
|
|
import { FaCheck } from "react-icons/fa";
|
|
import Cards from "../home/Cards";
|
|
import AddInviteModal from "./AddInviteModal";
|
|
import { Bounce, toast } from "react-toastify";
|
|
import {
|
|
FaCheckCircle,
|
|
FaClock,
|
|
FaHourglassHalf,
|
|
FaTasks,
|
|
FaChevronDown,
|
|
FaPlus,
|
|
FaUserPlus,
|
|
FaFilter,
|
|
FaCalendarAlt
|
|
} from 'react-icons/fa';
|
|
import TransactionDataTable from "./TransactionDataTable";
|
|
|
|
interface Transaction {
|
|
id: number;
|
|
status: string;
|
|
active: boolean;
|
|
subject: string | null;
|
|
createdAt: number;
|
|
expireAfter: number | null;
|
|
}
|
|
|
|
const Account = () => {
|
|
const mapApiDataToCards = (data: any): CardData[] => {
|
|
return [
|
|
{
|
|
title: 'Action Needed',
|
|
count: data.actionNeeded || 0,
|
|
icon: <FaTasks size={18} className="text-indigo-600" />,
|
|
gradient: 'bg-gradient-to-br from-indigo-50 to-indigo-100',
|
|
shadowColor: 'shadow-indigo-200/50',
|
|
iconBg: 'bg-indigo-100 border-indigo-200',
|
|
textColor: 'text-indigo-700',
|
|
trend: 'up'
|
|
},
|
|
{
|
|
title: 'Expiring Soon',
|
|
count: data.expiring || 0,
|
|
icon: <FaHourglassHalf size={18} className="text-rose-600" />,
|
|
gradient: 'bg-gradient-to-br from-rose-50 to-rose-100',
|
|
shadowColor: 'shadow-rose-200/50',
|
|
iconBg: 'bg-rose-100 border-rose-200',
|
|
textColor: 'text-rose-700',
|
|
trend: 'up'
|
|
},
|
|
{
|
|
title: 'Completed',
|
|
count: data.completed || 0,
|
|
icon: <FaCheckCircle size={18} className="text-teal-600" />,
|
|
gradient: 'bg-gradient-to-br from-teal-50 to-teal-100',
|
|
shadowColor: 'shadow-teal-200/50',
|
|
iconBg: 'bg-teal-100 border-teal-200',
|
|
textColor: 'text-teal-700',
|
|
trend: 'up'
|
|
},
|
|
// {
|
|
// title: 'Waiting for Others',
|
|
// count: data.waitingForOthers || 0,
|
|
// icon: <FaClock size={18} className="text-stone-600" />,
|
|
// gradient: 'bg-gradient-to-br from-blue-50 to-blue-100',
|
|
// shadowColor: 'shadow-blue-200/50',
|
|
// iconBg: 'bg-blue-100 border-blue-200',
|
|
// textColor: 'text-blue-700',
|
|
// trend: 'down'
|
|
// },
|
|
// {
|
|
// title: 'declined',
|
|
// count: data.declined || 0,
|
|
// icon: <FaClock size={18} className="text-purple-600" />,
|
|
// gradient: 'bg-gradient-to-br from-purple-50 to-purple-100',
|
|
// shadowColor: 'shadow-purple-200/50',
|
|
// iconBg: 'bg-purple-100 border-purple-200',
|
|
// textColor: 'text-purple-700',
|
|
// trend: 'down'
|
|
// },
|
|
// {
|
|
// title: 'cancelled',
|
|
// count: data.cancelled || 0,
|
|
// icon: <FaClock size={18} className="text-green-600" />,
|
|
// gradient: 'bg-gradient-to-br from-green-50 to-green-100',
|
|
// shadowColor: 'shadow-green-200/50',
|
|
// iconBg: 'bg-green-100 border-green-200',
|
|
// textColor: 'text-green-700',
|
|
// trend: 'down'
|
|
// },
|
|
{
|
|
title: 'draft',
|
|
count: data.draft || 0,
|
|
icon: <FaClock size={18} className="text-stone-600" />,
|
|
gradient: 'bg-gradient-to-br from-stone-50 to-stone-100',
|
|
shadowColor: 'shadow-stone-200/50',
|
|
iconBg: 'bg-stone-100 border-stone-200',
|
|
textColor: 'text-stone-700',
|
|
trend: 'down'
|
|
}
|
|
// Add more cards here if needed
|
|
];
|
|
};
|
|
|
|
const [activeAccountId, setActiveAccountId] = useState<string | null>(
|
|
JSON.parse(sessionStorage.getItem('activeAccountId') || 'null')
|
|
);
|
|
|
|
console.log("activeAccountId Trans.", activeAccountId)
|
|
// const { accountId } = useParams<{ accountId: string }>();
|
|
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
|
const [accountsData, setAccountsData] = useState([])
|
|
const [inviteLoading, setInviteLoading] = useState(false);
|
|
const [cards, setCards] = useState<CardData[]>([]);
|
|
const [accountID, setAccountID] = useState<number>()
|
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
|
|
// const getUserDetails = async () => {
|
|
// try {
|
|
// let res = await api.get('/api/user/details')
|
|
// let accountIDData = res?.data?.account?.id
|
|
// setAccountID(accountIDData)
|
|
// } catch (error) {
|
|
// console.log(error)
|
|
// }
|
|
// }
|
|
|
|
// useEffect(() => {
|
|
// getUserDetails()
|
|
// }, [])
|
|
|
|
// Listen for sessionStorage changes
|
|
useEffect(() => {
|
|
const handleStorageChange = (e: StorageEvent) => {
|
|
if (e.key === 'activeAccountId') {
|
|
const newActiveAccountId = e.newValue ? JSON.parse(e.newValue) : null;
|
|
setActiveAccountId(newActiveAccountId);
|
|
}
|
|
};
|
|
|
|
// Listen for storage events (works for changes from other tabs)
|
|
window.addEventListener('storage', handleStorageChange);
|
|
|
|
// Custom event listener for same-tab changes
|
|
const handleCustomStorageChange = (e: CustomEvent) => {
|
|
if (e.detail.key === 'activeAccountId') {
|
|
setActiveAccountId(e.detail.newValue);
|
|
}
|
|
};
|
|
|
|
window.addEventListener('sessionStorageChange', handleCustomStorageChange as EventListener);
|
|
|
|
return () => {
|
|
window.removeEventListener('storage', handleStorageChange);
|
|
window.removeEventListener('sessionStorageChange', handleCustomStorageChange as EventListener);
|
|
};
|
|
}, []);
|
|
|
|
|
|
const getDashboardData = async () => {
|
|
setIsLoading(true)
|
|
const payload = {
|
|
account: activeAccountId
|
|
};
|
|
|
|
try {
|
|
const res = await api.get('/api/dashboard', { params: payload });
|
|
console.log("Dashboard Data:", res.data);
|
|
const cardDataArray = mapApiDataToCards(res.data);
|
|
setCards(cardDataArray);
|
|
} catch (error) {
|
|
console.error("Error fetching dashboard data:", error);
|
|
} finally {
|
|
setIsLoading(false)
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (activeAccountId) {
|
|
getDashboardData()
|
|
}
|
|
}, [activeAccountId]);
|
|
|
|
const handleOpenModal = () => {
|
|
setIsModalOpen(true);
|
|
};
|
|
|
|
|
|
// useEffect(() => {
|
|
// if (accountID) fetchTransactions();
|
|
// }, [accountID]);
|
|
|
|
// const getAccountDetails = async () => {
|
|
// try {
|
|
// let res = await api.get('/api/user/accounts')
|
|
// let items = res?.data
|
|
// setAccountsData(items)
|
|
// } catch (error) {
|
|
// console.log(error)
|
|
// }
|
|
// }
|
|
|
|
// useEffect(() => {
|
|
// getAccountDetails()
|
|
// }, [])
|
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
const handleInvite = async (data: { i_accountName: number; email: string; role: string }) => {
|
|
setInviteLoading(true);
|
|
try {
|
|
const payloadInvite = {
|
|
email: data.email,
|
|
role: data.role
|
|
}
|
|
let res = await api.post(`/api/accounts/${data.i_accountName}/invite`, payloadInvite)
|
|
if (res?.data) {
|
|
toast.success("Invite Sent Successfully...!", {
|
|
position: "top-center",
|
|
autoClose: 1500,
|
|
hideProgressBar: false,
|
|
closeOnClick: false,
|
|
pauseOnHover: true,
|
|
draggable: true,
|
|
progress: undefined,
|
|
theme: "light",
|
|
transition: Bounce,
|
|
});
|
|
await fetchTransactions()
|
|
setIsModalOpen(false);
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to invite', err);
|
|
} finally {
|
|
setInviteLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Cards type="transactions" onOpenModal={handleOpenModal} cards={cards}
|
|
isLoading={isLoading} />
|
|
|
|
<TransactionDataTable />
|
|
|
|
{isModalOpen && <AddInviteModal onClose={() => setIsModalOpen(false)} onInvite={handleInvite} inviteLoading={inviteLoading}
|
|
accountOptions={accountsData} />}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Account;
|