Initial v2 commit: complete rebuild with unified API + React admin
Phase 1-14 complete: - Unified Express.js API (TypeScript, Prisma ORM, PostgreSQL 16) - React Admin GUI (Vite + Ant Design + Zustand) - JWT auth with refresh tokens - Influence: Campaigns, Representatives, Responses, Email Queue - Map: Locations, Cuts, Shifts, Canvassing System - NAR data import infrastructure (2025 format) - Listmonk newsletter integration - Landing page builder (GrapesJS) - MkDocs + Code Server integration - Volunteer portal with GPS tracking - Monitoring stack (Prometheus, Grafana, Alertmanager) - Pangolin tunnel integration Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
116
map/app/templates/email/login-details.html
Normal file
116
map/app/templates/email/login-details.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Your Login Details</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.logo {
|
||||
color: #a02c8d;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.content {
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.credentials-box {
|
||||
background-color: #f0f0f0;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.credential-item {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.credential-label {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
.credential-value {
|
||||
font-family: monospace;
|
||||
font-size: 16px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
.login-button {
|
||||
display: inline-block;
|
||||
background-color: #a02c8d;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.info {
|
||||
color: #3498db;
|
||||
font-size: 14px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="logo">{{APP_NAME}}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h2>Your Login Details</h2>
|
||||
<p>Hello {{USER_NAME}},</p>
|
||||
<p>Here are your login credentials for {{APP_NAME}}:</p>
|
||||
|
||||
<div class="credentials-box">
|
||||
<div class="credential-item">
|
||||
<span class="credential-label">Email:</span>
|
||||
<span class="credential-value">{{USER_EMAIL}}</span>
|
||||
</div>
|
||||
<div class="credential-item">
|
||||
<span class="credential-label">Password:</span>
|
||||
<span class="credential-value">{{PASSWORD}}</span>
|
||||
</div>
|
||||
<div class="credential-item">
|
||||
<span class="credential-label">Role:</span>
|
||||
<span class="credential-value">{{USER_ROLE}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>You can log in using the link below:</p>
|
||||
<p style="text-align: center;">
|
||||
<a href="{{LOGIN_URL}}" class="login-button">Login to {{APP_NAME}}</a>
|
||||
</p>
|
||||
|
||||
<p class="info">💡 For security reasons, we recommend changing your password after your first login.</p>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
|
||||
<p>If you have any questions, please contact your administrator.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
17
map/app/templates/email/login-details.txt
Normal file
17
map/app/templates/email/login-details.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Login Details - {{APP_NAME}}
|
||||
|
||||
Hello {{USER_NAME}},
|
||||
|
||||
Here are your login credentials for {{APP_NAME}}:
|
||||
|
||||
Email: {{USER_EMAIL}}
|
||||
Password: {{PASSWORD}}
|
||||
Role: {{USER_ROLE}}
|
||||
|
||||
You can log in at: {{LOGIN_URL}}
|
||||
|
||||
For security reasons, we recommend changing your password after your first login.
|
||||
|
||||
---
|
||||
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
|
||||
If you have any questions, please contact your administrator.
|
||||
79
map/app/templates/email/password-recovery.html
Normal file
79
map/app/templates/email/password-recovery.html
Normal file
@@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Your Password</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.logo {
|
||||
color: #a02c8d;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.content {
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.password-box {
|
||||
background-color: #f0f0f0;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.warning {
|
||||
color: #e74c3c;
|
||||
font-size: 14px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="logo">{{APP_NAME}}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h2>Password Recovery</h2>
|
||||
<p>Hello {{USER_NAME}},</p>
|
||||
<p>You requested your password for the account associated with <strong>{{USER_EMAIL}}</strong>.</p>
|
||||
<p>Your password is:</p>
|
||||
<div class="password-box">{{PASSWORD}}</div>
|
||||
<p>You can use this password to log in at: <a href="{{LOGIN_URL}}">{{LOGIN_URL}}</a></p>
|
||||
<p class="warning">⚠️ For security reasons, we recommend changing your password after logging in.</p>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
|
||||
<p>If you didn't request this password, please contact your administrator immediately.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
15
map/app/templates/email/password-recovery.txt
Normal file
15
map/app/templates/email/password-recovery.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
Password Recovery - {{APP_NAME}}
|
||||
|
||||
Hello {{USER_NAME}},
|
||||
|
||||
You requested your password for the account associated with {{USER_EMAIL}}.
|
||||
|
||||
Your password is: {{PASSWORD}}
|
||||
|
||||
You can use this password to log in at: {{LOGIN_URL}}
|
||||
|
||||
WARNING: For security reasons, we recommend changing your password after logging in.
|
||||
|
||||
---
|
||||
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
|
||||
If you didn't request this password, please contact your administrator immediately.
|
||||
182
map/app/templates/email/public-shift-signup-existing.html
Normal file
182
map/app/templates/email/public-shift-signup-existing.html
Normal file
@@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Shift Signup Confirmation</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
border-bottom: 3px solid #28a745;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
color: #28a745;
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
background: #d4edda;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid #28a745;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.shift-details {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.shift-details h2 {
|
||||
color: #28a745;
|
||||
margin-top: 0;
|
||||
margin-bottom: 15px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
margin: 8px 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-weight: bold;
|
||||
min-width: 100px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.actions {
|
||||
text-align: center;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
background: #28a745;
|
||||
color: white;
|
||||
padding: 12px 30px;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: #218838;
|
||||
}
|
||||
|
||||
.secondary-link {
|
||||
color: #28a745;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.secondary-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #dee2e6;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.important {
|
||||
background: #d1ecf1;
|
||||
border: 1px solid #bee5eb;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
color: #0c5460;
|
||||
}
|
||||
|
||||
.important strong {
|
||||
color: #0c5460;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>✅ Shift Signup Confirmed!</h1>
|
||||
</div>
|
||||
|
||||
<div class="welcome-message">
|
||||
<p><strong>Hi {{USER_NAME}},</strong></p>
|
||||
<p>Great news! You've been successfully signed up for another volunteer shift with {{APP_NAME}}.</p>
|
||||
</div>
|
||||
|
||||
<div class="shift-details">
|
||||
<h2>📅 {{SHIFT_TITLE}}</h2>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">📅 Date:</span>
|
||||
<span>{{SHIFT_DATE}}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">⏰ Time:</span>
|
||||
<span>{{SHIFT_TIME}}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">📍 Location:</span>
|
||||
<span>{{SHIFT_LOCATION}}</span>
|
||||
</div>
|
||||
{{#if SHIFT_DESCRIPTION}}
|
||||
<div style="margin-top: 15px;">
|
||||
<strong>Details:</strong><br>
|
||||
{{SHIFT_DESCRIPTION}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="important">
|
||||
<strong>What's Next?</strong>
|
||||
<ul style="margin: 10px 0; padding-left: 20px;">
|
||||
<li>Mark your calendar for {{SHIFT_DATE}} at {{SHIFT_TIME}}</li>
|
||||
<li>Login to your existing account using your current credentials</li>
|
||||
<li>You can view or cancel your signup anytime from your account</li>
|
||||
<li>We'll send you reminder details closer to the shift date</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{LOGIN_URL}}" class="button">🔐 Login to Your Account</a>
|
||||
<br>
|
||||
<p style="margin-top: 15px;">
|
||||
Once logged in, visit <a href="{{SHIFTS_URL}}" class="secondary-link">My Shifts</a> to manage all your volunteer signups.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>Thank you for continuing to volunteer with {{APP_NAME}}!</p>
|
||||
<p>Questions? Reply to this email and we'll help you out.</p>
|
||||
<p><small>Sent on {{TIMESTAMP}}</small></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
29
map/app/templates/email/public-shift-signup-existing.txt
Normal file
29
map/app/templates/email/public-shift-signup-existing.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
Hi {{USER_NAME}},
|
||||
|
||||
✅ SHIFT SIGNUP CONFIRMED!
|
||||
|
||||
Great news! You've been successfully signed up for another volunteer shift with {{APP_NAME}}.
|
||||
|
||||
📅 SHIFT DETAILS
|
||||
▸ Event: {{SHIFT_TITLE}}
|
||||
▸ Date: {{SHIFT_DATE}}
|
||||
▸ Time: {{SHIFT_TIME}}
|
||||
▸ Location: {{SHIFT_LOCATION}}
|
||||
{{#if SHIFT_DESCRIPTION}}
|
||||
▸ Details: {{SHIFT_DESCRIPTION}}
|
||||
{{/if}}
|
||||
|
||||
ℹ️ You can use your existing account credentials to:
|
||||
• Login at: {{LOGIN_URL}}
|
||||
• View all your shift signups at: {{SHIFTS_URL}}
|
||||
• Cancel or modify your signups anytime from your account
|
||||
|
||||
Need help? Reply to this email or contact our volunteer coordinator.
|
||||
|
||||
Thank you for your continued support!
|
||||
|
||||
---
|
||||
{{APP_NAME}} Volunteer Team
|
||||
Sent: {{TIMESTAMP}}
|
||||
|
||||
This is an automated message. Please do not reply directly to this email.
|
||||
36
map/app/templates/email/public-shift-signup-new.html
Normal file
36
map/app/templates/email/public-shift-signup-new.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
/* ...email styles... */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Welcome & Shift Confirmation</h1>
|
||||
|
||||
<p>Hi {{USER_NAME}},</p>
|
||||
|
||||
<p>Thank you for signing up to volunteer! Your account has been created and you're confirmed for:</p>
|
||||
|
||||
<div class="shift-details">
|
||||
<h2>{{SHIFT_TITLE}}</h2>
|
||||
<p><strong>Date:</strong> {{SHIFT_DATE}}</p>
|
||||
<p><strong>Time:</strong> {{SHIFT_TIME}}</p>
|
||||
<p><strong>Location:</strong> {{SHIFT_LOCATION}}</p>
|
||||
</div>
|
||||
|
||||
<div class="credentials">
|
||||
<h3>Your Login Details</h3>
|
||||
<p><strong>Email:</strong> {{USER_EMAIL}}</p>
|
||||
<p><strong>Temporary Password:</strong> <code>{{TEMP_PASSWORD}}</code></p>
|
||||
<p class="note">This is a temporary account that expires after your shift.</p>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{LOGIN_URL}}" class="button">Login to Your Account</a>
|
||||
<p>Once logged in, visit <a href="{{SHIFTS_URL}}">My Shifts</a> to view or cancel your signup.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
33
map/app/templates/email/public-shift-signup-new.txt
Normal file
33
map/app/templates/email/public-shift-signup-new.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
Hi {{USER_NAME}},
|
||||
|
||||
✅ SHIFT SIGNUP CONFIRMATION
|
||||
|
||||
Thank you for signing up to volunteer with {{APP_NAME}}! Your account has been created and you're confirmed for:
|
||||
|
||||
📅 SHIFT DETAILS
|
||||
▸ Event: {{SHIFT_TITLE}}
|
||||
▸ Date: {{SHIFT_DATE}}
|
||||
▸ Time: {{SHIFT_TIME}}
|
||||
▸ Location: {{SHIFT_LOCATION}}
|
||||
{{#if SHIFT_DESCRIPTION}}
|
||||
▸ Details: {{SHIFT_DESCRIPTION}}
|
||||
{{/if}}
|
||||
|
||||
🔑 YOUR LOGIN CREDENTIALS
|
||||
▸ Email: {{USER_EMAIL}}
|
||||
▸ Temporary Password: {{TEMP_PASSWORD}}
|
||||
|
||||
ℹ️ This is a temporary account that expires after your shift. Keep these credentials safe!
|
||||
|
||||
WHAT'S NEXT:
|
||||
• Mark your calendar for {{SHIFT_DATE}} at {{SHIFT_TIME}}
|
||||
• Login at: {{LOGIN_URL}}
|
||||
• Manage your signups at: {{SHIFTS_URL}}
|
||||
• We'll send reminder details closer to the shift date
|
||||
|
||||
Questions? Reply to this email and we'll help you out.
|
||||
|
||||
Thank you for volunteering with {{APP_NAME}}!
|
||||
|
||||
---
|
||||
Sent on {{TIMESTAMP}}
|
||||
156
map/app/templates/email/shift-details.html
Normal file
156
map/app/templates/email/shift-details.html
Normal file
@@ -0,0 +1,156 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Shift Details - {{SHIFT_TITLE}}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.logo {
|
||||
color: #a02c8d;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.content {
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.shift-details-box {
|
||||
background-color: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.detail-row {
|
||||
margin: 12px 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.detail-icon {
|
||||
width: 30px;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.detail-label {
|
||||
font-weight: bold;
|
||||
min-width: 80px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.detail-value {
|
||||
color: #2c3e50;
|
||||
flex: 1;
|
||||
}
|
||||
.description-section {
|
||||
margin-top: 20px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.highlight {
|
||||
background-color: #fff3cd;
|
||||
padding: 15px;
|
||||
border-left: 4px solid #ffc107;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.status-open {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
.status-full {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="logo">{{APP_NAME}}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h2>Shift Details: {{SHIFT_TITLE}}</h2>
|
||||
<p>Hello {{USER_NAME}},</p>
|
||||
<p>Here are the details for your upcoming volunteer shift:</p>
|
||||
|
||||
<div class="shift-details-box">
|
||||
<div class="detail-row">
|
||||
<span class="detail-icon">📅</span>
|
||||
<span class="detail-label">Date:</span>
|
||||
<span class="detail-value">{{SHIFT_DATE}}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-icon">⏰</span>
|
||||
<span class="detail-label">Time:</span>
|
||||
<span class="detail-value">{{SHIFT_START_TIME}} - {{SHIFT_END_TIME}}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-icon">📍</span>
|
||||
<span class="detail-label">Location:</span>
|
||||
<span class="detail-value">{{SHIFT_LOCATION}}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-icon">👥</span>
|
||||
<span class="detail-label">Volunteers:</span>
|
||||
<span class="detail-value">{{CURRENT_VOLUNTEERS}}/{{MAX_VOLUNTEERS}} signed up</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-icon">📊</span>
|
||||
<span class="detail-label">Status:</span>
|
||||
<span class="detail-value">
|
||||
<span class="status-badge status-{{SHIFT_STATUS_CLASS}}">{{SHIFT_STATUS}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="description-section" id="description-section"{{DESCRIPTION_DISPLAY_STYLE}}>
|
||||
<h3>Additional Information:</h3>
|
||||
<p>{{SHIFT_DESCRIPTION}}</p>
|
||||
</div>
|
||||
|
||||
<div class="highlight">
|
||||
<p><strong>Important:</strong> Please arrive 10-15 minutes early and wear weather appropriate wear. If you need to cancel, please do so as early as possible to allow other volunteers to sign up.</p>
|
||||
</div>
|
||||
|
||||
<p>Questions? Contact your shift coordinator or administrator.</p>
|
||||
<p>Thank you for volunteering!</p>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
|
||||
<p>Volunteer shift management system</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
30
map/app/templates/email/shift-details.txt
Normal file
30
map/app/templates/email/shift-details.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
Shift Details - {{SHIFT_TITLE}}
|
||||
|
||||
Hello {{USER_NAME}},
|
||||
|
||||
Here are the details for your upcoming volunteer shift:
|
||||
|
||||
SHIFT INFORMATION:
|
||||
==================
|
||||
Title: {{SHIFT_TITLE}}
|
||||
Date: {{SHIFT_DATE}}
|
||||
Time: {{SHIFT_START_TIME}} - {{SHIFT_END_TIME}}
|
||||
Location: {{SHIFT_LOCATION}}
|
||||
Volunteers: {{CURRENT_VOLUNTEERS}}/{{MAX_VOLUNTEERS}} signed up
|
||||
Status: {{SHIFT_STATUS}}
|
||||
|
||||
{{SHIFT_DESCRIPTION_SECTION}}
|
||||
|
||||
IMPORTANT NOTES:
|
||||
===============
|
||||
- Please arrive 10-15 minutes early
|
||||
- Bring photo ID
|
||||
- If you need to cancel, please do so as early as possible to allow other volunteers to sign up
|
||||
|
||||
Questions? Contact your shift coordinator or administrator.
|
||||
|
||||
Thank you for volunteering!
|
||||
|
||||
---
|
||||
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
|
||||
Volunteer shift management system
|
||||
109
map/app/templates/email/user-broadcast.html
Normal file
109
map/app/templates/email/user-broadcast.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{EMAIL_SUBJECT}}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.logo {
|
||||
color: #a02c8d;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.content {
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.message-content {
|
||||
line-height: 1.6;
|
||||
}
|
||||
.message-content h1,
|
||||
.message-content h2,
|
||||
.message-content h3 {
|
||||
color: #2c3e50;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.message-content h1 {
|
||||
font-size: 24px;
|
||||
border-bottom: 2px solid #e9ecef;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.message-content h2 {
|
||||
font-size: 20px;
|
||||
}
|
||||
.message-content h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.message-content ul,
|
||||
.message-content ol {
|
||||
margin: 15px 0;
|
||||
padding-left: 25px;
|
||||
}
|
||||
.message-content li {
|
||||
margin: 8px 0;
|
||||
}
|
||||
.message-content a {
|
||||
color: #a02c8d;
|
||||
text-decoration: none;
|
||||
}
|
||||
.message-content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.message-content strong {
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
.message-content blockquote {
|
||||
border-left: 4px solid #a02c8d;
|
||||
margin: 20px 0;
|
||||
padding: 10px 20px;
|
||||
background-color: #f8f9fa;
|
||||
font-style: italic;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="logo">{{APP_NAME}}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Hello {{USER_NAME}},</p>
|
||||
|
||||
<div class="message-content">
|
||||
{{EMAIL_CONTENT}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
|
||||
<p>{{SENDER_NAME}} - System Administrator</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
9
map/app/templates/email/user-broadcast.txt
Normal file
9
map/app/templates/email/user-broadcast.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
{{EMAIL_SUBJECT}}
|
||||
|
||||
Hello {{USER_NAME}},
|
||||
|
||||
{{EMAIL_CONTENT_TEXT}}
|
||||
|
||||
---
|
||||
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
|
||||
{{SENDER_NAME}} - System Administrator
|
||||
Reference in New Issue
Block a user