mirror of
https://github.com/soconnor0919/beenvoice.git
synced 2026-05-08 09:38:55 -04:00
Update Next.js to v15.5.6 and upgrade dependencies
Bump Next.js from 15.4.5 to 15.5.6 and update related dependencies. Also upgrade other packages to latest compatible versions including: - Radix UI components (all minor version updates) - Tiptap editor (3.0.7 → 3.11.0) - React and React DOM (19.1.1 → 19.2.0) - TanStack Query (5.84.0 → 5.90.10) - TypeScript and ESLint ecosystem - Tailwind CSS (4.1.11 → 4.1.17) - Various other patch and minor updates Additionally add theme support with next-themes and multiple color schemes (light, dark, sunset, forest).
This commit is contained in:
@@ -55,7 +55,7 @@ export function AnimatedStatsCard({
|
||||
void numericValue;
|
||||
|
||||
return (
|
||||
<Card className="stats-card">
|
||||
<Card>
|
||||
<CardContent className="p-6">
|
||||
<div className="flex items-center justify-between space-y-0 pb-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
|
||||
@@ -77,12 +77,12 @@ export function PDFDownloadButton({
|
||||
>
|
||||
{isGenerating ? (
|
||||
<>
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
<Loader2 className="mr-2 h-5 w-5 animate-spin" />
|
||||
<span>Generating PDF...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Download className="h-5 w-5" />
|
||||
<Download className="mr-2 h-5 w-5" />
|
||||
<span>Download PDF</span>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -136,7 +136,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
/>
|
||||
<Button asChild variant="default" className="hover-lift">
|
||||
<Link href={`/dashboard/invoices/${invoice.id}/edit`}>
|
||||
<Edit className="h-5 w-5" />
|
||||
<Edit className="mr-2 h-5 w-5" />
|
||||
<span>Edit</span>
|
||||
</Link>
|
||||
</Button>
|
||||
@@ -329,7 +329,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{invoice.items.map((item, _index) => (
|
||||
<Card key={item.id} className="invoice-item card-secondary">
|
||||
<Card key={item.id} className="invoice-item bg-secondary">
|
||||
<CardContent className="p-3">
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
|
||||
@@ -364,7 +364,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
))}
|
||||
|
||||
{/* Totals */}
|
||||
<div className="bg-muted/30 rounded-lg p-4">
|
||||
<div className="bg-secondary rounded-lg p-4">
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-wrap justify-between gap-x-4 gap-y-1">
|
||||
<span className="text-muted-foreground">Subtotal:</span>
|
||||
@@ -411,7 +411,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
|
||||
{/* Right Column - Actions */}
|
||||
<div className="space-y-6">
|
||||
<Card className="sticky top-6">
|
||||
<Card className="sticky top-20">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Check className="h-5 w-5" />
|
||||
@@ -419,7 +419,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<Button asChild variant="outline" className="w-full">
|
||||
<Button asChild variant="secondary" className="w-full">
|
||||
<Link href={`/dashboard/invoices/${invoice.id}/edit`}>
|
||||
<Edit className="mr-2 h-4 w-4" />
|
||||
Edit Invoice
|
||||
@@ -427,7 +427,11 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
</Button>
|
||||
|
||||
{invoice.items && invoice.client && (
|
||||
<PDFDownloadButton invoiceId={invoice.id} className="w-full" />
|
||||
<PDFDownloadButton
|
||||
invoiceId={invoice.id}
|
||||
className="w-full"
|
||||
variant="secondary"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Send Invoice Button - Show for draft, sent, and overdue */}
|
||||
@@ -435,6 +439,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
<EnhancedSendInvoiceButton
|
||||
invoiceId={invoice.id}
|
||||
className="w-full"
|
||||
variant="secondary"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -444,6 +449,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
invoiceId={invoice.id}
|
||||
className="w-full"
|
||||
showResend={true}
|
||||
variant="secondary"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -453,7 +459,8 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
<Button
|
||||
onClick={handleMarkAsPaid}
|
||||
disabled={updateStatus.isPending}
|
||||
className="bg-primary text-primary-foreground hover:bg-primary/90 w-full"
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
>
|
||||
{updateStatus.isPending ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
@@ -465,7 +472,7 @@ function InvoiceViewContent({ invoiceId }: { invoiceId: string }) {
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
variant="secondary"
|
||||
onClick={handleDelete}
|
||||
disabled={deleteInvoice.isPending}
|
||||
className="text-destructive hover:bg-destructive/10 w-full"
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
FileUp,
|
||||
Info,
|
||||
Key,
|
||||
Palette,
|
||||
Shield,
|
||||
Upload,
|
||||
User,
|
||||
@@ -61,6 +62,7 @@ import { Textarea } from "~/components/ui/textarea";
|
||||
import { api } from "~/trpc/react";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
import { Slider } from "~/components/ui/slider";
|
||||
import { ThemeSelector } from "./theme-selector";
|
||||
import { useAnimationPreferences } from "~/components/providers/animation-preferences-provider";
|
||||
|
||||
export function SettingsContent() {
|
||||
@@ -389,7 +391,7 @@ export function SettingsContent() {
|
||||
return (
|
||||
<div
|
||||
key={item.label}
|
||||
className="hover-lift bg-card border p-4 transition-shadow hover:shadow-sm"
|
||||
className="bg-card rounded-lg border p-4 transition-shadow hover:shadow-sm"
|
||||
style={{ animationDelay: `${index * 100}ms` }}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -615,11 +617,27 @@ export function SettingsContent() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Appearance Settings */}
|
||||
<Card className="bg-card border-border border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground flex items-center gap-2">
|
||||
<Palette className="text-primary h-5 w-5" />
|
||||
Appearance
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Customize the look and feel of the application
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ThemeSelector />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Data Management */}
|
||||
<Card className="bg-card border-border border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground flex items-center gap-2">
|
||||
<Shield className="text-icon-indigo h-5 w-5" />
|
||||
<Shield className="text-primary h-5 w-5" />
|
||||
Data Management
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -785,10 +803,10 @@ export function SettingsContent() {
|
||||
</Card>
|
||||
|
||||
{/* Danger Zone */}
|
||||
<Card className="bg-card border-border border border-l-4 border-l-red-500">
|
||||
<Card className="bg-card border-border border-l-destructive border border-l-4">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-destructive flex items-center gap-2">
|
||||
<AlertTriangle className="text-icon-red h-5 w-5" />
|
||||
<AlertTriangle className="text-destructive h-5 w-5" />
|
||||
Danger Zone
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -823,7 +841,7 @@ export function SettingsContent() {
|
||||
This action cannot be undone. This will permanently delete
|
||||
all your:
|
||||
</div>
|
||||
<ul className="border-border bg-muted/50 list-inside list-disc space-y-1 border p-3 text-sm">
|
||||
<ul className="border-border bg-muted/50 list-inside list-disc space-y-1 rounded-lg border p-3 text-sm">
|
||||
<li>Client information and contact details</li>
|
||||
<li>Business profiles and settings</li>
|
||||
<li>Invoices and invoice line items</li>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
"use client";
|
||||
|
||||
import { useTheme } from "next-themes";
|
||||
import { Check, Palette } from "lucide-react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "~/components/ui/dropdown-menu";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
export function ThemeSelector() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
const themes = [
|
||||
{ name: "light", label: "Light" },
|
||||
{ name: "dark", label: "Dark" },
|
||||
{ name: "theme-sunset", label: "Sunset" },
|
||||
{ name: "theme-forest", label: "Forest" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-1.5">
|
||||
<label className="font-medium">Theme</label>
|
||||
<p className="text-muted-foreground text-xs leading-snug">
|
||||
Select a theme for the application.
|
||||
</p>
|
||||
</div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-40 justify-between">
|
||||
<span>
|
||||
{themes.find((t) => t.name === theme)?.label ?? "Light"}
|
||||
</span>
|
||||
<Palette className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
{themes.map((t) => (
|
||||
<DropdownMenuItem
|
||||
key={t.name}
|
||||
className="flex justify-between"
|
||||
onClick={() => setTheme(t.name)}
|
||||
>
|
||||
<span>{t.label}</span>
|
||||
{theme === t.name && <Check className="h-4 w-4" />}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user