This commit is contained in:
Iliyan Angelov
2025-11-23 18:59:18 +02:00
parent be07802066
commit 627959f52b
1840 changed files with 236564 additions and 3475 deletions

View File

@@ -129,6 +129,9 @@ const BusinessDashboardPage: React.FC = () => {
if (response.status === 'success' && response.data) {
let invoiceList = response.data.invoices || [];
// Client-side filtering for search (only on current page results)
// Note: This is a limitation - search only works on current page
// For full search functionality, backend needs to support search parameter
if (invoiceFilters.search) {
invoiceList = invoiceList.filter((inv) =>
inv.invoice_number.toLowerCase().includes(invoiceFilters.search.toLowerCase()) ||
@@ -138,8 +141,15 @@ const BusinessDashboardPage: React.FC = () => {
}
setInvoices(invoiceList);
setInvoicesTotalPages(response.data.total_pages || 1);
setInvoicesTotalItems(response.data.total || 0);
// Only update pagination if not searching (to avoid incorrect counts)
if (!invoiceFilters.search) {
setInvoicesTotalPages(response.data.total_pages || 1);
setInvoicesTotalItems(response.data.total || 0);
} else {
// When searching, keep original pagination but show filtered count
setInvoicesTotalPages(response.data.total_pages || 1);
setInvoicesTotalItems(response.data.total || 0);
}
}
} catch (error: any) {
toast.error(error.response?.data?.message || 'Unable to load invoices');
@@ -354,28 +364,28 @@ const BusinessDashboardPage: React.FC = () => {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-slate-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-10 animate-fade-in">
<div className="max-w-7xl mx-auto px-2 sm:px-3 md:px-4 lg:px-6 xl:px-8 py-2 sm:py-4 md:py-6 lg:py-8 space-y-3 sm:space-y-4 md:space-y-6 lg:space-y-8 animate-fade-in">
{}
<div className="relative">
<div className="absolute inset-0 bg-gradient-to-r from-emerald-400/5 via-transparent to-purple-600/5 rounded-3xl blur-3xl"></div>
<div className="relative bg-white/80 backdrop-blur-xl rounded-3xl shadow-2xl border border-emerald-200/30 p-8 md:p-10">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-8">
<div className="flex items-start gap-5">
<div className="relative">
<div className="absolute inset-0 bg-gradient-to-br from-emerald-400 to-purple-600 rounded-2xl blur-lg opacity-50"></div>
<div className="relative p-4 rounded-2xl bg-gradient-to-br from-emerald-500 via-emerald-500 to-purple-600 shadow-xl border border-emerald-400/50">
<FileText className="w-8 h-8 text-white" />
<div className="absolute -top-1 -right-1 w-4 h-4 bg-gradient-to-br from-green-300 to-emerald-500 rounded-full shadow-lg animate-pulse"></div>
<div className="relative bg-white/80 backdrop-blur-xl rounded-xl sm:rounded-2xl md:rounded-3xl shadow-2xl border border-emerald-200/30 p-3 sm:p-4 md:p-6 lg:p-8">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 sm:gap-6 md:gap-8">
<div className="flex items-start gap-3 sm:gap-4 md:gap-5">
<div className="relative flex-shrink-0">
<div className="absolute inset-0 bg-gradient-to-br from-emerald-400 to-purple-600 rounded-xl sm:rounded-2xl blur-lg opacity-50"></div>
<div className="relative p-2.5 sm:p-3 md:p-4 rounded-xl sm:rounded-2xl bg-gradient-to-br from-emerald-500 via-emerald-500 to-purple-600 shadow-xl border border-emerald-400/50">
<FileText className="w-5 h-5 sm:w-6 sm:h-6 md:w-8 md:h-8 text-white" />
<div className="absolute -top-1 -right-1 w-3 h-3 sm:w-4 sm:h-4 bg-gradient-to-br from-green-300 to-emerald-500 rounded-full shadow-lg animate-pulse"></div>
</div>
</div>
<div className="space-y-3 flex-1">
<div className="flex items-center gap-3">
<h1 className="text-4xl md:text-5xl font-extrabold bg-gradient-to-r from-slate-900 via-emerald-700 to-slate-900 bg-clip-text text-transparent">
<div className="space-y-2 sm:space-y-3 flex-1">
<div className="flex items-center gap-2 sm:gap-3 flex-wrap">
<h1 className="text-2xl sm:text-3xl md:text-3xl font-extrabold bg-gradient-to-r from-slate-900 via-emerald-700 to-slate-900 bg-clip-text text-transparent">
Business Dashboard
</h1>
<Sparkles className="w-6 h-6 text-emerald-500 animate-pulse" />
<Sparkles className="w-4 h-4 sm:w-5 sm:h-5 text-emerald-500 animate-pulse" />
</div>
<p className="text-gray-600 text-base md:text-lg max-w-2xl leading-relaxed">
<p className="text-gray-600 text-xs sm:text-sm md:text-sm max-w-2xl leading-relaxed">
Manage invoices, payments, and promotional campaigns
</p>
</div>
@@ -383,36 +393,38 @@ const BusinessDashboardPage: React.FC = () => {
</div>
{}
<div className="mt-10 pt-8 border-t border-gradient-to-r from-transparent via-emerald-200/30 to-transparent">
<div className="flex flex-wrap gap-3">
{tabs.map((tab) => {
const Icon = tab.icon;
const isActive = activeTab === tab.id;
return (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`
group relative flex items-center gap-3 px-6 py-3.5 rounded-xl font-semibold text-sm
transition-all duration-300 overflow-hidden
${
isActive
? 'bg-gradient-to-r from-emerald-500 via-emerald-500 to-purple-600 text-white shadow-xl shadow-emerald-500/40 scale-105'
: 'bg-white/80 text-gray-700 border border-gray-200/60 hover:border-emerald-300/60 hover:bg-gradient-to-r hover:from-emerald-50/50 hover:to-purple-50/30 hover:shadow-lg hover:scale-102'
}
`}
>
{isActive && (
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent animate-shimmer"></div>
)}
<Icon className={`w-5 h-5 transition-transform duration-300 ${isActive ? 'text-white' : 'text-gray-600 group-hover:text-emerald-600 group-hover:scale-110'}`} />
<span className="relative z-10">{tab.label}</span>
{isActive && (
<div className="absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-green-300 via-emerald-400 to-purple-400"></div>
)}
</button>
);
})}
<div className="mt-4 sm:mt-6 md:mt-8 lg:mt-10 pt-4 sm:pt-6 md:pt-8 border-t border-gradient-to-r from-transparent via-emerald-200/30 to-transparent">
<div className="overflow-x-auto -mx-2 sm:-mx-3 px-2 sm:px-3 scrollbar-hide">
<div className="flex gap-2 sm:gap-3 min-w-max sm:min-w-0 sm:flex-wrap">
{tabs.map((tab) => {
const Icon = tab.icon;
const isActive = activeTab === tab.id;
return (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`
group relative flex items-center gap-1.5 sm:gap-2 md:gap-3 px-3 sm:px-4 md:px-6 py-2 sm:py-2.5 md:py-3.5 rounded-lg sm:rounded-xl font-semibold text-xs sm:text-sm flex-shrink-0
transition-all duration-300 overflow-hidden
${
isActive
? 'bg-gradient-to-r from-emerald-500 via-emerald-500 to-purple-600 text-white shadow-xl shadow-emerald-500/40 scale-105'
: 'bg-white/80 text-gray-700 border border-gray-200/60 hover:border-emerald-300/60 hover:bg-gradient-to-r hover:from-emerald-50/50 hover:to-purple-50/30 hover:shadow-lg hover:scale-102'
}
`}
>
{isActive && (
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent animate-shimmer"></div>
)}
<Icon className={`w-3.5 h-3.5 sm:w-4 sm:h-4 md:w-5 md:h-5 transition-transform duration-300 flex-shrink-0 ${isActive ? 'text-white' : 'text-gray-600 group-hover:text-emerald-600 group-hover:scale-110'}`} />
<span className="relative z-10 whitespace-nowrap">{tab.label}</span>
{isActive && (
<div className="absolute bottom-0 left-0 right-0 h-0.5 sm:h-1 bg-gradient-to-r from-green-300 via-emerald-400 to-purple-400"></div>
)}
</button>
);
})}
</div>
</div>
</div>
</div>
@@ -420,7 +432,7 @@ const BusinessDashboardPage: React.FC = () => {
{}
{activeTab === 'overview' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-5 md:gap-6 lg:gap-8">
<div
onClick={() => setActiveTab('invoices')}
className="group relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-blue-100/50 p-8 cursor-pointer transition-all duration-300 hover:shadow-2xl hover:scale-105 hover:border-blue-300/60 overflow-hidden"