You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.0 KiB
TypeScript
139 lines
4.0 KiB
TypeScript
"use server";
|
|
|
|
import { revalidatePath } from "next/cache";
|
|
import { z } from "zod";
|
|
import { getCurrentUser } from "@/data/auth";
|
|
import {
|
|
deletePelanggan,
|
|
insertPelanggan,
|
|
updatePelanggan,
|
|
type PelangganInput,
|
|
} from "@/data/pelanggan";
|
|
import {
|
|
logActionError,
|
|
type DeleteState,
|
|
type FormState,
|
|
} from "@/lib/server-action";
|
|
|
|
type PelangganField = keyof typeof pelangganSchema.shape;
|
|
export type SimpanPelangganState = FormState<PelangganField> & {
|
|
kdCustomer?: string;
|
|
};
|
|
|
|
export type HapusPelangganState = DeleteState;
|
|
|
|
const pelangganSchema = z.object({
|
|
nama: z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Nama wajib diisi")
|
|
.max(100, "Nama maksimal 100 karakter"),
|
|
alias: z.string().trim().max(11, "Alias maksimal 11 karakter"),
|
|
ktp: z.string().trim().max(16, "No. KTP maksimal 16 karakter"),
|
|
alamat: z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Alamat wajib diisi")
|
|
.max(100, "Alamat maksimal 100 karakter"),
|
|
wilayah: z.string().trim().max(200, "Wilayah maksimal 200 karakter"),
|
|
telp: z.string().trim().max(15, "Telepon maksimal 15 karakter"),
|
|
ponsel: z.string().trim().max(15, "Ponsel maksimal 15 karakter"),
|
|
email: z.string().trim().max(30, "Email maksimal 30 karakter"),
|
|
jenisCustomer: z.string().trim().max(1, "Jenis customer maksimal 1 karakter"),
|
|
upline: z.string().trim().max(11, "Upline maksimal 11 karakter"),
|
|
btsBon: z.coerce
|
|
.number({ error: "Harus berupa angka" })
|
|
.int("Harus bilangan bulat")
|
|
.min(0, "Tidak boleh negatif")
|
|
.max(2_000_000_000, "Maksimal 2.000.000.000"),
|
|
});
|
|
|
|
function emptyStringToNull(value: string): string | null {
|
|
return value === "" ? null : value;
|
|
}
|
|
|
|
export async function simpanPelanggan(
|
|
_prevState: SimpanPelangganState,
|
|
formData: FormData,
|
|
): Promise<SimpanPelangganState> {
|
|
const user = await getCurrentUser();
|
|
|
|
const fields = Object.keys(pelangganSchema.shape) as PelangganField[];
|
|
const values = Object.fromEntries(
|
|
fields.map((field) => [field, String(formData.get(field) ?? "")]),
|
|
) as Record<PelangganField, string>;
|
|
|
|
const parsed = pelangganSchema.safeParse(values);
|
|
if (!parsed.success) {
|
|
return {
|
|
ok: false,
|
|
fieldErrors: z.flattenError(parsed.error).fieldErrors,
|
|
values,
|
|
};
|
|
}
|
|
|
|
const input: PelangganInput = {
|
|
...parsed.data,
|
|
wilayah: emptyStringToNull(parsed.data.wilayah),
|
|
telp: emptyStringToNull(parsed.data.telp),
|
|
ponsel: emptyStringToNull(parsed.data.ponsel),
|
|
email: emptyStringToNull(parsed.data.email),
|
|
jenisCustomer: emptyStringToNull(parsed.data.jenisCustomer),
|
|
upline: emptyStringToNull(parsed.data.upline),
|
|
};
|
|
const kdCustomer = String(formData.get("kdCustomer") ?? "").trim();
|
|
|
|
try {
|
|
if (kdCustomer === "") {
|
|
const kdBaru = await insertPelanggan(input);
|
|
revalidatePath("/master/pelanggan");
|
|
return { ok: true, kdCustomer: kdBaru };
|
|
}
|
|
|
|
const updated = await updatePelanggan(kdCustomer, input);
|
|
if (!updated) {
|
|
return { ok: false, error: "Pelanggan tidak ditemukan", values };
|
|
}
|
|
revalidatePath("/master/pelanggan");
|
|
return { ok: true, kdCustomer };
|
|
} catch (error) {
|
|
logActionError(
|
|
"simpanPelanggan",
|
|
{ userId: user.id, kdCustomer: kdCustomer || "(baru)", nama: input.nama },
|
|
error,
|
|
);
|
|
return {
|
|
ok: false,
|
|
error: "Gagal menyimpan pelanggan, coba simpan ulang",
|
|
values,
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function hapusPelanggan(
|
|
_prevState: HapusPelangganState,
|
|
formData: FormData,
|
|
): Promise<HapusPelangganState> {
|
|
const user = await getCurrentUser();
|
|
|
|
const kdCustomer = String(formData.get("kdCustomer") ?? "").trim();
|
|
if (kdCustomer === "") {
|
|
return { ok: false, error: "Kode pelanggan tidak ada" };
|
|
}
|
|
|
|
try {
|
|
const deleted = await deletePelanggan(kdCustomer);
|
|
if (!deleted) {
|
|
return { ok: false, error: "Pelanggan tidak ditemukan" };
|
|
}
|
|
revalidatePath("/master/pelanggan");
|
|
return { ok: true };
|
|
} catch (error) {
|
|
logActionError("hapusPelanggan", { userId: user.id, kdCustomer }, error);
|
|
return {
|
|
ok: false,
|
|
error: "Gagal menghapus pelanggan, coba hapus ulang",
|
|
};
|
|
}
|
|
}
|