@zssz-soft/firebase-functions-shared 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/config/app.config.d.ts +13 -0
- package/lib/config/app.config.d.ts.map +1 -1
- package/lib/config/app.config.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/modules/booking/booking-email.templates.d.ts +52 -0
- package/lib/modules/booking/booking-email.templates.d.ts.map +1 -1
- package/lib/modules/booking/booking-email.templates.js +768 -0
- package/lib/modules/booking/booking-email.templates.js.map +1 -1
- package/lib/modules/booking/booking-email.triggers.d.ts.map +1 -1
- package/lib/modules/booking/booking-email.triggers.js.map +1 -1
- package/lib/modules/events/booking-event.handlers.d.ts +44 -0
- package/lib/modules/events/booking-event.handlers.d.ts.map +1 -0
- package/lib/modules/events/booking-event.handlers.js +274 -0
- package/lib/modules/events/booking-event.handlers.js.map +1 -0
- package/lib/modules/events/booking-event.models.d.ts +109 -0
- package/lib/modules/events/booking-event.models.d.ts.map +1 -0
- package/lib/modules/events/booking-event.models.js +110 -0
- package/lib/modules/events/booking-event.models.js.map +1 -0
- package/lib/modules/events/booking-event.triggers.d.ts +46 -0
- package/lib/modules/events/booking-event.triggers.d.ts.map +1 -0
- package/lib/modules/events/booking-event.triggers.js +178 -0
- package/lib/modules/events/booking-event.triggers.js.map +1 -0
- package/lib/modules/events/event.models.d.ts +53 -0
- package/lib/modules/events/event.models.d.ts.map +1 -0
- package/lib/modules/events/event.models.js +18 -0
- package/lib/modules/events/event.models.js.map +1 -0
- package/lib/modules/events/index.d.ts +29 -0
- package/lib/modules/events/index.d.ts.map +1 -0
- package/lib/modules/events/index.js +49 -0
- package/lib/modules/events/index.js.map +1 -0
- package/package.json +1 -1
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.generateGuestConfirmationEmail = generateGuestConfirmationEmail;
|
|
10
10
|
exports.generateAdminNotificationEmail = generateAdminNotificationEmail;
|
|
11
|
+
exports.generateBookingApprovedEmail = generateBookingApprovedEmail;
|
|
12
|
+
exports.generateBookingReadyEmail = generateBookingReadyEmail;
|
|
13
|
+
exports.generateBookingRejectedEmail = generateBookingRejectedEmail;
|
|
14
|
+
exports.generateBookingCompletedEmail = generateBookingCompletedEmail;
|
|
15
|
+
exports.generateBookingCancelledEmail = generateBookingCancelledEmail;
|
|
16
|
+
exports.generateVipConfirmationEmail = generateVipConfirmationEmail;
|
|
17
|
+
exports.generateVipStaffNotificationEmail = generateVipStaffNotificationEmail;
|
|
11
18
|
const config_1 = require("../../config");
|
|
12
19
|
/**
|
|
13
20
|
* Translation keys for email templates
|
|
@@ -52,6 +59,38 @@ const translations = {
|
|
|
52
59
|
fromWebsite: 'Weboldalról',
|
|
53
60
|
fromPhone: 'Telefonon',
|
|
54
61
|
fromEmail: 'Emailben',
|
|
62
|
+
// Booking approved
|
|
63
|
+
bookingApproved: 'Foglalásod visszaigazolva!',
|
|
64
|
+
bookingApprovedMessage: 'Örömmel értesítünk, hogy a foglalásod <strong>jóváhagyásra került</strong>!',
|
|
65
|
+
bookingApprovedMessageText: 'Örömmel értesítünk, hogy a foglalásod jóváhagyásra került!',
|
|
66
|
+
prepareForArrival: 'Készülj az érkezésre! Hamarosan küldünk további információkat.',
|
|
67
|
+
// Booking ready
|
|
68
|
+
readyForCheckin: 'Beköltözésre kész!',
|
|
69
|
+
readyForCheckinMessage: 'Szállásod <strong>készen áll</strong> a fogadásodra! Minden feltétel teljesült a beköltözéshez.',
|
|
70
|
+
readyForCheckinMessageText: 'Szállásod készen áll a fogadásodra! Minden feltétel teljesült a beköltözéshez.',
|
|
71
|
+
// Booking rejected
|
|
72
|
+
bookingRejected: 'Foglalás elutasítva',
|
|
73
|
+
bookingRejectedMessage: 'Sajnálattal értesítünk, hogy a foglalásod <strong>nem hagyható jóvá</strong>.',
|
|
74
|
+
bookingRejectedMessageText: 'Sajnálattal értesítünk, hogy a foglalásod nem hagyható jóvá.',
|
|
75
|
+
rejectionReason: 'Indoklás',
|
|
76
|
+
noReasonProvided: 'Nincs megadva',
|
|
77
|
+
// Booking completed
|
|
78
|
+
bookingCompleted: 'Köszönjük, hogy nálunk szálltál!',
|
|
79
|
+
bookingCompletedMessage: 'Reméljük, hogy kellemes időt töltöttél nálunk! Köszönjük, hogy minket választottál.',
|
|
80
|
+
feedbackRequest: 'Kérjük, értékeld a szállásodat, hogy továbbra is magas színvonalat tudjunk nyújtani!',
|
|
81
|
+
// Booking cancelled
|
|
82
|
+
bookingCancelled: 'Foglalás lemondva',
|
|
83
|
+
bookingCancelledMessage: 'A foglalásod <strong>lemondásra került</strong>.',
|
|
84
|
+
bookingCancelledMessageText: 'A foglalásod lemondásra került.',
|
|
85
|
+
cancellationReason: 'Lemondás oka',
|
|
86
|
+
refundAmount: 'Visszatérítés összege',
|
|
87
|
+
// VIP
|
|
88
|
+
vipConfirmation: 'VIP Foglalás visszaigazolva!',
|
|
89
|
+
vipConfirmationMessage: 'Köszönjük a foglalásod! Prémium vendégként a foglalásod <strong>azonnal visszaigazolásra került</strong>.',
|
|
90
|
+
vipConfirmationMessageText: 'Köszönjük a foglalásod! Prémium vendégként a foglalásod azonnal visszaigazolásra került.',
|
|
91
|
+
vipStaffAlert: 'VIP foglalás érkezett!',
|
|
92
|
+
vipStaffAlertMessage: '<strong>Figyelem!</strong> VIP foglalás érkezett, amely azonnali visszaigazolást kapott.',
|
|
93
|
+
vipStaffAlertMessageText: 'Figyelem! VIP foglalás érkezett, amely azonnali visszaigazolást kapott.',
|
|
55
94
|
},
|
|
56
95
|
en: {
|
|
57
96
|
// Guest confirmation
|
|
@@ -92,6 +131,38 @@ const translations = {
|
|
|
92
131
|
fromWebsite: 'Website',
|
|
93
132
|
fromPhone: 'Phone',
|
|
94
133
|
fromEmail: 'Email',
|
|
134
|
+
// Booking approved
|
|
135
|
+
bookingApproved: 'Your booking is confirmed!',
|
|
136
|
+
bookingApprovedMessage: 'We are pleased to inform you that your booking has been <strong>approved</strong>!',
|
|
137
|
+
bookingApprovedMessageText: 'We are pleased to inform you that your booking has been approved!',
|
|
138
|
+
prepareForArrival: 'Get ready for your arrival! We will send you more information soon.',
|
|
139
|
+
// Booking ready
|
|
140
|
+
readyForCheckin: 'Ready for Check-in!',
|
|
141
|
+
readyForCheckinMessage: 'Your accommodation is <strong>ready</strong> for your arrival! All conditions have been met for check-in.',
|
|
142
|
+
readyForCheckinMessageText: 'Your accommodation is ready for your arrival! All conditions have been met for check-in.',
|
|
143
|
+
// Booking rejected
|
|
144
|
+
bookingRejected: 'Booking Rejected',
|
|
145
|
+
bookingRejectedMessage: 'We regret to inform you that your booking <strong>could not be approved</strong>.',
|
|
146
|
+
bookingRejectedMessageText: 'We regret to inform you that your booking could not be approved.',
|
|
147
|
+
rejectionReason: 'Reason',
|
|
148
|
+
noReasonProvided: 'Not provided',
|
|
149
|
+
// Booking completed
|
|
150
|
+
bookingCompleted: 'Thank you for staying with us!',
|
|
151
|
+
bookingCompletedMessage: 'We hope you had a pleasant stay! Thank you for choosing us.',
|
|
152
|
+
feedbackRequest: 'Please rate your stay to help us maintain our high standards!',
|
|
153
|
+
// Booking cancelled
|
|
154
|
+
bookingCancelled: 'Booking Cancelled',
|
|
155
|
+
bookingCancelledMessage: 'Your booking has been <strong>cancelled</strong>.',
|
|
156
|
+
bookingCancelledMessageText: 'Your booking has been cancelled.',
|
|
157
|
+
cancellationReason: 'Cancellation reason',
|
|
158
|
+
refundAmount: 'Refund amount',
|
|
159
|
+
// VIP
|
|
160
|
+
vipConfirmation: 'VIP Booking Confirmed!',
|
|
161
|
+
vipConfirmationMessage: 'Thank you for your booking! As a premium guest, your booking has been <strong>instantly confirmed</strong>.',
|
|
162
|
+
vipConfirmationMessageText: 'Thank you for your booking! As a premium guest, your booking has been instantly confirmed.',
|
|
163
|
+
vipStaffAlert: 'VIP Booking Received!',
|
|
164
|
+
vipStaffAlertMessage: '<strong>Attention!</strong> A VIP booking has been received and instantly confirmed.',
|
|
165
|
+
vipStaffAlertMessageText: 'Attention! A VIP booking has been received and instantly confirmed.',
|
|
95
166
|
},
|
|
96
167
|
};
|
|
97
168
|
/**
|
|
@@ -436,6 +507,703 @@ ${t.paymentMethod}: ${getPaymentMethodText(booking.payment.method, lang)}
|
|
|
436
507
|
|
|
437
508
|
${t.loginToAdmin}
|
|
438
509
|
|
|
510
|
+
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
511
|
+
`.trim();
|
|
512
|
+
return { subject, html, text };
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Generate booking approved email
|
|
516
|
+
* Sent to guest when admin approves their booking (pending_approval → confirmed)
|
|
517
|
+
*/
|
|
518
|
+
function generateBookingApprovedEmail(booking, _context) {
|
|
519
|
+
const config = (0, config_1.getConfig)();
|
|
520
|
+
const lang = getLanguage(booking);
|
|
521
|
+
const t = translations[lang];
|
|
522
|
+
const accommodationName = getDisplayName(booking.accommodation.name, lang);
|
|
523
|
+
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`;
|
|
524
|
+
const currentYear = new Date().getFullYear();
|
|
525
|
+
const subject = `${t.bookingApproved} - ${accommodationName}`;
|
|
526
|
+
const html = `
|
|
527
|
+
<!DOCTYPE html>
|
|
528
|
+
<html>
|
|
529
|
+
<head>
|
|
530
|
+
<meta charset="utf-8">
|
|
531
|
+
<style>
|
|
532
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
533
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
534
|
+
.header { background-color: #28a745; color: white; padding: 20px; text-align: center; }
|
|
535
|
+
.content { padding: 20px; background-color: #f9f9f9; }
|
|
536
|
+
.details { background-color: white; padding: 15px; margin: 15px 0; border-radius: 4px; }
|
|
537
|
+
.detail-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
|
|
538
|
+
.detail-label { font-weight: bold; color: #555; }
|
|
539
|
+
.footer { padding: 20px; text-align: center; color: #777; font-size: 12px; }
|
|
540
|
+
.highlight { color: #28a745; font-weight: bold; }
|
|
541
|
+
.success-box { background-color: #d4edda; border: 1px solid #c3e6cb; padding: 15px; border-radius: 4px; margin: 15px 0; }
|
|
542
|
+
h3 { margin-top: 0; color: #333; }
|
|
543
|
+
</style>
|
|
544
|
+
</head>
|
|
545
|
+
<body>
|
|
546
|
+
<div class="container">
|
|
547
|
+
<div class="header">
|
|
548
|
+
<h1>${config.appName}</h1>
|
|
549
|
+
<h2>${t.bookingApproved}</h2>
|
|
550
|
+
</div>
|
|
551
|
+
<div class="content">
|
|
552
|
+
<p>${t.greeting(guestName)}</p>
|
|
553
|
+
<div class="success-box">
|
|
554
|
+
${t.bookingApprovedMessage}
|
|
555
|
+
</div>
|
|
556
|
+
|
|
557
|
+
<div class="details">
|
|
558
|
+
<h3>${t.accommodation}</h3>
|
|
559
|
+
<div class="detail-row">
|
|
560
|
+
<span class="detail-label">${t.accommodationName}:</span>
|
|
561
|
+
<span>${accommodationName}</span>
|
|
562
|
+
</div>
|
|
563
|
+
</div>
|
|
564
|
+
|
|
565
|
+
<div class="details">
|
|
566
|
+
<h3>${t.stayDetails}</h3>
|
|
567
|
+
<div class="detail-row">
|
|
568
|
+
<span class="detail-label">${t.checkIn}:</span>
|
|
569
|
+
<span class="highlight">${formatDate(booking.stay.checkIn, lang)}</span>
|
|
570
|
+
</div>
|
|
571
|
+
<div class="detail-row">
|
|
572
|
+
<span class="detail-label">${t.checkOut}:</span>
|
|
573
|
+
<span class="highlight">${formatDate(booking.stay.checkOut, lang)}</span>
|
|
574
|
+
</div>
|
|
575
|
+
<div class="detail-row">
|
|
576
|
+
<span class="detail-label">${t.nights}:</span>
|
|
577
|
+
<span>${booking.stay.nights} ${t.nightsUnit}</span>
|
|
578
|
+
</div>
|
|
579
|
+
<div class="detail-row">
|
|
580
|
+
<span class="detail-label">${t.guests}:</span>
|
|
581
|
+
<span>${booking.stay.guestCount} ${t.guestsUnit}</span>
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
|
|
585
|
+
<div class="details">
|
|
586
|
+
<h3>${t.paymentInfo}</h3>
|
|
587
|
+
<div class="detail-row">
|
|
588
|
+
<span class="detail-label">${t.amount}:</span>
|
|
589
|
+
<span class="highlight">${formatPrice(booking.priceDetail.totalPrice, booking.priceDetail.currency, lang)}</span>
|
|
590
|
+
</div>
|
|
591
|
+
<div class="detail-row">
|
|
592
|
+
<span class="detail-label">${t.paymentMethod}:</span>
|
|
593
|
+
<span>${getPaymentMethodText(booking.payment.method, lang)}</span>
|
|
594
|
+
</div>
|
|
595
|
+
</div>
|
|
596
|
+
|
|
597
|
+
<p>${t.prepareForArrival}</p>
|
|
598
|
+
<p>${t.contactUs}</p>
|
|
599
|
+
</div>
|
|
600
|
+
<div class="footer">
|
|
601
|
+
<p>© ${currentYear} ${config.appName}. ${t.allRightsReserved}</p>
|
|
602
|
+
</div>
|
|
603
|
+
</div>
|
|
604
|
+
</body>
|
|
605
|
+
</html>
|
|
606
|
+
`;
|
|
607
|
+
const text = `
|
|
608
|
+
${t.greeting(guestName)}
|
|
609
|
+
|
|
610
|
+
${t.bookingApprovedMessageText}
|
|
611
|
+
|
|
612
|
+
${t.accommodation.toUpperCase()}
|
|
613
|
+
${t.accommodationName}: ${accommodationName}
|
|
614
|
+
|
|
615
|
+
${t.stayDetails.toUpperCase()}
|
|
616
|
+
${t.checkIn}: ${formatDate(booking.stay.checkIn, lang)}
|
|
617
|
+
${t.checkOut}: ${formatDate(booking.stay.checkOut, lang)}
|
|
618
|
+
${t.nights}: ${booking.stay.nights} ${t.nightsUnit}
|
|
619
|
+
${t.guests}: ${booking.stay.guestCount} ${t.guestsUnit}
|
|
620
|
+
|
|
621
|
+
${t.paymentInfo.toUpperCase()}
|
|
622
|
+
${t.amount}: ${formatPrice(booking.priceDetail.totalPrice, booking.priceDetail.currency, lang)}
|
|
623
|
+
${t.paymentMethod}: ${getPaymentMethodText(booking.payment.method, lang)}
|
|
624
|
+
|
|
625
|
+
${t.prepareForArrival}
|
|
626
|
+
|
|
627
|
+
${t.contactUs}
|
|
628
|
+
|
|
629
|
+
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
630
|
+
`.trim();
|
|
631
|
+
return { subject, html, text };
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Generate booking ready email
|
|
635
|
+
* Sent to guest when booking is marked ready for check-in (confirmed → ready)
|
|
636
|
+
*/
|
|
637
|
+
function generateBookingReadyEmail(booking, _context) {
|
|
638
|
+
const config = (0, config_1.getConfig)();
|
|
639
|
+
const lang = getLanguage(booking);
|
|
640
|
+
const t = translations[lang];
|
|
641
|
+
const accommodationName = getDisplayName(booking.accommodation.name, lang);
|
|
642
|
+
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`;
|
|
643
|
+
const currentYear = new Date().getFullYear();
|
|
644
|
+
const subject = `${t.readyForCheckin} - ${accommodationName}`;
|
|
645
|
+
const html = `
|
|
646
|
+
<!DOCTYPE html>
|
|
647
|
+
<html>
|
|
648
|
+
<head>
|
|
649
|
+
<meta charset="utf-8">
|
|
650
|
+
<style>
|
|
651
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
652
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
653
|
+
.header { background-color: #20c997; color: white; padding: 20px; text-align: center; }
|
|
654
|
+
.content { padding: 20px; background-color: #f9f9f9; }
|
|
655
|
+
.details { background-color: white; padding: 15px; margin: 15px 0; border-radius: 4px; }
|
|
656
|
+
.detail-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
|
|
657
|
+
.detail-label { font-weight: bold; color: #555; }
|
|
658
|
+
.footer { padding: 20px; text-align: center; color: #777; font-size: 12px; }
|
|
659
|
+
.highlight { color: #20c997; font-weight: bold; }
|
|
660
|
+
.ready-box { background-color: #d1f2eb; border: 1px solid #b3e6d8; padding: 15px; border-radius: 4px; margin: 15px 0; }
|
|
661
|
+
h3 { margin-top: 0; color: #333; }
|
|
662
|
+
</style>
|
|
663
|
+
</head>
|
|
664
|
+
<body>
|
|
665
|
+
<div class="container">
|
|
666
|
+
<div class="header">
|
|
667
|
+
<h1>${config.appName}</h1>
|
|
668
|
+
<h2>${t.readyForCheckin}</h2>
|
|
669
|
+
</div>
|
|
670
|
+
<div class="content">
|
|
671
|
+
<p>${t.greeting(guestName)}</p>
|
|
672
|
+
<div class="ready-box">
|
|
673
|
+
${t.readyForCheckinMessage}
|
|
674
|
+
</div>
|
|
675
|
+
|
|
676
|
+
<div class="details">
|
|
677
|
+
<h3>${t.stayDetails}</h3>
|
|
678
|
+
<div class="detail-row">
|
|
679
|
+
<span class="detail-label">${t.accommodationName}:</span>
|
|
680
|
+
<span>${accommodationName}</span>
|
|
681
|
+
</div>
|
|
682
|
+
<div class="detail-row">
|
|
683
|
+
<span class="detail-label">${t.checkIn}:</span>
|
|
684
|
+
<span class="highlight">${formatDate(booking.stay.checkIn, lang)}</span>
|
|
685
|
+
</div>
|
|
686
|
+
<div class="detail-row">
|
|
687
|
+
<span class="detail-label">${t.checkOut}:</span>
|
|
688
|
+
<span class="highlight">${formatDate(booking.stay.checkOut, lang)}</span>
|
|
689
|
+
</div>
|
|
690
|
+
</div>
|
|
691
|
+
|
|
692
|
+
<p>${t.contactUs}</p>
|
|
693
|
+
</div>
|
|
694
|
+
<div class="footer">
|
|
695
|
+
<p>© ${currentYear} ${config.appName}. ${t.allRightsReserved}</p>
|
|
696
|
+
</div>
|
|
697
|
+
</div>
|
|
698
|
+
</body>
|
|
699
|
+
</html>
|
|
700
|
+
`;
|
|
701
|
+
const text = `
|
|
702
|
+
${t.greeting(guestName)}
|
|
703
|
+
|
|
704
|
+
${t.readyForCheckinMessageText}
|
|
705
|
+
|
|
706
|
+
${t.stayDetails.toUpperCase()}
|
|
707
|
+
${t.accommodationName}: ${accommodationName}
|
|
708
|
+
${t.checkIn}: ${formatDate(booking.stay.checkIn, lang)}
|
|
709
|
+
${t.checkOut}: ${formatDate(booking.stay.checkOut, lang)}
|
|
710
|
+
|
|
711
|
+
${t.contactUs}
|
|
712
|
+
|
|
713
|
+
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
714
|
+
`.trim();
|
|
715
|
+
return { subject, html, text };
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Generate booking rejected email
|
|
719
|
+
* Sent to guest when admin rejects their booking (pending_approval → cancelled)
|
|
720
|
+
*/
|
|
721
|
+
function generateBookingRejectedEmail(booking, context) {
|
|
722
|
+
const config = (0, config_1.getConfig)();
|
|
723
|
+
const lang = getLanguage(booking);
|
|
724
|
+
const t = translations[lang];
|
|
725
|
+
const accommodationName = getDisplayName(booking.accommodation.name, lang);
|
|
726
|
+
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`;
|
|
727
|
+
const currentYear = new Date().getFullYear();
|
|
728
|
+
const reason = (context === null || context === void 0 ? void 0 : context.reason) || t.noReasonProvided;
|
|
729
|
+
const subject = `${t.bookingRejected} - ${accommodationName}`;
|
|
730
|
+
const html = `
|
|
731
|
+
<!DOCTYPE html>
|
|
732
|
+
<html>
|
|
733
|
+
<head>
|
|
734
|
+
<meta charset="utf-8">
|
|
735
|
+
<style>
|
|
736
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
737
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
738
|
+
.header { background-color: #dc3545; color: white; padding: 20px; text-align: center; }
|
|
739
|
+
.content { padding: 20px; background-color: #f9f9f9; }
|
|
740
|
+
.details { background-color: white; padding: 15px; margin: 15px 0; border-radius: 4px; }
|
|
741
|
+
.detail-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
|
|
742
|
+
.detail-label { font-weight: bold; color: #555; }
|
|
743
|
+
.footer { padding: 20px; text-align: center; color: #777; font-size: 12px; }
|
|
744
|
+
.reject-box { background-color: #f8d7da; border: 1px solid #f5c6cb; padding: 15px; border-radius: 4px; margin: 15px 0; }
|
|
745
|
+
h3 { margin-top: 0; color: #333; }
|
|
746
|
+
</style>
|
|
747
|
+
</head>
|
|
748
|
+
<body>
|
|
749
|
+
<div class="container">
|
|
750
|
+
<div class="header">
|
|
751
|
+
<h1>${config.appName}</h1>
|
|
752
|
+
<h2>${t.bookingRejected}</h2>
|
|
753
|
+
</div>
|
|
754
|
+
<div class="content">
|
|
755
|
+
<p>${t.greeting(guestName)}</p>
|
|
756
|
+
<div class="reject-box">
|
|
757
|
+
${t.bookingRejectedMessage}
|
|
758
|
+
</div>
|
|
759
|
+
|
|
760
|
+
<div class="details">
|
|
761
|
+
<h3>${t.stayDetails}</h3>
|
|
762
|
+
<div class="detail-row">
|
|
763
|
+
<span class="detail-label">${t.accommodationName}:</span>
|
|
764
|
+
<span>${accommodationName}</span>
|
|
765
|
+
</div>
|
|
766
|
+
<div class="detail-row">
|
|
767
|
+
<span class="detail-label">${t.checkIn}:</span>
|
|
768
|
+
<span>${formatDate(booking.stay.checkIn, lang)}</span>
|
|
769
|
+
</div>
|
|
770
|
+
<div class="detail-row">
|
|
771
|
+
<span class="detail-label">${t.checkOut}:</span>
|
|
772
|
+
<span>${formatDate(booking.stay.checkOut, lang)}</span>
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
|
|
776
|
+
<div class="details">
|
|
777
|
+
<div class="detail-row">
|
|
778
|
+
<span class="detail-label">${t.rejectionReason}:</span>
|
|
779
|
+
<span>${reason}</span>
|
|
780
|
+
</div>
|
|
781
|
+
</div>
|
|
782
|
+
|
|
783
|
+
<p>${t.contactUs}</p>
|
|
784
|
+
</div>
|
|
785
|
+
<div class="footer">
|
|
786
|
+
<p>© ${currentYear} ${config.appName}. ${t.allRightsReserved}</p>
|
|
787
|
+
</div>
|
|
788
|
+
</div>
|
|
789
|
+
</body>
|
|
790
|
+
</html>
|
|
791
|
+
`;
|
|
792
|
+
const text = `
|
|
793
|
+
${t.greeting(guestName)}
|
|
794
|
+
|
|
795
|
+
${t.bookingRejectedMessageText}
|
|
796
|
+
|
|
797
|
+
${t.stayDetails.toUpperCase()}
|
|
798
|
+
${t.accommodationName}: ${accommodationName}
|
|
799
|
+
${t.checkIn}: ${formatDate(booking.stay.checkIn, lang)}
|
|
800
|
+
${t.checkOut}: ${formatDate(booking.stay.checkOut, lang)}
|
|
801
|
+
|
|
802
|
+
${t.rejectionReason}: ${reason}
|
|
803
|
+
|
|
804
|
+
${t.contactUs}
|
|
805
|
+
|
|
806
|
+
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
807
|
+
`.trim();
|
|
808
|
+
return { subject, html, text };
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Generate booking completed email
|
|
812
|
+
* Sent to guest after checkout (ready → completed)
|
|
813
|
+
*/
|
|
814
|
+
function generateBookingCompletedEmail(booking, _context) {
|
|
815
|
+
const config = (0, config_1.getConfig)();
|
|
816
|
+
const lang = getLanguage(booking);
|
|
817
|
+
const t = translations[lang];
|
|
818
|
+
const accommodationName = getDisplayName(booking.accommodation.name, lang);
|
|
819
|
+
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`;
|
|
820
|
+
const currentYear = new Date().getFullYear();
|
|
821
|
+
const subject = `${t.bookingCompleted} - ${accommodationName}`;
|
|
822
|
+
const html = `
|
|
823
|
+
<!DOCTYPE html>
|
|
824
|
+
<html>
|
|
825
|
+
<head>
|
|
826
|
+
<meta charset="utf-8">
|
|
827
|
+
<style>
|
|
828
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
829
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
830
|
+
.header { background-color: #17a2b8; color: white; padding: 20px; text-align: center; }
|
|
831
|
+
.content { padding: 20px; background-color: #f9f9f9; }
|
|
832
|
+
.footer { padding: 20px; text-align: center; color: #777; font-size: 12px; }
|
|
833
|
+
.thankyou-box { background-color: #d1ecf1; border: 1px solid #bee5eb; padding: 15px; border-radius: 4px; margin: 15px 0; }
|
|
834
|
+
</style>
|
|
835
|
+
</head>
|
|
836
|
+
<body>
|
|
837
|
+
<div class="container">
|
|
838
|
+
<div class="header">
|
|
839
|
+
<h1>${config.appName}</h1>
|
|
840
|
+
<h2>${t.bookingCompleted}</h2>
|
|
841
|
+
</div>
|
|
842
|
+
<div class="content">
|
|
843
|
+
<p>${t.greeting(guestName)}</p>
|
|
844
|
+
<div class="thankyou-box">
|
|
845
|
+
${t.bookingCompletedMessage}
|
|
846
|
+
</div>
|
|
847
|
+
|
|
848
|
+
<p>${t.feedbackRequest}</p>
|
|
849
|
+
<p>${t.contactUs}</p>
|
|
850
|
+
</div>
|
|
851
|
+
<div class="footer">
|
|
852
|
+
<p>© ${currentYear} ${config.appName}. ${t.allRightsReserved}</p>
|
|
853
|
+
</div>
|
|
854
|
+
</div>
|
|
855
|
+
</body>
|
|
856
|
+
</html>
|
|
857
|
+
`;
|
|
858
|
+
const text = `
|
|
859
|
+
${t.greeting(guestName)}
|
|
860
|
+
|
|
861
|
+
${t.bookingCompletedMessage}
|
|
862
|
+
|
|
863
|
+
${t.feedbackRequest}
|
|
864
|
+
|
|
865
|
+
${t.contactUs}
|
|
866
|
+
|
|
867
|
+
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
868
|
+
`.trim();
|
|
869
|
+
return { subject, html, text };
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Generate booking cancelled email
|
|
873
|
+
* Sent when a booking is cancelled (various transitions → cancelled)
|
|
874
|
+
*/
|
|
875
|
+
function generateBookingCancelledEmail(booking, context) {
|
|
876
|
+
const config = (0, config_1.getConfig)();
|
|
877
|
+
const lang = getLanguage(booking);
|
|
878
|
+
const t = translations[lang];
|
|
879
|
+
const accommodationName = getDisplayName(booking.accommodation.name, lang);
|
|
880
|
+
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`;
|
|
881
|
+
const currentYear = new Date().getFullYear();
|
|
882
|
+
const subject = `${t.bookingCancelled} - ${accommodationName}`;
|
|
883
|
+
const refundSection = (context === null || context === void 0 ? void 0 : context.refundAmount) !== undefined
|
|
884
|
+
? `
|
|
885
|
+
<div class="details">
|
|
886
|
+
<div class="detail-row">
|
|
887
|
+
<span class="detail-label">${t.refundAmount}:</span>
|
|
888
|
+
<span>${formatPrice(context.refundAmount, booking.priceDetail.currency, lang)}</span>
|
|
889
|
+
</div>
|
|
890
|
+
</div>
|
|
891
|
+
`
|
|
892
|
+
: '';
|
|
893
|
+
const html = `
|
|
894
|
+
<!DOCTYPE html>
|
|
895
|
+
<html>
|
|
896
|
+
<head>
|
|
897
|
+
<meta charset="utf-8">
|
|
898
|
+
<style>
|
|
899
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
900
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
901
|
+
.header { background-color: #6c757d; color: white; padding: 20px; text-align: center; }
|
|
902
|
+
.content { padding: 20px; background-color: #f9f9f9; }
|
|
903
|
+
.details { background-color: white; padding: 15px; margin: 15px 0; border-radius: 4px; }
|
|
904
|
+
.detail-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
|
|
905
|
+
.detail-label { font-weight: bold; color: #555; }
|
|
906
|
+
.footer { padding: 20px; text-align: center; color: #777; font-size: 12px; }
|
|
907
|
+
.cancel-box { background-color: #e2e3e5; border: 1px solid #d6d8db; padding: 15px; border-radius: 4px; margin: 15px 0; }
|
|
908
|
+
h3 { margin-top: 0; color: #333; }
|
|
909
|
+
</style>
|
|
910
|
+
</head>
|
|
911
|
+
<body>
|
|
912
|
+
<div class="container">
|
|
913
|
+
<div class="header">
|
|
914
|
+
<h1>${config.appName}</h1>
|
|
915
|
+
<h2>${t.bookingCancelled}</h2>
|
|
916
|
+
</div>
|
|
917
|
+
<div class="content">
|
|
918
|
+
<p>${t.greeting(guestName)}</p>
|
|
919
|
+
<div class="cancel-box">
|
|
920
|
+
${t.bookingCancelledMessage}
|
|
921
|
+
</div>
|
|
922
|
+
|
|
923
|
+
<div class="details">
|
|
924
|
+
<h3>${t.stayDetails}</h3>
|
|
925
|
+
<div class="detail-row">
|
|
926
|
+
<span class="detail-label">${t.accommodationName}:</span>
|
|
927
|
+
<span>${accommodationName}</span>
|
|
928
|
+
</div>
|
|
929
|
+
<div class="detail-row">
|
|
930
|
+
<span class="detail-label">${t.checkIn}:</span>
|
|
931
|
+
<span>${formatDate(booking.stay.checkIn, lang)}</span>
|
|
932
|
+
</div>
|
|
933
|
+
<div class="detail-row">
|
|
934
|
+
<span class="detail-label">${t.checkOut}:</span>
|
|
935
|
+
<span>${formatDate(booking.stay.checkOut, lang)}</span>
|
|
936
|
+
</div>
|
|
937
|
+
</div>
|
|
938
|
+
|
|
939
|
+
${refundSection}
|
|
940
|
+
|
|
941
|
+
<p>${t.contactUs}</p>
|
|
942
|
+
</div>
|
|
943
|
+
<div class="footer">
|
|
944
|
+
<p>© ${currentYear} ${config.appName}. ${t.allRightsReserved}</p>
|
|
945
|
+
</div>
|
|
946
|
+
</div>
|
|
947
|
+
</body>
|
|
948
|
+
</html>
|
|
949
|
+
`;
|
|
950
|
+
const refundText = (context === null || context === void 0 ? void 0 : context.refundAmount) !== undefined
|
|
951
|
+
? `\n${t.refundAmount}: ${formatPrice(context.refundAmount, booking.priceDetail.currency, lang)}\n`
|
|
952
|
+
: '';
|
|
953
|
+
const text = `
|
|
954
|
+
${t.greeting(guestName)}
|
|
955
|
+
|
|
956
|
+
${t.bookingCancelledMessageText}
|
|
957
|
+
|
|
958
|
+
${t.stayDetails.toUpperCase()}
|
|
959
|
+
${t.accommodationName}: ${accommodationName}
|
|
960
|
+
${t.checkIn}: ${formatDate(booking.stay.checkIn, lang)}
|
|
961
|
+
${t.checkOut}: ${formatDate(booking.stay.checkOut, lang)}
|
|
962
|
+
${refundText}
|
|
963
|
+
${t.contactUs}
|
|
964
|
+
|
|
965
|
+
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
966
|
+
`.trim();
|
|
967
|
+
return { subject, html, text };
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Generate VIP confirmation email
|
|
971
|
+
* Sent to VIP guest when booking is instantly confirmed (express workflow)
|
|
972
|
+
*/
|
|
973
|
+
function generateVipConfirmationEmail(booking, _context) {
|
|
974
|
+
const config = (0, config_1.getConfig)();
|
|
975
|
+
const lang = getLanguage(booking);
|
|
976
|
+
const t = translations[lang];
|
|
977
|
+
const accommodationName = getDisplayName(booking.accommodation.name, lang);
|
|
978
|
+
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`;
|
|
979
|
+
const currentYear = new Date().getFullYear();
|
|
980
|
+
const subject = `${t.vipConfirmation} - ${accommodationName}`;
|
|
981
|
+
const html = `
|
|
982
|
+
<!DOCTYPE html>
|
|
983
|
+
<html>
|
|
984
|
+
<head>
|
|
985
|
+
<meta charset="utf-8">
|
|
986
|
+
<style>
|
|
987
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
988
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
989
|
+
.header { background-color: #9b59b6; color: white; padding: 20px; text-align: center; }
|
|
990
|
+
.content { padding: 20px; background-color: #f9f9f9; }
|
|
991
|
+
.details { background-color: white; padding: 15px; margin: 15px 0; border-radius: 4px; }
|
|
992
|
+
.detail-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
|
|
993
|
+
.detail-label { font-weight: bold; color: #555; }
|
|
994
|
+
.footer { padding: 20px; text-align: center; color: #777; font-size: 12px; }
|
|
995
|
+
.highlight { color: #9b59b6; font-weight: bold; }
|
|
996
|
+
.vip-box { background-color: #e8daef; border: 1px solid #d7bde2; padding: 15px; border-radius: 4px; margin: 15px 0; }
|
|
997
|
+
h3 { margin-top: 0; color: #333; }
|
|
998
|
+
</style>
|
|
999
|
+
</head>
|
|
1000
|
+
<body>
|
|
1001
|
+
<div class="container">
|
|
1002
|
+
<div class="header">
|
|
1003
|
+
<h1>${config.appName}</h1>
|
|
1004
|
+
<h2>${t.vipConfirmation}</h2>
|
|
1005
|
+
</div>
|
|
1006
|
+
<div class="content">
|
|
1007
|
+
<p>${t.greeting(guestName)}</p>
|
|
1008
|
+
<div class="vip-box">
|
|
1009
|
+
${t.vipConfirmationMessage}
|
|
1010
|
+
</div>
|
|
1011
|
+
|
|
1012
|
+
<div class="details">
|
|
1013
|
+
<h3>${t.accommodation}</h3>
|
|
1014
|
+
<div class="detail-row">
|
|
1015
|
+
<span class="detail-label">${t.accommodationName}:</span>
|
|
1016
|
+
<span>${accommodationName}</span>
|
|
1017
|
+
</div>
|
|
1018
|
+
</div>
|
|
1019
|
+
|
|
1020
|
+
<div class="details">
|
|
1021
|
+
<h3>${t.stayDetails}</h3>
|
|
1022
|
+
<div class="detail-row">
|
|
1023
|
+
<span class="detail-label">${t.checkIn}:</span>
|
|
1024
|
+
<span class="highlight">${formatDate(booking.stay.checkIn, lang)}</span>
|
|
1025
|
+
</div>
|
|
1026
|
+
<div class="detail-row">
|
|
1027
|
+
<span class="detail-label">${t.checkOut}:</span>
|
|
1028
|
+
<span class="highlight">${formatDate(booking.stay.checkOut, lang)}</span>
|
|
1029
|
+
</div>
|
|
1030
|
+
<div class="detail-row">
|
|
1031
|
+
<span class="detail-label">${t.nights}:</span>
|
|
1032
|
+
<span>${booking.stay.nights} ${t.nightsUnit}</span>
|
|
1033
|
+
</div>
|
|
1034
|
+
<div class="detail-row">
|
|
1035
|
+
<span class="detail-label">${t.guests}:</span>
|
|
1036
|
+
<span>${booking.stay.guestCount} ${t.guestsUnit}</span>
|
|
1037
|
+
</div>
|
|
1038
|
+
</div>
|
|
1039
|
+
|
|
1040
|
+
<div class="details">
|
|
1041
|
+
<h3>${t.paymentInfo}</h3>
|
|
1042
|
+
<div class="detail-row">
|
|
1043
|
+
<span class="detail-label">${t.amount}:</span>
|
|
1044
|
+
<span class="highlight">${formatPrice(booking.priceDetail.totalPrice, booking.priceDetail.currency, lang)}</span>
|
|
1045
|
+
</div>
|
|
1046
|
+
<div class="detail-row">
|
|
1047
|
+
<span class="detail-label">${t.paymentMethod}:</span>
|
|
1048
|
+
<span>${getPaymentMethodText(booking.payment.method, lang)}</span>
|
|
1049
|
+
</div>
|
|
1050
|
+
</div>
|
|
1051
|
+
|
|
1052
|
+
<p>${t.contactUs}</p>
|
|
1053
|
+
</div>
|
|
1054
|
+
<div class="footer">
|
|
1055
|
+
<p>© ${currentYear} ${config.appName}. ${t.allRightsReserved}</p>
|
|
1056
|
+
</div>
|
|
1057
|
+
</div>
|
|
1058
|
+
</body>
|
|
1059
|
+
</html>
|
|
1060
|
+
`;
|
|
1061
|
+
const text = `
|
|
1062
|
+
${t.greeting(guestName)}
|
|
1063
|
+
|
|
1064
|
+
${t.vipConfirmationMessageText}
|
|
1065
|
+
|
|
1066
|
+
${t.accommodation.toUpperCase()}
|
|
1067
|
+
${t.accommodationName}: ${accommodationName}
|
|
1068
|
+
|
|
1069
|
+
${t.stayDetails.toUpperCase()}
|
|
1070
|
+
${t.checkIn}: ${formatDate(booking.stay.checkIn, lang)}
|
|
1071
|
+
${t.checkOut}: ${formatDate(booking.stay.checkOut, lang)}
|
|
1072
|
+
${t.nights}: ${booking.stay.nights} ${t.nightsUnit}
|
|
1073
|
+
${t.guests}: ${booking.stay.guestCount} ${t.guestsUnit}
|
|
1074
|
+
|
|
1075
|
+
${t.paymentInfo.toUpperCase()}
|
|
1076
|
+
${t.amount}: ${formatPrice(booking.priceDetail.totalPrice, booking.priceDetail.currency, lang)}
|
|
1077
|
+
${t.paymentMethod}: ${getPaymentMethodText(booking.payment.method, lang)}
|
|
1078
|
+
|
|
1079
|
+
${t.contactUs}
|
|
1080
|
+
|
|
1081
|
+
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
1082
|
+
`.trim();
|
|
1083
|
+
return { subject, html, text };
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Generate VIP staff notification email
|
|
1087
|
+
* Sent to staff when a VIP booking is instantly confirmed
|
|
1088
|
+
* Always in Hungarian
|
|
1089
|
+
*/
|
|
1090
|
+
function generateVipStaffNotificationEmail(booking, _context) {
|
|
1091
|
+
const config = (0, config_1.getConfig)();
|
|
1092
|
+
const lang = 'hu'; // Staff emails always in Hungarian
|
|
1093
|
+
const t = translations[lang];
|
|
1094
|
+
const accommodationName = getDisplayName(booking.accommodation.name, lang);
|
|
1095
|
+
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`;
|
|
1096
|
+
const currentYear = new Date().getFullYear();
|
|
1097
|
+
const subject = `${t.vipStaffAlert} - ${accommodationName}`;
|
|
1098
|
+
const html = `
|
|
1099
|
+
<!DOCTYPE html>
|
|
1100
|
+
<html>
|
|
1101
|
+
<head>
|
|
1102
|
+
<meta charset="utf-8">
|
|
1103
|
+
<style>
|
|
1104
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
1105
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
1106
|
+
.header { background-color: #9b59b6; color: white; padding: 20px; text-align: center; }
|
|
1107
|
+
.content { padding: 20px; background-color: #f9f9f9; }
|
|
1108
|
+
.details { background-color: white; padding: 15px; margin: 15px 0; border-radius: 4px; }
|
|
1109
|
+
.detail-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
|
|
1110
|
+
.detail-label { font-weight: bold; color: #555; }
|
|
1111
|
+
.footer { padding: 20px; text-align: center; color: #777; font-size: 12px; }
|
|
1112
|
+
.highlight { color: #9b59b6; font-weight: bold; }
|
|
1113
|
+
.vip-alert { background-color: #FFF3CD; border: 1px solid #FFECB5; padding: 15px; border-radius: 4px; margin: 15px 0; }
|
|
1114
|
+
h3 { margin-top: 0; color: #333; }
|
|
1115
|
+
</style>
|
|
1116
|
+
</head>
|
|
1117
|
+
<body>
|
|
1118
|
+
<div class="container">
|
|
1119
|
+
<div class="header">
|
|
1120
|
+
<h1>${config.appName}</h1>
|
|
1121
|
+
<h2>${t.vipStaffAlert}</h2>
|
|
1122
|
+
</div>
|
|
1123
|
+
<div class="content">
|
|
1124
|
+
<div class="vip-alert">
|
|
1125
|
+
${t.vipStaffAlertMessage}
|
|
1126
|
+
</div>
|
|
1127
|
+
|
|
1128
|
+
<div class="details">
|
|
1129
|
+
<h3>${t.guestDetails}</h3>
|
|
1130
|
+
<div class="detail-row">
|
|
1131
|
+
<span class="detail-label">${t.name}:</span>
|
|
1132
|
+
<span class="highlight">${guestName}</span>
|
|
1133
|
+
</div>
|
|
1134
|
+
<div class="detail-row">
|
|
1135
|
+
<span class="detail-label">${t.email}:</span>
|
|
1136
|
+
<span>${booking.guest.email}</span>
|
|
1137
|
+
</div>
|
|
1138
|
+
${booking.guest.phoneNumber
|
|
1139
|
+
? `
|
|
1140
|
+
<div class="detail-row">
|
|
1141
|
+
<span class="detail-label">${t.phone}:</span>
|
|
1142
|
+
<span>${booking.guest.phoneNumber}</span>
|
|
1143
|
+
</div>
|
|
1144
|
+
`
|
|
1145
|
+
: ''}
|
|
1146
|
+
</div>
|
|
1147
|
+
|
|
1148
|
+
<div class="details">
|
|
1149
|
+
<h3>${t.stayDetails}</h3>
|
|
1150
|
+
<div class="detail-row">
|
|
1151
|
+
<span class="detail-label">${t.accommodationName}:</span>
|
|
1152
|
+
<span>${accommodationName}</span>
|
|
1153
|
+
</div>
|
|
1154
|
+
<div class="detail-row">
|
|
1155
|
+
<span class="detail-label">${t.checkIn}:</span>
|
|
1156
|
+
<span class="highlight">${formatDate(booking.stay.checkIn, lang)}</span>
|
|
1157
|
+
</div>
|
|
1158
|
+
<div class="detail-row">
|
|
1159
|
+
<span class="detail-label">${t.checkOut}:</span>
|
|
1160
|
+
<span class="highlight">${formatDate(booking.stay.checkOut, lang)}</span>
|
|
1161
|
+
</div>
|
|
1162
|
+
<div class="detail-row">
|
|
1163
|
+
<span class="detail-label">${t.nights}:</span>
|
|
1164
|
+
<span>${booking.stay.nights} ${t.nightsUnit}</span>
|
|
1165
|
+
</div>
|
|
1166
|
+
<div class="detail-row">
|
|
1167
|
+
<span class="detail-label">${t.guests}:</span>
|
|
1168
|
+
<span>${booking.stay.guestCount} ${t.guestsUnit}</span>
|
|
1169
|
+
</div>
|
|
1170
|
+
</div>
|
|
1171
|
+
|
|
1172
|
+
<div class="details">
|
|
1173
|
+
<h3>${t.paymentInfo}</h3>
|
|
1174
|
+
<div class="detail-row">
|
|
1175
|
+
<span class="detail-label">${t.amount}:</span>
|
|
1176
|
+
<span class="highlight">${formatPrice(booking.priceDetail.totalPrice, booking.priceDetail.currency, lang)}</span>
|
|
1177
|
+
</div>
|
|
1178
|
+
</div>
|
|
1179
|
+
</div>
|
|
1180
|
+
<div class="footer">
|
|
1181
|
+
<p>© ${currentYear} ${config.appName}. ${t.allRightsReserved}</p>
|
|
1182
|
+
</div>
|
|
1183
|
+
</div>
|
|
1184
|
+
</body>
|
|
1185
|
+
</html>
|
|
1186
|
+
`;
|
|
1187
|
+
const text = `
|
|
1188
|
+
${t.vipStaffAlert.toUpperCase()}
|
|
1189
|
+
|
|
1190
|
+
${t.vipStaffAlertMessageText}
|
|
1191
|
+
|
|
1192
|
+
${t.guestDetails.toUpperCase()}
|
|
1193
|
+
${t.name}: ${guestName}
|
|
1194
|
+
${t.email}: ${booking.guest.email}
|
|
1195
|
+
${booking.guest.phoneNumber ? `${t.phone}: ${booking.guest.phoneNumber}` : ''}
|
|
1196
|
+
|
|
1197
|
+
${t.stayDetails.toUpperCase()}
|
|
1198
|
+
${t.accommodationName}: ${accommodationName}
|
|
1199
|
+
${t.checkIn}: ${formatDate(booking.stay.checkIn, lang)}
|
|
1200
|
+
${t.checkOut}: ${formatDate(booking.stay.checkOut, lang)}
|
|
1201
|
+
${t.nights}: ${booking.stay.nights} ${t.nightsUnit}
|
|
1202
|
+
${t.guests}: ${booking.stay.guestCount} ${t.guestsUnit}
|
|
1203
|
+
|
|
1204
|
+
${t.paymentInfo.toUpperCase()}
|
|
1205
|
+
${t.amount}: ${formatPrice(booking.priceDetail.totalPrice, booking.priceDetail.currency, lang)}
|
|
1206
|
+
|
|
439
1207
|
© ${currentYear} ${config.appName}. ${t.allRightsReserved}
|
|
440
1208
|
`.trim();
|
|
441
1209
|
return { subject, html, text };
|