@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.
Files changed (34) hide show
  1. package/lib/config/app.config.d.ts +13 -0
  2. package/lib/config/app.config.d.ts.map +1 -1
  3. package/lib/config/app.config.js.map +1 -1
  4. package/lib/index.d.ts +1 -0
  5. package/lib/index.d.ts.map +1 -1
  6. package/lib/index.js +1 -0
  7. package/lib/index.js.map +1 -1
  8. package/lib/modules/booking/booking-email.templates.d.ts +52 -0
  9. package/lib/modules/booking/booking-email.templates.d.ts.map +1 -1
  10. package/lib/modules/booking/booking-email.templates.js +768 -0
  11. package/lib/modules/booking/booking-email.templates.js.map +1 -1
  12. package/lib/modules/booking/booking-email.triggers.d.ts.map +1 -1
  13. package/lib/modules/booking/booking-email.triggers.js.map +1 -1
  14. package/lib/modules/events/booking-event.handlers.d.ts +44 -0
  15. package/lib/modules/events/booking-event.handlers.d.ts.map +1 -0
  16. package/lib/modules/events/booking-event.handlers.js +274 -0
  17. package/lib/modules/events/booking-event.handlers.js.map +1 -0
  18. package/lib/modules/events/booking-event.models.d.ts +109 -0
  19. package/lib/modules/events/booking-event.models.d.ts.map +1 -0
  20. package/lib/modules/events/booking-event.models.js +110 -0
  21. package/lib/modules/events/booking-event.models.js.map +1 -0
  22. package/lib/modules/events/booking-event.triggers.d.ts +46 -0
  23. package/lib/modules/events/booking-event.triggers.d.ts.map +1 -0
  24. package/lib/modules/events/booking-event.triggers.js +178 -0
  25. package/lib/modules/events/booking-event.triggers.js.map +1 -0
  26. package/lib/modules/events/event.models.d.ts +53 -0
  27. package/lib/modules/events/event.models.d.ts.map +1 -0
  28. package/lib/modules/events/event.models.js +18 -0
  29. package/lib/modules/events/event.models.js.map +1 -0
  30. package/lib/modules/events/index.d.ts +29 -0
  31. package/lib/modules/events/index.d.ts.map +1 -0
  32. package/lib/modules/events/index.js +49 -0
  33. package/lib/modules/events/index.js.map +1 -0
  34. 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>&copy; ${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>&copy; ${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>&copy; ${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>&copy; ${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>&copy; ${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>&copy; ${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>&copy; ${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 };