'use server'; import db from '@/lib/db'; import { z } from 'zod'; import { revalidatePath } from 'next/cache'; import { redirect } from 'next/navigation'; export type Flow = { id: number; name: string; description: string | null; path: string; createdAt: string; updatedAt: string; }; const flowSchema = z.object({ id: z.coerce.number().optional(), name: z.string().min(1, 'Name is required'), description: z.string().optional(), path: z.string().min(1, 'Path is required').startsWith('/', { message: 'Path must start with /' }), }); type State = { success: boolean; message: string; errors?: z.ZodIssue[] | null; } export async function getFlows(): Promise { try { const stmt = db.prepare( 'SELECT id, name, description, path, createdAt, updatedAt FROM flows ORDER BY createdAt DESC' ); const flows = stmt.all() as Flow[]; return flows; } catch (error) { console.error('Failed to fetch flows:', error); return []; } } export async function getFlow(id: number): Promise { try { const stmt = db.prepare('SELECT * FROM flows WHERE id = ?'); const flow = stmt.get(id) as Flow | undefined; return flow || null; } catch (error) { console.error(`Failed to fetch flow with id ${id}:`, error); return null; } } export async function saveFlow(prevState: State, formData: FormData): Promise { const validatedFields = flowSchema.safeParse(Object.fromEntries(formData.entries())); if (!validatedFields.success) { return { success: false, message: 'Invalid fields.', errors: validatedFields.error.issues, }; } const { id, name, description, path } = validatedFields.data; try { if (id) { // Check if path is unique before updating const checkStmt = db.prepare('SELECT id FROM flows WHERE path = ? AND id != ?'); const existing = checkStmt.get(path, id); if (existing) { return { success: false, message: 'A flow with this path already exists.', errors: [{ path: ['path'], message: 'A flow with this path already exists.', code: 'custom' }], }; } // Update existing flow const stmt = db.prepare( 'UPDATE flows SET name = ?, description = ?, path = ?, updatedAt = CURRENT_TIMESTAMP WHERE id = ?' ); stmt.run(name, description || null, path, id); } else { // Check if path is unique before inserting const checkStmt = db.prepare('SELECT id FROM flows WHERE path = ?'); const existing = checkStmt.get(path); if (existing) { return { success: false, message: 'A flow with this path already exists.', errors: [{ path: ['path'], message: 'A flow with this path already exists.', code: 'custom' }], }; } // Create new flow const stmt = db.prepare( 'INSERT INTO flows (name, description, path) VALUES (?, ?, ?)' ); stmt.run(name, description || null, path); } } catch (error: any) { console.error('Failed to save flow:', error); if (error.code === 'SQLITE_CONSTRAINT_UNIQUE') { return { success: false, message: 'A flow with this path already exists.', errors: [{ path: ['path'], message: 'A flow with this path already exists.', code: 'custom' }], }; } return { success: false, message: 'An internal error occurred.', errors: null, }; } revalidatePath('/admin/flows'); redirect('/admin/flows'); } export async function deleteFlow(id: number): Promise<{ success: boolean, message: string }> { try { // Prevent deletion of the default flow (ID 1) if (id === 1) { return { success: false, message: "The default flow cannot be deleted." }; } const stmt = db.prepare('DELETE FROM flows WHERE id = ?'); stmt.run(id); revalidatePath('/admin/flows'); return { success: true, message: 'Flow deleted successfully.' }; } catch (error) { console.error('Failed to delete flow:', error); return { success: false, message: 'An internal error occurred.' }; } }