Files
EmailManager/App.tsx
2025-12-11 08:56:41 +01:00

137 lines
4.5 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import TemplateList from './components/TemplateList';
import TemplateEditor from './components/TemplateEditor';
import { ViewState, EmailTemplate, SQL_SCHEMA } from './types';
import { getTemplates, deleteTemplate } from './services/storage';
import { Database } from 'lucide-react';
const App: React.FC = () => {
const [view, setView] = useState<ViewState>('dashboard');
const [templates, setTemplates] = useState<EmailTemplate[]>([]);
const [selectedTemplate, setSelectedTemplate] = useState<EmailTemplate | undefined>(undefined);
const [showSchema, setShowSchema] = useState(false);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
refreshTemplates();
}, []);
const refreshTemplates = async () => {
setIsLoading(true);
const data = await getTemplates();
setTemplates(data);
setIsLoading(false);
};
const handleCreate = () => {
setSelectedTemplate(undefined);
setView('editor');
};
const handleEdit = (t: EmailTemplate) => {
setSelectedTemplate(t);
setView('editor');
};
const handleClone = (t: EmailTemplate) => {
// Create a copy of the template with a new ID and updated name
const clonedTemplate: EmailTemplate = {
...t,
id: crypto.randomUUID(), // Generate new ID so it's treated as a new insert
name: `${t.name} (Copy)`,
updatedAt: new Date().toISOString()
};
setSelectedTemplate(clonedTemplate);
setView('editor');
};
const handleDelete = async (id: string) => {
if (window.confirm("Are you sure you want to delete this template?")) {
await deleteTemplate(id);
await refreshTemplates();
}
};
const handleSave = async () => {
await refreshTemplates();
setView('dashboard');
};
return (
<div className="min-h-screen bg-slate-50 text-slate-900 font-sans">
{view === 'dashboard' && (
<>
{isLoading ? (
<div className="flex h-screen items-center justify-center text-slate-500">
Loading templates...
</div>
) : (
<TemplateList
templates={templates}
onCreate={handleCreate}
onEdit={handleEdit}
onClone={handleClone}
onDelete={handleDelete}
/>
)}
<div className="fixed bottom-6 right-6">
<button
onClick={() => setShowSchema(true)}
className="bg-slate-800 text-white px-4 py-3 rounded-full shadow-lg hover:bg-slate-900 flex items-center gap-2 text-sm font-medium transition-transform hover:scale-105"
>
<Database size={18} />
DB Schema
</button>
</div>
</>
)}
{view === 'editor' && (
<TemplateEditor
initialTemplate={selectedTemplate}
onBack={() => setView('dashboard')}
onSave={handleSave}
/>
)}
{/* Database Schema Modal (Global Help) */}
{showSchema && (
<div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-2xl max-w-2xl w-full p-6">
<h2 className="text-xl font-bold mb-4 flex items-center gap-2">
<Database className="text-brand-600"/>
Database Setup for n8n
</h2>
<p className="text-slate-600 text-sm mb-4">
To make this app work with your internal software, create this table in your MySQL or PostgreSQL database.
</p>
<div className="bg-slate-900 text-slate-100 p-4 rounded-lg overflow-x-auto custom-scrollbar mb-4">
<pre className="text-xs font-mono leading-relaxed">{SQL_SCHEMA}</pre>
</div>
<div className="flex justify-end gap-3">
<button
onClick={() => {
navigator.clipboard.writeText(SQL_SCHEMA);
alert("Schema copied!");
}}
className="px-4 py-2 bg-slate-100 text-slate-700 font-medium rounded hover:bg-slate-200"
>
Copy SQL
</button>
<button
onClick={() => setShowSchema(false)}
className="px-4 py-2 bg-brand-600 text-white font-medium rounded hover:bg-brand-700"
>
Close
</button>
</div>
</div>
</div>
)}
</div>
);
};
export default App;