the hourly rate is not being saved
This commit is contained in:
+27
-4
@@ -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
|
// Check if the admin user already exists
|
||||||
const stmt = db.prepare('SELECT * FROM users WHERE email = ?');
|
const userStmt = db.prepare('SELECT * FROM users WHERE email = ?');
|
||||||
const adminUser = stmt.get('admin@example.com');
|
const adminUser = userStmt.get('admin@example.com');
|
||||||
|
|
||||||
if (!adminUser) {
|
if (!adminUser) {
|
||||||
// Insert the default admin user
|
// Insert the default admin user
|
||||||
// In a real application, you should hash the password!
|
// 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 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.');
|
console.log('Admin user created.');
|
||||||
} else {
|
} else {
|
||||||
console.log('Admin user already exists.');
|
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.');
|
console.log('Seeding complete.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ export default function AdminLayout({
|
|||||||
Email
|
Email
|
||||||
</SidebarMenuSubButton>
|
</SidebarMenuSubButton>
|
||||||
</SidebarMenuSubItem>
|
</SidebarMenuSubItem>
|
||||||
|
<SidebarMenuSubItem>
|
||||||
|
<SidebarMenuSubButton href="/admin/settings/hourly-rate" >
|
||||||
|
<Settings />
|
||||||
|
Hourly Rate
|
||||||
|
</SidebarMenuSubButton>
|
||||||
|
</SidebarMenuSubItem>
|
||||||
</SidebarMenuSub>
|
</SidebarMenuSub>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
|
|||||||
@@ -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<HTMLFormElement>) => {
|
||||||
|
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 (
|
||||||
|
<Card className="max-w-2xl">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Hourly Rate Settings</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Set the default hourly rate used for project estimations.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<Label htmlFor="hourlyRate">Hourly Rate ($)</Label>
|
||||||
|
<Input
|
||||||
|
id="hourlyRate"
|
||||||
|
name="hourlyRate"
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
placeholder="e.g., 100.00"
|
||||||
|
value={hourlyRate}
|
||||||
|
onChange={(e) => setHourlyRate(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button type="submit" className="self-start" disabled={isPending}>
|
||||||
|
{isPending ? 'Saving...' : 'Save Hourly Rate'}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HourlyRateSettingsPage;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
|
import db from '@/lib/db';
|
||||||
|
|
||||||
|
export async function getSetting(key: string): Promise<string | null> {
|
||||||
|
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<void> {
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-1
@@ -3,7 +3,7 @@ import Database from 'better-sqlite3';
|
|||||||
// Use a file-based database in development
|
// Use a file-based database in development
|
||||||
const db = new Database('local.db');
|
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(`
|
db.exec(`
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
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;
|
export default db;
|
||||||
|
|||||||
Reference in New Issue
Block a user