Files
estimation-flow/src/lib/actions/flows.ts
T

113 lines
3.1 KiB
TypeScript
Raw Normal View History

'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 /' }),
});
2025-07-18 04:52:21 +00:00
type State = {
success: boolean;
message: string;
errors?: z.ZodIssue[] | null;
}
export async function getFlows(): Promise<Flow[]> {
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<Flow | null> {
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;
}
}
2025-07-18 04:52:21 +00:00
export async function saveFlow(prevState: State, formData: FormData): Promise<State> {
const validatedFields = flowSchema.safeParse(Object.fromEntries(formData.entries()));
if (!validatedFields.success) {
return {
success: false,
message: 'Invalid fields.',
2025-07-18 04:52:21 +00:00
errors: validatedFields.error.issues,
};
}
const { id, name, description, path } = validatedFields.data;
try {
if (id) {
// 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 {
// 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);
2025-07-18 04:52:21 +00:00
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,
2025-07-18 04:52:21 +00:00
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 {
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.' };
}
}