From 248e26d880a7930b0bbe95a7d81ea45c46107af0 Mon Sep 17 00:00:00 2001 From: CycroftX Date: Tue, 3 Feb 2026 20:58:38 +0530 Subject: [PATCH] Implement Quick Actions functionality on Financials page (Monthly Report Download, Tax Settings) --- .../components/TaxSettingsSheet.tsx | 172 ++++++++++++++++++ src/pages/Financials.tsx | 54 +++++- 2 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 src/features/financials/components/TaxSettingsSheet.tsx diff --git a/src/features/financials/components/TaxSettingsSheet.tsx b/src/features/financials/components/TaxSettingsSheet.tsx new file mode 100644 index 0000000..63cca39 --- /dev/null +++ b/src/features/financials/components/TaxSettingsSheet.tsx @@ -0,0 +1,172 @@ + +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import * as z from "zod"; +import { Loader2, Landmark } from "lucide-react"; + +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, +} from "@/components/ui/sheet"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { toast } from "sonner"; + +const taxSettingsSchema = z.object({ + gstNumber: z.string().min(15, "GST Number must be 15 characters").max(15, "GST Number must be 15 characters"), + panNumber: z.string().min(10, "PAN Number must be 10 characters").max(10, "PAN Number must be 10 characters"), + platformFeePercentage: z.string().regex(/^\d+(\.\d{1,2})?$/, "Must be a valid percentage"), + taxPercentage: z.string().regex(/^\d+(\.\d{1,2})?$/, "Must be a valid percentage"), +}); + +type FormValues = z.infer; + +interface TaxSettingsSheetProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +export function TaxSettingsSheet({ open, onOpenChange }: TaxSettingsSheetProps) { + const [isSubmitting, setIsSubmitting] = useState(false); + + const form = useForm({ + resolver: zodResolver(taxSettingsSchema), + defaultValues: { + gstNumber: "27AAAAA0000A1Z5", + panNumber: "AAAAA0000A", + platformFeePercentage: "12", + taxPercentage: "18", + }, + }); + + async function onSubmit(data: FormValues) { + setIsSubmitting(true); + // Simulate API call + await new Promise((resolve) => setTimeout(resolve, 1500)); + + console.log("Tax settings updated:", data); + toast.success("Tax settings updated successfully"); + + setIsSubmitting(false); + onOpenChange(false); + } + + return ( + + + + Tax & Platform Settings + + Configure platform fees and tax details. + + + +
+ + +
+ +
+

Global Settings

+

These settings apply to all new events and transactions by default.

+
+
+ + ( + + Default Platform Fee (%) + + + + + Percentage of ticket sales taken as platform revenue. + + + + )} + /> + + ( + + Govt. Tax (GST) (%) + + + + + Applicable GST on platform fees. + + + + )} + /> + +
+ ( + + Company GSTIN + + + + + + )} + /> + + ( + + Company PAN + + + + + + )} + /> +
+ +
+ + +
+ + +
+
+ ); +} diff --git a/src/pages/Financials.tsx b/src/pages/Financials.tsx index 2c45e2b..6d97b56 100644 --- a/src/pages/Financials.tsx +++ b/src/pages/Financials.tsx @@ -1,16 +1,54 @@ -import { IndianRupee, TrendingUp, Wallet } from 'lucide-react'; +import { useState } from 'react'; +import { IndianRupee, TrendingUp, Wallet, Download } from 'lucide-react'; import { AppLayout } from '@/components/layout/AppLayout'; import { formatCurrency, mockRevenueData } from '@/data/mockData'; +import { mockTransactions } from '@/data/mockFinancialData'; import { SettlementTable } from '@/features/financials/components/SettlementTable'; import { TransactionList } from '@/features/financials/components/TransactionList'; +import { TaxSettingsSheet } from '@/features/financials/components/TaxSettingsSheet'; +import { toast } from 'sonner'; export default function Financials() { + const [showTaxSettings, setShowTaxSettings] = useState(false); + const totalRevenue = mockRevenueData.reduce((sum, d) => sum + d.revenue, 0); const totalPayouts = mockRevenueData.reduce((sum, d) => sum + d.payouts, 0); // Calculating platform fee (approx 10% of revenue for mock) const platformEarnings = totalRevenue * 0.12; + const handleDownloadReport = () => { + try { + const headers = ['ID', 'Date', 'Type', 'Title', 'Partner', 'Amount', 'Status']; + const csvContent = [ + headers.join(','), + ...mockTransactions.map(tx => [ + tx.id, + new Date(tx.date).toLocaleDateString(), + tx.type, + `"${tx.title}"`, + `"${tx.partner}"`, + tx.amount, + tx.status + ].join(',')) + ].join('\n'); + + const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); + const link = document.createElement('a'); + const url = URL.createObjectURL(blob); + link.setAttribute('href', url); + link.setAttribute('download', 'financial_report.csv'); + link.style.visibility = 'hidden'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + toast.success("Monthly report downloaded successfully"); + } catch (error) { + toast.error("Failed to generate report"); + } + }; + return (

Quick Actions

- - @@ -85,6 +129,8 @@ export default function Financials() {
+ +
); }