Fix Compres Gambar && seed gambar profile - landing page
@@ -80,9 +80,11 @@
|
|||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
"readdirp": "^4.1.1",
|
"readdirp": "^4.1.1",
|
||||||
"recharts": "^2.15.3",
|
"recharts": "^2.15.3",
|
||||||
|
"sharp": "^0.34.3",
|
||||||
"swr": "^2.3.2",
|
"swr": "^2.3.2",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"valtio": "^2.1.3",
|
"valtio": "^2.1.3",
|
||||||
|
"zlib": "^1.0.5",
|
||||||
"zod": "^3.24.3"
|
"zod": "^3.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
137
prisma/data/file-storage.json
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "cmff0rr4z0002vn0twp333m2",
|
||||||
|
"name": "S6RIjFaPvdQm3oq4rM4X9-desktop.webp",
|
||||||
|
"realName": "bares.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/S6RIjFaPvdQm3oq4rM4X9-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff0tnf00003vn0t3kgzi0u0",
|
||||||
|
"name": "_pVNEmThU5ICGa8gv3gh_-desktop.webp",
|
||||||
|
"realName": "bicara-darma.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/_pVNEmThU5ICGa8gv3gh_-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff0uykf0004vn0trmmxpgfh",
|
||||||
|
"name": "bv6rdKvjxkkjUSGLQ0lvB-desktop.webp",
|
||||||
|
"realName": "daves.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/bv6rdKvjxkkjUSGLQ0lvB-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff0z34f0005vn0tjtvq519p",
|
||||||
|
"name": "Z4hWaV04CvoE20MjccQsV-desktop.webp",
|
||||||
|
"realName": "mangan.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/Z4hWaV04CvoE20MjccQsV-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff38cyq000bvn0t9f01cz3f",
|
||||||
|
"name": "LvLAtOqWojx4sn6NjJWB9-desktop.webp",
|
||||||
|
"realName": "gelah-melah.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/LvLAtOqWojx4sn6NjJWB9-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff0zqvd0007vn0tv6o5hjcq",
|
||||||
|
"name": "gR2mcvAQVgJ2-rM5coYJj-desktop.webp",
|
||||||
|
"realName": "inovasi-desa-darmasaba.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/gR2mcvAQVgJ2-rM5coYJj-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff1013m0008vn0th7t0d64d",
|
||||||
|
"name": "JpL-9F8-IGztMn8E2ce02-desktop.webp",
|
||||||
|
"realName": "pdkt.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/JpL-9F8-IGztMn8E2ce02-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff10cwq0009vn0tse8dzu3j",
|
||||||
|
"name": "bxAk4AsGbJTC705_IVdes-desktop.webp",
|
||||||
|
"realName": "sajjiana-dharma-raksaka.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/bxAk4AsGbJTC705_IVdes-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff2w5ly000avn0telhct71k",
|
||||||
|
"name": "Vbj_osnMJUkGEQGDTLwV--desktop.webp",
|
||||||
|
"realName": "perbekel.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/Vbj_osnMJUkGEQGDTLwV--desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff3joae0000vn6h8sgs0ilg",
|
||||||
|
"name": "7hox9spUxj56hY_EBYLnj-desktop.webp",
|
||||||
|
"realName": "youtube.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/7hox9spUxj56hY_EBYLnj-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff3ll130001vn6hkhls3f5y",
|
||||||
|
"name": "ChihV7_1eS-AGtSg9UwMv-desktop.webp",
|
||||||
|
"realName": "gmail.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/ChihV7_1eS-AGtSg9UwMv-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff3mtat0002vn6hs8vyyhdd",
|
||||||
|
"name": "z8v9ZREwOJHKGIRYauROt-desktop.webp",
|
||||||
|
"realName": "facebook.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/z8v9ZREwOJHKGIRYauROt-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff3nv180003vn6h5jvedidq",
|
||||||
|
"name": "BLjMxTKoCNE31uOURR3IU-desktop.webp",
|
||||||
|
"realName": "telephone-call.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/BLjMxTKoCNE31uOURR3IU-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff3oouh0004vn6hd94brzv9",
|
||||||
|
"name": "hkJYAeTNWK_vYaYS20w3I-desktop.webp",
|
||||||
|
"realName": "instagram.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/hkJYAeTNWK_vYaYS20w3I-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmff3q12g0005vn6h5ojov2qa",
|
||||||
|
"name": "6XEoZ9SFu59COpil03Gya-desktop.webp",
|
||||||
|
"realName": "tiktok.png",
|
||||||
|
"path": "uploads/images",
|
||||||
|
"mimeType": "image/webp",
|
||||||
|
"link": "/api/fileStorage/findUnique/6XEoZ9SFu59COpil03Gya-desktop.webp",
|
||||||
|
"category": "image"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -2,31 +2,37 @@
|
|||||||
{
|
{
|
||||||
"id": "cmds8w2q60002vnbe6i8qhkuo",
|
"id": "cmds8w2q60002vnbe6i8qhkuo",
|
||||||
"name": "Telephone Desa Darmasaba",
|
"name": "Telephone Desa Darmasaba",
|
||||||
"iconUrl": "081239580000"
|
"iconUrl": "081239580000",
|
||||||
|
"imageId": "cmff3nv180003vn6h5jvedidq"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds8z7u20005vnbegyyvnbk0",
|
"id": "cmds8z7u20005vnbegyyvnbk0",
|
||||||
"name": "Email Desa Darmasaba",
|
"name": "Email Desa Darmasaba",
|
||||||
"iconUrl": "desadarmasaba@badungkab.go.id"
|
"iconUrl": "desadarmasaba@badungkab.go.id",
|
||||||
|
"imageId": "cmff3ll130001vn6hkhls3f5y"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9023u0008vnbe3oxmhwyf",
|
"id": "cmds9023u0008vnbe3oxmhwyf",
|
||||||
"name": "Desa Darmasaba",
|
"name": "Desa Darmasaba",
|
||||||
"iconUrl": "https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg"
|
"iconUrl": "https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg",
|
||||||
|
"imageId": "cmff3joae0000vn6h8sgs0ilg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds90oul000bvnbe2bqkptoi",
|
"id": "cmds90oul000bvnbe2bqkptoi",
|
||||||
"name": "Pemerintah Desa Darmasaba",
|
"name": "Pemerintah Desa Darmasaba",
|
||||||
"iconUrl": "https://www.facebook.com/DarmasabaDesaku"
|
"iconUrl": "https://www.facebook.com/DarmasabaDesaku",
|
||||||
|
"imageId": "cmff3mtat0002vn6hs8vyyhdd"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds91i4e000evnbe8gtf1gub",
|
"id": "cmds91i4e000evnbe8gtf1gub",
|
||||||
"name": "ddarmasaba",
|
"name": "ddarmasaba",
|
||||||
"iconUrl": "https://www.instagram.com/ddarmasaba/"
|
"iconUrl": "https://www.instagram.com/ddarmasaba/",
|
||||||
|
"imageId": "cmff3oouh0004vn6hd94brzv9"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds92de5000hvnbemlu6sq5x",
|
"id": "cmds92de5000hvnbemlu6sq5x",
|
||||||
"name": "desa.darmasaba",
|
"name": "desa.darmasaba",
|
||||||
"iconUrl": "https://www.tiktok.com/@desa.darmasaba?is_from_webapp=1&sender_device=pc"
|
"iconUrl": "https://www.tiktok.com/@desa.darmasaba?is_from_webapp=1&sender_device=pc",
|
||||||
|
"imageId": "cmff3q12g0005vn6h5ojov2qa"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{
|
{
|
||||||
"id": "edit",
|
"id": "edit",
|
||||||
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
||||||
"position": "Perbekel Darmasaba periode 2021-2027"
|
"position": "Perbekel Darmasaba periode 2021-2027",
|
||||||
|
"imageId": "cmff2w5ly000avn0telhct71k"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,50 +1,51 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"id": "cmdr7039z0002vn5rttctt9hn",
|
|
||||||
"name": "Davest",
|
|
||||||
"description": "Darmasaba Village Festval",
|
|
||||||
"link": "https://darmasaba.desa.id/berita/55862-rakor-davest-2024"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "cmdr755pf0005vn5rp8tyuubw",
|
"id": "cmdr755pf0005vn5rp8tyuubw",
|
||||||
"name": "Dmangan",
|
"name": "Dmangan",
|
||||||
"description": "Darmasaba Aman Pangan",
|
"description": "Darmasaba Aman Pangan",
|
||||||
"link": "https://darmasaba.desa.id/berita/61452-kader-d-mangan-berhasil-meraih-prestasi-dalam-ajang-lomba-banjar-bali-quis-bbq-tahun-2024"
|
"link": "https://darmasaba.desa.id/berita/61452-kader-d-mangan-berhasil-meraih-prestasi-dalam-ajang-lomba-banjar-bali-quis-bbq-tahun-2024",
|
||||||
|
"imageId" : "cmff0z34f0005vn0tjtvq519p"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdr76nqk0008vn5rdddvcxnr",
|
"id": "cmdr76nqk0008vn5rdddvcxnr",
|
||||||
"name": "Bicara Darmasaba",
|
"name": "Bicara Darmasaba",
|
||||||
"description": "Bicara Darmasaba",
|
"description": "Bicara Darmasaba",
|
||||||
"link": "https://darmasaba.desa.id/berita/42506-bicara-darmasaba"
|
"link": "https://darmasaba.desa.id/berita/42506-bicara-darmasaba",
|
||||||
|
"imageId" : "cmff0tnf00003vn0t3kgzi0u0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdr77vbw000bvn5rvpmoq31s",
|
"id": "cmdr77vbw000bvn5rvpmoq31s",
|
||||||
"name": "Bares",
|
"name": "Bares",
|
||||||
"description": "Darmasaba Recycling Stock/Exchange",
|
"description": "Darmasaba Recycling Stock/Exchange",
|
||||||
"link": "http://darmasaba.desa.id/berita/56722-bares"
|
"link": "http://darmasaba.desa.id/berita/56722-bares",
|
||||||
|
"imageId" : "cmff0rr4z0002vn0twp333m2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdr7bxtp000evn5rmy85wihx",
|
"id": "cmdr7bxtp000evn5rmy85wihx",
|
||||||
"name": "Sajjana Dharma Raksaka",
|
"name": "Sajjana Dharma Raksaka",
|
||||||
"description": "Sajjana Dharma Raksaka",
|
"description": "Sajjana Dharma Raksaka",
|
||||||
"link": "https://ppid.badungkab.go.id/storage/dokumen/5RS9dldGkrgzMQq6bKdZsqsVRHI8gffWv4PGfb3r.pdf"
|
"link": "https://ppid.badungkab.go.id/storage/dokumen/5RS9dldGkrgzMQq6bKdZsqsVRHI8gffWv4PGfb3r.pdf",
|
||||||
|
"imageId" : "cmff10cwq0009vn0tse8dzu3j"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdr7dlnk000hvn5r9lur3z35",
|
"id": "cmdr7dlnk000hvn5r9lur3z35",
|
||||||
"name": "PDKT",
|
"name": "PDKT",
|
||||||
"description": "Perangkat Desa Kuat Teknologi",
|
"description": "Perangkat Desa Kuat Teknologi",
|
||||||
"link": "https://darmasaba.desa.id/berita/53752-p-d-k-t"
|
"link": "https://darmasaba.desa.id/berita/53752-p-d-k-t",
|
||||||
|
"imageId" : "cmff1013m0008vn0th7t0d64d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdr7ftob000mvn5rfhgdtg8v",
|
"id": "cmdr7ftob000mvn5rfhgdtg8v",
|
||||||
"name": "GM",
|
"name": "GM",
|
||||||
"description": "Galah Melah",
|
"description": "Galah Melah",
|
||||||
"link": "https://darmasaba.desa.id/berita/52880-galah-melah"
|
"link": "https://darmasaba.desa.id/berita/52880-galah-melah",
|
||||||
|
"imageId" : "cmff38cyq000bvn0t9f01cz3f"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdr7glue000pvn5r6onzslju",
|
"id": "cmdr7glue000pvn5r6onzslju",
|
||||||
"name": "Inovasi Desa Darmasaba",
|
"name": "Inovasi Desa Darmasaba",
|
||||||
"description": "Inovasi Desa Darmasaba",
|
"description": "Inovasi Desa Darmasaba",
|
||||||
"link": "https://darmasaba.desa.id/produk-lokal-desa"
|
"link": "https://darmasaba.desa.id/produk-lokal-desa",
|
||||||
|
"imageId" : "cmff0zqvd0007vn0tv6o5hjcq"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ model FileStorage {
|
|||||||
PejabatDesa PejabatDesa[]
|
PejabatDesa PejabatDesa[]
|
||||||
MediaSosial MediaSosial[]
|
MediaSosial MediaSosial[]
|
||||||
DesaAntiKorupsi DesaAntiKorupsi[]
|
DesaAntiKorupsi DesaAntiKorupsi[]
|
||||||
SDGSDesa SDGSDesa[]
|
SDGSDesa SdgsDesa[]
|
||||||
APBDesImage APBDes[] @relation("APBDesImage")
|
APBDesImage APBDes[] @relation("APBDesImage")
|
||||||
APBDesFile APBDes[] @relation("APBDesFile")
|
APBDesFile APBDes[] @relation("APBDesFile")
|
||||||
PrestasiDesa PrestasiDesa[]
|
PrestasiDesa PrestasiDesa[]
|
||||||
@@ -168,7 +168,7 @@ model KategoriDesaAntiKorupsi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//========================================= SDGS Desa ========================================= //
|
//========================================= SDGS Desa ========================================= //
|
||||||
model SDGSDesa {
|
model SdgsDesa {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String @unique
|
||||||
jumlah String
|
jumlah String
|
||||||
|
|||||||
206
prisma/seed.ts
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
||||||
import programInovasi from "./data/landing-page/profile/programInovasi.json";
|
import programInovasi from "./data/landing-page/profile/programInovasi.json";
|
||||||
@@ -15,7 +16,7 @@ import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PP
|
|||||||
import visiMisiPPID from "./data/ppid/visi-misi-ppid/visimisiPPID.json";
|
import visiMisiPPID from "./data/ppid/visi-misi-ppid/visimisiPPID.json";
|
||||||
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
||||||
import jenisKelamin from "./data/ppid/ikm/jenis-kelamin/jenis-kelamin.json";
|
import jenisKelamin from "./data/ppid/ikm/jenis-kelamin/jenis-kelamin.json";
|
||||||
import daftarInformasiPublik from "./data/ppid/daftar-informasi-publik-desa-darmasaba/daftarInformasi.json"
|
import daftarInformasiPublik from "./data/ppid/daftar-informasi-publik-desa-darmasaba/daftarInformasi.json";
|
||||||
import pilihanRatingResponden from "./data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
|
import pilihanRatingResponden from "./data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
|
||||||
import umurResponden from "./data/ppid/ikm/umur-responden/umur-responden.json";
|
import umurResponden from "./data/ppid/ikm/umur-responden/umur-responden.json";
|
||||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
import categoryPengumuman from "./data/category-pengumuman.json";
|
||||||
@@ -54,63 +55,90 @@ import programUnggulan from "./data/pendidikan/program-pendidikan-anak/program-u
|
|||||||
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
||||||
import roles from "./data/user/roles.json";
|
import roles from "./data/user/roles.json";
|
||||||
import users from "./data/user/users.json";
|
import users from "./data/user/users.json";
|
||||||
|
import fileStorage from "./data/file-storage.json";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
// =========== USER & ROLE ===========
|
// =========== USER & ROLE ===========
|
||||||
// In your seed.ts
|
// In your seed.ts
|
||||||
// =========== ROLES ===========
|
// =========== ROLES ===========
|
||||||
console.log("🔄 Seeding roles...");
|
console.log("🔄 Seeding roles...");
|
||||||
for (const r of roles) {
|
for (const r of roles) {
|
||||||
await prisma.role.upsert({
|
await prisma.role.upsert({
|
||||||
where: { id: r.id },
|
where: { id: r.id },
|
||||||
update: {
|
update: {
|
||||||
name: r.name,
|
name: r.name,
|
||||||
description: r.description,
|
description: r.description,
|
||||||
permissions: r.permissions,
|
permissions: r.permissions,
|
||||||
isActive: r.isActive,
|
isActive: r.isActive,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: r.id,
|
id: r.id,
|
||||||
name: r.name,
|
name: r.name,
|
||||||
description: r.description,
|
description: r.description,
|
||||||
permissions: r.permissions,
|
permissions: r.permissions,
|
||||||
isActive: r.isActive,
|
isActive: r.isActive,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
console.log("✅ Roles seeded");
|
|
||||||
|
|
||||||
// =========== USERS ===========
|
|
||||||
console.log("🔄 Seeding users...");
|
|
||||||
for (const u of users) {
|
|
||||||
// First verify the role exists
|
|
||||||
const roleExists = await prisma.role.findUnique({
|
|
||||||
where: { id: u.roleId }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!roleExists) {
|
|
||||||
console.error(`❌ Role with id ${u.roleId} not found for user ${u.nama}`);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
console.log("✅ Roles seeded");
|
||||||
|
|
||||||
await prisma.user.upsert({
|
// =========== USERS ===========
|
||||||
where: { id: u.id },
|
console.log("🔄 Seeding users...");
|
||||||
update: {
|
for (const u of users) {
|
||||||
username: u.nama,
|
// First verify the role exists
|
||||||
nomor: u.nomor,
|
const roleExists = await prisma.role.findUnique({
|
||||||
roleId: u.roleId,
|
where: { id: u.roleId },
|
||||||
isActive: u.isActive,
|
});
|
||||||
},
|
|
||||||
create: {
|
if (!roleExists) {
|
||||||
id: u.id,
|
console.error(`❌ Role with id ${u.roleId} not found for user ${u.nama}`);
|
||||||
username: u.nama,
|
continue;
|
||||||
nomor: u.nomor,
|
}
|
||||||
roleId: u.roleId,
|
|
||||||
isActive: u.isActive,
|
await prisma.user.upsert({
|
||||||
},
|
where: { id: u.id },
|
||||||
});
|
update: {
|
||||||
}
|
username: u.nama,
|
||||||
console.log("✅ Users seeded");
|
nomor: u.nomor,
|
||||||
|
roleId: u.roleId,
|
||||||
|
isActive: u.isActive,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: u.id,
|
||||||
|
username: u.nama,
|
||||||
|
nomor: u.nomor,
|
||||||
|
roleId: u.roleId,
|
||||||
|
isActive: u.isActive,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("✅ Users seeded");
|
||||||
|
|
||||||
|
// =========== FILE STORAGE ===========
|
||||||
|
console.log("🔄 Seeding file storage...");
|
||||||
|
for (const f of fileStorage) {
|
||||||
|
await prisma.fileStorage.upsert({
|
||||||
|
where: { id: f.id },
|
||||||
|
update: {
|
||||||
|
name: f.name,
|
||||||
|
realName: f.realName,
|
||||||
|
path: f.path,
|
||||||
|
mimeType: f.mimeType,
|
||||||
|
link: f.link,
|
||||||
|
category: f.category,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: f.id,
|
||||||
|
name: f.name,
|
||||||
|
realName: f.realName,
|
||||||
|
path: f.path,
|
||||||
|
mimeType: f.mimeType,
|
||||||
|
link: f.link,
|
||||||
|
category: f.category,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("✅ File storage seeded");
|
||||||
// =========== LANDING PAGE ===========
|
// =========== LANDING PAGE ===========
|
||||||
// =========== SUBMENU PROFILE ===========
|
// =========== SUBMENU PROFILE ===========
|
||||||
// =========== PROFILE PEJABAT DESA ===========
|
// =========== PROFILE PEJABAT DESA ===========
|
||||||
@@ -120,11 +148,13 @@ console.log("✅ Users seeded");
|
|||||||
update: {
|
update: {
|
||||||
name: p.name,
|
name: p.name,
|
||||||
position: p.position,
|
position: p.position,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
position: p.position,
|
position: p.position,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -134,18 +164,35 @@ console.log("✅ Users seeded");
|
|||||||
|
|
||||||
// =========== PROGRAM INOVASI ===========
|
// =========== PROGRAM INOVASI ===========
|
||||||
for (const p of programInovasi) {
|
for (const p of programInovasi) {
|
||||||
|
let imageId: string | null = null;
|
||||||
|
|
||||||
|
if (p.imageId) {
|
||||||
|
const imageExists = await prisma.fileStorage.findUnique({
|
||||||
|
where: { id: p.imageId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (imageExists) {
|
||||||
|
imageId = p.imageId;
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
`⚠️ imageId ${p.imageId} tidak ditemukan untuk ProgramInovasi ${p.name}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
await prisma.programInovasi.upsert({
|
await prisma.programInovasi.upsert({
|
||||||
where: { id: p.id },
|
where: { id: p.id },
|
||||||
update: {
|
update: {
|
||||||
name: p.name,
|
name: p.name,
|
||||||
description: p.description,
|
description: p.description,
|
||||||
link: p.link,
|
link: p.link,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
description: p.description,
|
description: p.description,
|
||||||
link: p.link,
|
link: p.link,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -158,11 +205,13 @@ console.log("✅ Users seeded");
|
|||||||
update: {
|
update: {
|
||||||
name: p.name,
|
name: p.name,
|
||||||
iconUrl: p.iconUrl,
|
iconUrl: p.iconUrl,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
iconUrl: p.iconUrl,
|
iconUrl: p.iconUrl,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -308,11 +357,8 @@ console.log("✅ Users seeded");
|
|||||||
|
|
||||||
// =========== SDGSDesa ===========
|
// =========== SDGSDesa ===========
|
||||||
for (const l of sdgsDesa) {
|
for (const l of sdgsDesa) {
|
||||||
await prisma.sDGSDesa.upsert({
|
await prisma.sdgsDesa.upsert({
|
||||||
where: {
|
where: { id: l.id },
|
||||||
name: l.name,
|
|
||||||
jumlah: l.jumlah,
|
|
||||||
},
|
|
||||||
update: {
|
update: {
|
||||||
name: l.name,
|
name: l.name,
|
||||||
jumlah: l.jumlah,
|
jumlah: l.jumlah,
|
||||||
@@ -558,29 +604,29 @@ console.log("✅ Users seeded");
|
|||||||
}
|
}
|
||||||
console.log("dasar hukum PPID success ...");
|
console.log("dasar hukum PPID success ...");
|
||||||
|
|
||||||
// =========== SUBMENU DAFTAR INFORMASI PUBLIK PPID ===========
|
// =========== SUBMENU DAFTAR INFORMASI PUBLIK PPID ===========
|
||||||
for (const v of daftarInformasiPublik) {
|
for (const v of daftarInformasiPublik) {
|
||||||
// Convert string date to Date object
|
// Convert string date to Date object
|
||||||
const tanggal = new Date(v.tanggal);
|
const tanggal = new Date(v.tanggal);
|
||||||
|
|
||||||
await prisma.daftarInformasiPublik.upsert({
|
await prisma.daftarInformasiPublik.upsert({
|
||||||
where: {
|
where: {
|
||||||
id: v.id,
|
id: v.id,
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
jenisInformasi: v.jenisInformasi,
|
jenisInformasi: v.jenisInformasi,
|
||||||
deskripsi: v.deskripsi,
|
deskripsi: v.deskripsi,
|
||||||
tanggal: tanggal,
|
tanggal: tanggal,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: v.id,
|
id: v.id,
|
||||||
jenisInformasi: v.jenisInformasi,
|
jenisInformasi: v.jenisInformasi,
|
||||||
deskripsi: v.deskripsi,
|
deskripsi: v.deskripsi,
|
||||||
tanggal: tanggal,
|
tanggal: tanggal,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("daftar informasi publik PPID success ...");
|
console.log("daftar informasi publik PPID success ...");
|
||||||
|
|
||||||
for (const l of pelayananPerizinanBerusaha) {
|
for (const l of pelayananPerizinanBerusaha) {
|
||||||
await prisma.pelayananPerizinanBerusaha.upsert({
|
await prisma.pelayananPerizinanBerusaha.upsert({
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
@@ -23,6 +23,7 @@ export default function SpashScreen() {
|
|||||||
<Paper p={"md"} miw={320}>
|
<Paper p={"md"} miw={320}>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Image
|
<Image
|
||||||
|
loading="lazy"
|
||||||
src={images["darmasaba-icon"]}
|
src={images["darmasaba-icon"]}
|
||||||
alt="darmasaba"
|
alt="darmasaba"
|
||||||
w={100}
|
w={100}
|
||||||
|
|||||||
@@ -23,7 +23,12 @@ type ProgramInovasiForm = Prisma.ProgramInovasiGetPayload<{
|
|||||||
|
|
||||||
const programInovasi = proxy({
|
const programInovasi = proxy({
|
||||||
create: {
|
create: {
|
||||||
form: {} as ProgramInovasiForm,
|
form: {
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
imageId: "",
|
||||||
|
link: ""
|
||||||
|
} as ProgramInovasiForm,
|
||||||
loading: false,
|
loading: false,
|
||||||
async create() {
|
async create() {
|
||||||
// Ensure all required fields are non-null
|
// Ensure all required fields are non-null
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ const sdgsDesa = proxy({
|
|||||||
].get({
|
].get({
|
||||||
query,
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
sdgsDesa.findMany.data = res.data.data || [];
|
sdgsDesa.findMany.data = res.data.data || [];
|
||||||
sdgsDesa.findMany.total = res.data.total || 0;
|
sdgsDesa.findMany.total = res.data.total || 0;
|
||||||
@@ -94,7 +94,7 @@ const sdgsDesa = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as Prisma.SDGSDesaGetPayload<{
|
data: null as Prisma.SdgsDesaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ function EditKolaborasiInovasi() {
|
|||||||
|
|
||||||
await sdgsState.edit.update();
|
await sdgsState.edit.update();
|
||||||
toast.success("sdgs desa berhasil diperbarui!");
|
toast.success("sdgs desa berhasil diperbarui!");
|
||||||
router.push("/admin/landing-page/sdgs");
|
router.push("/admin/landing-page/sdgs-desa");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating sdgs desa:", error);
|
console.error("Error updating sdgs desa:", error);
|
||||||
toast.error("Terjadi kesalahan saat memperbarui sdgs desa");
|
toast.error("Terjadi kesalahan saat memperbarui sdgs desa");
|
||||||
@@ -107,7 +107,7 @@ function EditKolaborasiInovasi() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Title order={4} ml="sm" c="dark">
|
<Title order={4} ml="sm" c="dark">
|
||||||
Edit SDGs Desa
|
Edit Sdgs Desa
|
||||||
</Title>
|
</Title>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ function EditKolaborasiInovasi() {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw="bold" fz="sm" mb={6}>
|
<Text fw="bold" fz="sm" mb={6}>
|
||||||
Gambar SDGs Desa
|
Gambar Sdgs Desa
|
||||||
</Text>
|
</Text>
|
||||||
<Dropzone
|
<Dropzone
|
||||||
onDrop={(files) => {
|
onDrop={(files) => {
|
||||||
@@ -172,8 +172,8 @@ function EditKolaborasiInovasi() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Nama SDGs Desa"
|
label="Nama Sdgs Desa"
|
||||||
placeholder="Masukkan nama SDGs Desa"
|
placeholder="Masukkan nama Sdgs Desa"
|
||||||
value={formData.name}
|
value={formData.name}
|
||||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||||
required
|
required
|
||||||
@@ -27,7 +27,7 @@ function DetailSDGSDesa() {
|
|||||||
sdgsState.delete.byId(selectedId)
|
sdgsState.delete.byId(selectedId)
|
||||||
setModalHapus(false)
|
setModalHapus(false)
|
||||||
setSelectedId(null)
|
setSelectedId(null)
|
||||||
router.push("/admin/landing-page/sdgs")
|
router.push("/admin/landing-page/sdgs-desa")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +62,13 @@ function DetailSDGSDesa() {
|
|||||||
>
|
>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Text fz="2xl" fw="bold" c={colors['blue-button']}>
|
<Text fz="2xl" fw="bold" c={colors['blue-button']}>
|
||||||
Detail SDGs Desa
|
Detail Sdgs Desa
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Paper bg="#ECEEF8" p="md" radius="md" shadow="xs">
|
<Paper bg="#ECEEF8" p="md" radius="md" shadow="xs">
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold" mb={4}>Nama SDGs Desa</Text>
|
<Text fz="lg" fw="bold" mb={4}>Nama Sdgs Desa</Text>
|
||||||
<Text fz="md" c="dimmed">{data.name || '-'}</Text>
|
<Text fz="md" c="dimmed">{data.name || '-'}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ function DetailSDGSDesa() {
|
|||||||
{data.image?.link ? (
|
{data.image?.link ? (
|
||||||
<Image
|
<Image
|
||||||
src={data.image.link}
|
src={data.image.link}
|
||||||
alt={data.name || 'Gambar SDGs Desa'}
|
alt={data.name || 'Gambar Sdgs Desa'}
|
||||||
w={200}
|
w={200}
|
||||||
h={200}
|
h={200}
|
||||||
radius="md"
|
radius="md"
|
||||||
@@ -94,7 +94,7 @@ function DetailSDGSDesa() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Group gap="sm" mt="md">
|
<Group gap="sm" mt="md">
|
||||||
<Tooltip label="Hapus SDGs Desa" withArrow position="top">
|
<Tooltip label="Hapus Sdgs Desa" withArrow position="top">
|
||||||
<Button
|
<Button
|
||||||
color="red"
|
color="red"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -110,10 +110,10 @@ function DetailSDGSDesa() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip label="Edit SDGs Desa" withArrow position="top">
|
<Tooltip label="Edit Sdgs Desa" withArrow position="top">
|
||||||
<Button
|
<Button
|
||||||
color="green"
|
color="green"
|
||||||
onClick={() => router.push(`/admin/landing-page/sdgs/${data.id}/edit`)}
|
onClick={() => router.push(`/admin/landing-page/sdgs-desa/${data.id}/edit`)}
|
||||||
variant="light"
|
variant="light"
|
||||||
radius="md"
|
radius="md"
|
||||||
size="md"
|
size="md"
|
||||||
@@ -131,7 +131,7 @@ function DetailSDGSDesa() {
|
|||||||
opened={modalHapus}
|
opened={modalHapus}
|
||||||
onClose={() => setModalHapus(false)}
|
onClose={() => setModalHapus(false)}
|
||||||
onConfirm={handleHapus}
|
onConfirm={handleHapus}
|
||||||
text="Apakah Anda yakin ingin menghapus SDGs Desa ini?"
|
text="Apakah Anda yakin ingin menghapus Sdgs Desa ini?"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
@@ -53,7 +53,7 @@ function CreateSDGsDesa() {
|
|||||||
await stateSDGSDesa.create.create();
|
await stateSDGSDesa.create.create();
|
||||||
|
|
||||||
resetForm();
|
resetForm();
|
||||||
router.push("/admin/landing-page/sdgs")
|
router.push("/admin/landing-page/sdgs-desa")
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
||||||
@@ -64,7 +64,7 @@ function CreateSDGsDesa() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Title order={4} ml="sm" c="dark">
|
<Title order={4} ml="sm" c="dark">
|
||||||
Tambah SDGs Desa
|
Tambah Sdgs Desa
|
||||||
</Title>
|
</Title>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ function CreateSDGsDesa() {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw="bold" fz="sm" mb={6}>
|
<Text fw="bold" fz="sm" mb={6}>
|
||||||
Gambar SDGs Desa
|
Gambar Sdgs Desa
|
||||||
</Text>
|
</Text>
|
||||||
<Dropzone
|
<Dropzone
|
||||||
onDrop={(files) => {
|
onDrop={(files) => {
|
||||||
@@ -143,10 +143,10 @@ function CreateSDGsDesa() {
|
|||||||
<TextInput
|
<TextInput
|
||||||
label={
|
label={
|
||||||
<Text fw="bold" fz="sm" mb={4}>
|
<Text fw="bold" fz="sm" mb={4}>
|
||||||
Nama SDGs Desa
|
Nama Sdgs Desa
|
||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
placeholder="Masukkan nama SDGs Desa"
|
placeholder="Masukkan nama Sdgs Desa"
|
||||||
value={stateSDGSDesa.create.form.name}
|
value={stateSDGSDesa.create.form.name}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
stateSDGSDesa.create.form.name = val.target.value;
|
stateSDGSDesa.create.form.name = val.target.value;
|
||||||
@@ -15,8 +15,8 @@ function SdgsDesa() {
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<HeaderSearch
|
<HeaderSearch
|
||||||
title='SDGs Desa'
|
title='Sdgs Desa'
|
||||||
placeholder='Cari SDGs Desa...'
|
placeholder='Cari Sdgs Desa...'
|
||||||
searchIcon={<IconSearch size={20} />}
|
searchIcon={<IconSearch size={20} />}
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
@@ -58,13 +58,13 @@ function ListSdgsDesa({ search }: { search: string }) {
|
|||||||
<Box py={10}>
|
<Box py={10}>
|
||||||
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb="md">
|
||||||
<Title order={4}>Daftar SDGs Desa</Title>
|
<Title order={4}>Daftar Sdgs Desa</Title>
|
||||||
<Tooltip label="Tambah SDGs Desa" withArrow>
|
<Tooltip label="Tambah Sdgs Desa" withArrow>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color={colors['blue-button']}
|
color={colors['blue-button']}
|
||||||
variant="light"
|
variant="light"
|
||||||
onClick={() => router.push('/admin/landing-page/sdgs/create')}
|
onClick={() => router.push('/admin/landing-page/sdgs-desa/create')}
|
||||||
>
|
>
|
||||||
Tambah Baru
|
Tambah Baru
|
||||||
</Button>
|
</Button>
|
||||||
@@ -74,7 +74,7 @@ function ListSdgsDesa({ search }: { search: string }) {
|
|||||||
<Table>
|
<Table>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh style={{ width: '60%' }}>Nama SDGs Desa</TableTh>
|
<TableTh style={{ width: '60%' }}>Nama Sdgs Desa</TableTh>
|
||||||
<TableTh style={{ width: '20%' }}>Jumlah</TableTh>
|
<TableTh style={{ width: '20%' }}>Jumlah</TableTh>
|
||||||
<TableTh style={{ width: '20%', textAlign: 'center' }}>Aksi</TableTh>
|
<TableTh style={{ width: '20%', textAlign: 'center' }}>Aksi</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -82,7 +82,7 @@ function ListSdgsDesa({ search }: { search: string }) {
|
|||||||
<TableTbody>
|
<TableTbody>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={3} style={{ textAlign: 'center', padding: '2rem' }}>
|
<TableTd colSpan={3} style={{ textAlign: 'center', padding: '2rem' }}>
|
||||||
<Text c="dimmed">Tidak ada data SDGs Desa</Text>
|
<Text c="dimmed">Tidak ada data Sdgs Desa</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableTbody>
|
</TableTbody>
|
||||||
@@ -97,13 +97,13 @@ function ListSdgsDesa({ search }: { search: string }) {
|
|||||||
<Box py={10}>
|
<Box py={10}>
|
||||||
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb="md">
|
||||||
<Title order={4}>Daftar SDGs Desa</Title>
|
<Title order={4}>Daftar Sdgs Desa</Title>
|
||||||
<Tooltip label="Tambah SDGs Desa" withArrow>
|
<Tooltip label="Tambah Sdgs Desa" withArrow>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color={colors['blue-button']}
|
color={colors['blue-button']}
|
||||||
variant="light"
|
variant="light"
|
||||||
onClick={() => router.push('/admin/landing-page/sdgs/create')}
|
onClick={() => router.push('/admin/landing-page/sdgs-desa/create')}
|
||||||
>
|
>
|
||||||
Tambah Baru
|
Tambah Baru
|
||||||
</Button>
|
</Button>
|
||||||
@@ -113,7 +113,7 @@ function ListSdgsDesa({ search }: { search: string }) {
|
|||||||
<Table highlightOnHover>
|
<Table highlightOnHover>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh style={{ width: '60%' }}>Nama SDGs Desa</TableTh>
|
<TableTh style={{ width: '60%' }}>Nama Sdgs Desa</TableTh>
|
||||||
<TableTh style={{ width: '20%' }}>Jumlah</TableTh>
|
<TableTh style={{ width: '20%' }}>Jumlah</TableTh>
|
||||||
<TableTh style={{ width: '20%', textAlign: 'center' }}>Aksi</TableTh>
|
<TableTh style={{ width: '20%', textAlign: 'center' }}>Aksi</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -137,7 +137,7 @@ function ListSdgsDesa({ search }: { search: string }) {
|
|||||||
variant="light"
|
variant="light"
|
||||||
color="blue"
|
color="blue"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => router.push(`/admin/landing-page/sdgs/${item.id}`)}
|
onClick={() => router.push(`/admin/landing-page/sdgs-desa/${item.id}`)}
|
||||||
>
|
>
|
||||||
<IconDeviceImacCog size={18} />
|
<IconDeviceImacCog size={18} />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -21,8 +21,8 @@ export const navBar = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "Landing_Page_4",
|
id: "Landing_Page_4",
|
||||||
name: "SDGs Desa",
|
name: "Sdgs Desa",
|
||||||
path: "/admin/landing-page/sdgs"
|
path: "/admin/landing-page/sdgs-desa"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "Landing_Page_5",
|
id: "Landing_Page_5",
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { Context } from "elysia";
|
|||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
|
import sharp from "sharp";
|
||||||
|
import zlib from "zlib";
|
||||||
|
|
||||||
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
|
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
|
||||||
|
|
||||||
@@ -11,6 +13,7 @@ const fileStorageCreate = async (context: Context) => {
|
|||||||
name: string;
|
name: string;
|
||||||
file: File;
|
file: File;
|
||||||
};
|
};
|
||||||
|
|
||||||
const file = body.file;
|
const file = body.file;
|
||||||
const name = body.name;
|
const name = body.name;
|
||||||
|
|
||||||
@@ -18,7 +21,6 @@ const fileStorageCreate = async (context: Context) => {
|
|||||||
if (!name) return { status: 400, body: "No name provided" };
|
if (!name) return { status: 400, body: "No name provided" };
|
||||||
if (!UPLOAD_DIR) return { status: 500, body: "UPLOAD_DIR is not defined" };
|
if (!UPLOAD_DIR) return { status: 500, body: "UPLOAD_DIR is not defined" };
|
||||||
|
|
||||||
// Tentukan kategori berdasarkan mimeType
|
|
||||||
const isImage = file.type.startsWith("image/");
|
const isImage = file.type.startsWith("image/");
|
||||||
const category = isImage ? "image" : "document";
|
const category = isImage ? "image" : "document";
|
||||||
|
|
||||||
@@ -26,25 +28,54 @@ const fileStorageCreate = async (context: Context) => {
|
|||||||
const rootPath = path.join(UPLOAD_DIR, pathName);
|
const rootPath = path.join(UPLOAD_DIR, pathName);
|
||||||
await fs.mkdir(rootPath, { recursive: true });
|
await fs.mkdir(rootPath, { recursive: true });
|
||||||
|
|
||||||
const ext = file.name.split(".").pop();
|
// Convert File ke Buffer
|
||||||
const newName = nanoid() + "." + ext;
|
const buffer = Buffer.from(await file.arrayBuffer());
|
||||||
|
let finalName = nanoid();
|
||||||
|
let finalMimeType = file.type;
|
||||||
|
|
||||||
|
if (isImage) {
|
||||||
|
// Simpan sebagai WebP untuk kompresi maksimal
|
||||||
|
const mobileBuffer = await sharp(buffer)
|
||||||
|
.resize({ width: 720 })
|
||||||
|
.webp({ quality: 80 })
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
const desktopBuffer = await sharp(buffer)
|
||||||
|
.resize({ width: 1920, withoutEnlargement: true })
|
||||||
|
.webp({ quality: 80 })
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
const mobileName = `${finalName}-mobile.webp`;
|
||||||
|
const desktopName = `${finalName}-desktop.webp`;
|
||||||
|
|
||||||
|
await fs.writeFile(path.join(rootPath, mobileName), mobileBuffer);
|
||||||
|
await fs.writeFile(path.join(rootPath, desktopName), desktopBuffer);
|
||||||
|
|
||||||
|
// Simpan metadata untuk versi desktop sebagai default
|
||||||
|
finalName = desktopName;
|
||||||
|
finalMimeType = "image/webp";
|
||||||
|
} else {
|
||||||
|
// Kompres dokumen (opsional pakai gzip)
|
||||||
|
const gzBuffer = zlib.gzipSync(buffer);
|
||||||
|
const docName = `${finalName}.gz`;
|
||||||
|
|
||||||
|
await fs.writeFile(path.join(rootPath, docName), gzBuffer);
|
||||||
|
|
||||||
|
finalName = docName;
|
||||||
|
finalMimeType = "application/gzip";
|
||||||
|
}
|
||||||
|
|
||||||
const data = await prisma.fileStorage.create({
|
const data = await prisma.fileStorage.create({
|
||||||
data: {
|
data: {
|
||||||
name: newName,
|
name: finalName,
|
||||||
realName: file.name,
|
realName: file.name,
|
||||||
path: rootPath,
|
path: rootPath,
|
||||||
mimeType: file.type,
|
mimeType: finalMimeType,
|
||||||
category,
|
category,
|
||||||
link: `/api/fileStorage/findUnique/${newName}`,
|
link: `/api/fileStorage/findUnique/${finalName}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await fs.writeFile(
|
|
||||||
path.join(rootPath, newName),
|
|
||||||
Buffer.from(await file.arrayBuffer())
|
|
||||||
);
|
|
||||||
|
|
||||||
return { data };
|
return { data };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default async function sdgsDesaCreate(context: Context) {
|
|||||||
const body = context.body as FormCreate;
|
const body = context.body as FormCreate;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await prisma.sDGSDesa.create({
|
const result = await prisma.sdgsDesa.create({
|
||||||
data: {
|
data: {
|
||||||
name: body.name,
|
name: body.name,
|
||||||
jumlah: body.jumlah,
|
jumlah: body.jumlah,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default async function sdgsDesaDelete(context: Context) {
|
|||||||
throw new Error("ID tidak ditemukan dalam parameter");
|
throw new Error("ID tidak ditemukan dalam parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleted = await prisma.sDGSDesa.delete({
|
const deleted = await prisma.sdgsDesa.delete({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ async function sdgsDesaFindMany(context: Context) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.sDGSDesa.findMany({
|
prisma.sdgsDesa.findMany({
|
||||||
where,
|
where,
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
@@ -30,7 +30,7 @@ async function sdgsDesaFindMany(context: Context) {
|
|||||||
take: limit,
|
take: limit,
|
||||||
orderBy: { jumlah: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
orderBy: { jumlah: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||||
}),
|
}),
|
||||||
prisma.sDGSDesa.count({
|
prisma.sdgsDesa.count({
|
||||||
where,
|
where,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default async function sdgsDesaFindUnique(context: Context) {
|
|||||||
throw new Error("ID tidak ditemukan dalam parameter");
|
throw new Error("ID tidak ditemukan dalam parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await prisma.sDGSDesa.findUnique({
|
const data = await prisma.sdgsDesa.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default async function sdgsDesaUpdate(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const updated = await prisma.sDGSDesa.update({
|
const updated = await prisma.sdgsDesa.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: {
|
data: {
|
||||||
name: body.name,
|
name: body.name,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import BackButton from '../../(pages)/desa/layanan/_com/BackButto';
|
|||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const [sdgsDesa, setSdgsDesa] = useState<Prisma.SDGSDesaGetPayload<{ include: { image: true } }>[]>([]);
|
const [sdgsDesa, setSdgsDesa] = useState<Prisma.SdgsDesaGetPayload<{ include: { image: true } }>[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { IconMoodSad } from "@tabler/icons-react"
|
|||||||
export default function SDGS() {
|
export default function SDGS() {
|
||||||
const theme = useMantineTheme()
|
const theme = useMantineTheme()
|
||||||
const mobile = useMediaQuery(`(max-width: ${theme.breakpoints.sm})`)
|
const mobile = useMediaQuery(`(max-width: ${theme.breakpoints.sm})`)
|
||||||
const [sdgsDesa, setSdgsDesa] = useState<Prisma.SDGSDesaGetPayload<{ include: { image: true } }>[] | null>(null)
|
const [sdgsDesa, setSdgsDesa] = useState<Prisma.SdgsDesaGetPayload<{ include: { image: true } }>[] | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchSdgsDesa = async () => {
|
const fetchSdgsDesa = async () => {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 1009 KiB |
|
Before Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 495 KiB |
|
Before Width: | Height: | Size: 366 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 142 KiB |