diff --git a/public/beenvoice.afdesign b/public/beenvoice.afdesign new file mode 100644 index 0000000..94d7617 Binary files /dev/null and b/public/beenvoice.afdesign differ diff --git a/src/app/dashboard/_components/animated-stats-card.tsx b/src/app/dashboard/_components/animated-stats-card.tsx new file mode 100644 index 0000000..45d97d8 --- /dev/null +++ b/src/app/dashboard/_components/animated-stats-card.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { + TrendingDown, + TrendingUp, + DollarSign, + Clock, + Users, +} from "lucide-react"; +import { Card, CardContent } from "~/components/ui/card"; + +type IconName = "DollarSign" | "Clock" | "Users" | "TrendingDown"; + +interface AnimatedStatsCardProps { + title: string; + value: string; + change: string; + trend: "up" | "down"; + iconName: IconName; + description: string; + delay?: number; + isCurrency?: boolean; + numericValue?: number; +} + +const iconMap = { + DollarSign, + Clock, + Users, + TrendingDown, +} as const; + +export function AnimatedStatsCard({ + title, + value, + change, + trend, + iconName, + description, + delay = 0, + isCurrency = false, + numericValue, +}: AnimatedStatsCardProps) { + const Icon = iconMap[iconName]; + const TrendIcon = trend === "up" ? TrendingUp : TrendingDown; + const isPositive = trend === "up"; + + // For now, always use the formatted value prop to ensure correct display + // Animation can be added back once the basic display is working correctly + const displayValue = value; + + // Suppress unused parameter warnings for now + void delay; + void isCurrency; + void numericValue; + + return ( + + +
+
+ +

{title}

+
+
+ + {change} +
+
+
+

{displayValue}

+

{description}

+
+
+
+ ); +} diff --git a/src/app/dashboard/businesses/page.tsx b/src/app/dashboard/businesses/page.tsx index 77cffa8..cfac894 100644 --- a/src/app/dashboard/businesses/page.tsx +++ b/src/app/dashboard/businesses/page.tsx @@ -16,13 +16,13 @@ async function BusinessesTable() { export default async function BusinessesPage() { return ( - <> +
-
); } diff --git a/src/app/dashboard/clients/page.tsx b/src/app/dashboard/clients/page.tsx index f61337c..a846349 100644 --- a/src/app/dashboard/clients/page.tsx +++ b/src/app/dashboard/clients/page.tsx @@ -7,13 +7,13 @@ import { ClientsTable } from "./_components/clients-table"; export default async function ClientsPage() { return ( - <> +
-
); } diff --git a/src/app/dashboard/invoices/[id]/page.tsx b/src/app/dashboard/invoices/[id]/page.tsx index 0ebcdfb..ab903e0 100644 --- a/src/app/dashboard/invoices/[id]/page.tsx +++ b/src/app/dashboard/invoices/[id]/page.tsx @@ -123,14 +123,18 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) { }; return ( -
+
- - -
); } diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index b32a175..db81690 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -3,14 +3,10 @@ import { ArrowUpRight, BarChart3, Calendar, - Clock, - DollarSign, Edit, Eye, FileText, Plus, - TrendingDown, - TrendingUp, Users, } from "lucide-react"; import Link from "next/link"; @@ -26,6 +22,7 @@ import type { StoredInvoiceStatus } from "~/types/invoice"; import { RevenueChart } from "~/app/dashboard/_components/revenue-chart"; import { InvoiceStatusChart } from "~/app/dashboard/_components/invoice-status-chart"; import { MonthlyMetricsChart } from "~/app/dashboard/_components/monthly-metrics-chart"; +import { AnimatedStatsCard } from "~/app/dashboard/_components/animated-stats-card"; // Hero section with clean mono design function DashboardHero({ firstName }: { firstName: string }) { @@ -160,80 +157,79 @@ async function DashboardStats() { return value > 0 ? `+${value.toFixed(1)}%` : `${value.toFixed(1)}%`; }; + // Debug logging to see actual values + console.log("Dashboard Stats Debug:", { + totalRevenue, + pendingAmount, + totalClients, + overdueInvoices: overdueInvoices.length, + revenueChange, + pendingChange, + clientChange, + overdueChange, + paidInvoicesCount: paidInvoices.length, + pendingInvoicesCount: pendingInvoices.length, + }); + const stats = [ { title: "Total Revenue", value: `$${totalRevenue.toLocaleString("en-US", { minimumFractionDigits: 2 })}`, + numericValue: totalRevenue, + isCurrency: true, change: formatTrend(revenueChange), trend: revenueChange >= 0 ? ("up" as const) : ("down" as const), - icon: DollarSign, + iconName: "DollarSign" as const, description: `From ${paidInvoices.length} paid invoices`, }, { title: "Pending Amount", value: `$${pendingAmount.toLocaleString("en-US", { minimumFractionDigits: 2 })}`, + numericValue: pendingAmount, + isCurrency: true, change: formatTrend(pendingChange), trend: pendingChange >= 0 ? ("up" as const) : ("down" as const), - icon: Clock, + iconName: "Clock" as const, description: `${pendingInvoices.length} invoices awaiting payment`, }, { title: "Active Clients", value: totalClients.toString(), + numericValue: totalClients, + isCurrency: false, change: formatTrend(clientChange, true), trend: clientChange >= 0 ? ("up" as const) : ("down" as const), - icon: Users, + iconName: "Users" as const, description: "Total registered clients", }, { title: "Overdue Invoices", value: overdueInvoices.length.toString(), + numericValue: overdueInvoices.length, + isCurrency: false, change: formatTrend(overdueChange, true), trend: overdueChange <= 0 ? ("up" as const) : ("down" as const), - icon: TrendingDown, + iconName: "TrendingDown" as const, description: "Invoices past due date", }, ]; return (
- {stats.map((stat) => { - const Icon = stat.icon; - const TrendIcon = stat.trend === "up" ? TrendingUp : TrendingDown; - const isPositive = stat.trend === "up"; - - return ( - - -
-
- -

- {stat.title} -

-
-
- - {stat.change} -
-
-
-

{stat.value}

-

- {stat.description} -

-
-
-
- ); - })} + {stats.map((stat, index) => ( + + ))}
); } @@ -327,7 +323,7 @@ function QuickActions() {
- -
) : (
- {recentInvoices.map((invoice) => ( + {recentInvoices.map((invoice, _index) => ( -
+
@@ -627,7 +628,7 @@ export default async function DashboardPage() { const firstName = session?.user?.name?.split(" ")[0] ?? "User"; return ( -
+
diff --git a/src/app/dashboard/settings/_components/settings-content.tsx b/src/app/dashboard/settings/_components/settings-content.tsx index 1071c0a..a8eaf8a 100644 --- a/src/app/dashboard/settings/_components/settings-content.tsx +++ b/src/app/dashboard/settings/_components/settings-content.tsx @@ -1,26 +1,38 @@ "use client"; -import { useState } from "react"; -import * as React from "react"; -import { useSession } from "next-auth/react"; import { + AlertTriangle, + Building, + ChevronDown, + Database, Download, + Eye, + EyeOff, + FileText, + FileUp, + Info, + Key, + Shield, Upload, User, - Database, - AlertTriangle, - Shield, - FileText, Users, - Building, - Key, - Eye, - FileUp, - ChevronDown, - Info, } from "lucide-react"; +import { useSession } from "next-auth/react"; +import * as React from "react"; +import { useState } from "react"; -import { api } from "~/trpc/react"; +import { toast } from "sonner"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "~/components/ui/alert-dialog"; import { Button } from "~/components/ui/button"; import { Card, @@ -34,22 +46,6 @@ import { CollapsibleContent, CollapsibleTrigger, } from "~/components/ui/collapsible"; -import { Input } from "~/components/ui/input"; -import { Label } from "~/components/ui/label"; -import { Textarea } from "~/components/ui/textarea"; -import { Badge } from "~/components/ui/badge"; -import { toast } from "sonner"; -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, -} from "~/components/ui/alert-dialog"; import { Dialog, DialogContent, @@ -59,6 +55,10 @@ import { DialogTitle, DialogTrigger, } from "~/components/ui/dialog"; +import { Input } from "~/components/ui/input"; +import { Label } from "~/components/ui/label"; +import { Textarea } from "~/components/ui/textarea"; +import { api } from "~/trpc/react"; export function SettingsContent() { const { data: session } = useSession(); @@ -300,7 +300,7 @@ export function SettingsContent() { {/* Profile & Account Overview */}
{/* Profile Section */} - + @@ -337,6 +337,7 @@ export function SettingsContent() { type="submit" disabled={updateProfileMutation.isPending} variant="default" + className="hover-lift" > {updateProfileMutation.isPending ? "Updating..." @@ -347,7 +348,7 @@ export function SettingsContent() { {/* Data Overview */} - + @@ -359,12 +360,13 @@ export function SettingsContent() {
- {dataStatItems.map((item) => { + {dataStatItems.map((item, index) => { const Icon = item.icon; return (
diff --git a/src/app/dashboard/settings/page.tsx b/src/app/dashboard/settings/page.tsx index 4308288..6540398 100644 --- a/src/app/dashboard/settings/page.tsx +++ b/src/app/dashboard/settings/page.tsx @@ -6,7 +6,7 @@ import { SettingsContent } from "./_components/settings-content"; export default async function SettingsPage() { return ( - <> +
- +
); } diff --git a/src/components/data/data-table.tsx b/src/components/data/data-table.tsx index 0abfd77..a655e72 100644 --- a/src/components/data/data-table.tsx +++ b/src/components/data/data-table.tsx @@ -361,7 +361,7 @@ export function DataTable({ key={row.id} data-state={row.getIsSelected() && "selected"} className={cn( - "hover:bg-muted/20 data-[state=selected]:bg-muted/50 border-border/40 border-b transition-colors", + "hover:bg-muted/20 data-[state=selected]:bg-muted/50 border-border/40 table-row border-b transition-colors", onRowClick && "cursor-pointer", )} onClick={(event) => diff --git a/src/components/data/status-badge.tsx b/src/components/data/status-badge.tsx index 3b16c64..d3ded76 100644 --- a/src/components/data/status-badge.tsx +++ b/src/components/data/status-badge.tsx @@ -51,7 +51,15 @@ export function StatusBadge({ const label = children ?? statusLabelMap[status]; return ( - + {label} ); diff --git a/src/components/forms/invoice-form.tsx b/src/components/forms/invoice-form.tsx index 2c6561e..0e491f5 100644 --- a/src/components/forms/invoice-form.tsx +++ b/src/components/forms/invoice-form.tsx @@ -493,7 +493,7 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) { return ( <> -
+
Delete Invoice )} -