@jhits/plugin-newsletter 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -3
- package/src/api/handler.ts +0 -693
- package/src/api/router.ts +0 -111
- package/src/index.server.ts +0 -12
- package/src/index.tsx +0 -313
- package/src/index.tsx.patch +0 -98
- package/src/init.tsx +0 -72
- package/src/lib/blocks/BlockRenderer.tsx +0 -125
- package/src/lib/email/EmailRenderer.tsx +0 -425
- package/src/lib/email/index.ts +0 -6
- package/src/lib/mappers/apiMapper.ts +0 -57
- package/src/lib/utils/blockHelpers.ts +0 -71
- package/src/lib/utils/slugify.ts +0 -43
- package/src/registry/BlockRegistry.ts +0 -53
- package/src/registry/index.ts +0 -5
- package/src/state/EditorContext.tsx +0 -279
- package/src/state/index.ts +0 -10
- package/src/state/reducer.ts +0 -561
- package/src/state/types.ts +0 -154
- package/src/types/block.ts +0 -275
- package/src/types/newsletter.ts +0 -151
- package/src/types/registry.ts +0 -14
- package/src/views/CanvasEditor/BlockWrapper.tsx +0 -143
- package/src/views/CanvasEditor/CanvasEditorView.tsx +0 -249
- package/src/views/CanvasEditor/EditorBody.tsx +0 -95
- package/src/views/CanvasEditor/EditorHeader.tsx +0 -139
- package/src/views/CanvasEditor/components/CustomBlockItem.tsx +0 -83
- package/src/views/CanvasEditor/components/EditorCanvas.tsx +0 -674
- package/src/views/CanvasEditor/components/EditorLibrary.tsx +0 -120
- package/src/views/CanvasEditor/components/EditorSidebar.tsx +0 -156
- package/src/views/CanvasEditor/components/ErrorBanner.tsx +0 -31
- package/src/views/CanvasEditor/components/LibraryItem.tsx +0 -71
- package/src/views/CanvasEditor/components/SlashCommandDetector.tsx +0 -196
- package/src/views/CanvasEditor/components/SlashCommandMenu.tsx +0 -131
- package/src/views/CanvasEditor/components/index.ts +0 -16
- package/src/views/CanvasEditor/hooks/index.ts +0 -7
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.ts +0 -136
- package/src/views/CanvasEditor/hooks/useNewsletterLoader.ts +0 -34
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.ts +0 -54
- package/src/views/CanvasEditor/hooks/useSlashCommand.ts +0 -106
- package/src/views/CanvasEditor/index.ts +0 -12
- package/src/views/NewsletterEditor.tsx +0 -38
- package/src/views/NewsletterManager.tsx +0 -240
- package/src/views/SettingsView.tsx +0 -216
- package/src/views/SubscribersView.tsx +0 -269
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Newsletter Manager View
|
|
3
|
-
* List and manage newsletters
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import React, { useState, useEffect } from 'react';
|
|
9
|
-
import { Plus, Mail, Calendar, Trash2, Edit2 } from 'lucide-react';
|
|
10
|
-
import { NewsletterListItem, NewsletterStatus } from '../types/newsletter';
|
|
11
|
-
|
|
12
|
-
export interface NewsletterManagerViewProps {
|
|
13
|
-
siteId: string;
|
|
14
|
-
locale: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function getStatusBadgeColor(status: NewsletterStatus) {
|
|
18
|
-
switch (status) {
|
|
19
|
-
case 'sent':
|
|
20
|
-
return 'bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20';
|
|
21
|
-
case 'scheduled':
|
|
22
|
-
return 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20';
|
|
23
|
-
case 'draft':
|
|
24
|
-
return 'bg-neutral-500/10 text-dashboard-text-secondary border-neutral-500/20';
|
|
25
|
-
case 'archived':
|
|
26
|
-
return 'bg-gray-500/10 text-gray-600 dark:text-gray-400 border-gray-500/20';
|
|
27
|
-
default:
|
|
28
|
-
return 'bg-neutral-500/10 text-dashboard-text-secondary border-neutral-500/20';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function NewsletterManagerView({ siteId, locale }: NewsletterManagerViewProps) {
|
|
33
|
-
const [newsletters, setNewsletters] = useState<NewsletterListItem[]>([]);
|
|
34
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
35
|
-
const [statusFilter, setStatusFilter] = useState<NewsletterStatus | 'all'>('all');
|
|
36
|
-
|
|
37
|
-
// Fetch newsletters
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
const fetchNewsletters = async () => {
|
|
40
|
-
try {
|
|
41
|
-
setIsLoading(true);
|
|
42
|
-
const response = await fetch('/api/plugin-newsletter/newsletters', {
|
|
43
|
-
credentials: 'include',
|
|
44
|
-
});
|
|
45
|
-
if (!response.ok) {
|
|
46
|
-
throw new Error('Failed to fetch newsletters');
|
|
47
|
-
}
|
|
48
|
-
const data = await response.json();
|
|
49
|
-
setNewsletters(Array.isArray(data) ? data : []);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
console.error('Failed to load newsletters:', error);
|
|
52
|
-
} finally {
|
|
53
|
-
setIsLoading(false);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
fetchNewsletters();
|
|
57
|
-
}, []);
|
|
58
|
-
|
|
59
|
-
// Filter newsletters
|
|
60
|
-
const filteredNewsletters = statusFilter === 'all'
|
|
61
|
-
? newsletters
|
|
62
|
-
: newsletters.filter(n => n.status === statusFilter);
|
|
63
|
-
|
|
64
|
-
// Handle create new newsletter
|
|
65
|
-
const handleCreate = () => {
|
|
66
|
-
window.location.href = '/dashboard/newsletter/new';
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// Handle edit newsletter
|
|
70
|
-
const handleEdit = (slug: string) => {
|
|
71
|
-
window.location.href = `/dashboard/newsletter/editor/${slug}`;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Handle delete newsletter
|
|
75
|
-
const handleDelete = async (slug: string, title: string) => {
|
|
76
|
-
if (!confirm(`Are you sure you want to delete "${title}"?`)) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
const response = await fetch(`/api/plugin-newsletter/newsletters/${slug}`, {
|
|
82
|
-
method: 'DELETE',
|
|
83
|
-
credentials: 'include',
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
if (!response.ok) {
|
|
87
|
-
throw new Error('Failed to delete newsletter');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Remove from local state
|
|
91
|
-
setNewsletters(prev => prev.filter(n => n.slug !== slug));
|
|
92
|
-
} catch (error: any) {
|
|
93
|
-
console.error('Failed to delete newsletter:', error);
|
|
94
|
-
alert(error.message || 'Failed to delete newsletter');
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// Format date
|
|
99
|
-
const formatDate = (dateString: string | undefined) => {
|
|
100
|
-
if (!dateString) return 'N/A';
|
|
101
|
-
const date = new Date(dateString);
|
|
102
|
-
return date.toLocaleDateString(locale, {
|
|
103
|
-
day: 'numeric',
|
|
104
|
-
month: 'short',
|
|
105
|
-
year: 'numeric',
|
|
106
|
-
});
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<div className="h-full w-full rounded-[2.5rem] bg-white dark:bg-neutral-900 p-8 overflow-y-auto">
|
|
111
|
-
<div className="max-w-7xl mx-auto">
|
|
112
|
-
{/* Header */}
|
|
113
|
-
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6 mb-8">
|
|
114
|
-
<div>
|
|
115
|
-
<h1 className="text-3xl font-black text-dashboard-text uppercase tracking-tighter mb-2">
|
|
116
|
-
Newsletters
|
|
117
|
-
</h1>
|
|
118
|
-
<p className="text-sm text-dashboard-text-secondary">
|
|
119
|
-
Create and manage your email newsletters
|
|
120
|
-
</p>
|
|
121
|
-
</div>
|
|
122
|
-
|
|
123
|
-
<div className="flex items-center gap-3">
|
|
124
|
-
{/* Status Filter */}
|
|
125
|
-
<select
|
|
126
|
-
value={statusFilter}
|
|
127
|
-
onChange={(e) => setStatusFilter(e.target.value as NewsletterStatus | 'all')}
|
|
128
|
-
className="bg-dashboard-bg border border-dashboard-border rounded-xl px-4 py-2.5 text-xs font-bold text-dashboard-text outline-none cursor-pointer uppercase tracking-widest"
|
|
129
|
-
>
|
|
130
|
-
<option value="all">All Status</option>
|
|
131
|
-
<option value="draft">Draft</option>
|
|
132
|
-
<option value="scheduled">Scheduled</option>
|
|
133
|
-
<option value="sent">Sent</option>
|
|
134
|
-
<option value="archived">Archived</option>
|
|
135
|
-
</select>
|
|
136
|
-
|
|
137
|
-
{/* Create Button */}
|
|
138
|
-
<button
|
|
139
|
-
onClick={handleCreate}
|
|
140
|
-
className="inline-flex items-center gap-2 px-6 py-3 rounded-full text-[10px] font-black uppercase tracking-widest transition-colors shadow-lg shadow-primary/20 bg-primary text-white hover:bg-primary/90"
|
|
141
|
-
>
|
|
142
|
-
<Plus size={14} />
|
|
143
|
-
New Newsletter
|
|
144
|
-
</button>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
|
|
148
|
-
{/* Newsletters Table */}
|
|
149
|
-
<div className="bg-dashboard-bg rounded-3xl border border-dashboard-border overflow-hidden">
|
|
150
|
-
{isLoading ? (
|
|
151
|
-
<div className="flex items-center justify-center py-20">
|
|
152
|
-
<div className="w-8 h-8 border-4 border-primary/20 border-t-primary rounded-full animate-spin" />
|
|
153
|
-
</div>
|
|
154
|
-
) : filteredNewsletters.length === 0 ? (
|
|
155
|
-
<div className="py-24 text-center">
|
|
156
|
-
<Mail size={64} className="mx-auto text-dashboard-text-secondary mb-4" />
|
|
157
|
-
<p className="text-dashboard-text-secondary font-serif italic text-lg mb-6">
|
|
158
|
-
{statusFilter === 'all' ? 'No newsletters yet.' : `No newsletters found with status "${statusFilter}".`}
|
|
159
|
-
</p>
|
|
160
|
-
<button
|
|
161
|
-
onClick={handleCreate}
|
|
162
|
-
className="inline-flex items-center gap-2 px-6 py-3 rounded-full text-[10px] font-black uppercase tracking-widest transition-colors shadow-lg shadow-primary/20 bg-primary text-white hover:bg-primary/90"
|
|
163
|
-
>
|
|
164
|
-
<Plus size={14} />
|
|
165
|
-
Create Your First Newsletter
|
|
166
|
-
</button>
|
|
167
|
-
</div>
|
|
168
|
-
) : (
|
|
169
|
-
<div className="overflow-x-auto">
|
|
170
|
-
<table className="w-full text-left border-collapse">
|
|
171
|
-
<thead>
|
|
172
|
-
<tr className="bg-dashboard-bg text-dashboard-text text-[10px] uppercase tracking-[0.2em] font-black border-b border-dashboard-border">
|
|
173
|
-
<th className="px-8 py-5">Title</th>
|
|
174
|
-
<th className="px-8 py-5">Subject</th>
|
|
175
|
-
<th className="px-8 py-5">Status</th>
|
|
176
|
-
<th className="px-8 py-5 text-right">Updated</th>
|
|
177
|
-
<th className="px-8 py-5 text-right">Actions</th>
|
|
178
|
-
</tr>
|
|
179
|
-
</thead>
|
|
180
|
-
<tbody className="divide-y divide-dashboard-border">
|
|
181
|
-
{filteredNewsletters.map((newsletter) => (
|
|
182
|
-
<tr
|
|
183
|
-
key={newsletter.id}
|
|
184
|
-
className="hover:bg-dashboard-bg transition-colors group"
|
|
185
|
-
>
|
|
186
|
-
<td className="px-8 py-5">
|
|
187
|
-
<div className="flex items-center gap-4">
|
|
188
|
-
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary group-hover:bg-primary group-hover:text-white transition-colors">
|
|
189
|
-
<Mail size={18} />
|
|
190
|
-
</div>
|
|
191
|
-
<span className="text-sm font-medium text-dashboard-text tracking-tight">
|
|
192
|
-
{newsletter.title}
|
|
193
|
-
</span>
|
|
194
|
-
</div>
|
|
195
|
-
</td>
|
|
196
|
-
<td className="px-8 py-5">
|
|
197
|
-
<span className="text-sm text-dashboard-text-secondary">
|
|
198
|
-
{newsletter.subject || 'No subject'}
|
|
199
|
-
</span>
|
|
200
|
-
</td>
|
|
201
|
-
<td className="px-8 py-5">
|
|
202
|
-
<span className={`text-[10px] font-black px-3 py-1 rounded-full uppercase border ${getStatusBadgeColor(newsletter.status)}`}>
|
|
203
|
-
{newsletter.status}
|
|
204
|
-
</span>
|
|
205
|
-
</td>
|
|
206
|
-
<td className="px-8 py-5 text-right text-xs text-dashboard-text-secondary font-medium">
|
|
207
|
-
<div className="flex items-center justify-end gap-2">
|
|
208
|
-
<Calendar size={14} />
|
|
209
|
-
{formatDate(newsletter.updatedAt)}
|
|
210
|
-
</div>
|
|
211
|
-
</td>
|
|
212
|
-
<td className="px-8 py-5 text-right">
|
|
213
|
-
<div className="flex items-center justify-end gap-2">
|
|
214
|
-
<button
|
|
215
|
-
onClick={() => handleEdit(newsletter.slug)}
|
|
216
|
-
className="p-2.5 rounded-full text-dashboard-text-secondary hover:text-primary hover:bg-primary/10 transition-colors"
|
|
217
|
-
title="Edit newsletter"
|
|
218
|
-
>
|
|
219
|
-
<Edit2 size={18} />
|
|
220
|
-
</button>
|
|
221
|
-
<button
|
|
222
|
-
onClick={() => handleDelete(newsletter.slug, newsletter.title)}
|
|
223
|
-
className="p-2.5 rounded-full text-dashboard-text-secondary hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
|
|
224
|
-
title="Delete newsletter"
|
|
225
|
-
>
|
|
226
|
-
<Trash2 size={18} />
|
|
227
|
-
</button>
|
|
228
|
-
</div>
|
|
229
|
-
</td>
|
|
230
|
-
</tr>
|
|
231
|
-
))}
|
|
232
|
-
</tbody>
|
|
233
|
-
</table>
|
|
234
|
-
</div>
|
|
235
|
-
)}
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
);
|
|
240
|
-
}
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Newsletter Settings View
|
|
3
|
-
* Interface for managing newsletter welcome email settings
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import React, { useState, useEffect } from 'react';
|
|
9
|
-
import { Save, RefreshCw, Mail, Settings2, Globe } from 'lucide-react';
|
|
10
|
-
import { NewsletterSettings } from '../types/newsletter';
|
|
11
|
-
|
|
12
|
-
export interface SettingsViewProps {
|
|
13
|
-
siteId: string;
|
|
14
|
-
locale: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const SUPPORTED_LANGUAGES = ['nl', 'en', 'sv'];
|
|
18
|
-
|
|
19
|
-
export function SettingsView({ siteId, locale }: SettingsViewProps) {
|
|
20
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
21
|
-
const [isSaving, setIsSaving] = useState(false);
|
|
22
|
-
const [showSuccess, setShowSuccess] = useState(false);
|
|
23
|
-
const [settings, setSettings] = useState<NewsletterSettings>({
|
|
24
|
-
id: 'welcome_automation',
|
|
25
|
-
languages: {
|
|
26
|
-
nl: { title: '', message: '' },
|
|
27
|
-
en: { title: '', message: '' },
|
|
28
|
-
sv: { title: '', message: '' },
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// Fetch settings on load
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
const fetchSettings = async () => {
|
|
35
|
-
try {
|
|
36
|
-
setIsLoading(true);
|
|
37
|
-
const response = await fetch('/api/plugin-newsletter/settings', {
|
|
38
|
-
credentials: 'include',
|
|
39
|
-
});
|
|
40
|
-
if (!response.ok) {
|
|
41
|
-
throw new Error('Failed to fetch settings');
|
|
42
|
-
}
|
|
43
|
-
const data = await response.json();
|
|
44
|
-
if (data.languages) {
|
|
45
|
-
setSettings({
|
|
46
|
-
id: data.id || 'welcome_automation',
|
|
47
|
-
languages: {
|
|
48
|
-
nl: data.languages.nl || { title: '', message: '' },
|
|
49
|
-
en: data.languages.en || { title: '', message: '' },
|
|
50
|
-
sv: data.languages.sv || { title: '', message: '' },
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
} catch (error) {
|
|
55
|
-
console.error('Failed to load settings:', error);
|
|
56
|
-
} finally {
|
|
57
|
-
setIsLoading(false);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
fetchSettings();
|
|
61
|
-
}, []);
|
|
62
|
-
|
|
63
|
-
// Save settings
|
|
64
|
-
const handleSave = async () => {
|
|
65
|
-
try {
|
|
66
|
-
setIsSaving(true);
|
|
67
|
-
const response = await fetch('/api/plugin-newsletter/settings', {
|
|
68
|
-
method: 'POST',
|
|
69
|
-
headers: { 'Content-Type': 'application/json' },
|
|
70
|
-
credentials: 'include',
|
|
71
|
-
body: JSON.stringify({
|
|
72
|
-
id: 'welcome_automation',
|
|
73
|
-
languages: settings.languages,
|
|
74
|
-
}),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
if (!response.ok) {
|
|
78
|
-
const error = await response.json();
|
|
79
|
-
throw new Error(error.error || 'Failed to save settings');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
setShowSuccess(true);
|
|
83
|
-
setTimeout(() => setShowSuccess(false), 3000);
|
|
84
|
-
} catch (error: any) {
|
|
85
|
-
console.error('Failed to save settings:', error);
|
|
86
|
-
alert(error.message || 'Failed to save settings');
|
|
87
|
-
} finally {
|
|
88
|
-
setIsSaving(false);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
// Update language setting
|
|
93
|
-
const updateLanguageSetting = (lang: string, field: 'title' | 'message', value: string) => {
|
|
94
|
-
setSettings(prev => ({
|
|
95
|
-
...prev,
|
|
96
|
-
languages: {
|
|
97
|
-
...prev.languages,
|
|
98
|
-
[lang]: {
|
|
99
|
-
...prev.languages[lang],
|
|
100
|
-
[field]: value,
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
}));
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
if (isLoading) {
|
|
107
|
-
return (
|
|
108
|
-
<div className="h-full w-full bg-white dark:bg-neutral-900 text-dashboard-text flex items-center justify-center">
|
|
109
|
-
<div className="text-center">
|
|
110
|
-
<RefreshCw className="w-8 h-8 animate-spin text-primary mx-auto mb-4" />
|
|
111
|
-
<p className="text-sm text-dashboard-text-secondary">Loading settings...</p>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<div className="h-full w-full rounded-[2.5rem] bg-white dark:bg-neutral-900 p-8 overflow-y-auto">
|
|
119
|
-
<div className="max-w-6xl mx-auto">
|
|
120
|
-
{/* Header */}
|
|
121
|
-
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6 mb-8">
|
|
122
|
-
<div>
|
|
123
|
-
<h1 className="text-3xl font-black text-dashboard-text uppercase tracking-tighter mb-2">
|
|
124
|
-
Newsletter Settings
|
|
125
|
-
</h1>
|
|
126
|
-
<p className="text-sm text-dashboard-text-secondary">
|
|
127
|
-
Configure welcome emails for new subscribers
|
|
128
|
-
</p>
|
|
129
|
-
</div>
|
|
130
|
-
<button
|
|
131
|
-
onClick={handleSave}
|
|
132
|
-
disabled={isSaving}
|
|
133
|
-
className={`inline-flex items-center gap-2 px-6 py-3 rounded-full text-[10px] font-black uppercase tracking-widest transition-colors shadow-lg shadow-primary/20 ${isSaving
|
|
134
|
-
? 'bg-neutral-400 text-white cursor-not-allowed'
|
|
135
|
-
: showSuccess
|
|
136
|
-
? 'bg-green-600 text-white'
|
|
137
|
-
: 'bg-primary text-white hover:bg-primary/90'
|
|
138
|
-
}`}
|
|
139
|
-
>
|
|
140
|
-
{isSaving ? (
|
|
141
|
-
<>
|
|
142
|
-
<RefreshCw className="w-4 h-4 animate-spin" />
|
|
143
|
-
Saving...
|
|
144
|
-
</>
|
|
145
|
-
) : showSuccess ? (
|
|
146
|
-
<>
|
|
147
|
-
<Settings2 className="w-4 h-4" />
|
|
148
|
-
Saved!
|
|
149
|
-
</>
|
|
150
|
-
) : (
|
|
151
|
-
<>
|
|
152
|
-
<Save className="w-4 h-4" />
|
|
153
|
-
Save Settings
|
|
154
|
-
</>
|
|
155
|
-
)}
|
|
156
|
-
</button>
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
{/* Welcome Email Settings */}
|
|
160
|
-
<section className="bg-dashboard-sidebar p-8 rounded-3xl border border-dashboard-border mb-8">
|
|
161
|
-
<div className="flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6">
|
|
162
|
-
<Mail size={20} className="text-primary" />
|
|
163
|
-
Welcome Email Automation
|
|
164
|
-
</div>
|
|
165
|
-
<p className="text-sm text-dashboard-text-secondary mb-8">
|
|
166
|
-
Configure the welcome email that will be sent automatically when someone subscribes to your newsletter.
|
|
167
|
-
</p>
|
|
168
|
-
|
|
169
|
-
{/* Language Tabs */}
|
|
170
|
-
<div className="space-y-8">
|
|
171
|
-
{SUPPORTED_LANGUAGES.map(lang => (
|
|
172
|
-
<div key={lang} className="bg-dashboard-card p-6 rounded-2xl border border-dashboard-border">
|
|
173
|
-
<div className="flex items-center gap-2 mb-6">
|
|
174
|
-
<Globe size={16} className="text-primary" />
|
|
175
|
-
<h3 className="text-lg font-black text-dashboard-text uppercase tracking-tight">
|
|
176
|
-
{lang.toUpperCase()} - {lang === 'nl' ? 'Dutch' : lang === 'en' ? 'English' : 'Swedish'}
|
|
177
|
-
</h3>
|
|
178
|
-
</div>
|
|
179
|
-
<div className="space-y-4">
|
|
180
|
-
<div>
|
|
181
|
-
<label className="text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest block mb-2">
|
|
182
|
-
Email Subject
|
|
183
|
-
</label>
|
|
184
|
-
<input
|
|
185
|
-
type="text"
|
|
186
|
-
value={settings.languages[lang]?.title || ''}
|
|
187
|
-
onChange={(e) => updateLanguageSetting(lang, 'title', e.target.value)}
|
|
188
|
-
placeholder={`Welcome email subject (${lang.toUpperCase()})`}
|
|
189
|
-
className="w-full px-4 py-3 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary transition-colors text-dashboard-text"
|
|
190
|
-
/>
|
|
191
|
-
</div>
|
|
192
|
-
<div>
|
|
193
|
-
<label className="text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest block mb-2">
|
|
194
|
-
Email Message
|
|
195
|
-
</label>
|
|
196
|
-
<textarea
|
|
197
|
-
value={settings.languages[lang]?.message || ''}
|
|
198
|
-
onChange={(e) => updateLanguageSetting(lang, 'message', e.target.value)}
|
|
199
|
-
placeholder={`Welcome email message (${lang.toUpperCase()}). Use **bold** for bold text and • for bullet points.`}
|
|
200
|
-
rows={8}
|
|
201
|
-
className="w-full px-4 py-3 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary transition-colors text-dashboard-text resize-none font-mono text-sm"
|
|
202
|
-
/>
|
|
203
|
-
<p className="text-[10px] text-dashboard-text-secondary mt-2">
|
|
204
|
-
Supports markdown: **bold**, • bullet points, line breaks
|
|
205
|
-
</p>
|
|
206
|
-
</div>
|
|
207
|
-
</div>
|
|
208
|
-
</div>
|
|
209
|
-
))}
|
|
210
|
-
</div>
|
|
211
|
-
</section>
|
|
212
|
-
</div>
|
|
213
|
-
</div>
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|