From c5b868e20177156ec0823e9edee5bbc370d14afb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E2=80=9Ckirukib=E2=80=9D?= <“kirubeljkl679@gmail.com”>
Date: Thu, 2 Apr 2026 11:11:29 +0300
Subject: [PATCH] add booking rating templates
Made-with: Cursor
---
src/App.tsx | 2 +-
src/components/EmailPreview.tsx | 2 +-
src/templates/templates.tsx | 495 ++++++++++++++++++++++++++++++++
3 files changed, 497 insertions(+), 2 deletions(-)
diff --git a/src/App.tsx b/src/App.tsx
index 6a37770..ffa3263 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -83,7 +83,7 @@ export default function App() {
},
grid: {
display: 'grid',
- gridTemplateColumns: '420px 1fr',
+ gridTemplateColumns: 'repeat(auto-fit, minmax(360px, 1fr))',
gap: 16,
alignItems: 'start',
},
diff --git a/src/components/EmailPreview.tsx b/src/components/EmailPreview.tsx
index e4f2609..4bbb995 100644
--- a/src/components/EmailPreview.tsx
+++ b/src/components/EmailPreview.tsx
@@ -11,7 +11,7 @@ export function EmailPreview({ html, loading }: { html: string; loading: boolean
) : (
Generate a preview to see the email here.
diff --git a/src/templates/templates.tsx b/src/templates/templates.tsx
index de48a8f..6495f55 100644
--- a/src/templates/templates.tsx
+++ b/src/templates/templates.tsx
@@ -584,6 +584,501 @@ const templates: EmailTemplateDefinition[] = [
)
},
},
+
+
+ {
+ id: 'booking_successful',
+ name: 'Successful Booking',
+ subjectTemplate: 'Your stay is confirmed, {{guestName}} ({{bookingId}})',
+ ctaLabel: 'View booking',
+ ctaHrefTemplate:
+ 'https://shitaye-hotel.kirubeljkl679.workers.dev/?bookingId={{bookingId}}',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Sarah M.' },
+ { key: 'bookingId', label: 'Booking ID', defaultValue: 'SH-8421' },
+ { key: 'roomType', label: 'Room type', defaultValue: 'Junior Studio' },
+ { key: 'checkInDate', label: 'Check-in date', inputType: 'date', defaultValue: '2026-04-15' },
+ { key: 'checkOutDate', label: 'Check-out date', inputType: 'date', defaultValue: '2026-04-18' },
+ ],
+ Component: function BookingSuccessfulEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const bookingId = data.bookingId || ''
+ const roomType = data.roomType || 'Room'
+ const checkInDate = data.checkInDate || '—'
+ const checkOutDate = data.checkOutDate || '—'
+ const href = interpolate('https://shitaye-hotel.kirubeljkl679.workers.dev/?bookingId={{bookingId}}', { bookingId })
+
+ return (
+
+
+ Stay confirmed
+
+
+ Hi {guestName},
+
+
+ We’re excited to host you at {brand.hotelName}. Your reservation for a{' '}
+ {roomType} is confirmed.
+
+
+
+
+
+
+
+ If you need any assistance before arrival, contact reception using the details in the footer.
+
+
+ )
+ },
+ },
+
+ {
+ id: 'booking_canceled',
+ name: 'Booking Cancelled (alt)',
+ subjectTemplate: 'Your booking has been cancelled, {{guestName}}',
+ ctaLabel: 'Book again',
+ ctaHrefTemplate: 'https://shitaye-hotel.kirubeljkl679.workers.dev/',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Hanna T.' },
+ { key: 'bookingId', label: 'Booking ID', defaultValue: 'SH-8421' },
+ { key: 'cancellationDate', label: 'Cancellation date', inputType: 'date', defaultValue: '2026-04-10' },
+ { key: 'cancellationReason', label: 'Cancellation reason', defaultValue: 'Schedule change' },
+ ],
+ Component: function BookingCanceledEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const bookingId = data.bookingId || ''
+ const cancellationDate = data.cancellationDate || '—'
+ const cancellationReason = data.cancellationReason || ''
+
+ return (
+
+
+ Booking cancelled
+
+
+ Hi {guestName}, we’re letting you know that booking {bookingId} has been cancelled.
+
+
+
+
+
+
+
+ If you have questions, reply to this email or contact reception.
+
+
+ )
+ },
+ },
+
+ {
+ id: 'laundry_order_confirmation',
+ name: 'Laundry Order Confirmation',
+ subjectTemplate: 'Your laundry order {{orderId}} is confirmed, {{guestName}}',
+ ctaLabel: 'Track laundry',
+ ctaHrefTemplate: 'https://shitaye-hotel.kirubeljkl679.workers.dev/laundry/status?order={{orderId}}',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Hanna T.' },
+ { key: 'orderId', label: 'Order ID', defaultValue: 'LA-55902' },
+ { key: 'serviceType', label: 'Service type', defaultValue: 'Wash & Fold' },
+ { key: 'pickupWindow', label: 'Pickup window', defaultValue: 'Today 6:00 PM - 7:30 PM' },
+ { key: 'deliveryWindow', label: 'Delivery window', defaultValue: 'Tomorrow 2:00 PM - 4:00 PM' },
+ { key: 'itemsDescription', label: 'Laundry notes / items', defaultValue: 'Shirts (6) + Trousers (3)' },
+ ],
+ Component: function LaundryOrderConfirmationEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const orderId = data.orderId || ''
+ const serviceType = data.serviceType || ''
+ const pickupWindow = data.pickupWindow || ''
+ const deliveryWindow = data.deliveryWindow || ''
+ const itemsDescription = data.itemsDescription || ''
+ const href = interpolate(
+ 'https://shitaye-hotel.kirubeljkl679.workers.dev/laundry/status?order={{orderId}}',
+ { orderId },
+ )
+
+ return (
+
+
+ Laundry order received
+
+
+ Hi {guestName}, we’ve received your laundry request ({orderId}).
+
+
+
+
+
+
+
+ We’ll send updates as your order moves through pickup and delivery.
+
+
+ )
+ },
+ },
+
+ {
+ id: 'room_service_order_confirmation',
+ name: 'Room Service Order Confirmation',
+ subjectTemplate: 'Your room service order {{orderId}} is confirmed, {{guestName}}',
+ ctaLabel: 'Track order',
+ ctaHrefTemplate: 'https://shitaye-hotel.kirubeljkl679.workers.dev/room-service/status?order={{orderId}}',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Daniel K.' },
+ { key: 'orderId', label: 'Order ID', defaultValue: 'RS-1029' },
+ { key: 'items', label: 'Items / notes', defaultValue: 'Breakfast tray (1) + Coffee (2)' },
+ { key: 'orderTime', label: 'Order time', defaultValue: 'Today 8:15 PM' },
+ { key: 'etaWindow', label: 'Estimated delivery', defaultValue: 'Within 25-35 minutes' },
+ ],
+ Component: function RoomServiceOrderConfirmationEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const orderId = data.orderId || ''
+ const items = data.items || ''
+ const orderTime = data.orderTime || ''
+ const etaWindow = data.etaWindow || ''
+
+ const href = interpolate(
+ 'https://shitaye-hotel.kirubeljkl679.workers.dev/room-service/status?order={{orderId}}',
+ { orderId },
+ )
+
+ return (
+
+
+ Room service confirmed
+
+
+ Hi {guestName}, we’ve received your room service order ({orderId}).
+
+
+
+
+ Order time
+ {orderTime}
+
+
+
+ Items / notes
+ {items}
+
+
+
+ Estimated delivery
+ {etaWindow}
+
+
+
+
+
+
+ If anything changes, reply to this email and we’ll assist you.
+
+
+ )
+ },
+ },
+
+ {
+ id: 'prize_winning',
+ name: 'Prize Winning',
+ subjectTemplate: 'Congratulations {{guestName}}! You won {{prizeName}}',
+ ctaLabel: 'Claim prize',
+ ctaHrefTemplate: 'https://shitaye-hotel.kirubeljkl679.workers.dev/prizes/claim?raffle={{raffleName}}&prize={{prizeName}}',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Sarah M.' },
+ { key: 'raffleName', label: 'Raffle name', defaultValue: 'FeastVille Lucky Draw' },
+ { key: 'prizeName', label: 'Prize name', defaultValue: 'Spa Session for Two' },
+ { key: 'claimByDate', label: 'Claim by', inputType: 'date', defaultValue: '2026-05-17' },
+ {
+ key: 'claimSteps',
+ label: 'Claim instructions',
+ defaultValue:
+ '1) Reply to this email; 2) Provide your entry code; 3) Our team will confirm your appointment',
+ },
+ ],
+ Component: function PrizeWinningEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const raffleName = data.raffleName || 'Raffle'
+ const prizeName = data.prizeName || 'Prize'
+ const claimByDate = data.claimByDate || '—'
+ const claimSteps = data.claimSteps || ''
+
+ const href = interpolate(
+ 'https://shitaye-hotel.kirubeljkl679.workers.dev/prizes/claim?raffle={{raffleName}}&prize={{prizeName}}',
+ { raffleName, prizeName },
+ )
+
+ return (
+
+
+ Congratulations!
+
+
+ You’ve won {prizeName} from {raffleName}.
+
+
+
+
+
+
+
+ {claimSteps.split(';').map((line, idx) => (
+
+ {line.trim()}
+
+
+ ))}
+
+
+
+
+
+
+
+ Need help? Contact us using the footer details.
+
+
+ )
+ },
+ },
+
+ {
+ id: 'points_awarded',
+ name: 'Points Awarded',
+ subjectTemplate: 'You were awarded {{pointsAwarded}} points, {{guestName}}',
+ ctaLabel: 'View rewards',
+ ctaHrefTemplate: 'https://shitaye-hotel.kirubeljkl679.workers.dev/loyalty?points={{pointsAwarded}}',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Hanna T.' },
+ { key: 'pointsAwarded', label: 'Points awarded', inputType: 'number', defaultValue: '120' },
+ { key: 'newBalance', label: 'New points balance', inputType: 'number', defaultValue: '840' },
+ { key: 'rewardDescription', label: 'Reward note', defaultValue: 'Thanks for staying with us. Keep booking to unlock premium perks!' },
+ { key: 'expiryDate', label: 'Expiry date', inputType: 'date', defaultValue: '2027-04-30' },
+ ],
+ Component: function PointsAwardedEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const pointsAwarded = data.pointsAwarded || '0'
+ const newBalance = data.newBalance || '0'
+ const rewardDescription = data.rewardDescription || ''
+ const expiryDate = data.expiryDate || '—'
+
+ const href = interpolate(
+ 'https://shitaye-hotel.kirubeljkl679.workers.dev/loyalty?points={{pointsAwarded}}',
+ { pointsAwarded },
+ )
+
+ return (
+
+
+ Points update
+
+
+ Hi {guestName}, you’ve been awarded {pointsAwarded} points. Your new balance is {newBalance}.
+
+
+
+
+
+
+
+ Rewards are our way of saying thank you for choosing {brand.hotelName}.
+
+
+ )
+ },
+ },
+
+ {
+ id: 'booking_rating_google',
+ name: 'Booking Rating (Google)',
+ subjectTemplate: 'Rate your stay at {{hotelName}} — {{guestName}}',
+ ctaLabel: 'Leave a Google review',
+ ctaHrefTemplate: '{{googleReviewUrl}}',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Sarah M.' },
+ { key: 'bookingId', label: 'Booking ID', defaultValue: 'SH-8421' },
+ { key: 'googleReviewUrl', label: 'Google review URL', defaultValue: 'https://g.page/r/your-hotel/review' },
+ { key: 'stayDate', label: 'Stay date (optional)', defaultValue: 'April 2026' },
+ ],
+ Component: function BookingRatingGoogleEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const bookingId = data.bookingId || ''
+ const googleReviewUrl = data.googleReviewUrl || '#'
+ const stayDate = data.stayDate || ''
+
+ const replyHref = `mailto:${brand.footer.email || 'reservations@example.com'}?subject=${encodeURI(
+ 'Feedback for booking ' + bookingId
+ )}`
+
+ return (
+
+
+ How was your stay?
+
+
+ Hi {guestName}, thank you for staying with us at {brand.hotelName}.
+ {stayDate ? (
+ <>
+ {' '}Your stay: {stayDate}.
+ >
+ ) : null}
+
+
+
+
+ Please share your experience with a quick review. It only takes a moment.
+
+
+
+
+
+
+ Prefer to share feedback directly? Reply to this email and our team will respond.
+ {' '}
+
+ Reply now
+
+
+
+ )
+ },
+ },
+
+ {
+ id: 'booking_rating_personal',
+ name: 'Booking Rating (Direct Reply)',
+ subjectTemplate: 'Help us improve: reply with your feedback, {{guestName}}',
+ ctaLabel: 'Reply to this email',
+ ctaHrefTemplate: 'mailto:{{contactEmail}}',
+ variables: [
+ { key: 'guestName', label: 'Guest name', defaultValue: 'Daniel K.' },
+ { key: 'bookingId', label: 'Booking ID', defaultValue: 'SH-8421' },
+ { key: 'ratingScale', label: 'Rating scale text (optional)', defaultValue: '1 (low) to 5 (excellent)' },
+ ],
+ Component: function BookingRatingPersonalEmail({ brand, data }) {
+ const guestName = data.guestName || 'Guest'
+ const bookingId = data.bookingId || ''
+ const ratingScale = data.ratingScale || ''
+
+ const href = `mailto:${brand.footer.email || 'reservations@example.com'}?subject=${encodeURI(
+ 'Feedback for booking ' + bookingId
+ )}`
+
+ return (
+
+
+ Your feedback matters
+
+
+ Hi {guestName}, we’re always improving. If you have a few seconds, please reply with how
+ your stay went for booking {bookingId}.
+
+
+
+
+ {ratingScale ? (
+ <>
+ Suggested scale: {ratingScale}.
+ >
+ ) : null}
+ {' '}Feel free to add any comments.
+
+
+
+
+
+
+ Thanks for choosing {brand.hotelName}.
+
+
+ )
+ },
+ },
+
]
export { templates as templateRegistry }