303 lines
12 KiB
TypeScript
303 lines
12 KiB
TypeScript
"use client";
|
|
|
|
import { useParams, usePathname } from "next/navigation";
|
|
import {
|
|
DollarSign,
|
|
Receipt,
|
|
CreditCard,
|
|
TrendingUp,
|
|
Plus,
|
|
Calendar,
|
|
} from "lucide-react";
|
|
import {
|
|
PageTemplate,
|
|
PageSection,
|
|
PageCard,
|
|
PageGrid,
|
|
} from "@/components/layout/page-template";
|
|
import { Button } from "@/components/ui/button";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const MONEY_NAV_ITEMS = [
|
|
{ title: "Expenses", icon: Receipt, href: "/money" },
|
|
{ title: "Costs", icon: TrendingUp, href: "/money#costs" },
|
|
{ title: "Pricing", icon: DollarSign, href: "/money#pricing" },
|
|
{ title: "Plans", icon: CreditCard, href: "/money#plans" },
|
|
];
|
|
|
|
const SAMPLE_EXPENSES = [
|
|
{ id: 1, name: "Logo Design", amount: 299, date: "2025-01-15", category: "Design" },
|
|
{ id: 2, name: "Domain Registration", amount: 12, date: "2025-01-10", category: "Infrastructure" },
|
|
{ id: 3, name: "SSL Certificate", amount: 69, date: "2025-01-08", category: "Infrastructure" },
|
|
];
|
|
|
|
const SAMPLE_COSTS = [
|
|
{ id: 1, name: "Vercel Hosting", amount: 20, frequency: "monthly", category: "Infrastructure" },
|
|
{ id: 2, name: "OpenAI API", amount: 45, frequency: "monthly", category: "Services" },
|
|
{ id: 3, name: "SendGrid Email", amount: 15, frequency: "monthly", category: "Services" },
|
|
{ id: 4, name: "Stripe Fees", amount: 0, frequency: "per transaction", category: "Services" },
|
|
];
|
|
|
|
export default function MoneyPage() {
|
|
const params = useParams();
|
|
const pathname = usePathname();
|
|
const workspace = params.workspace as string;
|
|
const projectId = params.projectId as string;
|
|
|
|
const sidebarItems = MONEY_NAV_ITEMS.map((item) => {
|
|
const fullHref = `/${workspace}/project/${projectId}${item.href}`;
|
|
return {
|
|
...item,
|
|
href: fullHref,
|
|
isActive: pathname === fullHref || pathname.startsWith(fullHref),
|
|
};
|
|
});
|
|
|
|
const totalExpenses = SAMPLE_EXPENSES.reduce((sum, e) => sum + e.amount, 0);
|
|
const monthlyCosts = SAMPLE_COSTS.filter(c => c.frequency === "monthly").reduce((sum, c) => sum + c.amount, 0);
|
|
const annualCosts = monthlyCosts * 12;
|
|
|
|
return (
|
|
<PageTemplate
|
|
sidebar={{
|
|
items: sidebarItems,
|
|
}}
|
|
>
|
|
{/* Financial Overview */}
|
|
<PageSection>
|
|
<PageGrid cols={4}>
|
|
<PageCard>
|
|
<div className="text-center">
|
|
<div className="h-10 w-10 rounded-lg bg-muted mx-auto mb-2 flex items-center justify-center">
|
|
<Receipt className="h-5 w-5 text-muted-foreground" />
|
|
</div>
|
|
<p className="text-3xl font-bold">${totalExpenses}</p>
|
|
<p className="text-sm text-muted-foreground">Total Expenses</p>
|
|
<p className="text-xs text-muted-foreground mt-1">One-time</p>
|
|
</div>
|
|
</PageCard>
|
|
<PageCard>
|
|
<div className="text-center">
|
|
<div className="h-10 w-10 rounded-lg bg-muted mx-auto mb-2 flex items-center justify-center">
|
|
<TrendingUp className="h-5 w-5 text-muted-foreground" />
|
|
</div>
|
|
<p className="text-3xl font-bold">${monthlyCosts}</p>
|
|
<p className="text-sm text-muted-foreground">Monthly Costs</p>
|
|
<p className="text-xs text-muted-foreground mt-1">Recurring</p>
|
|
</div>
|
|
</PageCard>
|
|
<PageCard>
|
|
<div className="text-center">
|
|
<div className="h-10 w-10 rounded-lg bg-muted mx-auto mb-2 flex items-center justify-center">
|
|
<Calendar className="h-5 w-5 text-muted-foreground" />
|
|
</div>
|
|
<p className="text-3xl font-bold">${annualCosts}</p>
|
|
<p className="text-sm text-muted-foreground">Annual Costs</p>
|
|
<p className="text-xs text-muted-foreground mt-1">Projected</p>
|
|
</div>
|
|
</PageCard>
|
|
<PageCard>
|
|
<div className="text-center">
|
|
<div className="h-10 w-10 rounded-lg bg-muted mx-auto mb-2 flex items-center justify-center">
|
|
<DollarSign className="h-5 w-5 text-muted-foreground" />
|
|
</div>
|
|
<p className="text-3xl font-bold">$0</p>
|
|
<p className="text-sm text-muted-foreground">Revenue</p>
|
|
<p className="text-xs text-muted-foreground mt-1">Not launched</p>
|
|
</div>
|
|
</PageCard>
|
|
</PageGrid>
|
|
</PageSection>
|
|
|
|
{/* Expenses (One-time) */}
|
|
<PageSection
|
|
title="Expenses"
|
|
description="One-time costs"
|
|
headerAction={
|
|
<Button size="sm" variant="ghost">
|
|
<Plus className="h-4 w-4 mr-2" />
|
|
Add Expense
|
|
</Button>
|
|
}
|
|
>
|
|
<PageCard>
|
|
<div className="space-y-2">
|
|
{SAMPLE_EXPENSES.map((expense) => (
|
|
<div
|
|
key={expense.id}
|
|
className="flex items-center gap-3 p-3 rounded-lg bg-muted/50"
|
|
>
|
|
<div className="h-8 w-8 rounded-lg bg-muted flex items-center justify-center shrink-0">
|
|
<Receipt className="h-4 w-4 text-muted-foreground" />
|
|
</div>
|
|
<div className="flex-1">
|
|
<p className="font-medium">{expense.name}</p>
|
|
<p className="text-xs text-muted-foreground">{expense.date}</p>
|
|
</div>
|
|
<div>
|
|
<span className="text-xs px-2 py-1 rounded-full bg-muted font-medium">
|
|
{expense.category}
|
|
</span>
|
|
</div>
|
|
<div className="text-right">
|
|
<p className="font-semibold">${expense.amount}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</PageCard>
|
|
</PageSection>
|
|
|
|
{/* Costs (Recurring) */}
|
|
<PageSection
|
|
title="Costs"
|
|
description="Recurring/ongoing expenses"
|
|
headerAction={
|
|
<Button size="sm" variant="ghost">
|
|
<Plus className="h-4 w-4 mr-2" />
|
|
Add Cost
|
|
</Button>
|
|
}
|
|
>
|
|
<PageCard>
|
|
<div className="space-y-2">
|
|
{SAMPLE_COSTS.map((cost) => (
|
|
<div
|
|
key={cost.id}
|
|
className="flex items-center gap-3 p-3 rounded-lg bg-muted/50"
|
|
>
|
|
<div className="h-8 w-8 rounded-lg bg-muted flex items-center justify-center shrink-0">
|
|
<TrendingUp className="h-4 w-4 text-muted-foreground" />
|
|
</div>
|
|
<div className="flex-1">
|
|
<p className="font-medium">{cost.name}</p>
|
|
<p className="text-xs text-muted-foreground capitalize">{cost.frequency}</p>
|
|
</div>
|
|
<div>
|
|
<span className="text-xs px-2 py-1 rounded-full bg-muted font-medium">
|
|
{cost.category}
|
|
</span>
|
|
</div>
|
|
<div className="text-right">
|
|
<p className="font-semibold">
|
|
{cost.amount === 0 ? "Variable" : `$${cost.amount}`}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</PageCard>
|
|
</PageSection>
|
|
|
|
{/* Pricing Strategy */}
|
|
<PageSection
|
|
title="Pricing"
|
|
description="Your product pricing strategy"
|
|
>
|
|
<PageCard>
|
|
<div className="text-center py-8 text-muted-foreground">
|
|
<DollarSign className="h-12 w-12 mx-auto mb-3 opacity-50" />
|
|
<p className="text-sm mb-4">
|
|
Define your pricing tiers and revenue model
|
|
</p>
|
|
<Button size="sm">
|
|
<Plus className="h-4 w-4 mr-2" />
|
|
Create Pricing Plan
|
|
</Button>
|
|
</div>
|
|
</PageCard>
|
|
</PageSection>
|
|
|
|
{/* Plans (Revenue Tiers) */}
|
|
<PageSection
|
|
title="Plans"
|
|
description="Subscription tiers and offerings"
|
|
>
|
|
<PageGrid cols={3}>
|
|
<PageCard>
|
|
<div className="text-center">
|
|
<h3 className="font-semibold text-lg mb-2">Free</h3>
|
|
<p className="text-3xl font-bold mb-1">$0</p>
|
|
<p className="text-xs text-muted-foreground mb-4">per month</p>
|
|
<ul className="text-sm space-y-2 text-left mb-6">
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>Basic features</span>
|
|
</li>
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>Community support</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</PageCard>
|
|
|
|
<PageCard className="border-primary">
|
|
<div className="text-center">
|
|
<div className="inline-block px-2 py-1 rounded-full bg-primary/10 text-primary text-xs font-medium mb-2">
|
|
Popular
|
|
</div>
|
|
<h3 className="font-semibold text-lg mb-2">Pro</h3>
|
|
<p className="text-3xl font-bold mb-1">$29</p>
|
|
<p className="text-xs text-muted-foreground mb-4">per month</p>
|
|
<ul className="text-sm space-y-2 text-left mb-6">
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>All features</span>
|
|
</li>
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>Priority support</span>
|
|
</li>
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>API access</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</PageCard>
|
|
|
|
<PageCard>
|
|
<div className="text-center">
|
|
<h3 className="font-semibold text-lg mb-2">Enterprise</h3>
|
|
<p className="text-3xl font-bold mb-1">Custom</p>
|
|
<p className="text-xs text-muted-foreground mb-4">contact us</p>
|
|
<ul className="text-sm space-y-2 text-left mb-6">
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>Unlimited everything</span>
|
|
</li>
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>Dedicated support</span>
|
|
</li>
|
|
<li className="flex items-center gap-2">
|
|
<div className="h-4 w-4 rounded-full bg-green-500/10 flex items-center justify-center">
|
|
<div className="h-1.5 w-1.5 rounded-full bg-green-600" />
|
|
</div>
|
|
<span>Custom integrations</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</PageCard>
|
|
</PageGrid>
|
|
</PageSection>
|
|
</PageTemplate>
|
|
);
|
|
}
|
|
|