323 lines
8.3 KiB
TypeScript
323 lines
8.3 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
Document,
|
|
Page,
|
|
Text,
|
|
View,
|
|
Image,
|
|
StyleSheet,
|
|
} from '@react-pdf/renderer';
|
|
|
|
interface TicketPDFProps {
|
|
userName?: string;
|
|
eventName?: string;
|
|
eventDate?: string;
|
|
eventTime?: string;
|
|
venue?: string;
|
|
ticketType?: string;
|
|
amount?: string;
|
|
qrCodeDataUrl?: string;
|
|
ticketNumber?: string;
|
|
purchaseDate?: string;
|
|
orderId?: string;
|
|
seatNumber?: string;
|
|
section?: string;
|
|
}
|
|
|
|
export const TicketPDF = ({
|
|
userName = 'Kirubel',
|
|
eventName = 'Summer Music Festival 2024',
|
|
eventDate = 'July 15, 2024',
|
|
eventTime = '7:00 PM',
|
|
venue = 'City Park Amphitheater',
|
|
ticketType = 'General Admission',
|
|
amount = '$75.00',
|
|
qrCodeDataUrl,
|
|
ticketNumber = 'EVT-12345',
|
|
purchaseDate = new Date().toLocaleDateString(),
|
|
orderId = 'ORD-12345',
|
|
seatNumber,
|
|
section,
|
|
}: TicketPDFProps) => {
|
|
return (
|
|
<Document>
|
|
<Page size="A4" style={styles.page}>
|
|
{/* Header */}
|
|
<View style={styles.header}>
|
|
<Text style={styles.headerTitle}>AMBA</Text>
|
|
<Text style={styles.headerSubtitle}>Event Ticket</Text>
|
|
</View>
|
|
|
|
{/* Ticket Number Badge */}
|
|
<View style={styles.ticketBadge}>
|
|
<Text style={styles.ticketBadgeText}>TICKET #{ticketNumber}</Text>
|
|
</View>
|
|
|
|
{/* Event Information Section */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Event Details</Text>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Event Name:</Text>
|
|
<Text style={styles.infoValue}>{eventName}</Text>
|
|
</View>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Date:</Text>
|
|
<Text style={styles.infoValue}>{eventDate}</Text>
|
|
</View>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Time:</Text>
|
|
<Text style={styles.infoValue}>{eventTime}</Text>
|
|
</View>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Venue:</Text>
|
|
<Text style={styles.infoValue}>{venue}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Ticket Holder Information */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Ticket Holder</Text>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Name:</Text>
|
|
<Text style={styles.infoValue}>{userName}</Text>
|
|
</View>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Ticket Type:</Text>
|
|
<Text style={styles.infoValue}>{ticketType}</Text>
|
|
</View>
|
|
{seatNumber && (
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Seat:</Text>
|
|
<Text style={styles.infoValue}>{seatNumber}</Text>
|
|
</View>
|
|
)}
|
|
{section && (
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Section:</Text>
|
|
<Text style={styles.infoValue}>{section}</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
|
|
{/* Payment Information */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Payment Information</Text>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Amount Paid:</Text>
|
|
<Text style={styles.infoValue}>{amount}</Text>
|
|
</View>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Order ID:</Text>
|
|
<Text style={styles.infoValue}>{orderId}</Text>
|
|
</View>
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>Purchase Date:</Text>
|
|
<Text style={styles.infoValue}>{purchaseDate}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* QR Code Section */}
|
|
{qrCodeDataUrl && (
|
|
<View style={styles.qrSection}>
|
|
<Text style={styles.qrTitle}>Entry QR Code</Text>
|
|
<Text style={styles.qrInstructions}>
|
|
Present this QR code at the venue entrance for quick access
|
|
</Text>
|
|
<View style={styles.qrContainer}>
|
|
<Image
|
|
src={qrCodeDataUrl}
|
|
style={styles.qrCode}
|
|
/>
|
|
</View>
|
|
<Text style={styles.qrNote}>
|
|
Ticket Number: {ticketNumber}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
|
|
{/* Footer */}
|
|
<View style={styles.footer}>
|
|
<Text style={styles.footerText}>
|
|
This ticket is non-transferable and non-refundable.
|
|
</Text>
|
|
<Text style={styles.footerText}>
|
|
Please arrive at least 30 minutes before the event start time.
|
|
</Text>
|
|
<Text style={styles.footerText}>
|
|
For support, contact: support@amba.app
|
|
</Text>
|
|
</View>
|
|
|
|
{/* Terms and Conditions */}
|
|
<View style={styles.termsSection}>
|
|
<Text style={styles.termsTitle}>Terms & Conditions</Text>
|
|
<Text style={styles.termsText}>
|
|
• This ticket grants admission to the specified event only
|
|
</Text>
|
|
<Text style={styles.termsText}>
|
|
• The ticket holder must present valid ID if requested
|
|
</Text>
|
|
<Text style={styles.termsText}>
|
|
• The venue reserves the right to refuse entry
|
|
</Text>
|
|
<Text style={styles.termsText}>
|
|
• Lost or stolen tickets cannot be replaced
|
|
</Text>
|
|
<Text style={styles.termsText}>
|
|
• Recording devices may be prohibited
|
|
</Text>
|
|
</View>
|
|
</Page>
|
|
</Document>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
page: {
|
|
padding: 40,
|
|
backgroundColor: '#ffffff',
|
|
fontFamily: 'Helvetica',
|
|
},
|
|
header: {
|
|
marginBottom: 30,
|
|
textAlign: 'center',
|
|
borderBottom: '2px solid #105D38',
|
|
paddingBottom: 20,
|
|
},
|
|
headerTitle: {
|
|
fontSize: 32,
|
|
fontWeight: 'bold',
|
|
color: '#105D38',
|
|
marginBottom: 5,
|
|
},
|
|
headerSubtitle: {
|
|
fontSize: 16,
|
|
color: '#666666',
|
|
textTransform: 'uppercase',
|
|
letterSpacing: 2,
|
|
},
|
|
ticketBadge: {
|
|
backgroundColor: '#105D38',
|
|
padding: 10,
|
|
borderRadius: 5,
|
|
marginBottom: 25,
|
|
textAlign: 'center',
|
|
},
|
|
ticketBadgeText: {
|
|
color: '#ffffff',
|
|
fontSize: 14,
|
|
fontWeight: 'bold',
|
|
textAlign: 'center',
|
|
},
|
|
section: {
|
|
marginBottom: 20,
|
|
padding: 15,
|
|
backgroundColor: '#f8fafc',
|
|
borderRadius: 5,
|
|
border: '1px solid #e2e8f0',
|
|
},
|
|
sectionTitle: {
|
|
fontSize: 18,
|
|
fontWeight: 'bold',
|
|
color: '#1e293b',
|
|
marginBottom: 12,
|
|
borderBottom: '1px solid #cbd5e1',
|
|
paddingBottom: 8,
|
|
},
|
|
infoRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
marginBottom: 10,
|
|
paddingBottom: 8,
|
|
borderBottom: '1px solid #e2e8f0',
|
|
},
|
|
infoLabel: {
|
|
fontSize: 12,
|
|
color: '#FFB668',
|
|
fontWeight: '600',
|
|
flex: 1,
|
|
},
|
|
infoValue: {
|
|
fontSize: 12,
|
|
color: '#105D38',
|
|
fontWeight: 'normal',
|
|
flex: 2,
|
|
textAlign: 'right',
|
|
},
|
|
qrSection: {
|
|
marginTop: 30,
|
|
marginBottom: 20,
|
|
padding: 20,
|
|
backgroundColor: '#E6F4EC',
|
|
borderRadius: 5,
|
|
border: '2px solid #FFB668',
|
|
alignItems: 'center',
|
|
},
|
|
qrTitle: {
|
|
fontSize: 20,
|
|
fontWeight: 'bold',
|
|
color: '#105D38',
|
|
marginBottom: 8,
|
|
},
|
|
qrInstructions: {
|
|
fontSize: 11,
|
|
color: '#666666',
|
|
marginBottom: 15,
|
|
textAlign: 'center',
|
|
},
|
|
qrContainer: {
|
|
padding: 15,
|
|
backgroundColor: '#ffffff',
|
|
borderRadius: 5,
|
|
border: '2px solid #cbd5e1',
|
|
marginBottom: 10,
|
|
},
|
|
qrCode: {
|
|
width: 200,
|
|
height: 200,
|
|
},
|
|
qrNote: {
|
|
fontSize: 10,
|
|
color: '#666666',
|
|
marginTop: 10,
|
|
fontWeight: 'bold',
|
|
},
|
|
footer: {
|
|
marginTop: 20,
|
|
marginBottom: 15,
|
|
padding: 15,
|
|
backgroundColor: '#f8fafc',
|
|
borderRadius: 5,
|
|
border: '1px solid #e2e8f0',
|
|
},
|
|
footerText: {
|
|
fontSize: 9,
|
|
color: '#64748b',
|
|
marginBottom: 5,
|
|
textAlign: 'center',
|
|
lineHeight: 1.4,
|
|
},
|
|
termsSection: {
|
|
marginTop: 15,
|
|
padding: 15,
|
|
backgroundColor: '#fff7ed',
|
|
borderRadius: 5,
|
|
border: '1px solid #fed7aa',
|
|
},
|
|
termsTitle: {
|
|
fontSize: 14,
|
|
fontWeight: 'bold',
|
|
color: '#9a3412',
|
|
marginBottom: 10,
|
|
},
|
|
termsText: {
|
|
fontSize: 9,
|
|
color: '#7c2d12',
|
|
marginBottom: 5,
|
|
lineHeight: 1.4,
|
|
},
|
|
});
|
|
|
|
export default TicketPDF;
|
|
|