diff --git a/scripts/seed.ts b/scripts/seed.ts index ac30a4a..39eb0b0 100644 --- a/scripts/seed.ts +++ b/scripts/seed.ts @@ -15,22 +15,45 @@ function seed() { ) `); + // Create settings table if it doesn't exist + db.exec(` + CREATE TABLE IF NOT EXISTS settings ( + key TEXT PRIMARY KEY, + value TEXT + ) + `); + // Check if the admin user already exists - const stmt = db.prepare('SELECT * FROM users WHERE email = ?'); - const adminUser = stmt.get('admin@example.com'); + const userStmt = db.prepare('SELECT * FROM users WHERE email = ?'); + const adminUser = userStmt.get('admin@example.com'); if (!adminUser) { // Insert the default admin user // In a real application, you should hash the password! - const insert = db.prepare( + const insertUser = db.prepare( "INSERT INTO users (email, password, name) VALUES (?, ?, ?)" ); - insert.run("admin@example.com", "password", "Admin User"); + insertUser.run("admin@example.com", "password", "Admin User"); console.log('Admin user created.'); } else { console.log('Admin user already exists.'); } + // Check if the hourly_rate setting already exists + const settingStmt = db.prepare('SELECT * FROM settings WHERE key = ?'); + const hourlyRateSetting = settingStmt.get('hourly_rate'); + + if (!hourlyRateSetting) { + // Insert the default hourly rate + const insertSetting = db.prepare( + "INSERT INTO settings (key, value) VALUES (?, ?)" + ); + insertSetting.run("hourly_rate", "100"); + console.log('Default hourly rate set.'); + } else { + console.log('Hourly rate setting already exists.'); + } + console.log('Seeding complete.'); } diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx index d9dfc5a..26ae2d4 100644 --- a/src/app/admin/layout.tsx +++ b/src/app/admin/layout.tsx @@ -53,6 +53,12 @@ export default function AdminLayout({ Email + + + + Hourly Rate + + diff --git a/src/app/admin/settings/hourly-rate/page.tsx b/src/app/admin/settings/hourly-rate/page.tsx new file mode 100644 index 0000000..26c9770 --- /dev/null +++ b/src/app/admin/settings/hourly-rate/page.tsx @@ -0,0 +1,71 @@ +"use client"; + +import { useEffect, useState, useTransition } from 'react'; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Label } from "@/components/ui/label"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { useToast } from "@/hooks/use-toast"; +import { getSetting, setSetting } from '@/lib/actions/settings'; + +const HourlyRateSettingsPage = () => { + const { toast } = useToast(); + const [hourlyRate, setHourlyRate] = useState(''); + const [isPending, startTransition] = useTransition(); + + useEffect(() => { + async function fetchHourlyRate() { + const rate = await getSetting('hourly_rate'); + if (rate) { + setHourlyRate(rate); + } + } + fetchHourlyRate(); + }, []); + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + startTransition(async () => { + try { + await setSetting('hourly_rate', hourlyRate); + toast({ title: "Hourly Rate Saved", description: "The hourly rate has been updated successfully." }); + } catch (error) { + console.error("Failed to save hourly rate:", error); + toast({ title: "Error", description: "Failed to save hourly rate.", variant: "destructive" }); + } + }); + }; + + return ( + + + Hourly Rate Settings + + Set the default hourly rate used for project estimations. + + + + + + Hourly Rate ($) + setHourlyRate(e.target.value)} + required + /> + + + {isPending ? 'Saving...' : 'Save Hourly Rate'} + + + + + ); +}; + +export default HourlyRateSettingsPage; diff --git a/src/lib/actions/settings.ts b/src/lib/actions/settings.ts new file mode 100644 index 0000000..192ad5c --- /dev/null +++ b/src/lib/actions/settings.ts @@ -0,0 +1,26 @@ +'use server'; + +import db from '@/lib/db'; + +export async function getSetting(key: string): Promise { + try { + const stmt = db.prepare('SELECT value FROM settings WHERE key = ?'); + const result = stmt.get(key) as { value: string } | undefined; + return result?.value ?? null; + } catch (error) { + console.error(`Failed to get setting "${key}":`, error); + return null; + } +} + +export async function setSetting(key: string, value: string): Promise { + try { + const stmt = db.prepare( + 'INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value' + ); + stmt.run(key, value); + } catch (error) { + console.error(`Failed to set setting "${key}":`, error); + throw new Error(`Could not update setting for ${key}`); + } +} diff --git a/src/lib/db.ts b/src/lib/db.ts index ba3d3a7..9d290df 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -3,7 +3,7 @@ import Database from 'better-sqlite3'; // Use a file-based database in development const db = new Database('local.db'); -// Create the users table if it doesn't exist +// Create the tables if they don't exist db.exec(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -13,4 +13,12 @@ db.exec(` ) `); +db.exec(` + CREATE TABLE IF NOT EXISTS settings ( + key TEXT PRIMARY KEY, + value TEXT + ) +`); + + export default db;