Files
Bookra/apps/auth-service/internal/email/templates.go
T
Tomas Dvorak 48c3e15a38 cleanup
2026-05-05 09:48:07 +02:00

744 lines
34 KiB
Go

package email
import (
"fmt"
)
// Bookra Design System - Warm editorial aesthetic
// Canvas: warm cream backgrounds (#fbf9f6)
// Ink: warm dark brown (#2a221e)
// Accent: terracotta (#a65c3e)
// Logo bg: #24201d, Logo text: #f7f2e8
const (
canvas = "#fbf9f6" // Warm cream background
canvasSubtle = "#f5f2ed" // Slightly darker cream
ink = "#2a221e" // Warm dark brown
inkMuted = "#5c514a" // Muted brown
inkSubtle = "#8b7f76" // Light muted brown
accent = "#a65c3e" // Terracotta
accentHover = "#8f4d33" // Darker terracotta
accentSubtle = "#f5ebe7" // Light terracotta tint
logoBg = "#24201d" // Logo dark brown
logoText = "#f7f2e8" // Logo cream
border = "#e8e2da" // Warm border
white = "#ffffff"
)
type EmailTemplate struct {
Subject string
HTML string
Text string
}
func MagicLinkEmail(toName, magicURL string, locale string) EmailTemplate {
if locale == "cs" {
return magicLinkEmailCS(toName, magicURL)
}
return magicLinkEmailEN(toName, magicURL)
}
func WelcomeEmail(name string, locale string) EmailTemplate {
if locale == "cs" {
return welcomeEmailCS(name)
}
return welcomeEmailEN(name)
}
func BookingConfirmationEmail(customerName, businessName, serviceName, dateTime, location string, locale string) EmailTemplate {
if locale == "cs" {
return bookingConfirmationCS(customerName, businessName, serviceName, dateTime, location)
}
return bookingConfirmationEN(customerName, businessName, serviceName, dateTime, location)
}
func PasswordResetEmail(name, resetURL string, locale string) EmailTemplate {
if locale == "cs" {
return passwordResetCS(name, resetURL)
}
return passwordResetEN(name, resetURL)
}
func magicLinkEmailEN(toName, magicURL string) EmailTemplate {
subject := "Your sign-in link for Bookra"
if toName == "" {
toName = "there"
}
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>%s</title>
<style>
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; letter-spacing: -0.02em; }
.tagline { color: %s; font-size: 15px; margin-top: 6px; font-style: italic; }
.content { padding: 48px 40px; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 20px; font-weight: 600; color: %s; margin-bottom: 16px; }
.message { font-size: 17px; line-height: 1.6; color: %s; margin-bottom: 32px; }
.button-wrap { margin: 40px 0; }
.button { display: inline-block; background: %s; color: %s; padding: 16px 40px; text-decoration: none; border-radius: 8px; font-family: 'Space Grotesk', sans-serif; font-weight: 500; font-size: 15px; transition: background 0.2s; }
.button:hover { background: %s; }
.link-box { background: %s; border: 1px solid %s; border-radius: 8px; padding: 20px; margin: 32px 0; }
.link-label { font-size: 12px; font-weight: 600; color: %s; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 8px; font-family: 'Space Grotesk', sans-serif; }
.link-url { font-size: 14px; color: %s; word-break: break-all; font-family: 'JetBrains Mono', monospace; }
.expiry { background: %s; border-left: 3px solid %s; padding: 16px 20px; margin: 32px 0; font-size: 15px; color: %s; }
.help { font-size: 15px; color: %s; margin-top: 40px; padding-top: 32px; border-top: 1px solid %s; font-style: italic; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
.footer-links { margin-top: 12px; }
.footer-links a { color: %s; text-decoration: none; font-size: 13px; margin: 0 12px; font-family: 'Space Grotesk', sans-serif; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
<div class="tagline">Calm booking software</div>
</div>
<div class="content">
<div class="greeting">Hi %s,</div>
<div class="message">
You requested a sign-in link for your Bookra account. Click below to access your account securely — no password needed.
</div>
<div class="button-wrap">
<a href="%s" class="button">Sign In to Bookra</a>
</div>
<div class="link-box">
<div class="link-label">Or copy this link</div>
<div class="link-url">%s</div>
</div>
<div class="expiry">
This link expires in <strong>15 minutes</strong> for security.
</div>
<div class="help">
Didn't request this? You can safely ignore it — someone may have entered your email by mistake.
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
<div class="footer-links">
<a href="https://bookra.tdvorak.dev/privacy">Privacy</a>
<a href="https://bookra.tdvorak.dev/terms">Terms</a>
</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink, inkSubtle,
ink, inkMuted,
accent, white, accentHover,
canvasSubtle, border, inkSubtle, inkMuted,
accentSubtle, accent, accent,
inkSubtle, border,
canvas, border, inkMuted, inkMuted,
toName, magicURL, magicURL)
text := fmt.Sprintf(`Bookra — Sign-in Link
Hi %s,
Sign in to Bookra (link expires in 15 minutes):
%s
Didn't request this? You can safely ignore this email.
© 2024 Bookra`, toName, magicURL)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}
func magicLinkEmailCS(toName, magicURL string) EmailTemplate {
subject := "Váš přihlašovací odkaz do Bookra"
if toName == "" {
toName = "vás"
}
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>%s</title>
<style>
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; letter-spacing: -0.02em; }
.tagline { color: %s; font-size: 15px; margin-top: 6px; font-style: italic; }
.content { padding: 48px 40px; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 20px; font-weight: 600; color: %s; margin-bottom: 16px; }
.message { font-size: 17px; line-height: 1.6; color: %s; margin-bottom: 32px; }
.button-wrap { margin: 40px 0; }
.button { display: inline-block; background: %s; color: %s; padding: 16px 40px; text-decoration: none; border-radius: 8px; font-family: 'Space Grotesk', sans-serif; font-weight: 500; font-size: 15px; }
.button:hover { background: %s; }
.link-box { background: %s; border: 1px solid %s; border-radius: 8px; padding: 20px; margin: 32px 0; }
.link-label { font-size: 12px; font-weight: 600; color: %s; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 8px; font-family: 'Space Grotesk', sans-serif; }
.link-url { font-size: 14px; color: %s; word-break: break-all; font-family: 'JetBrains Mono', monospace; }
.expiry { background: %s; border-left: 3px solid %s; padding: 16px 20px; margin: 32px 0; font-size: 15px; color: %s; }
.help { font-size: 15px; color: %s; margin-top: 40px; padding-top: 32px; border-top: 1px solid %s; font-style: italic; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
.footer-links { margin-top: 12px; }
.footer-links a { color: %s; text-decoration: none; font-size: 13px; margin: 0 12px; font-family: 'Space Grotesk', sans-serif; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
<div class="tagline">Klidný rezervační software</div>
</div>
<div class="content">
<div class="greeting">Dobrý den %s,</div>
<div class="message">
Požádali jste o přihlašovací odkaz k účtu Bookra. Klikněte níže pro bezpečný přístup — heslo není potřeba.
</div>
<div class="button-wrap">
<a href="%s" class="button">Přihlásit se do Bookra</a>
</div>
<div class="link-box">
<div class="link-label">Nebo zkopírujte tento odkaz</div>
<div class="link-url">%s</div>
</div>
<div class="expiry">
Tento odkaz vyprší za <strong>15 minut</strong> z bezpečnostních důvodů.
</div>
<div class="help">
Nepožádali jste o tento email? Můžete ho bezpečně ignorovat.
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
<div class="footer-links">
<a href="https://bookra.tdvorak.dev/privacy">Ochrana soukromí</a>
<a href="https://bookra.tdvorak.dev/terms">Podmínky</a>
</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink, inkSubtle,
ink, inkMuted,
accent, white, accentHover,
canvasSubtle, border, inkSubtle, inkMuted,
accentSubtle, accent, accent,
inkSubtle, border,
canvas, border, inkMuted, inkMuted,
toName, magicURL, magicURL)
text := fmt.Sprintf(`Bookra — Přihlašovací odkaz
Dobrý den %s,
Přihlaste se do Bookra (odkaz vyprší za 15 minut):
%s
Nepožádali jste o tento email? Můžete ho ignorovat.
© 2024 Bookra`, toName, magicURL)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}
func welcomeEmailEN(name string) EmailTemplate {
subject := "Welcome to Bookra"
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400&display=swap');
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; }
.content { padding: 48px 40px; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 600; color: %s; margin-bottom: 16px; }
.message { font-size: 18px; line-height: 1.6; color: %s; margin-bottom: 32px; }
.features { background: %s; border-radius: 12px; padding: 32px; margin: 32px 0; }
.feature { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 20px; }
.feature:last-child { margin-bottom: 0; }
.feature-icon { width: 24px; height: 24px; background: %s; border-radius: 6px; display: flex; align-items: center; justify-content: center; color: %s; font-size: 14px; flex-shrink: 0; font-family: 'Space Grotesk', sans-serif; }
.feature-text { font-size: 16px; color: %s; line-height: 1.5; }
.button-wrap { margin: 40px 0; text-align: center; }
.button { display: inline-block; background: %s; color: %s; padding: 16px 40px; text-decoration: none; border-radius: 8px; font-family: 'Space Grotesk', sans-serif; font-weight: 500; font-size: 15px; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
</div>
<div class="content">
<div class="greeting">Welcome, %s</div>
<div class="message">
Thanks for joining Bookra. We're here to help you manage bookings with calm and clarity.
</div>
<div class="features">
<div class="feature">
<div class="feature-icon">✓</div>
<div class="feature-text"><strong>Smart scheduling</strong> — Automatic conflict detection and buffer times</div>
</div>
<div class="feature">
<div class="feature-icon">✓</div>
<div class="feature-text"><strong>Customer insights</strong> — History and preferences at your fingertips</div>
</div>
<div class="feature">
<div class="feature-icon">✓</div>
<div class="feature-text"><strong>Reminders</strong> — Reduce no-shows with gentle notifications</div>
</div>
</div>
<div class="button-wrap">
<a href="https://bookra.tdvorak.dev/dashboard" class="button">Open Dashboard</a>
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink,
ink, inkMuted, canvasSubtle,
accent, white, inkMuted,
accent, white,
canvas, border, inkMuted,
name)
text := fmt.Sprintf(`Welcome to Bookra, %s
Thanks for joining. We're here to help you manage bookings with calm and clarity.
Get started: https://bookra.tdvorak.dev/dashboard
© 2024 Bookra`, name)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}
func welcomeEmailCS(name string) EmailTemplate {
subject := "Vítejte v Bookra"
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400&display=swap');
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; }
.content { padding: 48px 40px; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 600; color: %s; margin-bottom: 16px; }
.message { font-size: 18px; line-height: 1.6; color: %s; margin-bottom: 32px; }
.features { background: %s; border-radius: 12px; padding: 32px; margin: 32px 0; }
.feature { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 20px; }
.feature:last-child { margin-bottom: 0; }
.feature-icon { width: 24px; height: 24px; background: %s; border-radius: 6px; display: flex; align-items: center; justify-content: center; color: %s; font-size: 14px; flex-shrink: 0; }
.feature-text { font-size: 16px; color: %s; line-height: 1.5; }
.button-wrap { margin: 40px 0; text-align: center; }
.button { display: inline-block; background: %s; color: %s; padding: 16px 40px; text-decoration: none; border-radius: 8px; font-family: 'Space Grotesk', sans-serif; font-weight: 500; font-size: 15px; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
</div>
<div class="content">
<div class="greeting">Vítejte, %s</div>
<div class="message">
Děkujeme za registraci. Pomůžeme vám spravovat rezervace s klidem a přehledem.
</div>
<div class="features">
<div class="feature">
<div class="feature-icon">✓</div>
<div class="feature-text"><strong>Chytré plánování</strong> — Automatická detekce konfliktů</div>
</div>
<div class="feature">
<div class="feature-icon">✓</div>
<div class="feature-text"><strong>Přehled o zákaznících</strong> — Historie a preference</div>
</div>
<div class="feature">
<div class="feature-icon">✓</div>
<div class="feature-text"><strong>Připomenutí</strong> — Méně zapomenutých termínů</div>
</div>
</div>
<div class="button-wrap">
<a href="https://bookra.tdvorak.dev/dashboard" class="button">Otevřít aplikaci</a>
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink,
ink, inkMuted, canvasSubtle,
accent, white, inkMuted,
accent, white,
canvas, border, inkMuted,
name)
text := fmt.Sprintf(`Vítejte v Bookra, %s
Děkujeme za registraci. Pomůžeme vám spravovat rezervace s klidem.
Otevřít aplikaci: https://bookra.tdvorak.dev/dashboard
© 2024 Bookra`, name)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}
func bookingConfirmationEN(customerName, businessName, serviceName, dateTime, location string) EmailTemplate {
subject := fmt.Sprintf("Confirmed: %s with %s", serviceName, businessName)
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Newsreader:ital,opsz,wght@0,6..72,400&display=swap');
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; }
.content { padding: 48px 40px; }
.badge { display: inline-block; background: %s; color: %s; padding: 8px 16px; border-radius: 20px; font-size: 13px; font-weight: 600; margin-bottom: 24px; font-family: 'Space Grotesk', sans-serif; text-transform: uppercase; letter-spacing: 0.05em; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; color: %s; margin-bottom: 8px; }
.message { font-size: 17px; color: %s; margin-bottom: 32px; }
.details { background: %s; border-radius: 12px; padding: 28px; margin: 32px 0; }
.detail-row { display: flex; padding: 14px 0; border-bottom: 1px solid %s; }
.detail-row:last-child { border-bottom: none; }
.detail-label { width: 120px; font-size: 12px; font-weight: 600; color: %s; text-transform: uppercase; letter-spacing: 0.05em; font-family: 'Space Grotesk', sans-serif; }
.detail-value { flex: 1; font-size: 16px; color: %s; font-weight: 500; }
.help { font-size: 15px; color: %s; margin-top: 32px; padding-top: 32px; border-top: 1px solid %s; font-style: italic; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
</div>
<div class="content">
<div class="badge">Confirmed</div>
<div class="greeting">Hello %s,</div>
<div class="message">
Your booking with <strong>%s</strong> is confirmed.
</div>
<div class="details">
<div class="detail-row">
<div class="detail-label">Service</div>
<div class="detail-value">%s</div>
</div>
<div class="detail-row">
<div class="detail-label">When</div>
<div class="detail-value">%s</div>
</div>
<div class="detail-row">
<div class="detail-label">Where</div>
<div class="detail-value">%s</div>
</div>
</div>
<div class="help">
Need to reschedule? Contact %s directly.
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink,
accentSubtle, accent, ink, inkMuted,
canvasSubtle, border, inkSubtle, ink,
inkSubtle, border,
canvas, border, inkMuted,
customerName, businessName, serviceName, dateTime, location, businessName)
text := fmt.Sprintf(`Booking Confirmed
Hello %s,
Your booking with %s is confirmed.
Service: %s
When: %s
Where: %s
Need to reschedule? Contact %s.
© 2024 Bookra`,
customerName, businessName, serviceName, dateTime, location, businessName)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}
func bookingConfirmationCS(customerName, businessName, serviceName, dateTime, location string) EmailTemplate {
subject := fmt.Sprintf("Potvrzeno: %s v %s", serviceName, businessName)
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Newsreader:ital,opsz,wght@0,6..72,400&display=swap');
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; }
.content { padding: 48px 40px; }
.badge { display: inline-block; background: %s; color: %s; padding: 8px 16px; border-radius: 20px; font-size: 13px; font-weight: 600; margin-bottom: 24px; font-family: 'Space Grotesk', sans-serif; text-transform: uppercase; letter-spacing: 0.05em; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; color: %s; margin-bottom: 8px; }
.message { font-size: 17px; color: %s; margin-bottom: 32px; }
.details { background: %s; border-radius: 12px; padding: 28px; margin: 32px 0; }
.detail-row { display: flex; padding: 14px 0; border-bottom: 1px solid %s; }
.detail-row:last-child { border-bottom: none; }
.detail-label { width: 120px; font-size: 12px; font-weight: 600; color: %s; text-transform: uppercase; letter-spacing: 0.05em; font-family: 'Space Grotesk', sans-serif; }
.detail-value { flex: 1; font-size: 16px; color: %s; font-weight: 500; }
.help { font-size: 15px; color: %s; margin-top: 32px; padding-top: 32px; border-top: 1px solid %s; font-style: italic; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
</div>
<div class="content">
<div class="badge">Potvrzeno</div>
<div class="greeting">Dobrý den %s,</div>
<div class="message">
Vaše rezervace v <strong>%s</strong> je potvrzena.
</div>
<div class="details">
<div class="detail-row">
<div class="detail-label">Služba</div>
<div class="detail-value">%s</div>
</div>
<div class="detail-row">
<div class="detail-label">Termín</div>
<div class="detail-value">%s</div>
</div>
<div class="detail-row">
<div class="detail-label">Místo</div>
<div class="detail-value">%s</div>
</div>
</div>
<div class="help">
Potřebujete přeobjednat? Kontaktujte přímo %s.
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink,
accentSubtle, accent, ink, inkMuted,
canvasSubtle, border, inkSubtle, ink,
inkSubtle, border,
canvas, border, inkMuted,
customerName, businessName, serviceName, dateTime, location, businessName)
text := fmt.Sprintf(`Rezervace potvrzena
Dobrý den %s,
Vaše rezervace v %s je potvrzena.
Služba: %s
Termín: %s
Místo: %s
Potřebujete přeobjednat? Kontaktujte %s.
© 2024 Bookra`,
customerName, businessName, serviceName, dateTime, location, businessName)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}
func passwordResetEN(name, resetURL string) EmailTemplate {
subject := "Reset your Bookra password"
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; }
.content { padding: 48px 40px; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 20px; font-weight: 600; color: %s; margin-bottom: 16px; }
.message { font-size: 17px; line-height: 1.6; color: %s; margin-bottom: 32px; }
.button-wrap { margin: 40px 0; }
.button { display: inline-block; background: %s; color: %s; padding: 16px 40px; text-decoration: none; border-radius: 8px; font-family: 'Space Grotesk', sans-serif; font-weight: 500; font-size: 15px; }
.expiry { background: %s; border-left: 3px solid %s; padding: 16px 20px; margin: 32px 0; font-size: 15px; color: %s; }
.help { font-size: 15px; color: %s; margin-top: 40px; padding-top: 32px; border-top: 1px solid %s; font-style: italic; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
</div>
<div class="content">
<div class="greeting">Hi %s,</div>
<div class="message">
We received a request to reset your password. Click below to choose a new one.
</div>
<div class="button-wrap">
<a href="%s" class="button">Reset Password</a>
</div>
<div class="expiry">
This link expires in <strong>1 hour</strong>.
</div>
<div class="help">
Didn't request this? You can safely ignore it.
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink,
ink, inkMuted,
accent, white,
accentSubtle, accent, accent,
inkSubtle, border,
canvas, border, inkMuted,
name, resetURL)
text := fmt.Sprintf(`Reset Password — Bookra
Hi %s,
Reset your password (expires in 1 hour):
%s
Didn't request this? You can safely ignore it.
© 2024 Bookra`, name, resetURL)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}
func passwordResetCS(name, resetURL string) EmailTemplate {
subject := "Reset hesla pro Bookra"
html := fmt.Sprintf(`<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
body { margin: 0; padding: 0; font-family: 'Newsreader', Georgia, serif; background: %s; -webkit-font-smoothing: antialiased; }
.container { max-width: 600px; margin: 0 auto; background: %s; }
.header { background: %s; padding: 48px 40px; text-align: center; border-bottom: 1px solid %s; }
.logo { width: 56px; height: 56px; background: %s; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; color: %s; }
.brand { color: %s; font-family: 'Space Grotesk', sans-serif; font-size: 24px; font-weight: 600; margin-top: 16px; }
.content { padding: 48px 40px; }
.greeting { font-family: 'Space Grotesk', sans-serif; font-size: 20px; font-weight: 600; color: %s; margin-bottom: 16px; }
.message { font-size: 17px; line-height: 1.6; color: %s; margin-bottom: 32px; }
.button-wrap { margin: 40px 0; }
.button { display: inline-block; background: %s; color: %s; padding: 16px 40px; text-decoration: none; border-radius: 8px; font-family: 'Space Grotesk', sans-serif; font-weight: 500; font-size: 15px; }
.expiry { background: %s; border-left: 3px solid %s; padding: 16px 20px; margin: 32px 0; font-size: 15px; color: %s; }
.help { font-size: 15px; color: %s; margin-top: 40px; padding-top: 32px; border-top: 1px solid %s; font-style: italic; }
.footer { background: %s; padding: 32px 40px; text-align: center; border-top: 1px solid %s; }
.footer-text { font-size: 14px; color: %s; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">B</div>
<div class="brand">Bookra</div>
</div>
<div class="content">
<div class="greeting">Dobrý den %s,</div>
<div class="message">
Obdrželi jsme žádost o reset hesla. Klikněte níže pro nastavení nového.
</div>
<div class="button-wrap">
<a href="%s" class="button">Resetovat heslo</a>
</div>
<div class="expiry">
Tento odkaz vyprší za <strong>1 hodinu</strong>.
</div>
<div class="help">
Nepožádali jste o tento email? Můžete ho bezpečně ignorovat.
</div>
</div>
<div class="footer">
<div class="footer-text">© 2024 Bookra</div>
</div>
</div>
</body>
</html>`,
subject, canvas, white, canvas, border,
logoBg, logoText, ink,
ink, inkMuted,
accent, white,
accentSubtle, accent, accent,
inkSubtle, border,
canvas, border, inkMuted,
name, resetURL)
text := fmt.Sprintf(`Reset hesla — Bookra
Dobrý den %s,
Reset hesla (vyprší za 1 hodinu):
%s
Nepožádali jste o tento email? Můžete ho ignorovat.
© 2024 Bookra`, name, resetURL)
return EmailTemplate{Subject: subject, HTML: html, Text: text}
}