206 lines
6.8 KiB
TypeScript
206 lines
6.8 KiB
TypeScript
import { jsPDF } from 'jspdf';
|
|
import autoTable from 'jspdf-autotable';
|
|
import { Event } from '../types';
|
|
|
|
export const generateEventDetailsPDF = (event: Event) => {
|
|
const doc = new jsPDF();
|
|
|
|
// Set fonts and colors
|
|
doc.setFont('helvetica');
|
|
|
|
// --- Header Section ---
|
|
doc.setFillColor(0, 74, 153); // #004a99
|
|
doc.rect(0, 0, 210, 40, 'F');
|
|
|
|
doc.setTextColor(255, 255, 255);
|
|
doc.setFontSize(22);
|
|
doc.setFont('helvetica', 'bold');
|
|
doc.text('RAJALAKSHMI INSTITUTE OF TECHNOLOGY', 105, 18, { align: 'center' });
|
|
|
|
doc.setFontSize(14);
|
|
doc.setFont('helvetica', 'normal');
|
|
doc.text('OFFICIAL EVENT PROPOSAL & VERIFICATION DOCUMENT', 105, 28, { align: 'center' });
|
|
|
|
// --- Basic Information ---
|
|
let startY = 50;
|
|
doc.setTextColor(0, 0, 0);
|
|
|
|
const addSectionTitle = (title: string, yPos: number) => {
|
|
doc.setFontSize(14);
|
|
doc.setFont('helvetica', 'bold');
|
|
doc.setTextColor(0, 74, 153);
|
|
doc.text(title, 14, yPos);
|
|
doc.setDrawColor(0, 74, 153);
|
|
doc.setLineWidth(0.5);
|
|
doc.line(14, yPos + 2, 196, yPos + 2);
|
|
doc.setTextColor(0, 0, 0);
|
|
return yPos + 10;
|
|
};
|
|
|
|
startY = addSectionTitle('1. General Overview', startY);
|
|
|
|
doc.setFontSize(10);
|
|
doc.setFont('helvetica', 'bold');
|
|
|
|
const basicInfo = [
|
|
['Event Title:', event.title.toUpperCase()],
|
|
['Category & Domain:', `${event.category} - ${event.domain || 'N/A'}`],
|
|
['Conducting Dept:', event.conducting_dept || 'General'],
|
|
['Coordinator:', event.coordinator || 'N/A'],
|
|
['Club / Entity:', event.club || 'N/A'],
|
|
['Participant Type:', event.participantType || 'Internal'],
|
|
['Creation Date:', event.request_by_faculty ? new Date(event.request_by_faculty).toLocaleString() : 'N/A']
|
|
];
|
|
|
|
basicInfo.forEach((info, idx) => {
|
|
doc.setFont('helvetica', 'bold');
|
|
doc.text(info[0], 14, startY + (idx * 7));
|
|
doc.setFont('helvetica', 'normal');
|
|
doc.text(info[1], 55, startY + (idx * 7));
|
|
});
|
|
|
|
startY += (basicInfo.length * 7) + 10;
|
|
|
|
// --- Operational Logistics ---
|
|
startY = addSectionTitle('2. Operational Logistics', startY);
|
|
|
|
const eventTime = event.schedule && event.schedule.length > 0 ? `${event.schedule[0].start_time} - ${event.schedule[0].end_time}` : 'N/A';
|
|
const logisticsInfo = [
|
|
['Date & Time:', `${event.date} at ${eventTime}`],
|
|
['Duration:', `${event.durationDays || 1} Day(s)`],
|
|
['Venue:', event.location || 'N/A'],
|
|
['Event Format:', event.isTeamEvent ? `Team Play (Max ${event.teamSizeLimit || 1} members)` : 'Solo Participation'],
|
|
['Registration Deadline:', event.registrationDeadline ? new Date(event.registrationDeadline).toLocaleString() : 'N/A'],
|
|
['Global Capacity:', event.maxParticipants ? `${event.maxParticipants} Seats` : 'Unlimited']
|
|
];
|
|
|
|
logisticsInfo.forEach((info, idx) => {
|
|
doc.setFont('helvetica', 'bold');
|
|
doc.text(info[0], 14, startY + (idx * 7));
|
|
doc.setFont('helvetica', 'normal');
|
|
doc.text(info[1], 55, startY + (idx * 7));
|
|
});
|
|
|
|
startY += (logisticsInfo.length * 7) + 10;
|
|
|
|
// --- Detailed Summary ---
|
|
startY = addSectionTitle('3. Detailed Summary', startY);
|
|
doc.setFont('helvetica', 'normal');
|
|
doc.setFontSize(10);
|
|
|
|
const splitSummary = doc.splitTextToSize(event.event_summary || 'No detailed summary provided for this event.', 180);
|
|
doc.text(splitSummary, 14, startY);
|
|
|
|
startY += (splitSummary.length * 5) + 10;
|
|
|
|
// --- Schedule & Resource Persons ---
|
|
if (startY > 230) {
|
|
doc.addPage();
|
|
startY = 20;
|
|
}
|
|
|
|
if (event.schedule && event.schedule.length > 0) {
|
|
startY = addSectionTitle('4. Schedule & Resource Persons', startY);
|
|
|
|
const scheduleData = event.schedule.map(slot => [
|
|
`Day ${slot.day_idx} - Batch ${slot.batch_idx}`,
|
|
`${slot.date} (${slot.start_time} - ${slot.end_time})`,
|
|
slot.resource_person ? `${slot.resource_person.name}\n${slot.resource_person.dept || ''} ${slot.resource_person.college_name || ''}` : 'N/A',
|
|
slot.resource_person ? `${slot.resource_person.email}\n${slot.resource_person.phone}` : 'N/A'
|
|
]);
|
|
|
|
autoTable(doc, {
|
|
startY: startY,
|
|
head: [['Session', 'Timing', 'Resource Person', 'Contact']],
|
|
body: scheduleData,
|
|
theme: 'grid',
|
|
headStyles: { fillColor: [0, 74, 153] },
|
|
styles: { fontSize: 9 }
|
|
});
|
|
|
|
startY = (doc as any).lastAutoTable.finalY + 15;
|
|
}
|
|
|
|
// --- Department Quotas ---
|
|
if (startY > 230) {
|
|
doc.addPage();
|
|
startY = 20;
|
|
}
|
|
|
|
if (event.deptLimits && Object.keys(event.deptLimits).length > 0) {
|
|
startY = addSectionTitle('5. Department Seat Quotas', startY);
|
|
|
|
const quotaData = Object.entries(event.deptLimits).map(([dept, maxSeats]) => {
|
|
const current = event.currentDeptCounts?.[dept] || 0;
|
|
return [dept, `${current} Enrolled`, `${maxSeats} Limit`];
|
|
});
|
|
|
|
autoTable(doc, {
|
|
startY: startY,
|
|
head: [['Department', 'Current Enrollment', 'Max Seats Allocated']],
|
|
body: quotaData,
|
|
theme: 'grid',
|
|
headStyles: { fillColor: [249, 115, 22] }, // Orange theme for quotas
|
|
styles: { fontSize: 9 }
|
|
});
|
|
|
|
startY = (doc as any).lastAutoTable.finalY + 15;
|
|
}
|
|
|
|
// --- Financial Projections ---
|
|
if (startY > 230) {
|
|
doc.addPage();
|
|
startY = 20;
|
|
}
|
|
|
|
startY = addSectionTitle('6. Financial Projections', startY);
|
|
|
|
const financeData = [
|
|
['Refreshment Expenses', `Rs. ${event.refreshment_expense || 0}`],
|
|
['Transportation Expenses', `Rs. ${event.transportation_expense || 0}`],
|
|
['Session Coverage Fees', `Rs. ${(event as any).session_coverage_fee || 0}`],
|
|
['Total Projected Budget', `Rs. ${event.total_expense || 0}`]
|
|
];
|
|
|
|
autoTable(doc, {
|
|
startY: startY,
|
|
body: financeData,
|
|
theme: 'plain',
|
|
styles: { fontSize: 10, cellPadding: 3 },
|
|
columnStyles: { 0: { fontStyle: 'bold' }, 1: { halign: 'right' } },
|
|
didParseCell: function(data) {
|
|
if (data.row.index === 3) {
|
|
data.cell.styles.fontStyle = 'bold';
|
|
data.cell.styles.textColor = [16, 185, 129]; // Emerald 500
|
|
}
|
|
}
|
|
});
|
|
|
|
startY = (doc as any).lastAutoTable.finalY + 15;
|
|
|
|
// --- Footer / Verification Box ---
|
|
if (startY > 250) {
|
|
doc.addPage();
|
|
startY = 20;
|
|
}
|
|
|
|
doc.setDrawColor(0, 0, 0);
|
|
doc.setLineWidth(0.2);
|
|
doc.rect(14, startY, 182, 35);
|
|
|
|
doc.setFontSize(9);
|
|
doc.setFont('helvetica', 'italic');
|
|
doc.text('This is a system generated event verification document.', 105, startY + 6, { align: 'center' });
|
|
|
|
doc.setFont('helvetica', 'bold');
|
|
doc.setFontSize(10);
|
|
doc.text(`Status: ${event.verificationStatus || 'PENDING'}`, 20, startY + 18);
|
|
|
|
doc.setFontSize(8);
|
|
doc.text(`Generated on: ${new Date().toLocaleString()}`, 20, startY + 28);
|
|
doc.text('Rajalakshmi Institute of Technology - Events Hub', 130, startY + 28);
|
|
|
|
// Save PDF
|
|
doc.save(`${event.title.replace(/\s+/g, '_')}_Verification_Report.pdf`);
|
|
};
|