-
- {/* User Dropdown */}
-
- {/* Avatar Button */}
-
-
- {user ? (
- {(user?.firstName + " " + user?.lastName).split(' ').map((item) => item.slice(0, 1)).join("").toUpperCase()}
- ) : (
-
- )}
-
-
-
- {/* Enhanced Dropdown */}
- {open && (
-
- {/* User Info Section */}
-
-
-
- {(user) ? (
-
- {(user?.firstName + " " + user?.lastName).split(' ').map((item) => item.slice(0, 1)).join("").toUpperCase()}
- ) : (
-
- )}
-
-
-
{user.firstName + ' ' + user.lastName || '-'}
-
{user.email || '-'}
-
- Account #{user?.account?.name || '-'}
-
-
-
-
-
- {/* Account List Section */}
-
-
-
-
- Switch Account
-
-
-
-
- {/* Accounts Dropdown */}
- {accountsOpen && (
-
- {loadingAccounts ? (
-
-
-
-
- ) : (
-
- {accounts.length > 0 ? (accounts?.map((account) => (
-
handleAccountSwitch(account)}
- className="w-full px-4 py-3 hover:bg-white transition-colors cursor-pointer text-left"
- >
-
-
-
- {account.accountName.slice(0, 2).toUpperCase()}
-
-
-
- {account.accountName}
- {account.status && (
-
- )}
-
-
{account.company}
-
-
-
- {account.role}
-
-
-
- ))) :
No Account... }
-
-
- )}
-
- )}
-
-
- {/* Logout Section */}
-
-
-
- Log Out
-
-
-
- )}
-
+
+
+
+
+ {user ? (
+
+ {(user?.name?.slice(0, 2)).toUpperCase()}
+
+ ) : (
+
+ )}
-
- );
+
+
+ {open && (
+
+
+
+
+ {user ? (
+
+ {(user?.name?.slice(0, 2)).toUpperCase()}
+
+ ) : (
+
+ )}
+
+
+
{user?.name || '-'}
+
{user?.email || '-'}
+
+ Account #{user?.account?.name || '-'}
+
+
+
+
+
+
+
+
+
+ Switch Account
+
+
+
+
+ {accountsOpen && (
+
+ {loadingAccounts ? (
+
+
+
+
+ ) : (
+
+ {accounts?.length > 0 ? (
+ accounts?.map((account) => (
+
handleAccountSwitch(account)}
+ className={`w-full px-4 py-3 hover:bg-white transition-colors cursor-pointer text-left`}
+ >
+
+
+
+ {account.accountName.slice(0, 2).toUpperCase()}
+
+
+
+ {account.accountName}
+ {account.accountId === activeAccountId && (
+
+ )}
+
+
+
+
+ {account.role}
+
+
+
+ ))
+ ) : (
+
No Account...
+ )}
+
+ )}
+
+ )}
+
+
+
+
+
+ Log Out
+
+
+
+ )}
+
+
+
+ );
};
export default CommonNav;
\ No newline at end of file
diff --git a/src/components/accounts/Account.tsx b/src/components/accounts/Account.tsx
index fee10b2..ccb0d87 100644
--- a/src/components/accounts/Account.tsx
+++ b/src/components/accounts/Account.tsx
@@ -67,36 +67,36 @@ const Account = () => {
textColor: 'text-teal-700',
trend: 'up'
},
- {
- title: 'Waiting for Others',
- count: data.waitingForOthers || 0,
- icon:
,
- 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:
,
- 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:
,
- 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: 'Waiting for Others',
+ // count: data.waitingForOthers || 0,
+ // icon:
,
+ // 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:
,
+ // 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:
,
+ // 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,
@@ -110,6 +110,14 @@ const Account = () => {
// Add more cards here if needed
];
};
+
+ const [activeAccountId, setActiveAccountId] = useState
(
+ JSON.parse(sessionStorage.getItem('activeAccountId') || 'null')
+ );
+
+ const [currentEmailId, setCurrentEmailId] = useState('null');
+
+ console.log("activeAccountId Trans.", activeAccountId)
// const { accountId } = useParams<{ accountId: string }>();
const [transactions, setTransactions] = useState([]);
const [selectedTransactions, setSelectedTransactions] = useState([]);
@@ -121,25 +129,58 @@ const Account = () => {
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)
- }
- }
+ // 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()
+ // }, [])
useEffect(() => {
- getUserDetails()
- }, [])
+ const userDetails = JSON.parse(sessionStorage.getItem('userDetails'));
+ setCurrentEmailId(userDetails?.email)
+ }, []);
+
+
+ // 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: accountID
+ account: activeAccountId
};
try {
@@ -154,50 +195,51 @@ const Account = () => {
}
};
- useEffect(() => {
- if (accountID) {
- getDashboardData()
- fetchTransactions();
- }
- }, [accountID]);
-
- const handleOpenModal = () => {
- setIsModalOpen(true);
- };
-
const fetchTransactions = async () => {
console.log("fetchTransactions")
try {
- const response = await api(`/api/accounts/${accountID}/transactions`);
+ 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]);
+
+ 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)
- }
- }
+ // 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()
- }, [])
+ // useEffect(() => {
+ // getAccountDetails()
+ // }, [])
const navigate = useNavigate();
const handleTransactionClick = (id: number) => {
- navigate(`/accounts/${accountID}/transactions/${id}`);
+ navigate(`/accounts/${activeAccountId}/transactions/${id}`);
};
const handleInvite = async (data: { i_accountName: number; email: string; role: string }) => {
@@ -235,7 +277,7 @@ const Account = () => {
return (
<>
+ isLoading={isLoading} />
{transactions.length > 0 && (
@@ -247,7 +289,8 @@ const Account = () => {
Active
Last Change
Expire After (days)
-
+ Sign
+ Action
@@ -284,6 +327,9 @@ const Account = () => {
{tx.expireAfter ?? "-"}
+
+ {tx?.createdBy?.email === currentEmailId ? Sign now : "-"}
+
diff --git a/src/components/accounts/AccountNav.tsx b/src/components/accounts/AccountNav.tsx
index 9e6ac4f..ccfc83b 100644
--- a/src/components/accounts/AccountNav.tsx
+++ b/src/components/accounts/AccountNav.tsx
@@ -1,21 +1,13 @@
import React, { useEffect, useRef, useState } from 'react';
-// import { useSelector } from 'react-redux';
import { Link, useLocation, useNavigate } from 'react-router-dom';
import { FaSignOutAlt, FaUser, FaBuilding, FaChevronDown, FaCheck } from "react-icons/fa";
import api from '../../config/api';
-// import { FaUser, FaSignOutAlt, FaBuilding, FaChevronDown, FaCheck } from 'react-icons/fa';
-
-// import { RootState } from '../../store/store';
-// import { UserState } from '../../store/slices/userSlice';
-
-
interface AccountNavProps {
accountName?: string | null;
transactionName?: string | null;
}
-// Define the shape of state object
interface Account {
id: number;
isDefault: boolean;
@@ -23,32 +15,45 @@ interface Account {
}
interface UserData {
- id: string;
- firstName: string;
- lastName: string;
+ id: number;
+ name: string;
email: string;
language: string;
account: Account;
}
interface AccountDataArray {
- accountId: number, accountName: string, role: string, status: boolean
+ userId: number,
+ userEmail: string,
+ name: string,
+ accountId: number;
+ accountName: string;
+ role: string;
+ status: string;
}
+// Helper function to dispatch custom storage event
+const dispatchSessionStorageChange = (key: string, newValue: any) => {
+ window.dispatchEvent(new CustomEvent('sessionStorageChange', {
+ detail: { key, newValue }
+ }));
+};
+
const AccountNav: React.FC = ({ accountName = null, transactionName = null }) => {
- // const user: UserState = useSelector((state: RootState) => state.user);
+ const activeAccountId = JSON.parse(sessionStorage.getItem('activeAccountId') || 'null');
+ const userDetails = JSON.parse(sessionStorage.getItem('userDetails') || '{}');
+ console.log("activeAccountId", activeAccountId);
const [open, setOpen] = useState(false);
const [accountsOpen, setAccountsOpen] = useState(false);
const [loadingAccounts, setLoadingAccounts] = useState(false);
const [accounts, setAccounts] = useState([]);
- const [hasModalBeenClosed, setHasModalBeenClosed] = useState(false); // Track if modal was closed
- const dropdownRef = useRef(null);
+ const [hasModalBeenClosed, setHasModalBeenClosed] = useState(false);
+ const dropdownRef = useRef(null);
const [user, setUser] = useState({
- id: "",
- firstName: "",
- lastName: "",
+ id: 0,
+ name: "",
email: "",
language: "",
account: {
@@ -58,13 +63,17 @@ const AccountNav: React.FC = ({ accountName = null, transaction
},
});
+ console.log("user", user)
const getAccountDetails = async () => {
try {
- let res = await api.get('/api/user/accounts')
- let items = res?.data
- console.log('items', items)
- // Extract only the fields you want
+ let res = await api.get('/api/user/accounts');
+ let items = res?.data;
+ console.log('items', items);
+
const cleanedData: AccountDataArray[] = items.map((item: any) => ({
+ userId: item.userId,
+ userEmail: item.userEmail,
+ name: item.name,
accountId: item.accountId,
accountName: item.accountName,
role: item.role,
@@ -73,89 +82,137 @@ const AccountNav: React.FC = ({ accountName = null, transaction
setAccounts(cleanedData);
} catch (error) {
- console.log(error)
+ console.log(error);
}
- }
-
+ };
const handleAccountsClick = async () => {
setAccountsOpen(!accountsOpen);
-
+
if (!accountsOpen) {
setLoadingAccounts(true);
-
- // Fetch API if:
- // 1. No accounts data exists (first time), OR
- // 2. Modal was previously closed (need fresh data)
+
if (accounts.length === 0 || hasModalBeenClosed) {
await getAccountDetails();
- setHasModalBeenClosed(false); // Reset the flag after fetching
+ setHasModalBeenClosed(false);
}
-
+
setLoadingAccounts(false);
}
};
- const handleAccountSwitch = (account) => {
- setUser(prev => ({
- ...prev,
- account: { name: account.name, id: account.id }
- }));
+ const handleAccountSwitch = (account: any) => {
+ console.log("handleAccountSwitch", account);
- // Update accounts active status
- setAccounts(prevAccounts =>
- prevAccounts.map(acc => ({
- ...acc,
- isActive: acc.id === account.id
- }))
- );
+ // Update sessionStorage
+ sessionStorage.setItem('activeAccountId', JSON.stringify(account.accountId));
+
+ // Dispatch custom event
+ dispatchSessionStorageChange('activeAccountId', account.accountId);
+
+ // Update user state
+
+ setUser({
+ id: account.userId,
+ name: account.name,
+ email: account.userEmail,
+ language: "", // set it if available
+ account: {
+ id: account.accountId,
+ isDefault: false, // update as needed
+ name: account.accountName,
+ },
+ });
+
+ sessionStorage.setItem('userDetails', JSON.stringify({
+ id: account.userId,
+ name: account.name,
+ email: account.userEmail,
+ language: "", // set it if available
+ account: {
+ id: account.accountId,
+ isDefault: false, // update as needed
+ name: account.accountName,
+ },
+ }));
setAccountsOpen(false);
setOpen(false);
};
- const navigate = useNavigate()
+
+ const navigate = useNavigate();
const getUserDetails = async () => {
try {
- let res = await api.get(`/api/user/details`)
- console.log("getuser", res)
- setUser(res?.data)
+ let res = await api.get(`/api/user/details`);
+ console.log("getuser", res);
+ const item = res?.data;
+ if (item) {
+ const userData = {
+ id: item?.id,
+ name : item?.firstName + " " + item?.lastName ,
+ email: item?.email,
+ language: "",
+ account: {
+ id: item?.account.id,
+ isDefault: false,
+ name: item?.account.name,
+ },
+ };
+
+ console.log("userData",userData)
+
+ setUser(userData);
+ sessionStorage.setItem('userDetails', JSON.stringify(userData));
+ sessionStorage.setItem('activeAccountId', JSON.stringify(userData.account.id));
+
+ // Dispatch event for initial load
+ dispatchSessionStorageChange('activeAccountId', userData.account.id);
+
+ console.log("Data is saved in sessionStorage");
+ }
+
+
} catch (error) {
console.error("Error fetching user details:", error);
}
- }
+ };
useEffect(() => {
- getUserDetails()
- }, [])
-
+ if (!activeAccountId) {
+ getUserDetails();
+ } else {
+ setUser(userDetails);
+ }
+ }, []);
const location = useLocation();
- const pathnames = location.pathname
+ const rawPathnames = location.pathname
.split("/")
- .filter((x) => x && isNaN(Number(x))); // remove numeric IDs
+ .filter((x) => x && isNaN(Number(x)));
+
+ // Special case: if first segment is 's' and next is 'settings', remove 's'
+ const pathnames =
+ rawPathnames[0] === "s" && rawPathnames[1] === "settings"
+ ? rawPathnames.slice(1)
+ : rawPathnames;
const labelMap: Record = {
accounts: "Accounts",
transactions: "Transactions",
templates: "Templates"
- // Add more routes here if needed
};
- // const [open, setOpen] = useState(false);
- // const dropdownRef = useRef(null);
-
- // Close dropdown when clicked outside
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
if (open) {
- setHasModalBeenClosed(true); // Mark modal as closed when clicking outside
+ setHasModalBeenClosed(true);
}
setOpen(false);
- setAccountsOpen(false); // Also close accounts dropdown
+ setAccountsOpen(false);
}
}
@@ -165,24 +222,24 @@ const AccountNav: React.FC = ({ accountName = null, transaction
const handleLogout = async () => {
try {
- let res = await api.post('/api/auth/logout')
+ let res = await api.post('/api/auth/logout');
if (res.status === 200) {
+ sessionStorage.clear();
setOpen(false);
- navigate("/login")
+ navigate("/login");
}
} catch (error) {
- console.log(error)
+ console.log(error);
}
};
- // Handle main dropdown toggle
const handleMainDropdownToggle = () => {
if (open) {
- setHasModalBeenClosed(true); // Mark as closed when manually closing
+ setHasModalBeenClosed(true);
}
setOpen(!open);
if (!open) {
- setAccountsOpen(false); // Close accounts dropdown when opening main dropdown
+ setAccountsOpen(false);
}
};
@@ -191,7 +248,6 @@ const AccountNav: React.FC = ({ accountName = null, transaction
.replace(/[-_]/g, " ")
.replace(/\b\w/g, (char) => char.toUpperCase());
-
const ShimmerRow = () => (
@@ -205,7 +261,6 @@ const AccountNav: React.FC
= ({ accountName = null, transaction
);
-
return (