feat(03-02): add createClient, updateClient, deleteClient server actions
- 'use server' file with Zod validation (name min 1 char, valid email) - createClient: validate, insert, revalidatePath /portal/clients - updateClient: bind pattern (id, prevState, formData), revalidates client list + profile - deleteClient: auth check, delete by id, revalidatePath /portal/clients - Fixed Zod v4 .issues access (not .errors — v4 API change)
This commit is contained in:
83
teressa-copeland-homes/src/lib/actions/clients.ts
Normal file
83
teressa-copeland-homes/src/lib/actions/clients.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
import { db } from "@/lib/db";
|
||||||
|
import { clients } from "@/lib/db/schema";
|
||||||
|
import { auth } from "@/lib/auth";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
|
||||||
|
const clientSchema = z.object({
|
||||||
|
name: z.string().min(1, "Name is required"),
|
||||||
|
email: z.string().email("Valid email address required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function createClient(
|
||||||
|
_prevState: { error?: string; success?: boolean } | null,
|
||||||
|
formData: FormData
|
||||||
|
): Promise<{ error?: string; success?: boolean }> {
|
||||||
|
const session = await auth();
|
||||||
|
if (!session) {
|
||||||
|
return { error: "Unauthorized" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = clientSchema.safeParse({
|
||||||
|
name: formData.get("name"),
|
||||||
|
email: formData.get("email"),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!parsed.success) {
|
||||||
|
return { error: parsed.error.issues[0].message };
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.insert(clients).values({
|
||||||
|
name: parsed.data.name,
|
||||||
|
email: parsed.data.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
revalidatePath("/portal/clients");
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateClient(
|
||||||
|
id: string,
|
||||||
|
_prevState: { error?: string; success?: boolean } | null,
|
||||||
|
formData: FormData
|
||||||
|
): Promise<{ error?: string; success?: boolean }> {
|
||||||
|
const session = await auth();
|
||||||
|
if (!session) {
|
||||||
|
return { error: "Unauthorized" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = clientSchema.safeParse({
|
||||||
|
name: formData.get("name"),
|
||||||
|
email: formData.get("email"),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!parsed.success) {
|
||||||
|
return { error: parsed.error.issues[0].message };
|
||||||
|
}
|
||||||
|
|
||||||
|
await db
|
||||||
|
.update(clients)
|
||||||
|
.set({ name: parsed.data.name, email: parsed.data.email, updatedAt: new Date() })
|
||||||
|
.where(eq(clients.id, id));
|
||||||
|
|
||||||
|
revalidatePath("/portal/clients");
|
||||||
|
revalidatePath("/portal/clients/" + id);
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteClient(
|
||||||
|
id: string
|
||||||
|
): Promise<{ error?: string; success?: boolean }> {
|
||||||
|
const session = await auth();
|
||||||
|
if (!session) {
|
||||||
|
return { error: "Unauthorized" };
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.delete(clients).where(eq(clients.id, id));
|
||||||
|
|
||||||
|
revalidatePath("/portal/clients");
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user