diff --git a/scripts/seed.ts b/scripts/seed.ts
index 83b452c..5acdab7 100644
--- a/scripts/seed.ts
+++ b/scripts/seed.ts
@@ -13,6 +13,15 @@ function seed() {
)
`);
+ // Create email_templates table
+ db.exec(`
+ CREATE TABLE IF NOT EXISTS email_templates (
+ id INTEGER PRIMARY KEY,
+ subject TEXT,
+ body TEXT
+ )
+ `);
+
// Check if the hourly_rate setting already exists
const settingStmt = db.prepare('SELECT * FROM settings WHERE key = ?');
const hourlyRateSetting = settingStmt.get('hourly_rate');
@@ -28,6 +37,32 @@ function seed() {
console.log('Hourly rate setting already exists.');
}
+ // Check if default email template exists
+ const templateStmt = db.prepare('SELECT * FROM email_templates WHERE id = ?');
+ const defaultTemplate = templateStmt.get(1);
+
+ if (!defaultTemplate) {
+ const insertTemplate = db.prepare(
+ "INSERT INTO email_templates (id, subject, body) VALUES (?, ?, ?)"
+ );
+ const defaultSubject = "Your Project Estimate is Ready!";
+ const defaultBody = `Hello, [User Name],
+
+Thank you for using EstimateFlow. We've prepared a rough estimate for your project based on your selections.
+
+[EstimateDetails]
+
+Please note that this is a preliminary estimate. For a more detailed quote and to discuss your project further, please don't hesitate to contact us.
+
+Best regards,
+The EstimateFlow Team`;
+ insertTemplate.run(1, defaultSubject, defaultBody);
+ console.log('Default email template created.');
+ } else {
+ console.log('Default email template already exists.');
+ }
+
+
console.log('Seeding complete.');
}
diff --git a/src/app/admin/settings/email-templates/page.tsx b/src/app/admin/settings/email-templates/page.tsx
index a7589ec..11cedaf 100644
--- a/src/app/admin/settings/email-templates/page.tsx
+++ b/src/app/admin/settings/email-templates/page.tsx
@@ -1,8 +1,95 @@
+'use client';
+
+import { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
+import { useToast } from '@/hooks/use-toast';
+import { getEmailTemplate, updateEmailTemplate } from '@/lib/actions/email';
+import { Input } from '@/components/ui/input';
+import { Textarea } from '@/components/ui/textarea';
+import { Label } from '@/components/ui/label';
+
+type EmailTemplate = {
+ subject: string;
+ body: string;
+};
+
+function EmailPreview({ template }: { template: EmailTemplate }) {
+ const previewBody = template.body.replace(
+ '[EstimateDetails]',
+ `
+
+
Custom Development Estimate
+
[Custom Hours]+ hours
+
+
+
Ready-Made Tools Estimate
+
[Ready-Made Hours]+ hours
+
+
`
+ ).replace(/\n/g, '
');
+
+ return (
+
+ );
+}
export default function EmailTemplatesPage() {
+ const [isEditing, setIsEditing] = useState(false);
+ const [template, setTemplate] = useState({ subject: '', body: '' });
+ const [isLoading, setIsLoading] = useState(true);
+ const { toast } = useToast();
+
+ useEffect(() => {
+ async function fetchTemplate() {
+ setIsLoading(true);
+ try {
+ const fetchedTemplate = await getEmailTemplate();
+ if (fetchedTemplate) {
+ setTemplate(fetchedTemplate);
+ } else {
+ throw new Error('Could not find email template.');
+ }
+ } catch (error: any) {
+ toast({
+ variant: 'destructive',
+ title: 'Error',
+ description: error.message || 'Failed to load email template.',
+ });
+ } finally {
+ setIsLoading(false);
+ }
+ }
+ fetchTemplate();
+ }, [toast]);
+
+ const handleSave = async () => {
+ try {
+ const result = await updateEmailTemplate(template);
+ if (result.success) {
+ toast({
+ title: 'Success',
+ description: 'Email template updated successfully.',
+ });
+ setIsEditing(false);
+ } else {
+ throw new Error(result.message);
+ }
+ } catch (error: any) {
+ toast({
+ variant: 'destructive',
+ title: 'Error',
+ description: error.message || 'Failed to save template.',
+ });
+ }
+ };
+
return (
@@ -18,33 +105,45 @@ export default function EmailTemplatesPage() {
Estimate Completion Email
This is the email users receive.
-
+ {!isEditing ? (
+
+ ) : (
+
+
+
+
+ )}
-
-
-
Your Project Estimate is Ready!
-
Hello, [User Name],
-
Thank you for using EstimateFlow. We've prepared a rough estimate for your project based on your selections.
-
-
-
-
Custom Development Estimate
-
[Custom Hours]+ hours
-
-
-
Ready-Made Tools Estimate
-
[Ready-Made Hours]+ hours
-
+ {isLoading ? (
+
Loading template...
+ ) : isEditing ? (
+
+
+
+ setTemplate({ ...template, subject: e.target.value })}
+ />
+
+
-
-
Please note that this is a preliminary estimate. For a more detailed quote and to discuss your project further, please don't hesitate to contact us.
-
-
Best regards,
-
The EstimateFlow Team
-
+ ) : (
+
+ )}
diff --git a/src/lib/actions/email.ts b/src/lib/actions/email.ts
new file mode 100644
index 0000000..d093c26
--- /dev/null
+++ b/src/lib/actions/email.ts
@@ -0,0 +1,54 @@
+
+'use server';
+
+import { z } from 'zod';
+import db from '@/lib/db';
+import { revalidatePath } from 'next/cache';
+
+const emailTemplateSchema = z.object({
+ subject: z.string().min(1, 'Subject is required.'),
+ body: z.string().min(1, 'Body is required.'),
+});
+
+/**
+ * Gets the email template from the database.
+ */
+export async function getEmailTemplate(): Promise<{ subject: string; body: string } | null> {
+ try {
+ const stmt = db.prepare('SELECT subject, body FROM email_templates WHERE id = ?');
+ // We assume there is only one template with id = 1
+ const template = stmt.get(1) as { subject: string; body: string } | undefined;
+ if (!template) {
+ return null;
+ }
+ return template;
+ } catch (error) {
+ console.error('Failed to get email template:', error);
+ return null;
+ }
+}
+
+/**
+ * Updates the email template in the database.
+ */
+export async function updateEmailTemplate(data: { subject: string; body: string }): Promise<{ success: boolean; message: string }> {
+ const validation = emailTemplateSchema.safeParse(data);
+ if (!validation.success) {
+ const errorMessages = validation.error.issues.map(issue => issue.message).join(' ');
+ return { success: false, message: `Invalid data provided: ${errorMessages}` };
+ }
+
+ const { subject, body } = validation.data;
+
+ try {
+ const stmt = db.prepare('UPDATE email_templates SET subject = ?, body = ? WHERE id = ?');
+ // We assume we're updating the template with id = 1
+ stmt.run(subject, body, 1);
+
+ revalidatePath('/admin/settings/email-templates');
+ return { success: true, message: 'Email template updated successfully!' };
+ } catch (error) {
+ console.error('Failed to update email template:', error);
+ return { success: false, message: 'An unexpected error occurred.' };
+ }
+}