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.
120 lines
3.1 KiB
TypeScript
120 lines
3.1 KiB
TypeScript
"use server";
|
|
|
|
import { revalidatePath } from "next/cache";
|
|
import { z } from "zod";
|
|
import { getCurrentUser } from "@/data/auth";
|
|
import {
|
|
countPemakaianSatuanBarang,
|
|
deleteSatuanBarang,
|
|
insertSatuanBarang,
|
|
updateSatuanBarang,
|
|
type SatuanBarangInput,
|
|
} from "@/data/satuan-barang";
|
|
import {
|
|
logActionError,
|
|
type DeleteState,
|
|
type FormState,
|
|
} from "@/lib/server-action";
|
|
|
|
export type SimpanSatuanBarangState = FormState<"namaSatuanBarang">;
|
|
export type HapusSatuanBarangState = DeleteState;
|
|
|
|
const satuanBarangSchema = z.object({
|
|
namaSatuanBarang: z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Nama satuan wajib diisi")
|
|
.max(30, "Maksimal 30 karakter"),
|
|
});
|
|
|
|
export async function simpanSatuanBarang(
|
|
_prevState: SimpanSatuanBarangState,
|
|
formData: FormData,
|
|
): Promise<SimpanSatuanBarangState> {
|
|
const user = await getCurrentUser();
|
|
const values = {
|
|
namaSatuanBarang: String(formData.get("namaSatuanBarang") ?? ""),
|
|
};
|
|
|
|
const parsed = satuanBarangSchema.safeParse(values);
|
|
if (!parsed.success) {
|
|
return {
|
|
ok: false,
|
|
fieldErrors: z.flattenError(parsed.error).fieldErrors,
|
|
values,
|
|
};
|
|
}
|
|
|
|
const input: SatuanBarangInput = parsed.data;
|
|
const idRaw = String(formData.get("idSatuanBarang") ?? "");
|
|
const id = idRaw ? Number.parseInt(idRaw, 10) : null;
|
|
if (id !== null && (!Number.isSafeInteger(id) || id <= 0)) {
|
|
return { ok: false, error: "ID satuan tidak valid", values };
|
|
}
|
|
|
|
try {
|
|
if (id !== null) {
|
|
const updated = await updateSatuanBarang(id, input);
|
|
if (!updated) {
|
|
return { ok: false, error: "Satuan tidak ditemukan", values };
|
|
}
|
|
revalidatePath("/master/satuan-barang");
|
|
return { ok: true };
|
|
}
|
|
|
|
await insertSatuanBarang(input);
|
|
revalidatePath("/master/satuan-barang");
|
|
return { ok: true };
|
|
} catch (error) {
|
|
logActionError(
|
|
"simpanSatuanBarang",
|
|
{
|
|
userId: user.id,
|
|
idSatuanBarang: id ?? "(baru)",
|
|
nama: input.namaSatuanBarang,
|
|
},
|
|
error,
|
|
);
|
|
return {
|
|
ok: false,
|
|
error: "Gagal menyimpan satuan, coba simpan ulang",
|
|
values,
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function hapusSatuanBarang(
|
|
_prevState: HapusSatuanBarangState,
|
|
formData: FormData,
|
|
): Promise<HapusSatuanBarangState> {
|
|
const user = await getCurrentUser();
|
|
|
|
const id = Number.parseInt(String(formData.get("idSatuanBarang") ?? ""), 10);
|
|
if (!Number.isSafeInteger(id) || id <= 0) {
|
|
return { ok: false, error: "ID satuan tidak ada" };
|
|
}
|
|
|
|
try {
|
|
const dipakai = await countPemakaianSatuanBarang(id);
|
|
if (dipakai > 0) {
|
|
return {
|
|
ok: false,
|
|
error: `Satuan masih dipakai ${dipakai} barang, tidak bisa dihapus`,
|
|
};
|
|
}
|
|
|
|
const deleted = await deleteSatuanBarang(id);
|
|
if (!deleted) {
|
|
return { ok: false, error: "Satuan tidak ditemukan" };
|
|
}
|
|
revalidatePath("/master/satuan-barang");
|
|
return { ok: true };
|
|
} catch (error) {
|
|
logActionError("hapusSatuanBarang", { userId: user.id, id }, error);
|
|
return {
|
|
ok: false,
|
|
error: "Gagal menghapus satuan, coba hapus ulang",
|
|
};
|
|
}
|
|
}
|