diff --git a/bun.lockb b/bun.lockb
index c1f0eda6..7f208dd4 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 4612a22c..61958b92 100644
--- a/package.json
+++ b/package.json
@@ -113,6 +113,7 @@
"@playwright/test": "^1.58.2",
"@testing-library/jest-dom": "^6.9.1",
"@types/cli-progress": "^3.11.6",
+ "@types/dompurify": "^3.2.0",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^20",
"@types/react": "^19",
diff --git a/src/app/admin/(dashboard)/_state/landing-page/profile.ts b/src/app/admin/(dashboard)/_state/landing-page/profile.ts
index d4abaf81..152f16d7 100644
--- a/src/app/admin/(dashboard)/_state/landing-page/profile.ts
+++ b/src/app/admin/(dashboard)/_state/landing-page/profile.ts
@@ -55,10 +55,15 @@ const programInovasi = proxy({
programInovasi.findMany.load();
return toast.success("Sukses menambahkan");
}
- console.log(res);
+ if (process.env.NODE_ENV === 'development') {
+ console.log(res);
+ }
return toast.error("failed create");
} catch (error) {
- console.log((error as Error).message);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Create error:", error);
+ }
+ toast.error("Gagal menambahkan data");
} finally {
programInovasi.create.loading = false;
}
@@ -91,13 +96,17 @@ const programInovasi = proxy({
programInovasi.findMany.total = res.data.total || 0;
programInovasi.findMany.totalPages = res.data.totalPages || 1;
} else {
- console.error("Failed to load pegawai:", res.data?.message);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Failed to load pegawai:", res.data?.message);
+ }
programInovasi.findMany.data = [];
programInovasi.findMany.total = 0;
programInovasi.findMany.totalPages = 1;
}
} catch (error) {
- console.error("Error loading pegawai:", error);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Error loading pegawai:", error);
+ }
programInovasi.findMany.data = [];
programInovasi.findMany.total = 0;
programInovasi.findMany.totalPages = 1;
@@ -112,19 +121,25 @@ const programInovasi = proxy({
image: true;
};
}> | null,
+ loading: false,
async load(id: string) {
try {
- const res = await fetch(`/api/landingpage/programinovasi/${id}`);
- if (res.ok) {
- const data = await res.json();
- programInovasi.findUnique.data = data.data ?? null;
+ programInovasi.findUnique.loading = true;
+ const res = await (ApiFetch.api.landingpage.programinovasi as any)[id].get();
+ if (res.data?.success) {
+ programInovasi.findUnique.data = res.data.data ?? null;
+ return res.data.data;
} else {
- console.error("Failed to fetch program inovasi:", res.statusText);
+ toast.error(res.data?.message || "Gagal memuat data program inovasi");
programInovasi.findUnique.data = null;
+ return null;
}
} catch (error) {
console.error("Error fetching program inovasi:", error);
programInovasi.findUnique.data = null;
+ return null;
+ } finally {
+ programInovasi.findUnique.loading = false;
}
},
},
@@ -135,27 +150,18 @@ const programInovasi = proxy({
try {
programInovasi.delete.loading = true;
+ const res = await (ApiFetch.api.landingpage.programinovasi as any)["del"][id].delete();
- const response = await fetch(
- `/api/landingpage/programinovasi/del/${id}`,
- {
- method: "DELETE",
- headers: {
- "Content-Type": "application/json",
- },
- }
- );
-
- const result = await response.json();
-
- if (response.ok && result?.success) {
- toast.success(result.message || "Program inovasi berhasil dihapus");
- await programInovasi.findMany.load(); // refresh list
+ if (res.data?.success) {
+ toast.success(res.data.message || "Program inovasi berhasil dihapus");
+ await programInovasi.findMany.load();
} else {
- toast.error(result?.message || "Gagal menghapus program inovasi");
+ toast.error(res.data?.message || "Gagal menghapus program inovasi");
}
} catch (error) {
- console.error("Gagal delete:", error);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Gagal delete:", error);
+ }
toast.error("Terjadi kesalahan saat menghapus program inovasi");
} finally {
programInovasi.delete.loading = false;
@@ -174,20 +180,11 @@ const programInovasi = proxy({
}
try {
- const response = await fetch(`/api/landingpage/programinovasi/${id}`, {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- },
- });
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
+ programInovasi.update.loading = true;
+ const res = await (ApiFetch.api.landingpage.programinovasi as any)[id].get();
- const result = await response.json();
-
- if (result?.success) {
- const data = result.data;
+ if (res.data?.success) {
+ const data = res.data.data;
this.id = data.id;
this.form = {
name: data.name,
@@ -197,13 +194,15 @@ const programInovasi = proxy({
};
return data;
} else {
- throw new Error(
- result?.message || "Gagal mengambil data program inovasi"
- );
+ toast.error(res.data?.message || "Gagal mengambil data program inovasi");
+ return null;
}
} catch (error) {
- console.error((error as Error).message);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Error loading program inovasi:", error);
+ }
toast.error("Terjadi kesalahan saat mengambil data program inovasi");
+ return null;
} finally {
programInovasi.update.loading = false;
}
@@ -221,41 +220,25 @@ const programInovasi = proxy({
try {
programInovasi.update.loading = true;
+ const res = await (ApiFetch.api.landingpage.programinovasi as any)[this.id].put({
+ name: this.form.name,
+ description: this.form.description,
+ imageId: this.form.imageId,
+ link: this.form.link,
+ });
- const response = await fetch(
- `/api/landingpage/programinovasi/${this.id}`,
- {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- name: this.form.name,
- description: this.form.description,
- imageId: this.form.imageId,
- link: this.form.link,
- }),
- }
- );
-
- 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) {
+ if (res.data?.success) {
toast.success("Berhasil update program inovasi");
- await programInovasi.findMany.load(); // refresh list
+ await programInovasi.findMany.load();
return true;
} else {
- throw new Error(result.message || "Gagal update program inovasi");
+ toast.error(res.data?.message || "Gagal update program inovasi");
+ return false;
}
} catch (error) {
- console.error("Error updating program inovasi:", error);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Error updating program inovasi:", error);
+ }
toast.error(
error instanceof Error
? error.message
@@ -443,7 +426,7 @@ const pejabatDesa = proxy({
const templateMediaSosial = z.object({
name: z.string().min(3, "Nama minimal 3 karakter"),
imageId: z.string().nullable().optional(),
- iconUrl: z.string().min(3, "Icon URL minimal 3 karakter"),
+ iconUrl: z.string().optional(), // ✅ Optional - tidak selalu required
icon: z.string().nullable().optional(),
});
@@ -484,10 +467,15 @@ const mediaSosial = proxy({
mediaSosial.findMany.load();
return toast.success("Sukses menambahkan");
}
- console.log(res);
+ if (process.env.NODE_ENV === 'development') {
+ console.log(res);
+ }
return toast.error("failed create");
} catch (error) {
- console.log((error as Error).message);
+ if (process.env.NODE_ENV === 'development') {
+ console.log((error as Error).message);
+ }
+ toast.error("Gagal menambahkan data");
} finally {
mediaSosial.create.loading = false;
}
@@ -518,13 +506,17 @@ const mediaSosial = proxy({
mediaSosial.findMany.total = res.data.total || 0;
mediaSosial.findMany.totalPages = res.data.totalPages || 1;
} else {
- console.error("Failed to load media sosial:", res.data?.message);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Failed to load media sosial:", res.data?.message);
+ }
mediaSosial.findMany.data = [];
mediaSosial.findMany.total = 0;
mediaSosial.findMany.totalPages = 1;
}
} catch (error) {
- console.error("Error loading media sosial:", error);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Error loading media sosial:", error);
+ }
mediaSosial.findMany.data = [];
mediaSosial.findMany.total = 0;
mediaSosial.findMany.totalPages = 1;
@@ -539,25 +531,32 @@ const mediaSosial = proxy({
image: true;
};
}> | null,
+ loading: false,
async load(id: string) {
if (!id) {
toast.warn("ID tidak valid");
return null;
}
- mediaSosial.update.loading = true;
+ mediaSosial.findUnique.loading = true;
try {
- const res = await fetch(`/api/landingpage/mediasosial/${id}`);
- if (res.ok) {
- const data = await res.json();
- mediaSosial.findUnique.data = data.data ?? null;
+ const res = await (ApiFetch.api.landingpage.mediasosial as any)[id].get();
+ if (res.data?.success) {
+ mediaSosial.findUnique.data = res.data.data ?? null;
+ return res.data.data;
} else {
- console.error("Failed to fetch media sosial:", res.statusText);
+ toast.error(res.data?.message || "Gagal memuat data media sosial");
mediaSosial.findUnique.data = null;
+ return null;
}
} catch (error) {
- console.error("Error fetching media sosial:", error);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Error fetching media sosial:", error);
+ }
mediaSosial.findUnique.data = null;
+ return null;
+ } finally {
+ mediaSosial.findUnique.loading = false;
}
},
},
@@ -568,24 +567,18 @@ const mediaSosial = proxy({
try {
mediaSosial.delete.loading = true;
+ const res = await (ApiFetch.api.landingpage.mediasosial as any)["del"][id].delete();
- const response = await fetch(`/api/landingpage/mediasosial/del/${id}`, {
- method: "DELETE",
- headers: {
- "Content-Type": "application/json",
- },
- });
-
- const result = await response.json();
-
- if (response.ok && result?.success) {
- toast.success(result.message || "Media Sosial berhasil dihapus");
- await mediaSosial.findMany.load(); // refresh list
+ if (res.data?.success) {
+ toast.success(res.data.message || "Media Sosial berhasil dihapus");
+ await mediaSosial.findMany.load();
} else {
- toast.error(result?.message || "Gagal menghapus media sosial");
+ toast.error(res.data?.message || "Gagal menghapus media sosial");
}
} catch (error) {
- console.error("Gagal delete:", error);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Gagal delete:", error);
+ }
toast.error("Terjadi kesalahan saat menghapus media sosial");
} finally {
mediaSosial.delete.loading = false;
@@ -603,43 +596,32 @@ const mediaSosial = proxy({
return null;
}
- mediaSosial.update.loading = true; // ✅ Tambahkan ini di awal
-
+ mediaSosial.update.loading = true;
try {
- const response = await fetch(`/api/landingpage/mediasosial/${id}`, {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- },
- });
+ const res = await (ApiFetch.api.landingpage.mediasosial as any)[id].get();
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- const result = await response.json();
-
- if (result?.success) {
- const data = result.data;
+ if (res.data?.success) {
+ const data = res.data.data;
this.id = data.id;
this.form = {
name: data.name || "",
imageId: data.imageId || null,
iconUrl: data.iconUrl || "",
icon: data.icon || null,
-
};
return data;
} else {
- throw new Error(
- result?.message || "Gagal mengambil data media sosial"
- );
+ toast.error(res.data?.message || "Gagal mengambil data media sosial");
+ return null;
}
} catch (error) {
- console.error((error as Error).message);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Error loading media sosial:", error);
+ }
toast.error("Terjadi kesalahan saat mengambil data media sosial");
+ return null;
} finally {
- mediaSosial.update.loading = false; // ✅ Supaya berhenti loading walau error
+ mediaSosial.update.loading = false;
}
},
@@ -655,41 +637,25 @@ const mediaSosial = proxy({
try {
mediaSosial.update.loading = true;
+ const res = await (ApiFetch.api.landingpage.mediasosial as any)[this.id].put({
+ name: this.form.name,
+ imageId: this.form.imageId,
+ iconUrl: this.form.iconUrl,
+ icon: this.form.icon,
+ });
- const response = await fetch(
- `/api/landingpage/mediasosial/${this.id}`,
- {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- name: this.form.name,
- imageId: this.form.imageId,
- iconUrl: this.form.iconUrl,
- icon: this.form.icon,
- }),
- }
- );
-
- 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) {
+ if (res.data?.success) {
toast.success("Berhasil update media sosial");
- await mediaSosial.findMany.load(); // refresh list
+ await mediaSosial.findMany.load();
return true;
} else {
- throw new Error(result.message || "Gagal update media sosial");
+ toast.error(res.data?.message || "Gagal update media sosial");
+ return false;
}
} catch (error) {
- console.error("Error updating media sosial:", error);
+ if (process.env.NODE_ENV === 'development') {
+ console.error("Error updating media sosial:", error);
+ }
toast.error(
error instanceof Error
? error.message
diff --git a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx
index c2e26cf6..e0a7cf84 100644
--- a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx
+++ b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx
@@ -8,6 +8,7 @@ import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react';
import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
+import DOMPurify from 'dompurify';
function DetailProgramInovasi() {
const stateProgramInovasi = useProxy(profileLandingPageState.programInovasi)
@@ -85,7 +86,7 @@ function DetailProgramInovasi() {
Deskripsi
-
+
diff --git a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx
index b2c30db0..0c68b120 100644
--- a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx
+++ b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx
@@ -6,6 +6,7 @@ import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
+import DOMPurify from 'dompurify';
import HeaderSearch from '../../../_com/header';
import profileLandingPageState from '../../../_state/landing-page/profile';
@@ -90,7 +91,7 @@ function ListProgramInovasi({ search }: { search: string }) {
{item.name}
-
+
@@ -144,7 +145,7 @@ function ListProgramInovasi({ search }: { search: string }) {
{/* Description */}
Deskripsi
-
+
{/* Link */}