SME-Web/src/components/home/Cards.tsx

238 lines
6.5 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import {
FaCheckCircle,
FaClock,
FaHourglassHalf,
FaTasks,
FaChevronDown,
FaPlus,
FaUserPlus,
FaFilter,
FaCalendarAlt
} from 'react-icons/fa';
import { useNavigate } from 'react-router-dom';
// Define a type for card data
interface CardData {
title: string;
count: number;
icon: JSX.Element;
gradient: string;
shadowColor: string;
iconBg: string;
textColor: string;
percentage?: number;
trend?: 'up' | 'down' | 'stable';
}
// interface CardData {
// title: string;
// count: number;
// icon: React.ReactNode;
// gradient: string;
// shadowColor: string;
// iconBg: string;
// textColor: string;
// trend: 'up' | 'down';
// }
interface CardsProps {
type?: 'dashboard' | 'account' | 'transactions';
onOpenModal?: () => void;
dashboardData: any;
fromDate: string;
toDate: string;
onDateRangeChange: (range: { from: string; to: string }) => void;
cards: CardData[];
isLoading: boolean
}
const AccountData: CardData[] = [
{
title: 'Active Accounts',
count: 12,
icon: <FaTasks size={18} className="text-blue-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: 'up'
},
{
title: 'In-Progress',
count: 8,
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: 'stable'
},
{
title: 'Completed',
count: 27,
icon: <FaCheckCircle 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: 'up'
},
{
title: 'Inactive',
count: 5,
icon: <FaHourglassHalf size={18} className="text-gray-600" />,
gradient: 'bg-gradient-to-br from-gray-50 to-gray-100',
shadowColor: 'shadow-gray-200/50',
iconBg: 'bg-gray-100 border-gray-200',
textColor: 'text-gray-700',
trend: 'down'
},
];
const filters = ['Last 7 Days', 'Last 30 Days', 'Last 6 Months', 'This Year'];
const accounts = ['All Accounts', 'Account 1', 'Account 2', 'Account 3'];
const Cards: React.FC<CardsProps> = ({ type = 'dashboard', onOpenModal, onDateRangeChange, cards, isLoading }) => {
const navigate = useNavigate();
const [selectedFilter, setSelectedFilter] = useState<string>('Last 7 Days');
// const [isLoading, setIsLoading] = useState<boolean>(true);
// useEffect(() => {
// setIsLoading(true);
// setTimeout(() => {
// if (type == 'account') {
// setShowCards(AccountData);
// } else {
// setShowCards(cards);
// }
// setIsLoading(false);
// }, 500);
// }, [type]);
useEffect(() => {
if (type == 'dashboard') {
const now = new Date();
let fromDate = new Date();
switch (selectedFilter) {
case 'Last 7 Days':
fromDate.setDate(now.getDate() - 7);
break;
case 'Last 30 Days':
fromDate.setDate(now.getDate() - 30);
break;
case 'Last 6 Months':
fromDate.setMonth(now.getMonth() - 6);
break;
case 'This Year':
fromDate = new Date(now.getFullYear(), 0, 1);
break;
default:
fromDate.setDate(now.getDate() - 7);
}
const from = fromDate.toISOString().split('T')[0];
const to = now.toISOString().split('T')[0];
onDateRangeChange({ from, to });
}
}, [selectedFilter]);
const getButtonConfig = () => {
switch (type) {
case 'account':
return {
text: 'Add Account',
icon: <FaPlus size={14} />,
gradient: 'bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800'
};
case 'transactions':
return {
text: 'Send Invite',
icon: <FaUserPlus size={14} />,
gradient: 'bg-gradient-to-r from-emerald-600 to-emerald-700 hover:from-emerald-700 hover:to-emerald-800'
};
default:
return null;
}
};
const buttonConfig = getButtonConfig();
const renderTrendIndicator = (trend: string | undefined, percentage: number | undefined) => {
if (!trend || !percentage) return null;
const trendColors = {
up: 'text-emerald-500',
down: 'text-red-500',
stable: 'text-gray-500'
};
const trendSymbols = {
up: '↗',
down: '↘',
stable: '→'
};
return (
<div className={`flex items-center text-xs ${trendColors[trend as keyof typeof trendColors]} mt-1`}>
<span className="mr-1">{trendSymbols[trend as keyof typeof trendSymbols]}</span>
{/* <span>{percentage}%</span> */}
</div>
);
};
return (
<div className="w-full">
{/* Cards */}
{isLoading ? (
<div className="w-full h-[10vh] px-6 py-3">
<div className="animate-pulse">
{/* <div className="h-8 bg-gray-200 rounded w-32 mb-8"></div> */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
{[...Array(4)].map((_, i) => (
<div key={i} className="h-10 bg-gray-200 border border-gray-100"></div>
))}
</div>
</div>
</div>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 shadow">
{cards.map((card, index) => (
<div
key={card.title}
onClick={() => navigate(card.navigateTo)}
className={`flex items-center justify-between bg-white px-4 py-3.5 transition-all duration-300 cursor-pointer ${index > 0 ? "border-l-1 border-gray-200" : ""}`}
style={{
animationDelay: `${index * 100}ms`,
}}
>
{/* Left side: Icon + Title */}
<div className="flex items-center gap-3">
<div className={`p-1.5 rounded-lg ${card.iconBg}`}>
{card.icon}
</div>
<h3 className="text-xs font-medium text-gray-600 text-nowrap">{card.title}</h3>
</div>
{/* Count */}
<p className={`text-sm font-bold`}>
{card.count}
</p>
</div>
))}
</div>
)}
</div>
);
};
export default Cards;