feat(10-02): implement lead management UI with list, detail, and form pages
- Create /admin/leads list page with LeadTable component showing all leads - Implement /admin/leads/[id] detail page with activity log and reminders - Add LeadForm component (CreateLeadModal and EditLeadModal) for CRUD operations - Create server actions (createLead, updateLead, deleteLead) with Zod validation - Add missing UI components (dialog.tsx, form.tsx) from shadcn - Install date-fns for date formatting with Italian locale support - All routes compile successfully with npm run build Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"use server";
|
||||
|
||||
import { z } from "zod";
|
||||
import { db } from "@/db";
|
||||
import { leads } from "@/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { createLeadSchema, updateLeadSchema } from "@/lib/lead-validators";
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
export async function createLead(data: z.infer<typeof createLeadSchema>) {
|
||||
const parsed = createLeadSchema.safeParse(data);
|
||||
|
||||
if (!parsed.success) {
|
||||
return { success: false, error: parsed.error.issues[0].message };
|
||||
}
|
||||
|
||||
try {
|
||||
const [lead] = await db
|
||||
.insert(leads)
|
||||
.values({
|
||||
name: parsed.data.name,
|
||||
email: parsed.data.email || null,
|
||||
phone: parsed.data.phone || null,
|
||||
company: parsed.data.company || null,
|
||||
status: parsed.data.status || "contacted",
|
||||
notes: parsed.data.notes || null,
|
||||
})
|
||||
.returning();
|
||||
|
||||
revalidatePath("/admin/leads");
|
||||
return { success: true, lead };
|
||||
} catch (error) {
|
||||
console.error("createLead error:", error);
|
||||
return { success: false, error: "Errore nella creazione del lead" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateLead(
|
||||
id: string,
|
||||
data: z.infer<typeof updateLeadSchema>
|
||||
) {
|
||||
const parsed = updateLeadSchema.safeParse(data);
|
||||
|
||||
if (!parsed.success) {
|
||||
return { success: false, error: parsed.error.issues[0].message };
|
||||
}
|
||||
|
||||
try {
|
||||
const updateData: Record<string, any> = { updated_at: new Date() };
|
||||
|
||||
if (parsed.data.name !== undefined) updateData.name = parsed.data.name;
|
||||
if (parsed.data.email !== undefined) updateData.email = parsed.data.email || null;
|
||||
if (parsed.data.phone !== undefined) updateData.phone = parsed.data.phone || null;
|
||||
if (parsed.data.company !== undefined) updateData.company = parsed.data.company || null;
|
||||
if (parsed.data.status !== undefined) updateData.status = parsed.data.status;
|
||||
if (parsed.data.notes !== undefined) updateData.notes = parsed.data.notes || null;
|
||||
|
||||
const [updated] = await db
|
||||
.update(leads)
|
||||
.set(updateData)
|
||||
.where(eq(leads.id, id))
|
||||
.returning();
|
||||
|
||||
revalidatePath("/admin/leads");
|
||||
revalidatePath(`/admin/leads/${id}`);
|
||||
return { success: true, lead: updated };
|
||||
} catch (error) {
|
||||
console.error("updateLead error:", error);
|
||||
return { success: false, error: "Errore nell'aggiornamento" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteLead(id: string) {
|
||||
try {
|
||||
await db.delete(leads).where(eq(leads.id, id));
|
||||
revalidatePath("/admin/leads");
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error("deleteLead error:", error);
|
||||
return { success: false, error: "Errore nell'eliminazione" };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user