feat: add more colors to cards

This commit is contained in:
Vasily Zubarev
2025-07-23 11:07:51 +02:00
parent 8897134901
commit 9305deda86
7 changed files with 404 additions and 287 deletions

View File

@@ -11,8 +11,8 @@ import { getFilesByTransactionId } from "@/models/files"
import { getProjects } from "@/models/projects" import { getProjects } from "@/models/projects"
import { getSettings } from "@/models/settings" import { getSettings } from "@/models/settings"
import { getTransactionById } from "@/models/transactions" import { getTransactionById } from "@/models/transactions"
import { notFound } from "next/navigation"
import Link from "next/link" import Link from "next/link"
import { notFound } from "next/navigation"
export default async function TransactionPage({ params }: { params: Promise<{ transactionId: string }> }) { export default async function TransactionPage({ params }: { params: Promise<{ transactionId: string }> }) {
const { transactionId } = await params const { transactionId } = await params
@@ -32,7 +32,7 @@ export default async function TransactionPage({ params }: { params: Promise<{ tr
return ( return (
<div className="flex flex-wrap flex-row items-start justify-center gap-4 max-w-6xl"> <div className="flex flex-wrap flex-row items-start justify-center gap-4 max-w-6xl">
<Card className="w-full flex-1 flex flex-col flex-wrap justify-center items-start overflow-hidden"> <Card className="w-full flex-1 flex flex-col flex-wrap justify-center items-start overflow-hidden bg-gradient-to-br from-violet-50/80 via-indigo-50/80 to-white border-violet-200/60">
{incompleteFields.length > 0 && ( {incompleteFields.length > 0 && (
<div className="w-full flex flex-col gap-1 rounded-md bg-yellow-50 p-5"> <div className="w-full flex flex-col gap-1 rounded-md bg-yellow-50 p-5">
<span> <span>
@@ -47,7 +47,7 @@ export default async function TransactionPage({ params }: { params: Promise<{ tr
</span> </span>
</div> </div>
)} )}
<div className="w-full p-5 bg-accent"> <div className="w-full p-5">
<TransactionEditForm <TransactionEditForm
transaction={transaction} transaction={transaction}
categories={categories} categories={categories}

View File

@@ -38,7 +38,10 @@ export default async function UnsortedPage() {
{files.length > 1 && <AnalyzeAllButton />} {files.length > 1 && <AnalyzeAllButton />}
</header> </header>
{config.selfHosted.isEnabled && !settings.openai_api_key && !settings.google_api_key && !settings.mistral_api_key && ( {config.selfHosted.isEnabled &&
!settings.openai_api_key &&
!settings.google_api_key &&
!settings.mistral_api_key && (
<Alert> <Alert>
<Settings className="h-4 w-4 mt-2" /> <Settings className="h-4 w-4 mt-2" />
<div className="flex flex-row justify-between pt-2"> <div className="flex flex-row justify-between pt-2">
@@ -60,7 +63,7 @@ export default async function UnsortedPage() {
<Card <Card
key={file.id} key={file.id}
id={file.id} id={file.id}
className="flex flex-row flex-wrap md:flex-nowrap justify-center items-start gap-5 p-5 bg-accent" className="flex flex-row flex-wrap md:flex-nowrap justify-center items-start gap-5 p-5 bg-gradient-to-br from-violet-50/80 via-indigo-50/80 to-white border-violet-200/60 rounded-2xl"
> >
<div className="w-full max-w-[500px]"> <div className="w-full max-w-[500px]">
<Card> <Card>

View File

@@ -6,23 +6,32 @@ import Link from "next/link"
export default function LandingPage() { export default function LandingPage() {
return ( return (
<div className="min-h-screen flex flex-col bg-[#FAFAFA]"> <div className="min-h-screen flex flex-col bg-gradient-to-br from-pink-50 via-purple-50 to-indigo-50">
<header className="py-6 px-4 md:px-8 bg-white/80 backdrop-blur-md shadow-sm fixed w-full z-10"> <header className="py-6 px-4 md:px-8 bg-white/90 backdrop-blur-xl shadow-lg border-b border-gradient-to-r from-pink-200 to-indigo-200 fixed w-full z-50">
<div className="max-w-7xl mx-auto flex justify-between items-center"> <div className="max-w-7xl mx-auto flex justify-between items-center">
<Link href="/" className="flex items-center gap-2"> <Link href="/" className="flex items-center gap-2 group">
<Image src="/logo/256.png" alt="Logo" width={32} height={32} className="h-8" /> <div className="relative">
<Image
src="/logo/256.png"
alt="Logo"
width={32}
height={32}
className="h-8 group-hover:scale-110 transition-transform duration-300"
/>
<div className="absolute inset-0 bg-gradient-to-r from-pink-600 to-indigo-600 rounded-full opacity-20 blur-md group-hover:opacity-40 transition-opacity duration-300" />
</div>
<ColoredText className="text-2xl font-bold">TaxHacker</ColoredText> <ColoredText className="text-2xl font-bold">TaxHacker</ColoredText>
</Link> </Link>
<div className="flex gap-1 md:gap-4 text-xs md:text-sm"> <div className="flex gap-1 md:gap-4 text-xs md:text-sm">
<Link <Link
href="/enter" href="/enter"
className="font-medium px-4 py-2 rounded-full border border-gray-200 hover:bg-gray-50 transition-all" className="font-medium px-4 py-2 rounded-full border-2 border-gradient-to-r from-pink-300 to-indigo-300 hover:from-pink-400 hover:to-indigo-400 bg-white/80 hover:bg-white transition-all duration-300 hover:scale-105"
> >
Log In Log In
</Link> </Link>
<Link <Link
href="/cloud" href="/cloud"
className="font-medium bg-gradient-to-r from-blue-600 to-indigo-600 text-white px-4 py-2 rounded-full hover:opacity-90 transition-all" className="font-medium bg-gradient-to-r from-pink-600 to-indigo-600 text-white px-4 py-2 rounded-full hover:from-pink-700 hover:to-indigo-700 transition-all duration-300 hover:scale-105 shadow-lg hover:shadow-xl"
> >
Sign Up Sign Up
</Link> </Link>
@@ -31,35 +40,40 @@ export default function LandingPage() {
</header> </header>
{/* Hero Section */} {/* Hero Section */}
<section className="pt-32 pb-16 px-8"> <section className="pt-32 pb-16 px-8 relative overflow-hidden">
<div className="max-w-7xl mx-auto"> {/* Background decoration */}
<div className="absolute inset-0 bg-gradient-to-br from-pink-100/50 via-purple-100/30 to-indigo-100/50" />
<div className="absolute top-20 left-10 w-72 h-72 bg-gradient-to-r from-pink-400 to-indigo-400 rounded-full opacity-10 blur-3xl animate-pulse" />
<div className="absolute bottom-20 right-10 w-96 h-96 bg-gradient-to-r from-indigo-400 to-pink-400 rounded-full opacity-10 blur-3xl animate-pulse" />
<div className="max-w-7xl mx-auto relative z-10">
<div className="text-center mb-12"> <div className="text-center mb-12">
<div className="inline-block px-4 py-2 rounded-full bg-purple-50 text-purple-600 text-sm font-medium mb-6"> <div className="inline-block px-6 py-3 rounded-full bg-gradient-to-r from-pink-600 to-indigo-600 text-white text-sm font-medium mb-6 shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105">
🚀 Under Active Development 🚀 Under Active Development
</div> </div>
<h1 className="text-5xl font-bold tracking-tight sm:text-6xl mb-6 bg-gradient-to-r from-gray-900 to-gray-600 bg-clip-text text-transparent pb-2"> <h1 className="text-5xl font-bold tracking-tight sm:text-6xl mb-6 bg-gradient-to-r from-gray-900 via-pink-700 to-indigo-700 bg-clip-text text-transparent pb-2">
Let AI finally care about your taxes, scan your receipts and analyze your expenses Let AI finally care about your taxes, scan your receipts and analyze your expenses
</h1> </h1>
<p className="text-xl text-gray-600 mb-8 max-w-2xl mx-auto"> <p className="text-xl text-gray-700 mb-8 max-w-2xl mx-auto font-medium">
A self-hosted accounting app crafted with love for freelancers and small businesses A self-hosted accounting app crafted with love for freelancers and small businesses
</p> </p>
<div className="flex gap-4 justify-center text-sm md:text-lg"> <div className="flex gap-4 justify-center text-sm md:text-lg">
<Link <Link
href="#start" href="#start"
className="px-8 py-3 bg-gradient-to-r from-blue-600 to-indigo-600 text-white font-medium rounded-full hover:opacity-90 transition-all shadow-lg shadow-blue-500/20" className="px-8 py-4 bg-gradient-to-r from-pink-600 to-indigo-600 text-white font-bold rounded-full hover:from-pink-700 hover:to-indigo-700 transition-all duration-300 shadow-xl hover:shadow-2xl hover:scale-110 border-2 border-white/20"
> >
Get Started Get Started
</Link> </Link>
<Link <Link
href="mailto:me@vas3k.ru" href="mailto:me@vas3k.ru"
className="px-8 py-3 border border-gray-200 text-gray-700 font-medium rounded-full hover:bg-gray-50 transition-all" className="px-8 py-4 border-2 border-gradient-to-r from-pink-300 to-indigo-300 text-gray-800 font-bold rounded-full hover:bg-gradient-to-r hover:from-pink-50 hover:to-indigo-50 transition-all duration-300 hover:scale-105 bg-white/80"
> >
Contact Us Contact Us 💌
</Link> </Link>
</div> </div>
</div> </div>
<div className="relative aspect-auto rounded-2xl overflow-hidden shadow-2xl ring-8 ring-gray-100 hover:scale-105 transition-all duration-300"> <div className="relative aspect-auto rounded-3xl overflow-hidden shadow-2xl ring-4 ring-gradient-to-r from-pink-200 to-indigo-200 hover:scale-105 transition-all duration-500 group">
<div className="absolute inset-0 bg-gradient-to-b from-blue-500/5 to-transparent z-10" /> <div className="absolute inset-0 bg-gradient-to-b from-pink-500/10 via-purple-500/10 to-indigo-500/10 z-10 group-hover:from-pink-500/20 group-hover:to-indigo-500/20 transition-all duration-500" />
<video className="w-full h-auto" autoPlay loop muted playsInline poster="/landing/title.webp"> <video className="w-full h-auto" autoPlay loop muted playsInline poster="/landing/title.webp">
<source src="/landing/video.mp4" type="video/mp4" /> <source src="/landing/video.mp4" type="video/mp4" />
<Image src="/landing/title.webp" alt="TaxHacker" width={1980} height={1224} priority /> <Image src="/landing/title.webp" alt="TaxHacker" width={1980} height={1224} priority />
@@ -69,133 +83,179 @@ export default function LandingPage() {
</section> </section>
{/* Features Section */} {/* Features Section */}
<section className="py-20 px-8"> <section className="py-20 px-8 relative">
<div className="max-w-7xl mx-auto"> <div className="absolute inset-0 bg-gradient-to-b from-white/50 to-indigo-50/50" />
<div className="max-w-7xl mx-auto relative z-10">
<div className="text-center mb-16"> <div className="text-center mb-16">
<h2 className="flex flex-col gap-3 mb-4 bg-gradient-to-r from-gray-900 to-gray-600 bg-clip-text text-transparent"> <h2 className="flex flex-col gap-3 mb-4">
<span className="text-6xl font-semibold text-muted-foreground">Fck Taxes</span> <span className="text-6xl font-bold bg-gradient-to-r from-pink-600 to-indigo-600 bg-clip-text text-transparent">
<span className="text-4xl font-bold">TaxHacker can save you time, money and nerves</span> Fck Taxes
</span>
<span className="text-4xl font-bold bg-gradient-to-r from-gray-900 to-gray-600 bg-clip-text text-transparent">
TaxHacker can save you time, money and nerves
</span>
</h2> </h2>
</div> </div>
{/* AI Scanner Feature */} {/* AI Scanner Feature */}
<div className="flex flex-wrap items-center gap-12 mb-20 bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100"> <div className="flex flex-wrap items-center gap-12 mb-20 bg-gradient-to-br from-white via-pink-50/30 to-indigo-50/30 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-pink-200 to-indigo-200 hover:shadow-2xl transition-all duration-500 group">
<div className="flex-1 min-w-60"> <div className="flex-1 min-w-60">
<div className="inline-block px-3 py-1 rounded-full bg-blue-50 text-blue-600 text-sm font-medium mb-4"> <div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-blue-500 to-indigo-600 text-white text-sm font-bold mb-4 shadow-lg">
LLM-Powered 🤖 LLM-Powered
</div> </div>
<h3 className="text-2xl font-semibold mb-4">Analyze photos and invoices with AI</h3> <h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-blue-700 to-indigo-700 bg-clip-text text-transparent">
<ul className="space-y-3 text-gray-600"> Analyze photos and invoices with AI
</h3>
<ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-blue-600 mr-3 text-lg"></span>
Upload your receipts or invoices in PDF for automatic recognition Upload your receipts or invoices in PDF for automatic recognition
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-blue-600 mr-3 text-lg"></span>
Extract key information like dates, amounts, and vendors Extract key information like dates, amounts, and vendors
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-blue-600 mr-3 text-lg"></span>
Works with any language, format and photo quality Works with any language, format and photo quality
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-blue-600 mr-3 text-lg"></span>
Automatically organize everything into a structured database Automatically organize everything into a structured database
</li> </li>
</ul> </ul>
</div> </div>
<div className="flex-1 relative aspect-auto rounded-2xl overflow-hidden shadow-2xl ring-8 ring-gray-100 hover:scale-105 transition-all duration-300"> <div className="flex-1 relative aspect-auto rounded-3xl overflow-hidden shadow-2xl ring-4 ring-gradient-to-r from-blue-200 to-indigo-200 hover:scale-105 transition-all duration-500">
<Image src="/landing/ai-scanner.webp" alt="AI Document Analyzer" width={1900} height={1524} /> <Image src="/landing/ai-scanner.webp" alt="AI Document Analyzer" width={1900} height={1524} />
</div> </div>
</div> </div>
{/* Multi-currency Feature */} {/* Multi-currency Feature */}
<div className="flex flex-wrap items-center gap-12 mb-20 bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100 flex-row-reverse"> <div className="flex flex-wrap items-center gap-12 mb-20 bg-gradient-to-br from-white via-green-50/30 to-emerald-50/30 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-green-200 to-emerald-200 hover:shadow-2xl transition-all duration-500 group flex-row-reverse">
<div className="flex-1 min-w-60"> <div className="flex-1 min-w-60">
<div className="inline-block px-3 py-1 rounded-full bg-green-50 text-green-600 text-sm font-medium mb-4"> <div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-green-500 to-emerald-600 text-white text-sm font-bold mb-4 shadow-lg">
Currency Converter 💱 Currency Converter
</div> </div>
<h3 className="text-2xl font-semibold mb-4">Automatically convert currencies</h3> <h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-green-700 to-emerald-700 bg-clip-text text-transparent">
<ul className="space-y-3 text-gray-600"> Automatically convert currencies
</h3>
<ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-green-600 mr-3 text-lg">💰</span>
Detects foreign currencies and coverts it to yours Detects foreign currencies and coverts it to yours
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-green-600 mr-3 text-lg">💰</span>
Historical exchange rate lookup on a date of transaction Historical exchange rate lookup on a date of transaction
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-green-600 mr-3 text-lg">💰</span>
Support for 170+ world currencies Support for 170+ world currencies
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-green-600 mr-3 text-lg">💰</span>
Even works with cryptocurrencies (BTC, ETH, LTC, etc.) Even works with cryptocurrencies (BTC, ETH, LTC, etc.)
</li> </li>
</ul> </ul>
</div> </div>
<div className="flex-1 relative aspect-auto rounded-2xl overflow-hidden shadow-2xl ring-8 ring-gray-100 hover:scale-105 transition-all duration-300"> <div className="flex-1 relative aspect-auto rounded-3xl overflow-hidden shadow-2xl ring-4 ring-gradient-to-r from-green-200 to-emerald-200 hover:scale-105 transition-all duration-500">
<Image src="/landing/multi-currency.webp" alt="Currency Converter" width={1400} height={1005} /> <Image src="/landing/multi-currency.webp" alt="Currency Converter" width={1400} height={1005} />
</div> </div>
</div> </div>
{/* Transaction Table Feature */} {/* Transaction Table Feature */}
<div className="flex flex-wrap items-center gap-12 mb-20 bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100 flex-row-reverse"> <div className="flex flex-wrap items-center gap-12 mb-20 bg-gradient-to-br from-white via-pink-50/30 to-rose-50/30 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-pink-200 to-rose-200 hover:shadow-2xl transition-all duration-500 group flex-row-reverse">
<div className="flex-1 relative aspect-auto rounded-2xl overflow-hidden shadow-2xl ring-8 ring-gray-100 hover:scale-105 transition-all duration-300"> <div className="flex-1 relative aspect-auto rounded-3xl overflow-hidden shadow-2xl ring-4 ring-gradient-to-r from-pink-200 to-rose-200 hover:scale-105 transition-all duration-500">
<Image src="/landing/transactions.webp" alt="Transactions Table" width={2000} height={1279} /> <Image src="/landing/transactions.webp" alt="Transactions Table" width={2000} height={1279} />
</div> </div>
<div className="flex-1 min-w-60"> <div className="flex-1 min-w-60">
<div className="inline-block px-3 py-1 rounded-full bg-pink-50 text-pink-600 text-sm font-medium mb-4"> <div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-pink-500 to-rose-600 text-white text-sm font-bold mb-4 shadow-lg">
Filters 🔍 Filters
</div> </div>
<h3 className="text-2xl font-semibold mb-4">Organize expenses and income</h3> <h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-pink-700 to-rose-700 bg-clip-text text-transparent">
<ul className="space-y-3 text-gray-600"> Organize expenses and income
</h3>
<ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-pink-600 mr-3 text-lg">📊</span>
Add, edit and manage your transactions Add, edit and manage your transactions
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-pink-600 mr-3 text-lg">📊</span>
Filter by any column, category or date range Filter by any column, category or date range
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-pink-600 mr-3 text-lg">📊</span>
Customize which columns to show in the table Customize which columns to show in the table
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-green-600 mr-2"></span> <span className="text-pink-600 mr-3 text-lg">📊</span>
Import transactions from CSV Import transactions from CSV
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
{/* Invoice Generator */}
<div className="flex flex-wrap items-center gap-12 mb-20 bg-gradient-to-br from-white via-purple-50/30 to-indigo-50/30 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-purple-200 to-indigo-200 hover:shadow-2xl transition-all duration-500 group">
<div className="flex-1 relative aspect-auto rounded-3xl overflow-hidden shadow-2xl ring-4 ring-gradient-to-r from-purple-200 to-indigo-200 hover:scale-105 transition-all duration-500">
<Image src="/landing/invoice-generator.webp" alt="Invoice Generator" width={1800} height={1081} />
</div>
<div className="flex-1 min-w-60">
<div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-purple-500 to-indigo-600 text-white text-sm font-bold mb-4 shadow-lg">
📋 Invoice Generator
</div>
<h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-purple-700 to-indigo-700 bg-clip-text text-transparent">
Create custom invoices
</h3>
<ul className="space-y-3 text-gray-700">
<li className="flex items-center">
<span className="text-purple-600 mr-3 text-lg">📄</span>
???
</li>
<li className="flex items-center">
<span className="text-purple-600 mr-3 text-lg">📄</span>
???
</li>
<li className="flex items-center">
<span className="text-purple-600 mr-3 text-lg">📄</span>
???
</li>
<li className="flex items-center">
<span className="text-purple-600 mr-3 text-lg">📄</span>
???
</li>
</ul>
</div>
</div>
{/* Custom Fields & Categories */} {/* Custom Fields & Categories */}
<div className="flex flex-wrap items-center gap-12 mb-20 bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100"> <div className="flex flex-wrap items-center gap-12 mb-20 bg-gradient-to-br from-white via-violet-50/30 to-purple-50/30 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-violet-200 to-purple-200 hover:shadow-2xl transition-all duration-500 group">
<div className="flex-1 relative aspect-auto rounded-2xl overflow-hidden shadow-2xl ring-8 ring-gray-100 hover:scale-105 transition-all duration-300"> <div className="flex-1 relative aspect-auto rounded-3xl overflow-hidden shadow-2xl ring-4 ring-gradient-to-r from-violet-200 to-purple-200 hover:scale-105 transition-all duration-500">
<Image src="/landing/custom-llm.webp" alt="Custom LLM promts" width={1800} height={1081} /> <Image src="/landing/custom-llm.webp" alt="Custom LLM promts" width={1800} height={1081} />
</div> </div>
<div className="flex-1 min-w-60"> <div className="flex-1 min-w-60">
<div className="inline-block px-3 py-1 rounded-full bg-purple-50 text-purple-600 text-sm font-medium mb-4"> <div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-violet-500 to-purple-600 text-white text-sm font-bold mb-4 shadow-lg">
Customization 🎨 Customization
</div> </div>
<h3 className="text-2xl font-semibold mb-4">Create custom LLM promts to extract anything</h3> <h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-violet-700 to-purple-700 bg-clip-text text-transparent">
<ul className="space-y-3 text-gray-600"> Create custom LLM promts to extract anything
</h3>
<ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-violet-600 mr-3 text-lg">🔧</span>
Create custom fields and categories with your own LLM prompts Create custom fields and categories with your own LLM prompts
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-violet-600 mr-3 text-lg">🔧</span>
Extract any additional information you need Extract any additional information you need
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-violet-600 mr-3 text-lg">🔧</span>
Automatically categorize by project or category Automatically categorize by project or category
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-violet-600 mr-3 text-lg">🔧</span>
Ask AI to assess risk level or any other criteria Ask AI to assess risk level or any other criteria
</li> </li>
</ul> </ul>
@@ -203,30 +263,32 @@ export default function LandingPage() {
</div> </div>
{/* Data Export */} {/* Data Export */}
<div className="flex flex-wrap items-center gap-12 mb-20 bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100 flex-row-reverse"> <div className="flex flex-wrap items-center gap-12 mb-20 bg-gradient-to-br from-white via-orange-50/30 to-amber-50/30 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-orange-200 to-amber-200 hover:shadow-2xl transition-all duration-500 group flex-row-reverse">
<div className="flex-1 relative aspect-auto rounded-2xl overflow-hidden shadow-2xl ring-8 ring-gray-100 hover:scale-105 transition-all duration-300"> <div className="flex-1 relative aspect-auto rounded-3xl overflow-hidden shadow-2xl ring-4 ring-gradient-to-r from-orange-200 to-amber-200 hover:scale-105 transition-all duration-500">
<Image src="/landing/export.webp" alt="Export" width={1200} height={1081} /> <Image src="/landing/export.webp" alt="Export" width={1200} height={1081} />
</div> </div>
<div className="flex-1 min-w-60"> <div className="flex-1 min-w-60">
<div className="inline-block px-3 py-1 rounded-full bg-orange-50 text-orange-600 text-sm font-medium mb-4"> <div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-orange-500 to-amber-600 text-white text-sm font-bold mb-4 shadow-lg">
Export 📦 Export
</div> </div>
<h3 className="text-2xl font-semibold mb-4">Your Data Your Rules</h3> <h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-orange-700 to-amber-700 bg-clip-text text-transparent">
<ul className="space-y-3 text-gray-600"> Your Data Your Rules
</h3>
<ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-orange-600 mr-2"></span> <span className="text-orange-600 mr-3 text-lg">📤</span>
Flexible filters to export your data for tax prep Flexible filters to export your data for tax prep
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-orange-600 mr-2"></span> <span className="text-orange-600 mr-3 text-lg">📤</span>
Full-text search across documents Full-text search across documents
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-orange-600 mr-2"></span> <span className="text-orange-600 mr-3 text-lg">📤</span>
Export to CSV with attached documents Export to CSV with attached documents
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-orange-600 mr-2"></span> <span className="text-orange-600 mr-3 text-lg">📤</span>
Download full data archive to migrate to another service Download full data archive to migrate to another service
</li> </li>
</ul> </ul>
@@ -236,83 +298,84 @@ export default function LandingPage() {
</section> </section>
{/* Deployment Options */} {/* Deployment Options */}
<section id="start" className="py-20 px-8 bg-white scroll-mt-20"> <section
<div className="max-w-7xl mx-auto"> id="start"
className="py-20 px-8 bg-gradient-to-br from-white via-pink-50/20 to-indigo-50/20 scroll-mt-20 relative"
>
<div className="absolute inset-0 bg-gradient-to-r from-pink-100/20 to-indigo-100/20" />
<div className="max-w-7xl mx-auto relative z-10">
<div className="text-center mb-16"> <div className="text-center mb-16">
<h2 className="text-3xl font-bold mb-4 bg-gradient-to-r from-gray-900 to-gray-600 bg-clip-text text-transparent"> <h2 className="text-3xl font-bold mb-4 bg-gradient-to-r from-pink-600 to-indigo-600 bg-clip-text text-transparent">
Choose Your Version of TaxHacker Choose Your Version of TaxHacker
</h2> </h2>
</div> </div>
<div className="grid md:grid-cols-2 gap-16"> <div className="grid md:grid-cols-2 gap-16">
{/* Self-Hosted Version */} {/* Self-Hosted Version */}
<div className="bg-gradient-to-b from-white to-gray-50 p-8 rounded-2xl shadow-lg ring-1 ring-gray-100"> <div className="bg-gradient-to-br from-white via-violet-50/50 to-indigo-50/50 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-violet-200 to-indigo-200 hover:shadow-2xl transition-all duration-500 hover:scale-105 group">
<div className="inline-block px-3 py-1 rounded-full bg-violet-50 text-violet-600 text-sm font-medium mb-4"> <div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-violet-500 to-indigo-600 text-white text-sm font-bold mb-4 shadow-lg">
Use Your Own Server 🏠 Use Your Own Server
</div> </div>
<h3 className="text-2xl font-semibold mb-4"> <h3 className="text-2xl font-bold mb-4">
<ColoredText>Self-Hosted Edition</ColoredText> <ColoredText>Self-Hosted Edition</ColoredText>
</h3> </h3>
<ul className="space-y-3 text-gray-600 mb-8"> <ul className="space-y-3 text-gray-700 mb-8">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-indigo-600 mr-3 text-lg">🆓</span>
Free and open source Free and open source
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-indigo-600 mr-3 text-lg">🔒</span>
Complete control over your data Complete control over your data
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-indigo-600 mr-3 text-lg">🏗</span>
Use at your own infrastructure Use at your own infrastructure
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-blue-600 mr-2"></span> <span className="text-indigo-600 mr-3 text-lg">🔑</span>
Bring your own OpenAI keys Bring your own keys (OpenAI, Gemini, Mistral, etc.)
</li> </li>
</ul> </ul>
<Link <Link
href="https://github.com/vas3k/TaxHacker" href="https://github.com/vas3k/TaxHacker"
target="_blank" target="_blank"
className="block w-full text-center px-6 py-3 bg-gradient-to-r from-blue-600 to-indigo-600 text-white font-medium rounded-full hover:opacity-90 transition-all shadow-lg shadow-blue-500/20" className="block w-full text-center px-6 py-4 bg-gradient-to-r from-violet-600 to-indigo-600 text-white font-bold rounded-full hover:from-violet-700 hover:to-indigo-700 transition-all duration-300 shadow-xl hover:shadow-2xl hover:scale-110"
> >
Free: Github + Docker Compose Free: Github + Docker Compose 🐳
</Link> </Link>
</div> </div>
{/* Cloud Version */} {/* Cloud Version */}
<div className="bg-gradient-to-b from-white to-gray-50 p-8 rounded-2xl shadow-lg ring-1 ring-gray-100"> <div className="bg-gradient-to-br from-white via-pink-50/50 to-purple-50/50 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-pink-200 to-purple-200 hover:shadow-2xl transition-all duration-500 hover:scale-105 group relative">
<div className="absolute top-4 right-4"> <div className="inline-block px-4 py-2 rounded-full bg-gradient-to-r from-pink-500 to-purple-600 text-white text-sm font-bold mb-4 shadow-lg">
<span className="px-3 py-1 bg-gray-100 text-gray-600 rounded-full text-sm">Coming Soon</span> We Host It For You
</div> </div>
<div className="inline-block px-3 py-1 rounded-full bg-purple-50 text-purple-600 text-sm font-medium mb-4"> <h3 className="text-2xl font-bold mb-4">
We Host It For You
</div>
<h3 className="text-2xl font-semibold mb-4">
<ColoredText>Cloud Edition</ColoredText> <ColoredText>Cloud Edition</ColoredText>
</h3> </h3>
<ul className="space-y-3 text-gray-600 mb-8"> <ul className="space-y-3 text-gray-700 mb-8">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-gray-400 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">🎯</span>
SaaS version for those who prefer less hassle SaaS version for those who prefer less hassle
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-gray-400 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">🤖</span>
We provide AI keys and storage We provide AI keys and storage
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-gray-400 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">💳</span>
Yearly subscription plans Yearly subscription plans
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-gray-400 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">🚀</span>
Automatic updates and new features Automatic updates and new features
</li> </li>
</ul> </ul>
<Link <Link
href="/cloud" href="/cloud"
className="block w-full text-center px-6 py-3 bg-gradient-to-r from-blue-600 to-indigo-600 text-white font-medium rounded-full hover:opacity-90 transition-all shadow-lg shadow-blue-500/20" className="block w-full text-center px-6 py-4 bg-gradient-to-r from-pink-600 to-purple-600 text-white font-bold rounded-full hover:from-pink-700 hover:to-purple-700 transition-all duration-300 shadow-xl hover:shadow-2xl hover:scale-110"
> >
Early Access: from 35/year Early Access: from 35/year 💎
</Link> </Link>
</div> </div>
</div> </div>
@@ -320,105 +383,116 @@ export default function LandingPage() {
</section> </section>
{/* Upcoming Features */} {/* Upcoming Features */}
<section className="py-20 px-8 bg-gradient-to-b from-white to-gray-50 mt-28"> <section className="py-20 px-8 bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 mt-28 relative overflow-hidden">
<div className="max-w-7xl mx-auto"> <div className="absolute top-10 left-10 w-64 h-64 bg-gradient-to-r from-pink-400 to-indigo-400 rounded-full opacity-5 blur-3xl" />
<div className="absolute bottom-10 right-10 w-80 h-80 bg-gradient-to-r from-indigo-400 to-pink-400 rounded-full opacity-5 blur-3xl" />
<div className="max-w-7xl mx-auto relative z-10">
<div className="text-center mb-16"> <div className="text-center mb-16">
<h2 className="text-3xl font-bold mb-4 bg-gradient-to-r from-gray-900 to-gray-600 bg-clip-text text-transparent"> <h2 className="text-3xl font-bold mb-4 bg-gradient-to-r from-pink-600 to-indigo-600 bg-clip-text text-transparent">
Upcoming Features Upcoming Features
</h2> </h2>
<p className="text-gray-600 max-w-2xl mx-auto"> <p className="text-gray-700 max-w-2xl mx-auto font-medium">
We&apos;re a small, indie project constantly improving. Here&apos;s what we&apos;re working on next. We&apos;re a small, indie project constantly improving. Here&apos;s what we&apos;re working on next.
</p> </p>
</div> </div>
<div className="grid md:grid-cols-2 gap-8 mb-16"> <div className="grid md:grid-cols-2 gap-8 mb-16">
{/* AI Improvements */} {/* AI Improvements */}
<div className="bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100"> <div className="bg-gradient-to-br from-white via-purple-50/50 to-indigo-50/50 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-purple-200 to-indigo-200 hover:shadow-2xl transition-all duration-500 hover:scale-105">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<span className="text-2xl">🤖</span> <span className="text-3xl">🤖</span>
<h3 className="text-xl font-semibold">Better AI Analytics & Agents</h3> <h3 className="text-xl font-bold bg-gradient-to-r from-purple-700 to-indigo-700 bg-clip-text text-transparent">
Better AI Analytics & Agents
</h3>
</div> </div>
<ul className="space-y-3 text-gray-600"> <ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">🔮</span>
Income & expense insights Income & expense insights
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">🔮</span>
AI agents to automate your workflows AI agents to automate your workflows
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">🔮</span>
Recommendations for tax optimization Recommendations for tax optimization
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-purple-600 mr-3 text-lg">🔮</span>
Custom and local LLM models Custom and local LLM models
</li> </li>
</ul> </ul>
</div> </div>
{/* Smart Reports */} {/* Smart Reports */}
<div className="bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100"> <div className="bg-gradient-to-br from-white via-pink-50/50 to-rose-50/50 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-pink-200 to-rose-200 hover:shadow-2xl transition-all duration-500 hover:scale-105">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<span className="text-2xl">📂</span> <span className="text-3xl">📊</span>
<h3 className="text-xl font-semibold">Smart Reports & Reminders</h3> <h3 className="text-xl font-bold bg-gradient-to-r from-pink-700 to-rose-700 bg-clip-text text-transparent">
Smart Reports & Reminders
</h3>
</div> </div>
<ul className="space-y-3 text-gray-600"> <ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-pink-600 mr-3 text-lg">📈</span>
Monthly or quarterly VAT reports Monthly or quarterly VAT reports
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-pink-600 mr-3 text-lg">📈</span>
Tax reminders Tax reminders
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-pink-600 mr-3 text-lg">📈</span>
Annual income & expense reports Annual income & expense reports
</li> </li>
</ul> </ul>
</div> </div>
{/* Transaction Review */} {/* Transaction Review */}
<div className="bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100"> <div className="bg-gradient-to-br from-white via-green-50/50 to-emerald-50/50 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-green-200 to-emerald-200 hover:shadow-2xl transition-all duration-500 hover:scale-105">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<span className="text-2xl">📥</span> <span className="text-3xl">📥</span>
<h3 className="text-xl font-semibold">Multiple Transaction Review</h3> <h3 className="text-xl font-bold bg-gradient-to-r from-green-700 to-emerald-700 bg-clip-text text-transparent">
Multiple Transaction Review
</h3>
</div> </div>
<ul className="space-y-3 text-gray-600"> <ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-green-600 mr-3 text-lg">💳</span>
Bank statement analysis Bank statement analysis
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-green-600 mr-3 text-lg">💳</span>
Automatic data completeness checks Automatic data completeness checks
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-green-600 mr-3 text-lg">💳</span>
Unpaid invoice tracking Unpaid invoice tracking
</li> </li>
</ul> </ul>
</div> </div>
{/* Custom Fields */} {/* Custom Fields */}
<div className="bg-white p-8 rounded-2xl shadow-sm ring-1 ring-gray-100"> <div className="bg-gradient-to-br from-white via-orange-50/50 to-amber-50/50 p-8 rounded-3xl shadow-xl ring-2 ring-gradient-to-r from-orange-200 to-amber-200 hover:shadow-2xl transition-all duration-500 hover:scale-105">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<span className="text-2xl">🤯</span> <span className="text-3xl">🧩</span>
<h3 className="text-xl font-semibold">Presets and Plugins</h3> <h3 className="text-xl font-bold bg-gradient-to-r from-orange-700 to-amber-700 bg-clip-text text-transparent">
Presets and Plugins
</h3>
</div> </div>
<ul className="space-y-3 text-gray-600"> <ul className="space-y-3 text-gray-700">
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-orange-600 mr-3 text-lg">🌍</span>
Presets for different countries and industries Presets for different countries and industries
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-orange-600 mr-3 text-lg">🌍</span>
Custom reports for various use-cases Custom reports for various use-cases
</li> </li>
<li className="flex items-center"> <li className="flex items-center">
<span className="text-purple-600 mr-2"></span> <span className="text-orange-600 mr-3 text-lg">🌍</span>
Community plugins and reports Community plugins and reports
</li> </li>
</ul> </ul>
@@ -430,10 +504,13 @@ export default function LandingPage() {
</div> </div>
</section> </section>
<footer className="py-8 px-8 bg-white"> <footer className="py-8 px-8 bg-gradient-to-r from-pink-50 to-indigo-50 border-t-2 border-gradient-to-r from-pink-200 to-indigo-200">
<div className="max-w-7xl mx-auto text-center text-sm text-gray-500"> <div className="max-w-7xl mx-auto text-center text-sm text-gray-600">
Made with in Berlin by{" "} Made with in Berlin by{" "}
<Link href="https://github.com/vas3k" className="underline"> <Link
href="https://github.com/vas3k"
className="underline font-semibold hover:text-pink-600 transition-colors"
>
@vas3k @vas3k
</Link> </Link>
</div> </div>
@@ -441,25 +518,37 @@ export default function LandingPage() {
<section className="py-12 px-8"> <section className="py-12 px-8">
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
<div className="flex flex-wrap gap-4 justify-center"> <div className="flex flex-wrap gap-4 justify-center">
<Link href={`mailto:${config.app.supportEmail}`} className="text-sm text-gray-600 hover:text-gray-900"> <Link
href={`mailto:${config.app.supportEmail}`}
className="text-sm text-gray-600 hover:text-pink-600 font-medium transition-colors"
>
Contact Us Contact Us
</Link> </Link>
<Link href="/docs/terms" className="text-sm text-gray-600 hover:text-gray-900"> <Link
href="/docs/terms"
className="text-sm text-gray-600 hover:text-pink-600 font-medium transition-colors"
>
Terms of Service Terms of Service
</Link> </Link>
<Link href="/docs/privacy_policy" className="text-sm text-gray-600 hover:text-gray-900"> <Link
href="/docs/privacy_policy"
className="text-sm text-gray-600 hover:text-pink-600 font-medium transition-colors"
>
Privacy Policy Privacy Policy
</Link> </Link>
<Link href="/docs/ai" className="text-sm text-gray-600 hover:text-gray-900"> <Link href="/docs/ai" className="text-sm text-gray-600 hover:text-pink-600 font-medium transition-colors">
AI Use Disclosure AI Use Disclosure
</Link> </Link>
<Link href="/docs/cookie" className="text-sm text-gray-600 hover:text-gray-900"> <Link
href="/docs/cookie"
className="text-sm text-gray-600 hover:text-pink-600 font-medium transition-colors"
>
Cookie Policy Cookie Policy
</Link> </Link>
<Link <Link
href="https://github.com/vas3k/TaxHacker" href="https://github.com/vas3k/TaxHacker"
target="_blank" target="_blank"
className="text-sm text-gray-600 hover:text-gray-900" className="text-sm text-gray-600 hover:text-pink-600 font-medium transition-colors"
> >
Source Code Source Code
</Link> </Link>

View File

@@ -16,19 +16,21 @@ export function ProjectsWidget({
return ( return (
<div className="grid gap-4 md:grid-cols-2"> <div className="grid gap-4 md:grid-cols-2">
{projects.map((project) => ( {projects.map((project) => (
<Card key={project.code}> <Link key={project.code} href={`/transactions?projectCode=${project.code}`}>
<CardHeader> <Card className="bg-gradient-to-tr from-white via-slate-50/40 to-purple-50/30 border-slate-200/60 hover:shadow-xl transition-all duration-500 hover:scale-[1.01] group cursor-pointer">
<CardHeader className="group-hover:translate-y-[-2px] transition-transform duration-300">
<CardTitle> <CardTitle>
<Link href={`/transactions?projectCode=${project.code}`}> <Badge
<Badge className="text-lg" style={{ backgroundColor: project.color }}> className="text-lg shadow-md hover:shadow-lg transition-all duration-300"
style={{ backgroundColor: project.color }}
>
{project.name} {project.name}
</Badge> </Badge>
</Link>
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent className="group-hover:translate-y-[-1px] transition-transform duration-300">
<div className="flex flex-wrap gap-4 justify-between items-center"> <div className="flex flex-wrap gap-4 justify-between items-center">
<div> <div className="bg-gradient-to-br from-green-50/80 to-emerald-50/60 p-3 rounded-xl border border-green-100/50">
<div className="text-sm font-medium text-muted-foreground">Income</div> <div className="text-sm font-medium text-muted-foreground">Income</div>
<div className="text-2xl font-bold text-green-500"> <div className="text-2xl font-bold text-green-500">
{Object.entries(statsPerProject[project.code]?.totalIncomePerCurrency).map(([currency, total]) => ( {Object.entries(statsPerProject[project.code]?.totalIncomePerCurrency).map(([currency, total]) => (
@@ -44,20 +46,25 @@ export function ProjectsWidget({
)} )}
</div> </div>
</div> </div>
<div> <div className="bg-gradient-to-br from-red-50/80 to-rose-50/60 p-3 rounded-xl border border-red-100/50">
<div className="text-sm font-medium text-muted-foreground">Expenses</div> <div className="text-sm font-medium text-muted-foreground">Expenses</div>
<div className="text-2xl font-bold text-red-500"> <div className="text-2xl font-bold text-red-500">
{Object.entries(statsPerProject[project.code]?.totalExpensesPerCurrency).map(([currency, total]) => ( {Object.entries(statsPerProject[project.code]?.totalExpensesPerCurrency).map(
<div key={currency} className="flex flex-col gap-2 font-bold text-red-500 text-base first:text-2xl"> ([currency, total]) => (
<div
key={currency}
className="flex flex-col gap-2 font-bold text-red-500 text-base first:text-2xl"
>
{formatCurrency(total, currency)} {formatCurrency(total, currency)}
</div> </div>
))} )
)}
{!Object.entries(statsPerProject[project.code]?.totalExpensesPerCurrency).length && ( {!Object.entries(statsPerProject[project.code]?.totalExpensesPerCurrency).length && (
<div className="font-bold text-base first:text-2xl">0.00</div> <div className="font-bold text-base first:text-2xl">0.00</div>
)} )}
</div> </div>
</div> </div>
<div> <div className="bg-gradient-to-br from-violet-50/80 to-indigo-50/60 p-3 rounded-xl border border-violet-100/50">
<div className="text-sm font-medium text-muted-foreground">Profit</div> <div className="text-sm font-medium text-muted-foreground">Profit</div>
<div className="text-2xl font-bold"> <div className="text-2xl font-bold">
{Object.entries(statsPerProject[project.code]?.profitPerCurrency).map(([currency, total]) => ( {Object.entries(statsPerProject[project.code]?.profitPerCurrency).map(([currency, total]) => (
@@ -78,13 +85,14 @@ export function ProjectsWidget({
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
</Link>
))} ))}
<Link <Link
href="/settings/projects" href="/settings/projects"
className="flex items-center justify-center gap-2 border-dashed border-2 border-gray-300 rounded-md p-4 text-muted-foreground hover:text-primary hover:border-primary" className="flex items-center justify-center gap-2 border-dashed border-2 border-gradient-to-r rounded-lg p-6 text-muted-foreground transition-all duration-300 hover:scale-[1.02] hover:shadow-lg group"
> >
<Plus className="h-4 w-4" /> <Plus className="h-5 w-5 group-hover:rotate-90 transition-transform duration-300" />
Create New Project <span className="font-medium">Create New Project</span>
</Link> </Link>
</div> </div>
) )

View File

@@ -7,6 +7,7 @@ import { getProjects } from "@/models/projects"
import { getDashboardStats, getProjectStats } from "@/models/stats" import { getDashboardStats, getProjectStats } from "@/models/stats"
import { TransactionFilters } from "@/models/transactions" import { TransactionFilters } from "@/models/transactions"
import { ArrowDown, ArrowUp, BicepsFlexed } from "lucide-react" import { ArrowDown, ArrowUp, BicepsFlexed } from "lucide-react"
import Link from "next/link"
export async function StatsWidget({ filters }: { filters: TransactionFilters }) { export async function StatsWidget({ filters }: { filters: TransactionFilters }) {
const user = await getCurrentUser() const user = await getCurrentUser()
@@ -27,21 +28,27 @@ export async function StatsWidget({ filters }: { filters: TransactionFilters })
</div> </div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4"> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card> <Link href="/transactions?type=income">
<Card className="bg-gradient-to-br from-white via-green-50/30 to-emerald-50/40 border-green-200/50 hover:shadow-lg transition-all duration-300 hover:scale-[1.02] cursor-pointer">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Income</CardTitle> <CardTitle className="text-sm font-medium">Total Income</CardTitle>
<ArrowUp className="h-4 w-4 text-green-500" /> <ArrowUp className="h-4 w-4 text-green-500" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
{Object.entries(stats.totalIncomePerCurrency).map(([currency, total]) => ( {Object.entries(stats.totalIncomePerCurrency).map(([currency, total]) => (
<div key={currency} className="flex gap-2 items-center font-bold text-base first:text-2xl text-green-500"> <div
key={currency}
className="flex gap-2 items-center font-bold text-base first:text-2xl text-green-500"
>
{formatCurrency(total, currency)} {formatCurrency(total, currency)}
</div> </div>
))} ))}
{!Object.entries(stats.totalIncomePerCurrency).length && <div className="text-2xl font-bold">0.00</div>} {!Object.entries(stats.totalIncomePerCurrency).length && <div className="text-2xl font-bold">0.00</div>}
</CardContent> </CardContent>
</Card> </Card>
<Card> </Link>
<Link href="/transactions?type=expense">
<Card className="bg-gradient-to-br from-white via-red-50/30 to-rose-50/40 border-red-200/50 hover:shadow-lg transition-all duration-300 hover:scale-[1.02] cursor-pointer">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Expenses</CardTitle> <CardTitle className="text-sm font-medium">Total Expenses</CardTitle>
<ArrowDown className="h-4 w-4 text-red-500" /> <ArrowDown className="h-4 w-4 text-red-500" />
@@ -55,7 +62,9 @@ export async function StatsWidget({ filters }: { filters: TransactionFilters })
{!Object.entries(stats.totalExpensesPerCurrency).length && <div className="text-2xl font-bold">0.00</div>} {!Object.entries(stats.totalExpensesPerCurrency).length && <div className="text-2xl font-bold">0.00</div>}
</CardContent> </CardContent>
</Card> </Card>
<Card> </Link>
<Link href="/transactions">
<Card className="bg-gradient-to-br from-white via-pink-50/30 to-indigo-50/40 border-pink-200/50 hover:shadow-lg transition-all duration-300 hover:scale-[1.02] cursor-pointer">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Net Profit</CardTitle> <CardTitle className="text-sm font-medium">Net Profit</CardTitle>
<BicepsFlexed className="h-4 w-4" /> <BicepsFlexed className="h-4 w-4" />
@@ -74,7 +83,9 @@ export async function StatsWidget({ filters }: { filters: TransactionFilters })
{!Object.entries(stats.profitPerCurrency).length && <div className="text-2xl font-bold">0.00</div>} {!Object.entries(stats.profitPerCurrency).length && <div className="text-2xl font-bold">0.00</div>}
</CardContent> </CardContent>
</Card> </Card>
<Card> </Link>
<Link href="/transactions">
<Card className="bg-gradient-to-br from-white via-blue-50/30 to-indigo-50/40 border-blue-200/50 hover:shadow-lg transition-all duration-300 hover:scale-[1.02] cursor-pointer">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Processed Transactions</CardTitle> <CardTitle className="text-sm font-medium">Processed Transactions</CardTitle>
</CardHeader> </CardHeader>
@@ -82,6 +93,7 @@ export async function StatsWidget({ filters }: { filters: TransactionFilters })
<div className="text-2xl font-bold">{stats.invoicesProcessed}</div> <div className="text-2xl font-bold">{stats.invoicesProcessed}</div>
</CardContent> </CardContent>
</Card> </Card>
</Link>
</div> </div>
<div> <div>

View File

@@ -1,6 +1,8 @@
"use client" "use client"
import { deleteTransactionAction, saveTransactionAction } from "@/app/(app)/transactions/actions" import { deleteTransactionAction, saveTransactionAction } from "@/app/(app)/transactions/actions"
import { ItemsDetectTool } from "@/components/agents/items-detect"
import ToolWindow from "@/components/agents/tool-window"
import { FormError } from "@/components/forms/error" import { FormError } from "@/components/forms/error"
import { FormSelectCategory } from "@/components/forms/select-category" import { FormSelectCategory } from "@/components/forms/select-category"
import { FormSelectCurrency } from "@/components/forms/select-currency" import { FormSelectCurrency } from "@/components/forms/select-currency"
@@ -8,14 +10,12 @@ import { FormSelectProject } from "@/components/forms/select-project"
import { FormSelectType } from "@/components/forms/select-type" import { FormSelectType } from "@/components/forms/select-type"
import { FormInput, FormTextarea } from "@/components/forms/simple" import { FormInput, FormTextarea } from "@/components/forms/simple"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { TransactionData } from "@/models/transactions"
import { Category, Currency, Field, Project, Transaction } from "@/prisma/client" import { Category, Currency, Field, Project, Transaction } from "@/prisma/client"
import { format } from "date-fns" import { format } from "date-fns"
import { Loader2, Save, Trash2 } from "lucide-react" import { Loader2, Save, Trash2 } from "lucide-react"
import { useRouter } from "next/navigation" import { useRouter } from "next/navigation"
import { startTransition, useActionState, useEffect, useMemo, useState } from "react" import { startTransition, useActionState, useEffect, useMemo, useState } from "react"
import ToolWindow from "@/components/agents/tool-window"
import { ItemsDetectTool } from "@/components/agents/items-detect"
import { TransactionData } from "@/models/transactions"
export default function TransactionEditForm({ export default function TransactionEditForm({
transaction, transaction,

View File

@@ -31,6 +31,7 @@ export type TransactionFilters = {
ordering?: string ordering?: string
categoryCode?: string categoryCode?: string
projectCode?: string projectCode?: string
type?: string
page?: number page?: number
} }
@@ -54,11 +55,11 @@ export const getTransactions = cache(
if (filters) { if (filters) {
if (filters.search) { if (filters.search) {
where.OR = [ where.OR = [
{ name: { contains: filters.search, mode: 'insensitive' } }, { name: { contains: filters.search, mode: "insensitive" } },
{ merchant: { contains: filters.search, mode: 'insensitive' } }, { merchant: { contains: filters.search, mode: "insensitive" } },
{ description: { contains: filters.search, mode: 'insensitive' } }, { description: { contains: filters.search, mode: "insensitive" } },
{ note: { contains: filters.search, mode: 'insensitive' } }, { note: { contains: filters.search, mode: "insensitive" } },
{ text: { contains: filters.search, mode: 'insensitive' } }, { text: { contains: filters.search, mode: "insensitive" } },
] ]
} }
@@ -77,6 +78,10 @@ export const getTransactions = cache(
where.projectCode = filters.projectCode where.projectCode = filters.projectCode
} }
if (filters.type) {
where.type = filters.type
}
if (filters.ordering) { if (filters.ordering) {
const isDesc = filters.ordering.startsWith("-") const isDesc = filters.ordering.startsWith("-")
const field = isDesc ? filters.ordering.slice(1) : filters.ordering const field = isDesc ? filters.ordering.slice(1) : filters.ordering
@@ -148,7 +153,7 @@ export const updateTransaction = async (id: string, userId: string, data: Transa
data: { data: {
...standard, ...standard,
extra: extra, extra: extra,
items: data.items ? data.items as Prisma.InputJsonValue : [], items: data.items ? (data.items as Prisma.InputJsonValue) : [],
}, },
}) })
} }