diff --git a/scripts/seed.ts b/scripts/seed.ts index 6a684c7..3b438f3 100644 --- a/scripts/seed.ts +++ b/scripts/seed.ts @@ -23,6 +23,19 @@ function seed() { ) `); + // Create flows table + db.exec(` + CREATE TABLE IF NOT EXISTS flows ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + description TEXT, + path TEXT NOT NULL, + createdAt DATETIME DEFAULT CURRENT_TIMESTAMP, + updatedAt DATETIME DEFAULT CURRENT_TIMESTAMP + ) + `); + + // Check if the hourly_rate setting already exists const settingStmt = db.prepare('SELECT * FROM settings WHERE key = ?'); const hourlyRateSetting = settingStmt.get('hourly_rate'); @@ -98,6 +111,20 @@ function seed() { console.log('Default email template updated.'); } + // Seed default flow + const flowStmt = db.prepare('SELECT * FROM flows WHERE id = ?'); + const defaultFlow = flowStmt.get(1); + + if (!defaultFlow) { + const insertFlow = db.prepare( + "INSERT INTO flows (id, name, description, path) VALUES (?, ?, ?, ?)" + ); + insertFlow.run(1, 'Cost Estimator', 'The main cost estimation tool for clients.', '/'); + console.log('Default flow created.'); + } else { + console.log('Default flow already exists.'); + } + console.log('Seeding complete.'); } diff --git a/src/app/admin/flows/[id]/page.tsx b/src/app/admin/flows/[id]/page.tsx new file mode 100644 index 0000000..568fe87 --- /dev/null +++ b/src/app/admin/flows/[id]/page.tsx @@ -0,0 +1,134 @@ + +'use client'; + +import { useEffect, useState } from 'react'; +import { useFormState } from 'react-dom'; +import { getFlow, saveFlow, type Flow } from '@/lib/actions/flows'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; +import { useToast } from '@/hooks/use-toast'; +import Link from 'next/link'; +import { ChevronLeft } from 'lucide-react'; +import { Skeleton } from '@/components/ui/skeleton'; + +interface FlowFormPageProps { + params: { id: string }; +} + +function SubmitButton({ isNew }: { isNew: boolean }) { + return ( + + ); +} + +export default function FlowFormPage({ params }: FlowFormPageProps) { + const [state, formAction] = useFormState(saveFlow, { success: false, message: '', errors: null }); + const [flow, setFlow] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const { toast } = useToast(); + + const isNew = params.id === 'new'; + + useEffect(() => { + if (!isNew) { + const fetchFlow = async () => { + setIsLoading(true); + const existingFlow = await getFlow(Number(params.id)); + setFlow(existingFlow); + setIsLoading(false); + }; + fetchFlow(); + } else { + setIsLoading(false); + } + }, [params.id, isNew]); + + useEffect(() => { + if (state.message) { + toast({ + title: state.success ? 'Success!' : 'Error', + description: state.message, + variant: state.success ? 'default' : 'destructive', + }); + } + }, [state, toast]); + + if (isLoading) { + return ( +
+ + + + + + + +
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ ) + } + + return ( +
+
+ +

+ {isNew ? 'Create New Flow' : 'Edit Flow'} +

+
+ + + + Flow Details + + {isNew ? 'Fill in the details for your new flow.' : 'Update the details for this flow.'} + + + + +
+ + + {state.errors?.name &&

{state.errors.name[0]}

} +
+
+ + + {state.errors?.path &&

{state.errors.path[0]}

} +
+
+ +