feat: email notifications, webhook support, ICS export — closes #110
Email Notifications: - SMTP configuration in Admin > Settings (host, port, user, pass, from) - App URL setting for email CTA links - Webhook URL support (Discord, Slack, custom) - Test email button with SMTP validation - Beautiful HTML email template with TREK logo, slogan, red heart footer - All notification texts translated in 8 languages (en/de/fr/es/nl/ru/zh/ar) - Emails sent in each user's language preference Notification Events: - Trip invitation (member added) - Booking created (new reservation) - Vacay fusion invite - Photos shared (Immich) - Collab chat message - Packing list category assignment User Notification Preferences: - Per-user toggle for each event type in Settings - Addon-aware: Vacay/Collab/Photos toggles hidden when addon disabled - Webhook opt-in per user ICS Calendar Export: - Download button next to PDF in day plan header - Exports trip dates + all reservations with details - Compatible with Google Calendar, Apple Calendar, Outlook Technical: - Nodemailer for SMTP - notification_preferences DB table with per-event columns - GET/PUT /auth/app-settings for admin config persistence - POST /notifications/test-smtp for validation - Dynamic imports for non-blocking notification sends
This commit is contained in:
@@ -714,6 +714,34 @@ export default function DayPlanSidebar({
|
||||
<FileDown size={13} strokeWidth={2} />
|
||||
{t('dayplan.pdf')}
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/trips/${tripId}/export.ics`, {
|
||||
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` },
|
||||
})
|
||||
if (!res.ok) throw new Error()
|
||||
const blob = await res.blob()
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `${trip?.title || 'trip'}.ics`
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
} catch { toast.error('ICS export failed') }
|
||||
}}
|
||||
title={t('dayplan.icsTooltip')}
|
||||
style={{
|
||||
flexShrink: 0, display: 'flex', alignItems: 'center', gap: 5,
|
||||
padding: '5px 10px', borderRadius: 8,
|
||||
border: '1px solid var(--border-primary)', background: 'none',
|
||||
color: 'var(--text-muted)', fontSize: 11, fontWeight: 500,
|
||||
cursor: 'pointer', fontFamily: 'inherit',
|
||||
}}
|
||||
>
|
||||
<FileDown size={13} strokeWidth={2} />
|
||||
ICS
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user