Menerapkan pagination di submenu pegawai & berita
This commit is contained in:
@@ -80,13 +80,33 @@ const berita = proxy({
|
|||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.desa.berita["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
loading: false,
|
||||||
berita.findMany.data = (res.data?.data ) ?? [];
|
|
||||||
|
async load(page = 1, limit = 10) {
|
||||||
|
berita.findMany.loading = true;
|
||||||
|
berita.findMany.page = page;
|
||||||
|
try {
|
||||||
|
const res = await ApiFetch.api.desa.berita["find-many"].get({
|
||||||
|
query: {
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
berita.findMany.data = res.data.data ?? [];
|
||||||
|
berita.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch berita paginated:", err);
|
||||||
|
} finally {
|
||||||
|
berita.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.BeritaGetPayload<{
|
| Prisma.BeritaGetPayload<{
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ const posisiOrganisasi = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["posisi-organisasi"]["create"].post(
|
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||||
this.form
|
"posisi-organisasi"
|
||||||
);
|
]["create"].post(this.form);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
toast.success("Berhasil menambahkan posisi organisasi");
|
toast.success("Berhasil menambahkan posisi organisasi");
|
||||||
posisiOrganisasi.findMany.load();
|
posisiOrganisasi.findMany.load();
|
||||||
@@ -62,12 +62,15 @@ const posisiOrganisasi = proxy({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/ekonomi/struktur-organisasi/posisi-organisasi/${id}`, {
|
const response = await fetch(
|
||||||
method: "GET",
|
`/api/ekonomi/struktur-organisasi/posisi-organisasi/${id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "GET",
|
||||||
},
|
headers: {
|
||||||
});
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -160,7 +163,9 @@ const posisiOrganisasi = proxy({
|
|||||||
}>,
|
}>,
|
||||||
async load() {
|
async load() {
|
||||||
try {
|
try {
|
||||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["posisi-organisasi"]["find-many"].get();
|
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||||
|
"posisi-organisasi"
|
||||||
|
]["find-many"].get();
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
// The API now returns the id field, so we can use it directly
|
// The API now returns the id field, so we can use it directly
|
||||||
this.data = res.data?.data ?? [];
|
this.data = res.data?.data ?? [];
|
||||||
@@ -209,238 +214,278 @@ const posisiOrganisasi = proxy({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const templatePegawai = z.object({
|
const templatePegawai = z.object({
|
||||||
namaLengkap: z.string().min(1, "Nama wajib diisi"),
|
namaLengkap: z.string().min(1, "Nama wajib diisi"),
|
||||||
gelarAkademik: z.string().optional(),
|
gelarAkademik: z.string().optional(),
|
||||||
imageId: z.string().nullable().optional(),
|
imageId: z.string().nullable().optional(),
|
||||||
tanggalMasuk: z.string().optional(), // ISO format
|
tanggalMasuk: z.string().optional(), // ISO format
|
||||||
email: z.string().email("Email tidak valid").optional(),
|
email: z.string().email("Email tidak valid").optional(),
|
||||||
telepon: z.string().optional(),
|
telepon: z.string().optional(),
|
||||||
alamat: z.string().optional(),
|
alamat: z.string().optional(),
|
||||||
posisiId: z.string().min(1, "Posisi wajib diisi"),
|
posisiId: z.string().min(1, "Posisi wajib diisi"),
|
||||||
isActive: z.boolean().default(true),
|
isActive: z.boolean().default(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
const pegawaiDefaultForm = {
|
|
||||||
namaLengkap: "",
|
|
||||||
gelarAkademik: "",
|
|
||||||
imageId: "",
|
|
||||||
tanggalMasuk: "",
|
|
||||||
email: "",
|
|
||||||
telepon: "",
|
|
||||||
alamat: "",
|
|
||||||
posisiId: "",
|
|
||||||
isActive: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const pegawai = proxy({
|
|
||||||
create: {
|
|
||||||
form: { ...pegawaiDefaultForm },
|
|
||||||
loading: false,
|
|
||||||
async submit() {
|
|
||||||
const cek = templatePegawai.safeParse(pegawai.create.form);
|
|
||||||
if (!cek.success) {
|
|
||||||
const err = cek.error.issues.map(i => i.message).join("\n");
|
|
||||||
toast.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
pegawai.create.loading = true;
|
|
||||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["pegawai"]["create"].post(
|
|
||||||
pegawai.create.form
|
|
||||||
);
|
|
||||||
if (res.status === 200) {
|
|
||||||
toast.success("Pegawai berhasil ditambahkan");
|
|
||||||
await pegawai.findMany.load();
|
|
||||||
} else {
|
|
||||||
toast.error(res.data?.message ?? "Gagal tambah pegawai");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Gagal create:", error);
|
|
||||||
toast.error("Terjadi kesalahan saat menambahkan pegawai");
|
|
||||||
} finally {
|
|
||||||
pegawai.create.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
findMany: {
|
|
||||||
data: null as (Prisma.PegawaiGetPayload<{ include: { posisi: true, image: true } }> & { isActive: boolean })[] | null,
|
|
||||||
async load() {
|
|
||||||
try {
|
|
||||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["pegawai"]["find-many"].get();
|
|
||||||
if (res.status === 200) {
|
|
||||||
pegawai.findMany.data = (res.data?.data ?? []).map((item: any) => ({
|
|
||||||
...item,
|
|
||||||
posisi: item.posisi || { id: '', nama: '' }, // Ensure posisi exists with required fields
|
|
||||||
isActive: item.isActive ?? true // Default to true if not provided
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
console.error('Failed to load pegawai:', res.data?.message);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error loading pegawai:', error);
|
|
||||||
pegawai.findMany.data = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
findUnique: {
|
|
||||||
data: null as (Prisma.PegawaiGetPayload<{ include: { posisi: true, image: true } }> & { isActive: boolean }) | null,
|
|
||||||
async load(id: string) {
|
|
||||||
const res = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${id}`);
|
|
||||||
if (res.ok) {
|
|
||||||
const json = await res.json();
|
|
||||||
pegawai.findUnique.data = json.data ? {
|
|
||||||
...json.data,
|
|
||||||
isActive: json.data.isActive ?? json.data.aktif ?? true // Fallback ke aktif:true jika tidak ada data
|
|
||||||
} : null;
|
|
||||||
} else {
|
|
||||||
pegawai.findUnique.data = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
delete: {
|
|
||||||
loading: false,
|
|
||||||
async byId(id: string) {
|
|
||||||
if (!id) return toast.warn("ID tidak valid");
|
|
||||||
try {
|
|
||||||
pegawai.delete.loading = true;
|
|
||||||
const res = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/del/${id}`, {
|
|
||||||
method: "DELETE",
|
|
||||||
});
|
|
||||||
const json = await res.json();
|
|
||||||
if (res.ok) {
|
|
||||||
toast.success(json.message ?? "Berhasil hapus pegawai");
|
|
||||||
await pegawai.findMany.load();
|
|
||||||
} else {
|
|
||||||
toast.error(json.message ?? "Gagal hapus pegawai");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Gagal delete:", error);
|
|
||||||
toast.error("Terjadi kesalahan saat menghapus");
|
|
||||||
} finally {
|
|
||||||
pegawai.delete.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
edit: {
|
|
||||||
id: "",
|
|
||||||
form: { ...pegawaiDefaultForm },
|
|
||||||
loading: false,
|
|
||||||
|
|
||||||
async load(id: string) {
|
|
||||||
if (!id) {
|
|
||||||
toast.warn("ID tidak valid");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${id}`, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (result?.success) {
|
|
||||||
const data = result.data;
|
|
||||||
this.id = data.id;
|
|
||||||
this.form = {
|
|
||||||
namaLengkap: data.namaLengkap,
|
|
||||||
gelarAkademik: data.gelarAkademik,
|
|
||||||
imageId: data.imageId,
|
|
||||||
tanggalMasuk: data.tanggalMasuk,
|
|
||||||
email: data.email,
|
|
||||||
telepon: data.telepon,
|
|
||||||
alamat: data.alamat,
|
|
||||||
posisiId: data.posisiId,
|
|
||||||
isActive: data.isActive,
|
|
||||||
};
|
|
||||||
return data; // Return the loaded data
|
|
||||||
} else {
|
|
||||||
throw new Error(result?.message || "Gagal memuat data");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error loading berita:", error);
|
|
||||||
toast.error(error instanceof Error ? error.message : "Gagal memuat data");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async submit() {
|
|
||||||
const cek = templatePegawai.safeParse(pegawai.edit.form);
|
|
||||||
if (!cek.success) {
|
|
||||||
const err = `[${cek.error.issues
|
|
||||||
.map((v) => `${v.path.join(".")}`)
|
|
||||||
.join("\n")}] required`;
|
|
||||||
toast.error(err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
pegawai.edit.loading = true;
|
|
||||||
|
|
||||||
// Format tanggalMasuk to ISO string if it exists
|
|
||||||
const formattedTanggalMasuk = this.form.tanggalMasuk
|
|
||||||
? new Date(this.form.tanggalMasuk).toISOString()
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const response = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${this.id}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
id: this.id,
|
|
||||||
namaLengkap: this.form.namaLengkap,
|
|
||||||
gelarAkademik: this.form.gelarAkademik,
|
|
||||||
imageId: this.form.imageId || null,
|
|
||||||
tanggalMasuk: formattedTanggalMasuk,
|
|
||||||
email: this.form.email,
|
|
||||||
telepon: this.form.telepon,
|
|
||||||
alamat: this.form.alamat,
|
|
||||||
posisiId: this.form.posisiId,
|
|
||||||
isActive: this.form.isActive,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
toast.success("Berhasil update pegawai");
|
|
||||||
await pegawai.findMany.load(); // refresh list
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new Error(result.message || "Gagal update pegawai");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating pegawai:", error);
|
|
||||||
toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat update pegawai");
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
pegawai.edit.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
pegawai.edit.id = "";
|
|
||||||
pegawai.edit.form = { ...pegawaiDefaultForm };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const pegawaiDefaultForm = {
|
||||||
|
namaLengkap: "",
|
||||||
|
gelarAkademik: "",
|
||||||
|
imageId: "",
|
||||||
|
tanggalMasuk: "",
|
||||||
|
email: "",
|
||||||
|
telepon: "",
|
||||||
|
alamat: "",
|
||||||
|
posisiId: "",
|
||||||
|
isActive: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const pegawai = proxy({
|
||||||
|
create: {
|
||||||
|
form: { ...pegawaiDefaultForm },
|
||||||
|
loading: false,
|
||||||
|
async submit() {
|
||||||
|
const cek = templatePegawai.safeParse(pegawai.create.form);
|
||||||
|
if (!cek.success) {
|
||||||
|
const err = cek.error.issues.map((i) => i.message).join("\n");
|
||||||
|
toast.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pegawai.create.loading = true;
|
||||||
|
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||||
|
"pegawai"
|
||||||
|
]["create"].post(pegawai.create.form);
|
||||||
|
if (res.status === 200) {
|
||||||
|
toast.success("Pegawai berhasil ditambahkan");
|
||||||
|
await pegawai.findMany.load();
|
||||||
|
} else {
|
||||||
|
toast.error(res.data?.message ?? "Gagal tambah pegawai");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal create:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat menambahkan pegawai");
|
||||||
|
} finally {
|
||||||
|
pegawai.create.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// In struktur-organisasi.ts
|
||||||
|
findMany: {
|
||||||
|
data: null as any[] | null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
total: 0,
|
||||||
|
loading: false,
|
||||||
|
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||||
|
pegawai.findMany.loading = true; // Use the full path to access the property
|
||||||
|
pegawai.findMany.page = page;
|
||||||
|
try {
|
||||||
|
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||||
|
"pegawai"
|
||||||
|
]["find-many"].get({
|
||||||
|
query: { page, limit },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
pegawai.findMany.data = res.data.data || [];
|
||||||
|
pegawai.findMany.total = res.data.total || 0;
|
||||||
|
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
||||||
|
} else {
|
||||||
|
console.error("Failed to load pegawai:", res.data?.message);
|
||||||
|
pegawai.findMany.data = [];
|
||||||
|
pegawai.findMany.total = 0;
|
||||||
|
pegawai.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading pegawai:", error);
|
||||||
|
pegawai.findMany.data = [];
|
||||||
|
pegawai.findMany.total = 0;
|
||||||
|
pegawai.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
pegawai.findMany.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
findUnique: {
|
||||||
|
data: null as
|
||||||
|
| (Prisma.PegawaiGetPayload<{
|
||||||
|
include: { posisi: true; image: true };
|
||||||
|
}> & { isActive: boolean })
|
||||||
|
| null,
|
||||||
|
async load(id: string) {
|
||||||
|
const res = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${id}`);
|
||||||
|
if (res.ok) {
|
||||||
|
const json = await res.json();
|
||||||
|
pegawai.findUnique.data = json.data
|
||||||
|
? {
|
||||||
|
...json.data,
|
||||||
|
isActive: json.data.isActive ?? json.data.aktif ?? true, // Fallback ke aktif:true jika tidak ada data
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
} else {
|
||||||
|
pegawai.findUnique.data = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
delete: {
|
||||||
|
loading: false,
|
||||||
|
async byId(id: string) {
|
||||||
|
if (!id) return toast.warn("ID tidak valid");
|
||||||
|
try {
|
||||||
|
pegawai.delete.loading = true;
|
||||||
|
const res = await fetch(
|
||||||
|
`/api/ekonomi/struktur-organisasi/pegawai/del/${id}`,
|
||||||
|
{
|
||||||
|
method: "DELETE",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const json = await res.json();
|
||||||
|
if (res.ok) {
|
||||||
|
toast.success(json.message ?? "Berhasil hapus pegawai");
|
||||||
|
await pegawai.findMany.load();
|
||||||
|
} else {
|
||||||
|
toast.error(json.message ?? "Gagal hapus pegawai");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal delete:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat menghapus");
|
||||||
|
} finally {
|
||||||
|
pegawai.delete.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
edit: {
|
||||||
|
id: "",
|
||||||
|
form: { ...pegawaiDefaultForm },
|
||||||
|
loading: false,
|
||||||
|
|
||||||
|
async load(id: string) {
|
||||||
|
if (!id) {
|
||||||
|
toast.warn("ID tidak valid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/ekonomi/struktur-organisasi/pegawai/${id}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result?.success) {
|
||||||
|
const data = result.data;
|
||||||
|
this.id = data.id;
|
||||||
|
this.form = {
|
||||||
|
namaLengkap: data.namaLengkap,
|
||||||
|
gelarAkademik: data.gelarAkademik,
|
||||||
|
imageId: data.imageId,
|
||||||
|
tanggalMasuk: data.tanggalMasuk,
|
||||||
|
email: data.email,
|
||||||
|
telepon: data.telepon,
|
||||||
|
alamat: data.alamat,
|
||||||
|
posisiId: data.posisiId,
|
||||||
|
isActive: data.isActive,
|
||||||
|
};
|
||||||
|
return data; // Return the loaded data
|
||||||
|
} else {
|
||||||
|
throw new Error(result?.message || "Gagal memuat data");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading berita:", error);
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error ? error.message : "Gagal memuat data"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async submit() {
|
||||||
|
const cek = templatePegawai.safeParse(pegawai.edit.form);
|
||||||
|
if (!cek.success) {
|
||||||
|
const err = `[${cek.error.issues
|
||||||
|
.map((v) => `${v.path.join(".")}`)
|
||||||
|
.join("\n")}] required`;
|
||||||
|
toast.error(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pegawai.edit.loading = true;
|
||||||
|
|
||||||
|
// Format tanggalMasuk to ISO string if it exists
|
||||||
|
const formattedTanggalMasuk = this.form.tanggalMasuk
|
||||||
|
? new Date(this.form.tanggalMasuk).toISOString()
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/ekonomi/struktur-organisasi/pegawai/${this.id}`,
|
||||||
|
{
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: this.id,
|
||||||
|
namaLengkap: this.form.namaLengkap,
|
||||||
|
gelarAkademik: this.form.gelarAkademik,
|
||||||
|
imageId: this.form.imageId || null,
|
||||||
|
tanggalMasuk: formattedTanggalMasuk,
|
||||||
|
email: this.form.email,
|
||||||
|
telepon: this.form.telepon,
|
||||||
|
alamat: this.form.alamat,
|
||||||
|
posisiId: this.form.posisiId,
|
||||||
|
isActive: this.form.isActive,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json().catch(() => ({}));
|
||||||
|
throw new Error(
|
||||||
|
errorData.message || `HTTP error! status: ${response.status}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
toast.success("Berhasil update pegawai");
|
||||||
|
await pegawai.findMany.load(); // refresh list
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "Gagal update pegawai");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating pegawai:", error);
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "Terjadi kesalahan saat update pegawai"
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
pegawai.edit.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
pegawai.edit.id = "";
|
||||||
|
pegawai.edit.form = { ...pegawaiDefaultForm };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Schema Zod untuk form validasi
|
// Schema Zod untuk form validasi
|
||||||
const templateHubunganOrganisasiForm = z.object({
|
const templateHubunganOrganisasiForm = z.object({
|
||||||
@@ -474,7 +519,9 @@ const hubunganOrganisasi = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
hubunganOrganisasi.create.loading = true;
|
hubunganOrganisasi.create.loading = true;
|
||||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["hubungan-organisasi"]["create"].post(hubunganOrganisasi.create.form);
|
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||||
|
"hubungan-organisasi"
|
||||||
|
]["create"].post(hubunganOrganisasi.create.form);
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
hubunganOrganisasi.findMany.load();
|
hubunganOrganisasi.findMany.load();
|
||||||
@@ -482,7 +529,7 @@ const hubunganOrganisasi = proxy({
|
|||||||
} else {
|
} else {
|
||||||
return toast.error(res.data?.message || "Gagal menambahkan data");
|
return toast.error(res.data?.message || "Gagal menambahkan data");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Gagal create:", error);
|
console.error("Gagal create:", error);
|
||||||
toast.error("Terjadi kesalahan saat menambahkan");
|
toast.error("Terjadi kesalahan saat menambahkan");
|
||||||
} finally {
|
} finally {
|
||||||
@@ -490,7 +537,7 @@ const hubunganOrganisasi = proxy({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<{
|
data: null as Array<{
|
||||||
id: string;
|
id: string;
|
||||||
atasanId: string;
|
atasanId: string;
|
||||||
@@ -528,20 +575,29 @@ const hubunganOrganisasi = proxy({
|
|||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
try {
|
try {
|
||||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["hubungan-organisasi"]["find-many"].get();
|
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||||
|
"hubungan-organisasi"
|
||||||
|
]["find-many"].get();
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
hubunganOrganisasi.findMany.data = (res.data?.data ?? []).map((item: any) => ({
|
hubunganOrganisasi.findMany.data = (res.data?.data ?? []).map(
|
||||||
...item,
|
(item: any) => ({
|
||||||
atasan: item.atasan ? {
|
...item,
|
||||||
...item.atasan,
|
atasan: item.atasan
|
||||||
isActive: item.atasan.isActive ?? item.atasan.aktif ?? true
|
? {
|
||||||
} : null,
|
...item.atasan,
|
||||||
bawahan: item.bawahan ? {
|
isActive: item.atasan.isActive ?? item.atasan.aktif ?? true,
|
||||||
...item.bawahan,
|
}
|
||||||
isActive: item.bawahan.isActive ?? item.bawahan.aktif ?? true
|
: null,
|
||||||
} : null
|
bawahan: item.bawahan
|
||||||
}));
|
? {
|
||||||
|
...item.bawahan,
|
||||||
|
isActive:
|
||||||
|
item.bawahan.isActive ?? item.bawahan.aktif ?? true,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
})
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
hubunganOrganisasi.findMany.data = [];
|
hubunganOrganisasi.findMany.data = [];
|
||||||
}
|
}
|
||||||
@@ -591,7 +647,9 @@ const hubunganOrganisasi = proxy({
|
|||||||
|
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`);
|
const res = await fetch(
|
||||||
|
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`
|
||||||
|
);
|
||||||
const result = await res.json();
|
const result = await res.json();
|
||||||
|
|
||||||
if (res.ok && result?.success) {
|
if (res.ok && result?.success) {
|
||||||
@@ -616,7 +674,9 @@ const hubunganOrganisasi = proxy({
|
|||||||
if (!id) return toast.warn("ID tidak valid");
|
if (!id) return toast.warn("ID tidak valid");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`);
|
const res = await fetch(
|
||||||
|
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`
|
||||||
|
);
|
||||||
const result = await res.json();
|
const result = await res.json();
|
||||||
|
|
||||||
if (res.ok && result?.success) {
|
if (res.ok && result?.success) {
|
||||||
@@ -633,7 +693,9 @@ const hubunganOrganisasi = proxy({
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading:", error);
|
console.error("Error loading:", error);
|
||||||
toast.error(error instanceof Error ? error.message : "Gagal memuat data");
|
toast.error(
|
||||||
|
error instanceof Error ? error.message : "Gagal memuat data"
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -690,9 +752,12 @@ const hubunganOrganisasi = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
hubunganOrganisasi.delete.loading = true;
|
hubunganOrganisasi.delete.loading = true;
|
||||||
const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/del/${id}`, {
|
const res = await fetch(
|
||||||
method: "DELETE",
|
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/del/${id}`,
|
||||||
});
|
{
|
||||||
|
method: "DELETE",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const result = await res.json();
|
const result = await res.json();
|
||||||
if (res.ok && result?.success) {
|
if (res.ok && result?.success) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Grid, GridCol, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
import { Box, Button, Grid, GridCol, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconCircleDashedPlus, IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
import { IconCircleDashedPlus, IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -29,12 +29,21 @@ function Berita() {
|
|||||||
function ListBerita({ search }: { search: string }) {
|
function ListBerita({ search }: { search: string }) {
|
||||||
const beritaState = useProxy(stateDashboardBerita)
|
const beritaState = useProxy(stateDashboardBerita)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = beritaState.berita.findMany;
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch pertama kali
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
beritaState.berita.findMany.load()
|
load(page); // awal page = 1
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
const filteredData = (beritaState.berita.findMany.data || []).filter(item => {
|
const filteredData = (data || []).filter((item) => {
|
||||||
const keyword = search.toLowerCase();
|
const keyword = search.toLowerCase();
|
||||||
return (
|
return (
|
||||||
item.judul.toLowerCase().includes(keyword) ||
|
item.judul.toLowerCase().includes(keyword) ||
|
||||||
@@ -42,67 +51,84 @@ function ListBerita({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (loading || !data) {
|
||||||
if (!beritaState.berita.findMany.data) {
|
return <Skeleton h={500} />;
|
||||||
return (
|
|
||||||
<Stack py={10}>
|
|
||||||
<Skeleton h={500} />
|
|
||||||
</Stack>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={10}>
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)} // ini penting!
|
||||||
|
total={totalPages}
|
||||||
|
mt="md"
|
||||||
|
mb="md"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Paper bg={colors["white-1"]} p={"md"}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Grid>
|
<Grid>
|
||||||
<GridCol span={{ base: 12, md: 11 }}>
|
<GridCol span={{ base: 12, md: 11 }}>
|
||||||
<Text fz={"xl"} fw={"bold"}>List Berita</Text>
|
<Text fz={"xl"} fw={"bold"}>
|
||||||
|
List Berita
|
||||||
|
</Text>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<GridCol span={{ base: 12, md: 1 }}>
|
<GridCol span={{ base: 12, md: 1 }}>
|
||||||
<Button onClick={() => router.push("/admin/desa/berita/create")} bg={colors['blue-button']}>
|
<Button
|
||||||
|
onClick={() => router.push("/admin/desa/berita/create")}
|
||||||
|
bg={colors["blue-button"]}
|
||||||
|
>
|
||||||
<IconCircleDashedPlus size={25} />
|
<IconCircleDashedPlus size={25} />
|
||||||
</Button>
|
</Button>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Box style={{ overflowX: "auto" }}>
|
<Box style={{ overflowX: "auto" }}>
|
||||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
<Table
|
||||||
|
striped
|
||||||
|
withRowBorders
|
||||||
|
withTableBorder
|
||||||
|
style={{ minWidth: "700px" }}
|
||||||
|
>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh w={250}>Judul</TableTh>
|
<TableTh w={250}>Judul</TableTh>
|
||||||
<TableTh w={250}>Kategori</TableTh>
|
<TableTh w={250}>Kategori</TableTh>
|
||||||
<TableTh w={250}>Image</TableTh>
|
<TableTh w={250}>Image</TableTh>
|
||||||
<TableTh w={200}>Detail</TableTh>
|
<TableTh w={200}>Detail</TableTh>
|
||||||
|
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody >
|
<TableTbody>
|
||||||
{filteredData.map((item) => (
|
{filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd >
|
<TableTd>
|
||||||
<Box w={100}>
|
<Box w={100}>
|
||||||
<Text truncate="end" fz={"sm"}>{item.judul}</Text>
|
<Text truncate="end" fz={"sm"}>
|
||||||
|
{item.judul}
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd >{item.kategoriBerita?.name}</TableTd>
|
<TableTd>{item.kategoriBerita?.name}</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Image w={100} src={item.image?.link} alt="gambar" />
|
<Image w={100} src={item.image?.link} alt="gambar" />
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button bg={"green"} onClick={() => router.push(`/admin/desa/berita/${item.id}`)}>
|
<Button
|
||||||
|
bg={"green"}
|
||||||
|
onClick={() =>
|
||||||
|
router.push(`/admin/desa/berita/${item.id}`)
|
||||||
|
}
|
||||||
|
>
|
||||||
<IconDeviceImacCog size={25} />
|
<IconDeviceImacCog size={25} />
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
|
|
||||||
</TableTr>
|
</TableTr>
|
||||||
))}
|
))}
|
||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table> </Box>
|
</Table>
|
||||||
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Berita;
|
export default Berita;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Badge, Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
import { Badge, Box, Button, Center, Group, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, ThemeIcon } from '@mantine/core';
|
||||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
import { IconCheck, IconDeviceImacCog, IconSearch, IconX } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import JudulList from '../../../_com/judulList';
|
import JudulList from '../../../_com/judulList';
|
||||||
@@ -30,46 +30,33 @@ function ListPegawai({ search }: { search: string }) {
|
|||||||
const stateOrganisasi = useProxy(strukturorganisasiState.pegawai);
|
const stateOrganisasi = useProxy(strukturorganisasiState.pegawai);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = stateOrganisasi.findMany;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadData = async () => {
|
load(page, 10);
|
||||||
try {
|
}, [page]);
|
||||||
// Clear existing data to ensure we see the loading state
|
|
||||||
stateOrganisasi.findMany.data = [];
|
|
||||||
|
|
||||||
// Load new data
|
const filteredData = useMemo(() => {
|
||||||
await stateOrganisasi.findMany.load();
|
if (!data) return [];
|
||||||
|
return data.filter(item => {
|
||||||
// Type guard to ensure data is an array
|
const keyword = search.toLowerCase();
|
||||||
const data = stateOrganisasi.findMany.data || [];
|
return (
|
||||||
if (data.length > 0) {
|
item.namaLengkap?.toLowerCase().includes(keyword) ||
|
||||||
console.log('4. First record sample:', data[0]);
|
item.gelarAkademik?.toLowerCase().includes(keyword) ||
|
||||||
}
|
item.telepon?.toLowerCase().includes(keyword) ||
|
||||||
} catch (error) {
|
item.posisi?.nama?.toLowerCase().includes(keyword)
|
||||||
console.error('Error loading pegawai data:', error);
|
);
|
||||||
stateOrganisasi.findMany.data = [];
|
});
|
||||||
}
|
}, [data, search]);
|
||||||
};
|
|
||||||
|
|
||||||
loadData();
|
|
||||||
|
|
||||||
// Cleanup function
|
|
||||||
return () => {
|
|
||||||
console.log('Cleanup: Unmounting component');
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const filteredData = (stateOrganisasi.findMany.data || []).filter(item => {
|
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.namaLengkap?.toLowerCase().includes(keyword) ||
|
|
||||||
item.gelarAkademik?.toLowerCase().includes(keyword) ||
|
|
||||||
item.telepon?.toLowerCase().includes(keyword) ||
|
|
||||||
item.posisi?.nama?.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle loading state
|
// Handle loading state
|
||||||
if (stateOrganisasi.findMany.data === null) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton height={300} />
|
<Skeleton height={300} />
|
||||||
@@ -77,8 +64,6 @@ function ListPegawai({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if data is an empty array
|
|
||||||
const data = stateOrganisasi.findMany.data || [];
|
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={10}>
|
||||||
@@ -95,48 +80,79 @@ function ListPegawai({ search }: { search: string }) {
|
|||||||
title='List Pegawai'
|
title='List Pegawai'
|
||||||
href='/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/create'
|
href='/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/create'
|
||||||
/>
|
/>
|
||||||
<Table striped withTableBorder withRowBorders>
|
<Box style={{ overflowX: "auto" }}>
|
||||||
<TableThead>
|
<Table striped withTableBorder withRowBorders>
|
||||||
<TableTr>
|
<TableThead>
|
||||||
<TableTh>Nama</TableTh>
|
<TableTr>
|
||||||
<TableTh>Gelar Akademik</TableTh>
|
<TableTh>Nama</TableTh>
|
||||||
<TableTh>Telepon</TableTh>
|
<TableTh>Gelar Akademik</TableTh>
|
||||||
<TableTh>Posisi</TableTh>
|
<TableTh>Telepon</TableTh>
|
||||||
<TableTh>Aktif</TableTh>
|
<TableTh>Posisi</TableTh>
|
||||||
<TableTh>Detail</TableTh>
|
<TableTh>Aktif</TableTh>
|
||||||
</TableTr>
|
<TableTh>Detail</TableTh>
|
||||||
</TableThead>
|
|
||||||
<TableTbody>
|
|
||||||
{(() => {
|
|
||||||
console.log('Rendering table with items:', stateOrganisasi.findMany.data);
|
|
||||||
return null;
|
|
||||||
})()}
|
|
||||||
{([...filteredData]
|
|
||||||
.sort((a, b) => {
|
|
||||||
if (a.isActive === b.isActive) {
|
|
||||||
return a.namaLengkap.localeCompare(b.namaLengkap); // kalau status sama, urut nama
|
|
||||||
}
|
|
||||||
return Number(b.isActive) - Number(a.isActive); // aktif duluan
|
|
||||||
}) // Aktif di atas
|
|
||||||
).map((item) => (
|
|
||||||
<TableTr key={item.id}>
|
|
||||||
<TableTd>{item.namaLengkap}</TableTd>
|
|
||||||
<TableTd>{item.gelarAkademik}</TableTd>
|
|
||||||
<TableTd>{item.telepon}</TableTd>
|
|
||||||
<TableTd>{item.posisi?.nama}</TableTd>
|
|
||||||
<TableTd>
|
|
||||||
<Badge color={item.isActive ? "green" : "red"}>{item.isActive ? "Aktif" : "Tidak Aktif"}</Badge>
|
|
||||||
</TableTd>
|
|
||||||
<TableTd>
|
|
||||||
<Button bg={"green"} onClick={() => router.push(`/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/${item.id}`)}>
|
|
||||||
<IconDeviceImacCog size={25} />
|
|
||||||
</Button>
|
|
||||||
</TableTd>
|
|
||||||
</TableTr>
|
</TableTr>
|
||||||
))}
|
</TableThead>
|
||||||
</TableTbody>
|
<TableTbody>
|
||||||
</Table>
|
{(() => {
|
||||||
|
console.log('Rendering table with items:', stateOrganisasi.findMany.data);
|
||||||
|
return null;
|
||||||
|
})()}
|
||||||
|
{([...filteredData]
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.isActive === b.isActive) {
|
||||||
|
return a.namaLengkap.localeCompare(b.namaLengkap); // kalau status sama, urut nama
|
||||||
|
}
|
||||||
|
return Number(b.isActive) - Number(a.isActive); // aktif duluan
|
||||||
|
}) // Aktif di atas
|
||||||
|
).map((item) => (
|
||||||
|
<TableTr key={item.id}>
|
||||||
|
<TableTd>{item.namaLengkap}</TableTd>
|
||||||
|
<TableTd>{item.gelarAkademik}</TableTd>
|
||||||
|
<TableTd>{item.telepon}</TableTd>
|
||||||
|
<TableTd>{item.posisi?.nama}</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Group gap="xs" wrap="nowrap">
|
||||||
|
<Box visibleFrom="sm">
|
||||||
|
<Badge color={item.isActive ? "green" : "red"}>
|
||||||
|
{item.isActive ? "Aktif" : "Tidak Aktif"}
|
||||||
|
</Badge>
|
||||||
|
</Box>
|
||||||
|
<Box hiddenFrom="sm">
|
||||||
|
{item.isActive ? (
|
||||||
|
<ThemeIcon color="green" variant="light" size="sm">
|
||||||
|
<IconCheck size={16} />
|
||||||
|
</ThemeIcon>
|
||||||
|
) : (
|
||||||
|
<ThemeIcon color="red" variant="light" size="sm">
|
||||||
|
<IconX size={16} />
|
||||||
|
</ThemeIcon>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Group>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Button bg={"green"} onClick={() => router.push(`/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/${item.id}`)}>
|
||||||
|
<IconDeviceImacCog size={25} />
|
||||||
|
</Button>
|
||||||
|
</TableTd>
|
||||||
|
</TableTr>
|
||||||
|
))}
|
||||||
|
</TableTbody>
|
||||||
|
</Table>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => {
|
||||||
|
load(newPage, 10);
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}}
|
||||||
|
total={totalPages}
|
||||||
|
mt="md"
|
||||||
|
mb="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,44 @@
|
|||||||
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
|
async function beritaFindManyPaginated(context: Context) {
|
||||||
|
const page = Number(context.query.page) || 1;
|
||||||
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
async function beritaFindMany() {
|
|
||||||
try {
|
try {
|
||||||
const data = await prisma.berita.findMany({
|
const [data, total] = await Promise.all([
|
||||||
where: { isActive: true },
|
prisma.berita.findMany({
|
||||||
include: {
|
where: { isActive: true },
|
||||||
image: true,
|
include: {
|
||||||
kategoriBerita: true,
|
image: true,
|
||||||
},
|
kategoriBerita: true,
|
||||||
});
|
},
|
||||||
|
skip,
|
||||||
|
take: limit,
|
||||||
|
orderBy: { createdAt: 'desc' }, // opsional, kalau mau urut berdasarkan waktu
|
||||||
|
}),
|
||||||
|
prisma.berita.count({
|
||||||
|
where: { isActive: true }
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Success fetch berita",
|
message: "Success fetch berita with pagination",
|
||||||
data,
|
data,
|
||||||
|
page,
|
||||||
|
totalPages: Math.ceil(total / limit),
|
||||||
|
total,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Find many error:", e);
|
console.error("Find many paginated error:", e);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "Failed fetch berita",
|
message: "Failed fetch berita with pagination",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default beritaFindMany;
|
export default beritaFindManyPaginated;
|
||||||
|
|||||||
@@ -1,26 +1,48 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
|
// Di findMany.ts
|
||||||
|
export default async function pegawaiFindMany(context: Context) {
|
||||||
|
const page = Number(context.query.page) || 1;
|
||||||
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
export default async function pegawaiFindMany() {
|
|
||||||
try {
|
try {
|
||||||
const pegawaiList = await prisma.pegawai.findMany({
|
const [data, total] = await Promise.all([
|
||||||
orderBy: { createdAt: "desc" },
|
prisma.pegawai.findMany({
|
||||||
include: {
|
where: { isActive: true },
|
||||||
posisi: true,
|
include: {
|
||||||
image: true,
|
posisi: true,
|
||||||
},
|
image: true,
|
||||||
});
|
},
|
||||||
|
skip,
|
||||||
|
take: limit,
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
}),
|
||||||
|
prisma.pegawai.count({
|
||||||
|
where: { isActive: true }
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(total / limit);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: pegawaiList,
|
message: "Success fetch pegawai with pagination",
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
total,
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (e) {
|
||||||
console.error("Error findMany pegawai:", error);
|
console.error("Find many paginated error:", e);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "Gagal mengambil data pegawai",
|
message: "Failed fetch pegawai with pagination",
|
||||||
error: error.message,
|
data: [],
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
total: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user