From 8993d20526776a17714ec7fef9af71547aac6ff9 Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Sun, 14 Sep 2025 19:48:45 +0200 Subject: [PATCH] Migrate dev server from MongoDB to SQLite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace mongooseAdapter with sqliteAdapter in payload config - Update database configuration to use file:./dev.db - Remove MongoDB memory database helper and references - Simplify start script by removing verbose logging and MongoDB messaging - Fix email processing with immediate send support and proper queue handling - Restructure app with route groups for frontend/admin separation - Add dashboard and test pages for email management - Update API routes for improved email processing and testing ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- dev.db | Bin 0 -> 286720 bytes dev/.env.local | 2 + dev/app/(frontend)/dashboard/page.tsx | 310 +++++++++++++ dev/app/(frontend)/layout.tsx | 24 + .../{ => (frontend)}/mailing-test/page.tsx | 82 +++- dev/app/api/process-emails/route.ts | 21 +- dev/app/api/test-email/route.ts | 25 +- dev/app/page.tsx | 11 + dev/dev.db | Bin 0 -> 286720 bytes dev/payload-types.ts | 52 ++- dev/payload.config.ts | 59 +-- dev/start-dev.js | 18 +- package.json | 3 - payload.config.ts | 31 -- src/jobs/processEmailsTask.ts | 15 +- src/payload-types.ts | 436 ------------------ 16 files changed, 496 insertions(+), 593 deletions(-) create mode 100644 dev.db create mode 100644 dev/.env.local create mode 100644 dev/app/(frontend)/dashboard/page.tsx create mode 100644 dev/app/(frontend)/layout.tsx rename dev/app/{ => (frontend)}/mailing-test/page.tsx (82%) create mode 100644 dev/app/page.tsx create mode 100644 dev/dev.db delete mode 100644 payload.config.ts delete mode 100644 src/payload-types.ts diff --git a/dev.db b/dev.db new file mode 100644 index 0000000000000000000000000000000000000000..ec19c6a66570286c20cedafecd0af4a669f736e9 GIT binary patch literal 286720 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 N_y4`O1bAQn|Nm4|f?EIp literal 0 HcmV?d00001 diff --git a/dev/.env.local b/dev/.env.local new file mode 100644 index 0000000..a17bd82 --- /dev/null +++ b/dev/.env.local @@ -0,0 +1,2 @@ +USE_MEMORY_DB=true +PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/dev/app/(frontend)/dashboard/page.tsx b/dev/app/(frontend)/dashboard/page.tsx new file mode 100644 index 0000000..79d7f3d --- /dev/null +++ b/dev/app/(frontend)/dashboard/page.tsx @@ -0,0 +1,310 @@ +'use client' + +import { useState, useEffect } from 'react' +import Link from 'next/link' + +interface EmailStats { + total: number + sent: number + pending: number + failed: number + processing: number +} + +export default function HomePage() { + const [emailStats, setEmailStats] = useState({ + total: 0, + sent: 0, + pending: 0, + failed: 0, + processing: 0 + }) + const [loading, setLoading] = useState(true) + + useEffect(() => { + fetchEmailStats() + }, []) + + const fetchEmailStats = async () => { + try { + const response = await fetch('/api/test-email') + const data = await response.json() + + if (data.outbox?.emails) { + const emails = data.outbox.emails + const stats: EmailStats = { + total: emails.length, + sent: emails.filter((email: any) => email.status === 'sent').length, + pending: emails.filter((email: any) => email.status === 'pending').length, + failed: emails.filter((email: any) => email.status === 'failed').length, + processing: emails.filter((email: any) => email.status === 'processing').length + } + setEmailStats(stats) + } + } catch (error) { + console.error('Error fetching email statistics:', error) + } finally { + setLoading(false) + } + } + + const StatCard = ({ label, value, color, description }: { label: string; value: number; color: string; description: string }) => ( +
+
+ {value} +
+
+ {label} +
+
+ {description} +
+
+ ) + + return ( +
+
+ {/* Header */} +
+

+ ๐Ÿ“ง PayloadCMS Mailing Plugin +

+

+ Development Dashboard +

+ +
+ + ๐Ÿ“Š Admin Panel + + + ๐Ÿงช Test Interface + +
+
+ + {/* Email Statistics */} +
+
+

+ Email Statistics +

+ +
+ + {loading ? ( +
+
Loading email statistics...
+
+ ) : ( +
+ + + + + {emailStats.processing > 0 && ( + + )} +
+ )} +
+ + {/* Quick Actions */} +
+

+ Quick Actions +

+
+
+

๐ŸŽฏ Test Email Sending

+

+ Send test emails using templates with the interactive testing interface. +

+ + Open Test Interface โ†’ + +
+ +
+

๐Ÿ“ Manage Templates

+

+ Create and edit email templates in the Payload admin interface. +

+ + Manage Templates โ†’ + +
+ +
+

๐Ÿ“ฌ Email Queue

+

+ View and manage the email outbox and delivery status. +

+ + View Email Queue โ†’ + +
+
+
+ + {/* Footer */} +
+ PayloadCMS Mailing Plugin Development Environment +
+
+
+ ) +} \ No newline at end of file diff --git a/dev/app/(frontend)/layout.tsx b/dev/app/(frontend)/layout.tsx new file mode 100644 index 0000000..9db289a --- /dev/null +++ b/dev/app/(frontend)/layout.tsx @@ -0,0 +1,24 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'PayloadCMS Mailing Plugin - Development', + description: 'Development environment for PayloadCMS Mailing Plugin', +} + +export default function FrontendLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {children} + + + ) +} \ No newline at end of file diff --git a/dev/app/mailing-test/page.tsx b/dev/app/(frontend)/mailing-test/page.tsx similarity index 82% rename from dev/app/mailing-test/page.tsx rename to dev/app/(frontend)/mailing-test/page.tsx index acb394e..2a9faa7 100644 --- a/dev/app/mailing-test/page.tsx +++ b/dev/app/(frontend)/mailing-test/page.tsx @@ -33,6 +33,8 @@ export default function MailingTestPage() { const [selectedTemplate, setSelectedTemplate] = useState('') const [toEmail, setToEmail] = useState('test@example.com') const [variables, setVariables] = useState>({}) + const [jsonVariables, setJsonVariables] = useState('{}') + const [jsonError, setJsonError] = useState('') const [emailType, setEmailType] = useState<'send' | 'schedule'>('send') const [scheduleDate, setScheduleDate] = useState('') const [loading, setLoading] = useState(false) @@ -58,6 +60,23 @@ export default function MailingTestPage() { const template = templates.find(t => t.slug === templateSlug) if (template?.previewData) { setVariables(template.previewData) + setJsonVariables(JSON.stringify(template.previewData, null, 2)) + } else { + setVariables({}) + setJsonVariables('{}') + } + setJsonError('') + } + + const handleJsonVariablesChange = (jsonString: string) => { + setJsonVariables(jsonString) + setJsonError('') + + try { + const parsed = JSON.parse(jsonString) + setVariables(parsed) + } catch (error) { + setJsonError(error instanceof Error ? error.message : 'Invalid JSON') } } @@ -67,6 +86,11 @@ export default function MailingTestPage() { return } + if (jsonError) { + setMessage('Please fix the JSON syntax error before sending') + return + } + setLoading(true) setMessage('') @@ -88,7 +112,8 @@ export default function MailingTestPage() { const result = await response.json() if (result.success) { - setMessage(`โœ… ${result.message} (ID: ${result.emailId})`) + const statusIcon = result.status === 'sent' ? '๐Ÿ“ง' : '๐Ÿ“ซ' + setMessage(`โœ… ${statusIcon} ${result.message} (ID: ${result.emailId})`) fetchData() // Refresh email queue } else { setMessage(`โŒ Error: ${result.error}`) @@ -204,28 +229,43 @@ export default function MailingTestPage() { )} - {selectedTemplateData?.variables && ( + {selectedTemplate && (
-

Template Variables:

- {selectedTemplateData.variables.map(variable => ( -
- - setVariables({ - ...variables, - [variable.name]: variable.type === 'number' ? Number(e.target.value) : - variable.type === 'boolean' ? e.target.checked : - e.target.value - })} - style={{ width: '100%', padding: '8px', borderRadius: '4px', border: '1px solid #ddd' }} - /> + +