mirror of
https://github.com/johndoe6345789/workforce-pay-bill-p.git
synced 2026-04-24 13:24:57 +00:00
Generated by Spark: Add export functionality to remaining views (Reports, Purchase Orders, Audit Trail)
This commit is contained in:
@@ -2,6 +2,7 @@ import { useState, useEffect, useMemo } from 'react'
|
||||
import { usePurchaseOrdersCrud } from '@/hooks/use-purchase-orders-crud'
|
||||
import { useInvoicesCrud } from '@/hooks/use-invoices-crud'
|
||||
import { useTranslation } from '@/hooks/use-translation'
|
||||
import { useDataExport } from '@/hooks/use-data-export'
|
||||
import {
|
||||
FileText,
|
||||
Plus,
|
||||
@@ -18,7 +19,8 @@ import {
|
||||
Trash,
|
||||
PencilSimple,
|
||||
Eye,
|
||||
X
|
||||
X,
|
||||
Download
|
||||
} from '@phosphor-icons/react'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -37,6 +39,7 @@ export function PurchaseOrderTracking() {
|
||||
const { t } = useTranslation()
|
||||
const { entities: purchaseOrders, create, update, remove } = usePurchaseOrdersCrud()
|
||||
const { invoices } = useInvoicesCrud()
|
||||
const { exportToCSV, exportToExcel } = useDataExport()
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [isCreateOpen, setIsCreateOpen] = useState(false)
|
||||
const [isDetailOpen, setIsDetailOpen] = useState(false)
|
||||
@@ -297,6 +300,30 @@ export function PurchaseOrderTracking() {
|
||||
)
|
||||
}, [invoices, selectedPO])
|
||||
|
||||
const handleExportPOs = () => {
|
||||
try {
|
||||
const exportData = filteredPOs.map(po => ({
|
||||
'PO Number': po.poNumber,
|
||||
'Client': po.clientName,
|
||||
'Status': po.status,
|
||||
'Issue Date': new Date(po.issueDate).toLocaleDateString(),
|
||||
'Expiry Date': po.expiryDate ? new Date(po.expiryDate).toLocaleDateString() : 'N/A',
|
||||
'Currency': po.currency,
|
||||
'Total Value': po.totalValue,
|
||||
'Utilised Value': po.utilisedValue,
|
||||
'Remaining Value': po.remainingValue,
|
||||
'Utilization %': ((po.utilisedValue / po.totalValue) * 100).toFixed(2),
|
||||
'Linked Invoices': po.linkedInvoices.length,
|
||||
'Created By': po.createdBy,
|
||||
'Created Date': new Date(po.createdDate).toLocaleDateString()
|
||||
}))
|
||||
exportToExcel(exportData, { filename: `purchase-orders-${new Date().toISOString().split('T')[0]}` })
|
||||
toast.success(t('purchaseOrders.messages.exportSuccess') || 'Purchase orders exported successfully')
|
||||
} catch (error) {
|
||||
toast.error(t('purchaseOrders.messages.exportError') || 'Failed to export purchase orders')
|
||||
}
|
||||
}
|
||||
|
||||
if (isLoadingState) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-96">
|
||||
@@ -315,10 +342,16 @@ export function PurchaseOrderTracking() {
|
||||
<h2 className="text-3xl font-semibold tracking-tight">{t('purchaseOrders.title')}</h2>
|
||||
<p className="text-muted-foreground mt-1">{t('purchaseOrders.subtitle')}</p>
|
||||
</div>
|
||||
<Button onClick={() => setIsCreateOpen(true)}>
|
||||
<Plus size={18} className="mr-2" />
|
||||
{t('purchaseOrders.createPO')}
|
||||
</Button>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" onClick={handleExportPOs} disabled={filteredPOs.length === 0}>
|
||||
<Download size={18} className="mr-2" />
|
||||
{t('purchaseOrders.export') || 'Export'}
|
||||
</Button>
|
||||
<Button onClick={() => setIsCreateOpen(true)}>
|
||||
<Plus size={18} className="mr-2" />
|
||||
{t('purchaseOrders.createPO')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
|
||||
@@ -18,8 +18,10 @@ import {
|
||||
import { useInvoicesCrud } from '@/hooks/use-invoices-crud'
|
||||
import { usePayrollCrud } from '@/hooks/use-payroll-crud'
|
||||
import { useTranslation } from '@/hooks/use-translation'
|
||||
import { useDataExport } from '@/hooks/use-data-export'
|
||||
import type { MarginAnalysis, ForecastData } from '@/lib/types'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
export function ReportsView() {
|
||||
const [selectedPeriod, setSelectedPeriod] = useState<'week' | 'month' | 'quarter' | 'year'>('month')
|
||||
@@ -28,6 +30,7 @@ export function ReportsView() {
|
||||
|
||||
const { invoices } = useInvoicesCrud()
|
||||
const { payrollRuns } = usePayrollCrud()
|
||||
const { exportToCSV, exportToExcel } = useDataExport()
|
||||
|
||||
const calculateMarginAnalysis = (): MarginAnalysis[] => {
|
||||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
@@ -111,6 +114,71 @@ export function ReportsView() {
|
||||
...forecast.map(f => Math.max(f.predictedRevenue, f.predictedCosts))
|
||||
)
|
||||
|
||||
const handleExportMarginAnalysis = () => {
|
||||
try {
|
||||
const exportData = marginAnalysis.map(item => ({
|
||||
Period: item.period,
|
||||
Year: selectedYear,
|
||||
Revenue: item.revenue,
|
||||
Costs: item.costs,
|
||||
Margin: item.margin,
|
||||
'Margin %': item.marginPercentage.toFixed(2)
|
||||
}))
|
||||
exportToCSV(exportData, { filename: `margin-analysis-${selectedYear}` })
|
||||
toast.success(t('reports.exportSuccess') || 'Margin analysis exported successfully')
|
||||
} catch (error) {
|
||||
toast.error(t('reports.exportError') || 'Failed to export margin analysis')
|
||||
}
|
||||
}
|
||||
|
||||
const handleExportForecast = () => {
|
||||
try {
|
||||
const exportData = forecast.map(item => ({
|
||||
Period: item.period,
|
||||
Year: selectedYear,
|
||||
'Predicted Revenue': item.predictedRevenue,
|
||||
'Predicted Costs': item.predictedCosts,
|
||||
'Predicted Margin': item.predictedMargin,
|
||||
'Confidence %': item.confidence
|
||||
}))
|
||||
exportToCSV(exportData, { filename: `forecast-${selectedYear}` })
|
||||
toast.success(t('reports.exportSuccess') || 'Forecast data exported successfully')
|
||||
} catch (error) {
|
||||
toast.error(t('reports.exportError') || 'Failed to export forecast data')
|
||||
}
|
||||
}
|
||||
|
||||
const handleExportAll = () => {
|
||||
try {
|
||||
const combinedData = [
|
||||
...marginAnalysis.map(item => ({
|
||||
Type: 'Actual',
|
||||
Period: item.period,
|
||||
Year: selectedYear,
|
||||
Revenue: item.revenue,
|
||||
Costs: item.costs,
|
||||
Margin: item.margin,
|
||||
'Margin %': item.marginPercentage.toFixed(2),
|
||||
Confidence: 100
|
||||
})),
|
||||
...forecast.map(item => ({
|
||||
Type: 'Forecast',
|
||||
Period: item.period,
|
||||
Year: selectedYear,
|
||||
Revenue: item.predictedRevenue,
|
||||
Costs: item.predictedCosts,
|
||||
Margin: item.predictedMargin,
|
||||
'Margin %': ((item.predictedMargin / item.predictedRevenue) * 100).toFixed(2),
|
||||
Confidence: item.confidence
|
||||
}))
|
||||
]
|
||||
exportToExcel(combinedData, { filename: `financial-report-${selectedYear}` })
|
||||
toast.success(t('reports.exportSuccess') || 'Complete report exported successfully')
|
||||
} catch (error) {
|
||||
toast.error(t('reports.exportError') || 'Failed to export complete report')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -130,7 +198,7 @@ export function ReportsView() {
|
||||
<SelectItem value="2023">2023</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline">
|
||||
<Button variant="outline" onClick={handleExportAll}>
|
||||
<Download size={18} className="mr-2" />
|
||||
{t('reports.exportReport')}
|
||||
</Button>
|
||||
@@ -214,8 +282,16 @@ export function ReportsView() {
|
||||
<TabsContent value="margin-analysis" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t('reports.marginAnalysisTitle')}</CardTitle>
|
||||
<CardDescription>{t('reports.marginAnalysisDescription', { year: selectedYear })}</CardDescription>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle>{t('reports.marginAnalysisTitle')}</CardTitle>
|
||||
<CardDescription>{t('reports.marginAnalysisDescription', { year: selectedYear })}</CardDescription>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onClick={handleExportMarginAnalysis}>
|
||||
<Download size={16} className="mr-2" />
|
||||
Export CSV
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-6">
|
||||
@@ -305,13 +381,21 @@ export function ReportsView() {
|
||||
<TabsContent value="forecasting" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Lightning size={20} weight="fill" className="text-accent" />
|
||||
{t('reports.forecastingTitle')}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{t('reports.forecastingDescription')}
|
||||
</CardDescription>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Lightning size={20} weight="fill" className="text-accent" />
|
||||
{t('reports.forecastingTitle')}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{t('reports.forecastingDescription')}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onClick={handleExportForecast} disabled={forecast.length === 0}>
|
||||
<Download size={16} className="mr-2" />
|
||||
Export CSV
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{forecast.length === 0 ? (
|
||||
|
||||
Reference in New Issue
Block a user