From 89fa8f81afc127288241bc6bc3041da09d54394c Mon Sep 17 00:00:00 2001 From: poduck Date: Sun, 14 Dec 2025 19:10:56 -0500 Subject: [PATCH] Fix: Display correct SmoothSchedule logo in email preview Replaced the blank base64 encoded logo with the actual SmoothSchedule logo in the email rendering pipeline. A Playwright E2E test was run to verify that the logo is correctly displayed in the email preview modal, ensuring it loads with natural dimensions and is visible. --- ...fa88b026d5419ae4ab64937dbb748dff0649bd.png | Bin 38683 -> 0 bytes ...bb7e32ecf71376161c96bc2259c44bb2a19be2a.md | 71 - frontend/playwright-report/index.html | 2 +- frontend/public/logo-branding.png | Bin 0 -> 9242 bytes frontend/src/App.tsx | 26 +- frontend/src/components/DevQuickLogin.tsx | 6 +- frontend/src/components/EmailTemplateForm.tsx | 543 ----- .../EmailTemplatePresetSelector.tsx | 292 --- .../src/components/EmailTemplateSelector.tsx | 117 +- frontend/src/components/Sidebar.tsx | 1 - .../__tests__/EmailTemplateSelector.test.tsx | 83 - frontend/src/index.css | 64 + frontend/src/layouts/SettingsLayout.tsx | 3 +- frontend/src/pages/EmailTemplateEditor.tsx | 285 +++ frontend/src/pages/EmailTemplates.tsx | 1038 ---------- frontend/src/pages/LoginPage.tsx | 4 +- frontend/src/pages/PublicPage.tsx | 17 + .../pages/settings/SystemEmailTemplates.tsx | 701 +++++++ .../puck/components/email/EmailBranding.tsx | 85 + .../src/puck/components/email/EmailButton.tsx | 86 + .../puck/components/email/EmailDivider.tsx | 27 + .../src/puck/components/email/EmailFooter.tsx | 88 + .../src/puck/components/email/EmailHeader.tsx | 85 + .../puck/components/email/EmailHeading.tsx | 84 + .../src/puck/components/email/EmailImage.tsx | 76 + .../src/puck/components/email/EmailLayout.tsx | 54 + .../src/puck/components/email/EmailPanel.tsx | 54 + .../src/puck/components/email/EmailSpacer.tsx | 39 + .../src/puck/components/email/EmailText.tsx | 58 + .../puck/components/email/EmailTwoColumn.tsx | 62 + frontend/src/puck/components/email/index.ts | 22 + frontend/src/puck/components/email/types.ts | 111 + frontend/src/puck/emailConfig.tsx | 86 + frontend/src/types.ts | 108 +- frontend/test-results/.last-run.json | 3 +- .../error-context.md | 71 - .../test-failed-1.png | Bin 38683 -> 0 bytes .../test-results/email-preview-footer.png | Bin 0 -> 109763 bytes frontend/tests/e2e/email-preview-logo.spec.ts | 123 ++ .../tests/e2e/email-template-editor.spec.ts | 94 + frontend/tests/e2e/site-builder-test.spec.ts | 29 + smoothschedule/PLAN_EMAIL_TEMPLATES.md | 567 ----- .../commerce/tickets/email_notifications.py | 365 +--- .../tickets/tests/test_email_notifications.py | 1006 +++------ .../messaging/default_templates.py | 955 +++++++++ .../communication/messaging/email_renderer.py | 533 +++++ .../communication/messaging/email_service.py | 189 ++ .../communication/messaging/email_tags.py | 305 +++ .../communication/messaging/email_types.py | 176 ++ .../messaging/management/__init__.py | 0 .../messaging/management/commands/__init__.py | 0 .../commands/seed_puck_email_templates.py | 111 + .../commands/update_tenant_to_business.py | 165 ++ .../0003_add_puck_email_template.py | 36 + .../0004_add_custom_email_template.py | 37 + .../communication/messaging/models.py | 291 +++ .../communication/messaging/serializers.py | 223 +- .../messaging/tests/test_email_templates.py | 731 +++++++ .../communication/messaging/urls.py | 11 +- .../communication/messaging/utils.py | 37 + .../communication/messaging/views.py | 435 +++- .../identity/core/quota_service.py | 13 +- .../smoothschedule/identity/core/signals.py | 62 + .../identity/core/tests/test_quota_service.py | 33 +- .../identity/users/tests/test_api_views.py | 55 +- .../platform/admin/tests/test_serializers.py | 32 +- .../smoothschedule/platform/admin/views.py | 5 + .../schedule/email_template_presets.py | 1106 ---------- .../commands/seed_email_templates.py | 1829 ----------------- .../migrations/0039_remove_emailtemplate.py | 23 + .../scheduling/schedule/models.py | 140 -- .../scheduling/schedule/safe_scripting.py | 275 +-- .../scheduling/schedule/serializers.py | 63 +- .../scheduling/schedule/tests/test_models.py | 105 - .../schedule/tests/test_safe_scripting.py | 87 +- .../schedule/tests/test_serializers.py | 131 -- .../scheduling/schedule/tests/test_views.py | 220 -- .../scheduling/schedule/urls.py | 3 +- .../scheduling/schedule/views.py | 253 +-- .../static/images/logo-branding.png | Bin 0 -> 9242 bytes 80 files changed, 7398 insertions(+), 7908 deletions(-) delete mode 100644 frontend/playwright-report/data/5ffa88b026d5419ae4ab64937dbb748dff0649bd.png delete mode 100644 frontend/playwright-report/data/bbb7e32ecf71376161c96bc2259c44bb2a19be2a.md create mode 100644 frontend/public/logo-branding.png delete mode 100644 frontend/src/components/EmailTemplateForm.tsx delete mode 100644 frontend/src/components/EmailTemplatePresetSelector.tsx delete mode 100644 frontend/src/components/__tests__/EmailTemplateSelector.test.tsx create mode 100644 frontend/src/pages/EmailTemplateEditor.tsx delete mode 100644 frontend/src/pages/EmailTemplates.tsx create mode 100644 frontend/src/pages/settings/SystemEmailTemplates.tsx create mode 100644 frontend/src/puck/components/email/EmailBranding.tsx create mode 100644 frontend/src/puck/components/email/EmailButton.tsx create mode 100644 frontend/src/puck/components/email/EmailDivider.tsx create mode 100644 frontend/src/puck/components/email/EmailFooter.tsx create mode 100644 frontend/src/puck/components/email/EmailHeader.tsx create mode 100644 frontend/src/puck/components/email/EmailHeading.tsx create mode 100644 frontend/src/puck/components/email/EmailImage.tsx create mode 100644 frontend/src/puck/components/email/EmailLayout.tsx create mode 100644 frontend/src/puck/components/email/EmailPanel.tsx create mode 100644 frontend/src/puck/components/email/EmailSpacer.tsx create mode 100644 frontend/src/puck/components/email/EmailText.tsx create mode 100644 frontend/src/puck/components/email/EmailTwoColumn.tsx create mode 100644 frontend/src/puck/components/email/index.ts create mode 100644 frontend/src/puck/components/email/types.ts create mode 100644 frontend/src/puck/emailConfig.tsx delete mode 100644 frontend/test-results/diagnose_ws-diagnose-websocket-connection-chromium/error-context.md delete mode 100644 frontend/test-results/diagnose_ws-diagnose-websocket-connection-chromium/test-failed-1.png create mode 100644 frontend/test-results/email-preview-footer.png create mode 100644 frontend/tests/e2e/email-preview-logo.spec.ts create mode 100644 frontend/tests/e2e/email-template-editor.spec.ts create mode 100644 frontend/tests/e2e/site-builder-test.spec.ts delete mode 100644 smoothschedule/PLAN_EMAIL_TEMPLATES.md create mode 100644 smoothschedule/smoothschedule/communication/messaging/default_templates.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/email_renderer.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/email_service.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/email_tags.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/email_types.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/management/__init__.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/management/commands/__init__.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/management/commands/seed_puck_email_templates.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/management/commands/update_tenant_to_business.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/migrations/0003_add_puck_email_template.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/migrations/0004_add_custom_email_template.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/tests/test_email_templates.py create mode 100644 smoothschedule/smoothschedule/communication/messaging/utils.py delete mode 100644 smoothschedule/smoothschedule/scheduling/schedule/email_template_presets.py delete mode 100644 smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_email_templates.py create mode 100644 smoothschedule/smoothschedule/scheduling/schedule/migrations/0039_remove_emailtemplate.py create mode 100644 smoothschedule/smoothschedule/static/images/logo-branding.png diff --git a/frontend/playwright-report/data/5ffa88b026d5419ae4ab64937dbb748dff0649bd.png b/frontend/playwright-report/data/5ffa88b026d5419ae4ab64937dbb748dff0649bd.png deleted file mode 100644 index 6fc8483e6565898beb3ff416cc6c181633316b79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38683 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 a4KqW;WzD$%jVeJv5e83JKbLh*2~7aC+!#v$ diff --git a/frontend/playwright-report/data/bbb7e32ecf71376161c96bc2259c44bb2a19be2a.md b/frontend/playwright-report/data/bbb7e32ecf71376161c96bc2259c44bb2a19be2a.md deleted file mode 100644 index d6dfb6c..0000000 --- a/frontend/playwright-report/data/bbb7e32ecf71376161c96bc2259c44bb2a19be2a.md +++ /dev/null @@ -1,71 +0,0 @@ -# Page snapshot - -```yaml -- generic [ref=e1]: - - generic [ref=e3]: - - generic [ref=e5]: - - button "Collapse sidebar" [ref=e6]: - - img [ref=e7] - - generic [ref=e13]: - - heading "Smooth Schedule" [level=1] [ref=e14] - - paragraph [ref=e15]: superuser - - navigation [ref=e16]: - - paragraph [ref=e17]: Operations - - link "Dashboard" [ref=e18] [cursor=pointer]: - - /url: /platform/dashboard - - img [ref=e19] - - generic [ref=e24]: Dashboard - - link "Businesses" [ref=e25] [cursor=pointer]: - - /url: /platform/businesses - - img [ref=e26] - - generic [ref=e30]: Businesses - - link "Users" [ref=e31] [cursor=pointer]: - - /url: /platform/users - - img [ref=e32] - - generic [ref=e37]: Users - - link "Support" [active] [ref=e38] [cursor=pointer]: - - /url: /platform/support - - img [ref=e39] - - generic [ref=e41]: Support - - paragraph [ref=e42]: System - - link "Staff" [ref=e43] [cursor=pointer]: - - /url: /platform/staff - - img [ref=e44] - - generic [ref=e46]: Staff - - link "Platform Settings" [ref=e47] [cursor=pointer]: - - /url: /platform/settings - - img [ref=e48] - - generic [ref=e51]: Platform Settings - - generic [ref=e52]: - - link "Help" [ref=e53] [cursor=pointer]: - - /url: /help/ticketing - - img [ref=e54] - - generic [ref=e57]: Help - - link "API Docs" [ref=e58] [cursor=pointer]: - - /url: /help/api - - img [ref=e59] - - generic [ref=e62]: API Docs - - generic [ref=e63]: - - banner [ref=e64]: - - generic [ref=e66]: - - img [ref=e67] - - generic [ref=e70]: smoothschedule.com - - generic [ref=e71]: / - - generic [ref=e72]: Admin Console - - generic [ref=e73]: - - button [ref=e74]: - - img [ref=e75] - - button "Open notifications" [ref=e78]: - - img [ref=e79] - - button "Super User Superuser SU" [ref=e83]: - - generic [ref=e84]: - - paragraph [ref=e85]: Super User - - paragraph [ref=e86]: Superuser - - generic [ref=e87]: SU - - img [ref=e88] - - main [ref=e90]: - - generic [ref=e91]: - - img [ref=e92] - - paragraph [ref=e94]: Error loading tickets - - generic [ref=e95]: $0k -``` \ No newline at end of file diff --git a/frontend/playwright-report/index.html b/frontend/playwright-report/index.html index 18ccdb3..6ebf236 100644 --- a/frontend/playwright-report/index.html +++ b/frontend/playwright-report/index.html @@ -82,4 +82,4 @@ Error generating stack: `+n.message+`
- \ No newline at end of file + \ No newline at end of file diff --git a/frontend/public/logo-branding.png b/frontend/public/logo-branding.png new file mode 100644 index 0000000000000000000000000000000000000000..66b4bccf3187bae1822055adf20b8f78f8e7c63d GIT binary patch literal 9242 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 X961_Cxe$4|^8=8VRRLE>n+5(q(@i6X literal 0 HcmV?d00001 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index b87bab8..90cac9c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -108,11 +108,12 @@ const PluginMarketplace = React.lazy(() => import('./pages/PluginMarketplace')); const MyPlugins = React.lazy(() => import('./pages/MyPlugins')); // Import My Plugins page const CreatePlugin = React.lazy(() => import('./pages/CreatePlugin')); // Import Create Plugin page const Tasks = React.lazy(() => import('./pages/Tasks')); // Import Tasks page for scheduled plugin executions -const EmailTemplates = React.lazy(() => import('./pages/EmailTemplates')); // Import Email Templates page +const SystemEmailTemplates = React.lazy(() => import('./pages/settings/SystemEmailTemplates')); // System email templates (Puck-based) const Contracts = React.lazy(() => import('./pages/Contracts')); // Import Contracts page const ContractTemplates = React.lazy(() => import('./pages/ContractTemplates')); // Import Contract Templates page const ContractSigning = React.lazy(() => import('./pages/ContractSigning')); // Import Contract Signing page (public) const PageEditor = React.lazy(() => import('./pages/PageEditor')); // Import PageEditor +const EmailTemplateEditor = React.lazy(() => import('./pages/EmailTemplateEditor')); // Import Email Template Editor const PublicPage = React.lazy(() => import('./pages/PublicPage')); // Import PublicPage const BookingFlow = React.lazy(() => import('./pages/BookingFlow')); // Import Booking Flow const Locations = React.lazy(() => import('./pages/Locations')); // Import Locations management page @@ -802,16 +803,7 @@ const AppContent: React.FC = () => { ) } /> - - ) : ( - - ) - } - /> + {/* Email templates are now accessed via Settings > Email Templates */} } /> { ) } /> + + ) : ( + + ) + } + /> { } /> } /> } /> - } /> + } /> } /> } /> } /> diff --git a/frontend/src/components/DevQuickLogin.tsx b/frontend/src/components/DevQuickLogin.tsx index 4b61c3e..6c99933 100644 --- a/frontend/src/components/DevQuickLogin.tsx +++ b/frontend/src/components/DevQuickLogin.tsx @@ -145,12 +145,12 @@ export function DevQuickLogin({ embedded = false, filter = 'all' }: DevQuickLogi if (needsRedirect) { // Redirect to the correct subdomain - window.location.href = buildSubdomainUrl(targetSubdomain, '/'); + window.location.href = buildSubdomainUrl(targetSubdomain, '/dashboard'); return; } - // Already on correct subdomain - just reload to update auth state - window.location.reload(); + // Already on correct subdomain - navigate to dashboard + window.location.href = '/dashboard'; } catch (error: any) { console.error('Quick login failed:', error); alert(`Failed to login as ${user.label}: ${error.message || 'Unknown error'}`); diff --git a/frontend/src/components/EmailTemplateForm.tsx b/frontend/src/components/EmailTemplateForm.tsx deleted file mode 100644 index 01a2d12..0000000 --- a/frontend/src/components/EmailTemplateForm.tsx +++ /dev/null @@ -1,543 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useMutation, useQuery } from '@tanstack/react-query'; -import { - X, - Save, - Eye, - Code, - FileText, - Monitor, - Smartphone, - Plus, - AlertTriangle, - ChevronDown, - Sparkles, - Check -} from 'lucide-react'; -import api from '../api/client'; -import { EmailTemplate, EmailTemplateCategory, EmailTemplateVariableGroup } from '../types'; -import EmailTemplatePresetSelector from './EmailTemplatePresetSelector'; - -interface EmailTemplateFormProps { - template?: EmailTemplate | null; - onClose: () => void; - onSuccess: () => void; -} - -const EmailTemplateForm: React.FC = ({ - template, - onClose, - onSuccess, -}) => { - const { t } = useTranslation(); - const isEditing = !!template; - - // Form state - const [name, setName] = useState(template?.name || ''); - const [description, setDescription] = useState(template?.description || ''); - const [subject, setSubject] = useState(template?.subject || ''); - const [htmlContent, setHtmlContent] = useState(template?.htmlContent || ''); - const [textContent, setTextContent] = useState(template?.textContent || ''); - const [category, setCategory] = useState(template?.category || 'OTHER'); - - // UI state - const [activeTab, setActiveTab] = useState<'html' | 'text'>('html'); - const [editorMode, setEditorMode] = useState<'visual' | 'code'>('code'); - const [previewDevice, setPreviewDevice] = useState<'desktop' | 'mobile'>('desktop'); - const [showPreview, setShowPreview] = useState(false); - const [showVariables, setShowVariables] = useState(false); - const [showPresetSelector, setShowPresetSelector] = useState(false); - const [showTwoVersionsWarning, setShowTwoVersionsWarning] = useState(() => { - // Check localStorage to see if user has dismissed the warning - try { - return localStorage.getItem('emailTemplates_twoVersionsWarning_dismissed') !== 'true'; - } catch { - return true; - } - }); - - // Fetch available variables - const { data: variablesData } = useQuery<{ variables: EmailTemplateVariableGroup[] }>({ - queryKey: ['email-template-variables'], - queryFn: async () => { - const { data } = await api.get('/email-templates/variables/'); - return data; - }, - }); - - // Preview mutation - const previewMutation = useMutation({ - mutationFn: async () => { - const { data } = await api.post('/email-templates/preview/', { - subject, - html_content: htmlContent, - text_content: textContent, - }); - return data; - }, - }); - - // Create/Update mutation - const saveMutation = useMutation({ - mutationFn: async () => { - const payload = { - name, - description, - subject, - html_content: htmlContent, - text_content: textContent, - category, - scope: 'BUSINESS', // Business users only create business templates - }; - - if (isEditing && template) { - const { data } = await api.patch(`/email-templates/${template.id}/`, payload); - return data; - } else { - const { data } = await api.post('/email-templates/', payload); - return data; - } - }, - onSuccess: () => { - onSuccess(); - }, - }); - - const handlePreview = () => { - previewMutation.mutate(); - setShowPreview(true); - }; - - const insertVariable = (code: string) => { - if (activeTab === 'html') { - setHtmlContent(prev => prev + code); - } else if (activeTab === 'text') { - setTextContent(prev => prev + code); - } - }; - - const handlePresetSelect = (preset: any) => { - setName(preset.name); - setDescription(preset.description); - setSubject(preset.subject); - setHtmlContent(preset.html_content); - setTextContent(preset.text_content); - setShowPresetSelector(false); - }; - - const handleDismissTwoVersionsWarning = () => { - setShowTwoVersionsWarning(false); - try { - localStorage.setItem('emailTemplates_twoVersionsWarning_dismissed', 'true'); - } catch { - // Ignore localStorage errors - } - }; - - const categories: { value: EmailTemplateCategory; label: string }[] = [ - { value: 'APPOINTMENT', label: t('emailTemplates.categoryAppointment', 'Appointment') }, - { value: 'REMINDER', label: t('emailTemplates.categoryReminder', 'Reminder') }, - { value: 'CONFIRMATION', label: t('emailTemplates.categoryConfirmation', 'Confirmation') }, - { value: 'MARKETING', label: t('emailTemplates.categoryMarketing', 'Marketing') }, - { value: 'NOTIFICATION', label: t('emailTemplates.categoryNotification', 'Notification') }, - { value: 'REPORT', label: t('emailTemplates.categoryReport', 'Report') }, - { value: 'OTHER', label: t('emailTemplates.categoryOther', 'Other') }, - ]; - - const isValid = name.trim() && subject.trim() && (htmlContent.trim() || textContent.trim()); - - return ( -
-
- {/* Modal Header */} -
-

- {isEditing - ? t('emailTemplates.edit', 'Edit Template') - : t('emailTemplates.create', 'Create Template')} -

- -
- - {/* Modal Body */} -
- {/* Choose from Preset Button */} - {!isEditing && ( -
- -

- {t('emailTemplates.presetHint', 'Start with a professionally designed template and customize it to your needs')} -

-
- )} - -
- {/* Left Column - Form */} -
- {/* Name */} -
- - setName(e.target.value)} - placeholder={t('emailTemplates.namePlaceholder', 'e.g., Appointment Confirmation')} - className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 focus:border-brand-500" - /> -
- - {/* Category */} -
- - -
- - {/* Description */} -
- - setDescription(e.target.value)} - placeholder={t('emailTemplates.descriptionPlaceholder', 'Brief description of when this template is used')} - className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 focus:border-brand-500" - /> -
- - {/* Subject */} -
- - setSubject(e.target.value)} - placeholder={t('emailTemplates.subjectPlaceholder', 'e.g., Your appointment is confirmed!')} - className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 focus:border-brand-500" - /> -
- - {/* Variables Dropdown */} -
- - - {showVariables && variablesData?.variables && ( -
- {variablesData.variables.map((group) => ( -
-

- {group.category} -

-
- {group.items.map((variable) => ( - - ))} -
-
- ))} -
- )} -
- - {/* Content Tabs */} -
- {/* Info callout about HTML and Text versions */} - {showTwoVersionsWarning && ( -
-
- -
-

- {t('emailTemplates.twoVersionsRequired', 'Please edit both email versions')} -

-

- {t('emailTemplates.twoVersionsExplanation', 'Your customers will receive one of two versions of this email depending on their email client. Edit both the HTML version (rich formatting) and the Plain Text version (simple text) below. Make sure both versions include the same information so all your customers get the complete message.')} -

- -
-
-
- )} - -
-
- - -
- - {/* Editor Mode Toggle (for HTML only) */} - {activeTab === 'html' && ( -
- - -
- )} -
- - {/* Content Editor */} - {activeTab === 'html' && ( -