import React from 'react'; import { Page, Text, View, Document, StyleSheet } from '@react-pdf/renderer'; import { format } from 'date-fns'; import { Operation, Balance, OperationType } from '../types'; const styles = StyleSheet.create({ page: { flexDirection: 'column', backgroundColor: '#F9FAFB', padding: 35, fontFamily: 'Helvetica', }, header: { marginBottom: 25, paddingBottom: 15, paddingTop: 20, paddingLeft: 25, paddingRight: 25, backgroundColor: '#1F2937', borderRadius: 8, }, title: { fontSize: 28, fontWeight: 'bold', color: '#FFFFFF', marginBottom: 8, letterSpacing: 0.5, }, subtitle: { fontSize: 12, color: '#D1D5DB', fontWeight: 'normal', }, balanceSection: { marginBottom: 20, }, balanceTitle: { fontSize: 18, fontWeight: 'bold', color: '#1F2937', marginTop: 15, marginBottom: 12, paddingBottom: 8, paddingLeft: 10, borderLeftWidth: 4, borderLeftColor: '#3B82F6', backgroundColor: '#EFF6FF', paddingTop: 8, paddingRight: 10, }, table: { display: 'flex', width: 'auto', borderRadius: 6, overflow: 'hidden', borderStyle: 'solid', borderWidth: 1, borderColor: '#D1D5DB', backgroundColor: '#FFFFFF', }, tableRow: { margin: 'auto', flexDirection: 'row', }, tableColHeader: { width: '25%', borderStyle: 'solid', borderWidth: 1, borderLeftWidth: 0, borderTopWidth: 0, borderColor: '#E5E7EB', backgroundColor: '#F3F4F6', padding: 8, }, tableCol: { width: '25%', borderStyle: 'solid', borderWidth: 1, borderLeftWidth: 0, borderTopWidth: 0, borderColor: '#E5E7EB', padding: 8, backgroundColor: '#FFFFFF', }, tableCellHeader: { margin: 'auto', fontSize: 10, fontWeight: 'bold', color: '#1F2937', textTransform: 'uppercase', letterSpacing: 0.5, }, tableCell: { margin: 'auto', fontSize: 10, color: '#4B5563', }, tableCellIncome: { margin: 'auto', fontSize: 10, color: '#059669', fontWeight: 'bold', }, tableCellExpense: { margin: 'auto', fontSize: 10, color: '#DC2626', fontWeight: 'bold', }, tableCellBalance: { margin: 'auto', fontSize: 10, color: '#1F2937', fontWeight: 'bold', }, totalRow: { flexDirection: 'row', marginTop: 12, justifyContent: 'flex-end', backgroundColor: '#EFF6FF', padding: 10, borderRadius: 6, }, totalText: { fontSize: 13, fontWeight: 'bold', color: '#1F2937', }, emptyMessage: { fontSize: 11, color: '#9CA3AF', fontStyle: 'italic', padding: 20, textAlign: 'center', backgroundColor: '#F9FAFB', borderRadius: 6, }, summaryCard: { backgroundColor: '#FFFFFF', padding: 15, borderRadius: 8, marginBottom: 15, borderLeftWidth: 4, borderLeftColor: '#3B82F6', } }); interface PDFDocumentProps { operations: Operation[]; balances: Balance[]; dateRange: { start: Date; end: Date }; associationName: string; } const PDFDocument: React.FC = ({ operations, balances, dateRange, associationName }) => { const summaryData = balances.map(balance => { const balanceOps = operations.filter(op => op.balanceId === balance.id); const previousOps = balanceOps.filter(op => new Date(op.date) < dateRange.start); const initialIncome = previousOps.filter(op => op.type === OperationType.INCOME).reduce((sum, op) => sum + op.amount, 0); const initialExpense = previousOps.filter(op => op.type === OperationType.EXPENSE).reduce((sum, op) => sum + op.amount, 0); const startBalance = balance.initialAmount + initialIncome - initialExpense; const periodOps = balanceOps.filter(op => { const opDate = new Date(op.date); return opDate >= dateRange.start && opDate <= dateRange.end; }); const periodIncome = periodOps.filter(op => op.type === OperationType.INCOME).reduce((sum, op) => sum + op.amount, 0); const periodExpense = periodOps.filter(op => op.type === OperationType.EXPENSE).reduce((sum, op) => sum + op.amount, 0); const endBalance = startBalance + periodIncome - periodExpense; return { balance, startBalance, endBalance, periodIncome, periodExpense, periodOps: periodOps.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) }; }); return ( {/* Summary Page */} {associationName} Report Period: {format(dateRange.start, 'MMM dd, yyyy')} - {format(dateRange.end, 'MMM dd, yyyy')} Summary Balance Start Income Expense End {summaryData.map((data) => ( {data.balance.name} {data.startBalance.toFixed(2)} € +{data.periodIncome.toFixed(2)} € -{data.periodExpense.toFixed(2)} € {data.endBalance.toFixed(2)} € ))} {/* Detailed Pages */} {summaryData.map((data) => ( {data.balance.name} - Details {data.periodOps.length > 0 ? ( Date Name Type Amount {data.periodOps.map((op) => ( {format(new Date(op.date), 'MMM dd, yyyy')} {op.name} {op.type} {op.type === OperationType.EXPENSE ? '-' : '+'}{op.amount.toFixed(2)} € ))} ) : ( No operations for this period. )} End Balance: {data.endBalance.toFixed(2)} € ))} ); }; export default PDFDocument;