From 2bb54b20436b667331ae10c0f5acf431cae0778f Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Fri, 4 Jul 2025 19:58:03 +0530 Subject: [PATCH] Edit Signature and Account Card , Trans --- src/components/accounts/Account.tsx | 16 ++ src/components/accounts/AccountNav.tsx | 256 ++++++++++++-------- src/components/accounts/Accounts.tsx | 81 ++++++- src/components/accounts/AddAccountModal.tsx | 52 ++++ src/components/accounts/AddInviteModal.tsx | 51 ++++ src/components/home/Cards.tsx | 120 ++++++--- src/index.css | 3 + 7 files changed, 440 insertions(+), 139 deletions(-) create mode 100644 src/components/accounts/AddAccountModal.tsx create mode 100644 src/components/accounts/AddInviteModal.tsx diff --git a/src/components/accounts/Account.tsx b/src/components/accounts/Account.tsx index 602a507..1d63d5a 100644 --- a/src/components/accounts/Account.tsx +++ b/src/components/accounts/Account.tsx @@ -4,6 +4,8 @@ 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"; interface Transaction { id: number; @@ -23,6 +25,12 @@ const Account = () => { const [transactions, setTransactions] = useState([]); const [selectedTransactions, setSelectedTransactions] = useState([]); + const [isModalOpen, setIsModalOpen] = useState(false); + + const handleOpenModal = () => { + setIsModalOpen(true); + }; + const fetchTransactions = async () => { try { const response = await api(`/api/accounts/${accountId}/transactions`); @@ -42,8 +50,14 @@ const Account = () => { navigate(`/accounts/${accountId}/transactions/${id}`); }; + const handleAddAccount = (accountName: string) => { + console.log(accountId) + setIsModalOpen(false); + }; + return ( <> + {transactions.length > 0 && (
@@ -102,6 +116,8 @@ const Account = () => {
)} + {isModalOpen && setIsModalOpen(false)} + onAddAccount={handleAddAccount} />} ); }; diff --git a/src/components/accounts/AccountNav.tsx b/src/components/accounts/AccountNav.tsx index 837322f..5024e7e 100644 --- a/src/components/accounts/AccountNav.tsx +++ b/src/components/accounts/AccountNav.tsx @@ -1,64 +1,63 @@ -import React, { use, useEffect } from 'react'; -import { useSelector } from 'react-redux'; -import { Link, useLocation, useParams } from 'react-router-dom'; -import { FaCog } from 'react-icons/fa'; -import { IoIosNotifications } from 'react-icons/io'; -import { RootState } from '../../store/store'; -import { UserState } from '../../store/slices/userSlice'; +import React, { useEffect, useRef, useState } from 'react'; +// import { useSelector } from 'react-redux'; +import { Link, useLocation } from 'react-router-dom'; +import { FaSignOutAlt,FaUser } from "react-icons/fa"; import api from '../../config/api'; -// const fetchAccountData = async (accountId: string) => { -// try { -// if(!accountId) return null; -// const response = await api.get(`/api/accounts/${accountId}`); -// return response.data; -// } catch (error) { -// console.error("Error fetching account data:", error); -// throw error; -// } -// } - -// const fetchTransactionData = async (accountId: string, transactionId: string) => { -// try { -// if(!accountId || !transactionId) return null; -// const response = await api.get(`/api/accounts/${accountId}/transactions/${transactionId}`); -// return response.data; -// } catch (error) { -// console.error("Error fetching account data:", error); -// throw error; -// } -// } - +// import { RootState } from '../../store/store'; +// import { UserState } from '../../store/slices/userSlice'; interface AccountNavProps { - accountName: string | null; - transactionName: string | null; + accountName?: string | null; + transactionName?: string | null; +} + +// Define the shape of state object +interface Account { + id: number; + isDefault: boolean; + name: string; +} + +interface UserData { + id: string; + firstName: string; + lastName: string; + email: string; + language: string; + account: Account; } const AccountNav: React.FC = ({ accountName = null, transactionName = null }) => { - const user: UserState = useSelector((state: RootState) => state.user); + // const user: UserState = useSelector((state: RootState) => state.user); - const initials = user.username - ? user.username - .split(' ') - .map((n) => n[0]) - .join('') - .slice(0, 2) - .toUpperCase() - : 'U'; + const [user, setUser] = useState({ + id: "", + firstName: "", + lastName: "", + email: "", + language: "", + account: { + id: 0, + isDefault: false, + name: "", + }, + }); + + const getUserDetails = async () => { + try { + let res = await api.get(`/api/user/details`) + console.log("getuser", res) + setUser(res?.data) + } catch (error) { + console.error("Error fetching user details:", error); + } + } + + useEffect(() => { + getUserDetails() + }, []) - // useEffect(() => { - // if (accountId) { - // api.get(`/api/accounts/${accountId}`) - // .then(response => { - // // Handle the account data if needed - // console.log(response.data, "Line 29"); - // }) - // .catch(error => { - // console.error("Error fetching account data:", error); - // }); - // } - // }, [accountId, transactionId]); const location = useLocation(); @@ -66,74 +65,121 @@ const AccountNav: React.FC = ({ accountName = null, transaction .split("/") .filter((x) => x && isNaN(Number(x))); // remove numeric IDs - const labelMap = { + const labelMap: Record = { accounts: "Accounts", transactions: "Transactions", // 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)) { + setOpen(false); + } + } + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + const handleLogout = () => { + // Add logout logic here + console.log('Logging out...'); + setOpen(false); + }; + + return (
+ - - {/*

Account

*/} - -
- {/* Notification + Settings with smaller gap */} -
+ {/* User Dropdown */} +
+ {/* Avatar Button */} - - - -
+ {/* Enhanced Dropdown */} + {open && ( +
+ {/* User Info Section */} +
+
+
+ {(user) ? ( + {(user.firstName.slice(0,1) + user.lastName.slice(0,1)).toUpperCase()} + ) : ( + + )} +
+
+
{user.firstName + ' ' +user.lastName || '-'}
+
{user.email || '-'}
+
+ Account #{user?.account?.name || '-'} +
+
+
+
- {/* Avatar with separate spacing */} -
- {user.picture ? ( - User avatar - ) : ( - initials + {/* Logout Section */} +
+ +
+
)}
@@ -141,4 +187,4 @@ const AccountNav: React.FC = ({ accountName = null, transaction ); }; -export default AccountNav; +export default AccountNav; \ No newline at end of file diff --git a/src/components/accounts/Accounts.tsx b/src/components/accounts/Accounts.tsx index ecfff3d..171f131 100644 --- a/src/components/accounts/Accounts.tsx +++ b/src/components/accounts/Accounts.tsx @@ -6,6 +6,9 @@ import AccountNav from "./AccountNav"; import api from "../../config/api"; import { AccountData, AccountStatus, UserRole } from "../../utlity/types"; import { useNavigate } from "react-router-dom"; +import Cards from "../home/Cards"; +import AddAccountModal from "./AddAccountModal"; +import { Bounce, toast } from "react-toastify"; // import { UserRole, AccountStatus, AccountData } from "../../types/account"; @@ -32,6 +35,13 @@ const getStatusLabel = ( const Accounts = () => { const [allAccounts, setAllAccounts] = useState([]); const [selectedAccounts, setSelectedAccounts] = useState([]); + const [isModalOpen, setIsModalOpen] = useState(false); + const [accounts, setAccounts] = useState([]); + const [openMenuId, setOpenMenuId] = useState(null); + + const handleOpenModal = () => { + setIsModalOpen(true); + }; const navigate = useNavigate(); @@ -53,8 +63,43 @@ const Accounts = () => { navigate(`/accounts/${id}/transactions`); }; + const handleAddAccount = (accountName: string) => { + setAccounts((prev) => [...prev, accountName]); + setIsModalOpen(false); + }; + + const handleMenuToggle = (accountId: string) => { + setOpenMenuId(openMenuId === accountId ? null : accountId); + }; + + const handleAction = async (accountId: string, action: 'accept' | 'reject') => { + try { + let response = await api.post(`/api/accounts/${accountId}/accept/invite`) + console.log(response) + if (response.data.status === 202) { + toast.success("Login Successful", { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: false, + pauseOnHover: true, + draggable: true, + progress: undefined, + theme: "light", + transition: Bounce, + }); + } + } catch (error) { + console.error('Error posting data:', error); + } finally { + setOpenMenuId(null); // close menu + } + }; + + return ( <> + {allAccounts.length > 0 && (
@@ -101,8 +146,38 @@ const Accounts = () => { {status.text} - ); @@ -111,6 +186,8 @@ const Accounts = () => {
- + + + + {/* Dropdown menu */} + {openMenuId === account.accountId && ( +
e.stopPropagation()} // prevent row click closing + > + + +
+ )}
)} + {isModalOpen && setIsModalOpen(false)} + onAddAccount={handleAddAccount} />} ); }; diff --git a/src/components/accounts/AddAccountModal.tsx b/src/components/accounts/AddAccountModal.tsx new file mode 100644 index 0000000..606972f --- /dev/null +++ b/src/components/accounts/AddAccountModal.tsx @@ -0,0 +1,52 @@ +import React, { useState } from 'react'; + +interface AddAccountModalProps { + onClose: () => void; + onAddAccount: (accountName: string) => void; +} + +const AddAccountModal: React.FC = ({ onClose, onAddAccount }) => { + const [inputValue, setInputValue] = useState(''); + + const handleAddClick = () => { + if (inputValue.trim()) { + onAddAccount(inputValue.trim()); + setInputValue(''); // clear input after submit + } + }; + + return ( +
+
+

Add New Account

+ setInputValue(e.target.value)} + className="w-full mb-4 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--primary)]" + /> +
+ + +
+
+
+ ); +}; + +export default AddAccountModal; diff --git a/src/components/accounts/AddInviteModal.tsx b/src/components/accounts/AddInviteModal.tsx new file mode 100644 index 0000000..dc72141 --- /dev/null +++ b/src/components/accounts/AddInviteModal.tsx @@ -0,0 +1,51 @@ +import { useState } from "react"; + +interface AddAccountModalProps { + onClose: () => void; + onAddAccount: (accountName: string) => void; +} +const AddInviteModal : React.FC = ({ onClose, onAddAccount }) => { + const [inputValue, setInputValue] = useState(''); + + const handleAddClick = () => { + if (inputValue.trim()) { + onAddAccount(inputValue.trim()); + setInputValue(''); // clear input after submit + } + }; + + return ( +
+
+

Send Invite

+ setInputValue(e.target.value)} + className="w-full mb-4 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-[var(--primary)]" + /> +
+ + +
+
+
+ ) +} + +export default AddInviteModal \ No newline at end of file diff --git a/src/components/home/Cards.tsx b/src/components/home/Cards.tsx index dbe9be0..16dbc30 100644 --- a/src/components/home/Cards.tsx +++ b/src/components/home/Cards.tsx @@ -1,7 +1,22 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { FaCheckCircle, FaClock, FaHourglassHalf, FaTasks } from 'react-icons/fa'; -const cards = [ +// Define a type for card data +interface CardData { + title: string; + count: number; + icon: JSX.Element; + ring: string; + bg: string; +} + +interface CardsProps { + type?: 'dashboard'; + // onCardClick?: (card: CardData) => void; + onOpenModal?: () => void; +} + +const cards: CardData[] = [ { title: 'Action Required', count: 12, @@ -32,48 +47,89 @@ const cards = [ }, ]; +const AccountData: CardData[] = [ + { + title: 'Transaction', + count: 12, + icon: , + ring: 'ring-orange-400/20', + bg: 'bg-orange-50', + }, + { + title: 'In-Progress', + count: 8, + icon: , + ring: 'ring-yellow-400/20', + bg: 'bg-yellow-50', + }, + { + title: 'Deactive', + count: 5, + icon: , + ring: 'ring-red-400/20', + bg: 'bg-red-50', + }, + { + title: 'Completed', + count: 27, + icon: , + ring: 'ring-green-400/20', + bg: 'bg-green-50', + }, +]; + const filters = ['Last 7 Days', 'Last 30 Days', 'Last 6 Months', 'This Year']; -const Cards = () => { - const [selectedFilter, setSelectedFilter] = useState('Last 7 Days'); +const Cards: React.FC = ({ type, onOpenModal }) => { + const [selectedFilter, setSelectedFilter] = useState('Last 7 Days'); + const [showCards, setShowCards] = useState([]); + + useEffect(() => { + if (type === 'account') { + setShowCards(AccountData); + } else { + setShowCards(cards); + } + }, [type]); return (
{/* Header */} -
-

Overview

+
+

Overview

-
- {/* Account Selector */} - - - {/* Date Filter */} - -
-
+
+ {/* Account Selector */} + + {/* Date Filter */} + + {type === 'account' && + } +
+
{/* Cards */}
- {cards.map((card) => ( + {showCards.map((card) => (