jai #1
|
|
@ -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<Transaction[]>([]);
|
||||
const [selectedTransactions, setSelectedTransactions] = useState<number[]>([]);
|
||||
|
||||
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 (
|
||||
<>
|
||||
<Cards type="account" onOpenModal={handleOpenModal} />
|
||||
{transactions.length > 0 && (
|
||||
<div className="overflow-x-auto py-4">
|
||||
<table className="min-w-full text-sm border border-gray-200 rounded bg-white shadow-sm">
|
||||
|
|
@ -102,6 +116,8 @@ const Account = () => {
|
|||
</table>
|
||||
</div>
|
||||
)}
|
||||
{isModalOpen && <AddInviteModal onClose={() => setIsModalOpen(false)}
|
||||
onAddAccount={handleAddAccount} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<AccountNavProps> = ({ 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<UserData>({
|
||||
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<AccountNavProps> = ({ accountName = null, transaction
|
|||
.split("/")
|
||||
.filter((x) => x && isNaN(Number(x))); // remove numeric IDs
|
||||
|
||||
const labelMap = {
|
||||
const labelMap: Record<string, string> = {
|
||||
accounts: "Accounts",
|
||||
transactions: "Transactions",
|
||||
// Add more routes here if needed
|
||||
};
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const dropdownRef = useRef<HTMLDivElement>(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 (
|
||||
<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">
|
||||
{pathnames.map((segment, index) => {
|
||||
const label = labelMap[segment] || segment;
|
||||
const to = "/" + pathnames.slice(0, index + 1).join("/");
|
||||
const isLast = index === pathnames.length - 1;
|
||||
|
||||
<nav className="text-md font-medium text-gray-800 capitalize">
|
||||
{pathnames.map((segment, index) => {
|
||||
const label = labelMap[segment] || segment;
|
||||
const to = "/" + pathnames.slice(0, index + 1).join("/");
|
||||
return (
|
||||
<span key={to}>
|
||||
{!isLast ? (
|
||||
<>
|
||||
<Link
|
||||
to={to}
|
||||
className="text-blue-600 hover:text-blue-700 hover:underline transition-colors"
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
<span className="mx-2 text-gray-400">{">"}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className="text-gray-900 font-semibold">{label}</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
const isLast = index === pathnames.length - 1;
|
||||
<div className="flex items-center space-x-2">
|
||||
|
||||
return (
|
||||
<span key={to}>
|
||||
{!isLast ? (
|
||||
<>
|
||||
<Link
|
||||
to={to}
|
||||
className="text-blue-600 hover:underline"
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
<span className="mx-1">{">"}</span>
|
||||
</>
|
||||
) : (
|
||||
<span>{label}</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
{/* <h1 className="text-md font-medium text-gray-800 capitalize">Account</h1> */}
|
||||
|
||||
<div className="flex items-center">
|
||||
{/* Notification + Settings with smaller gap */}
|
||||
<div className="flex items-center">
|
||||
{/* User Dropdown */}
|
||||
<div className="relative" ref={dropdownRef}>
|
||||
{/* Avatar Button */}
|
||||
<button
|
||||
aria-label="Notifications"
|
||||
className="p-2 rounded-full hover:bg-gray-100 transition-colors text-gray-600"
|
||||
className="flex items-center space-x-2 p-1 cursor-pointer rounded-lg transition-colors"
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-expanded={open}
|
||||
aria-haspopup="true"
|
||||
>
|
||||
<IoIosNotifications className="text-xl" />
|
||||
<div className="w-8 h-8 rounded-full overflow-hidden bg-gradient-to-br from-green-500 to-blue-600 flex items-center justify-center text-white font-semibold text-sm shadow-md">
|
||||
{user ? (
|
||||
<span
|
||||
className="w-full h-full object-cover p-1.5 font-bold"
|
||||
>{(user.firstName.slice(0,1) + user.lastName.slice(0,1)).toUpperCase()}</span>
|
||||
) : (
|
||||
<FaUser className="text-lg" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<Link
|
||||
to="/s/settings"
|
||||
aria-label="Settings"
|
||||
className="p-2 rounded-full hover:bg-gray-100 transition-colors text-gray-600"
|
||||
>
|
||||
<FaCog className="text-sm" />
|
||||
</Link>
|
||||
</div>
|
||||
{/* Enhanced Dropdown */}
|
||||
{open && (
|
||||
<div className="absolute right-0 mt-2 w-72 top-8 rounded-xl shadow-xl bg-white border border-gray-200 z-50 overflow-hidden">
|
||||
{/* User Info Section */}
|
||||
<div className="px-4 py-4 bg-gradient-to-r from-blue-50 to-purple-50 border-b border-gray-100">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="w-12 h-12 rounded-full overflow-hidden bg-gradient-to-br from-green-500 to-blue-600 flex items-center justify-center text-white font-semibold shadow-md">
|
||||
{(user) ? (
|
||||
<span
|
||||
className="w-full h-full object-cover px-3 text-xl py-2.5 font-bold"
|
||||
>{(user.firstName.slice(0,1) + user.lastName.slice(0,1)).toUpperCase()}</span>
|
||||
) : (
|
||||
<FaUser className="text-lg" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-semibold text-gray-900 truncate">{user.firstName + ' ' +user.lastName || '-'}</div>
|
||||
<div className="text-sm text-gray-600 truncate">{user.email || '-'}</div>
|
||||
<div className="text-xs text-gray-500 mt-1">
|
||||
Account #{user?.account?.name || '-'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Avatar with separate spacing */}
|
||||
<div className="w-9 h-9 ms-3 rounded-full overflow-hidden bg-[var(--primary)] flex items-center justify-center text-white font-semibold text-sm">
|
||||
{user.picture ? (
|
||||
<img
|
||||
src={user.picture}
|
||||
alt="User avatar"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
initials
|
||||
{/* Logout Section */}
|
||||
<div className="border-t border-gray-100 ">
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="w-full flex items-center px-4 py-3 text-sm text-red-600 hover:bg-red-50 transition-colors cursor-pointer"
|
||||
>
|
||||
<FaSignOutAlt className="mr-3" />
|
||||
<span>Log Out</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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<AccountData[]>([]);
|
||||
const [selectedAccounts, setSelectedAccounts] = useState<number[]>([]);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [accounts, setAccounts] = useState<string[]>([]);
|
||||
const [openMenuId, setOpenMenuId] = useState<string | null>(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 (
|
||||
<>
|
||||
<Cards type="account" onOpenModal={handleOpenModal} />
|
||||
{allAccounts.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">
|
||||
|
|
@ -101,8 +146,38 @@ const Accounts = () => {
|
|||
{status.text}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
<PiDotsThreeOutlineVerticalFill className="text-lg text-slate-300 hover:text-black mx-auto" />
|
||||
<td className="px-4 py-3 text-center relative">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleMenuToggle(account.accountId);
|
||||
}}
|
||||
className="mx-auto"
|
||||
aria-label="Actions menu"
|
||||
>
|
||||
<PiDotsThreeOutlineVerticalFill className="text-lg text-slate-300 hover:text-black" />
|
||||
</button>
|
||||
|
||||
{/* Dropdown menu */}
|
||||
{openMenuId === account.accountId && (
|
||||
<div
|
||||
className="absolute right-13 top-6 mt-1 w-18 bg-white border text-[13px] font-bold border-gray-300 rounded-md shadow-lg z-10"
|
||||
onClick={(e) => e.stopPropagation()} // prevent row click closing
|
||||
>
|
||||
<button
|
||||
className="w-full px-3 py-1 text-left text-green-700 hover:bg-green-100 rounded-t-md cursor-pointer"
|
||||
onClick={() => handleAction(account.accountId, 'accept')}
|
||||
>
|
||||
Accept
|
||||
</button>
|
||||
<button
|
||||
className="w-full px-3 py-1 text-left text-red-700 hover:bg-red-100 rounded-b-md cursor-pointer"
|
||||
onClick={() => handleAction(account.accountId, 'reject')}
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
|
@ -111,6 +186,8 @@ const Accounts = () => {
|
|||
</table>
|
||||
</div>
|
||||
)}
|
||||
{isModalOpen && <AddAccountModal onClose={() => setIsModalOpen(false)}
|
||||
onAddAccount={handleAddAccount} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
interface AddAccountModalProps {
|
||||
onClose: () => void;
|
||||
onAddAccount: (accountName: string) => void;
|
||||
}
|
||||
|
||||
const AddAccountModal: React.FC<AddAccountModalProps> = ({ onClose, onAddAccount }) => {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
|
||||
const handleAddClick = () => {
|
||||
if (inputValue.trim()) {
|
||||
onAddAccount(inputValue.trim());
|
||||
setInputValue(''); // clear input after submit
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 backdrop-blur-sm flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg shadow-xl p-6 w-80">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-4">Add New Account</h3>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter account name"
|
||||
value={inputValue}
|
||||
onChange={(e) => 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)]"
|
||||
/>
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
setInputValue('');
|
||||
onClose();
|
||||
}}
|
||||
className="px-4 py-1.5 text-[13px] cursor-pointer font-semibold text-gray-600 hover:bg-gray-100 rounded-md transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleAddClick}
|
||||
className="px-2 py-1.5 cursor-pointer font-semibold bg-[var(--modalSubmitBG)] text-[13px] text-white hover:bg-[var(--modalSubmitBGHover)] rounded-md transition-colors"
|
||||
disabled={!inputValue.trim()}
|
||||
>
|
||||
Add Account
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddAccountModal;
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import { useState } from "react";
|
||||
|
||||
interface AddAccountModalProps {
|
||||
onClose: () => void;
|
||||
onAddAccount: (accountName: string) => void;
|
||||
}
|
||||
const AddInviteModal : React.FC<AddAccountModalProps> = ({ onClose, onAddAccount }) => {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
|
||||
const handleAddClick = () => {
|
||||
if (inputValue.trim()) {
|
||||
onAddAccount(inputValue.trim());
|
||||
setInputValue(''); // clear input after submit
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 backdrop-blur-sm flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg shadow-xl p-6 w-80">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-4">Send Invite</h3>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter account name"
|
||||
value={inputValue}
|
||||
onChange={(e) => 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)]"
|
||||
/>
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
setInputValue('');
|
||||
onClose();
|
||||
}}
|
||||
className="px-4 py-1.5 text-[13px] cursor-pointer font-semibold text-gray-600 hover:bg-gray-100 rounded-md transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleAddClick}
|
||||
className="px-2 py-1.5 cursor-pointer font-semibold bg-[var(--modalSubmitBG)] text-[13px] text-white hover:bg-[var(--modalSubmitBGHover)] rounded-md transition-colors"
|
||||
disabled={!inputValue.trim()}
|
||||
>
|
||||
Add Account
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AddInviteModal
|
||||
|
|
@ -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: <FaTasks size={20} className="text-orange-500" />,
|
||||
ring: 'ring-orange-400/20',
|
||||
bg: 'bg-orange-50',
|
||||
},
|
||||
{
|
||||
title: 'In-Progress',
|
||||
count: 8,
|
||||
icon: <FaClock size={20} className="text-yellow-500" />,
|
||||
ring: 'ring-yellow-400/20',
|
||||
bg: 'bg-yellow-50',
|
||||
},
|
||||
{
|
||||
title: 'Deactive',
|
||||
count: 5,
|
||||
icon: <FaHourglassHalf size={20} className="text-red-500" />,
|
||||
ring: 'ring-red-400/20',
|
||||
bg: 'bg-red-50',
|
||||
},
|
||||
{
|
||||
title: 'Completed',
|
||||
count: 27,
|
||||
icon: <FaCheckCircle size={20} className="text-green-500" />,
|
||||
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<CardsProps> = ({ type, onOpenModal }) => {
|
||||
const [selectedFilter, setSelectedFilter] = useState<string>('Last 7 Days');
|
||||
const [showCards, setShowCards] = useState<CardData[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (type === 'account') {
|
||||
setShowCards(AccountData);
|
||||
} else {
|
||||
setShowCards(cards);
|
||||
}
|
||||
}, [type]);
|
||||
|
||||
return (
|
||||
<div className="w-full px-4 py-3">
|
||||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between mb-5 gap-3">
|
||||
<h2 className="text-lg font-medium text-gray-700">Overview</h2>
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between mb-5 gap-3">
|
||||
<h2 className="text-lg font-medium text-gray-700">Overview</h2>
|
||||
|
||||
<div className="flex gap-2 w-full md:w-auto">
|
||||
{/* Account Selector */}
|
||||
<select
|
||||
value={'All'}
|
||||
onChange={() => {}}
|
||||
className="text-sm text-gray-700 border border-gray-300 rounded-sm px-3 py-1.5 focus:outline-none bg-white shadow-sm"
|
||||
>
|
||||
<option>All</option>
|
||||
<option>Account 1</option>
|
||||
<option>Account 2</option>
|
||||
<option>Account 3</option>
|
||||
</select>
|
||||
|
||||
{/* Date Filter */}
|
||||
<select
|
||||
value={selectedFilter}
|
||||
onChange={(e) => setSelectedFilter(e.target.value)}
|
||||
className="text-sm text-gray-700 border border-gray-300 rounded-sm px-3 py-1.5 focus:outline-none bg-white shadow-sm"
|
||||
>
|
||||
{filters.map((f) => (
|
||||
<option key={f}>{f}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 w-full md:w-auto">
|
||||
{/* Account Selector */}
|
||||
<select
|
||||
value={'All'}
|
||||
onChange={() => { }}
|
||||
className="text-sm text-gray-700 border border-gray-300 rounded-sm px-3 py-1.5 focus:outline-none bg-white shadow-sm"
|
||||
>
|
||||
<option>All</option>
|
||||
<option>Account 1</option>
|
||||
<option>Account 2</option>
|
||||
<option>Account 3</option>
|
||||
</select>
|
||||
|
||||
{/* Date Filter */}
|
||||
<select
|
||||
value={selectedFilter}
|
||||
onChange={(e) => setSelectedFilter(e.target.value)}
|
||||
className="text-sm text-gray-700 border border-gray-300 rounded-sm px-3 py-1.5 focus:outline-none bg-white shadow-sm"
|
||||
>
|
||||
{filters.map((f) => (
|
||||
<option key={f}>{f}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
{type === 'account' &&
|
||||
<button className="px-2 py-1.5 cursor-pointer font-semibold bg-[var(--primary)] text-[13px] text-white hover:bg-[var(--primaryLight2)] rounded-md transition-colors" onClick={onOpenModal}>Add Account</button>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
<div className="cursor-pointer grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{cards.map((card) => (
|
||||
{showCards.map((card) => (
|
||||
<div
|
||||
key={card.title}
|
||||
className={`rounded-md bg-white/60 backdrop-blur-md border border-gray-200 p-5 transition-transform shadow-md hover:scale-[1.02] hover:shadow-lg`}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@
|
|||
--hideModalBg: #2d2d2d;
|
||||
|
||||
--processStepOneTextHead: #000000;
|
||||
|
||||
--modalSubmitBG:#1919d7;
|
||||
--modalSubmitBGHover:#395ee1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue