Compare commits
1 Commits
fix/admin/
...
nico/fix-p
| Author | SHA1 | Date | |
|---|---|---|---|
| 87eb501661 |
@@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
Warnings:
|
|
||||||
|
|
||||||
- You are about to alter the column `nama` on the `KategoriPotensi` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(100)`.
|
|
||||||
- You are about to alter the column `name` on the `PotensiDesa` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(255)`.
|
|
||||||
- You are about to alter the column `kategoriId` on the `PotensiDesa` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(36)`.
|
|
||||||
- A unique constraint covering the columns `[nama]` on the table `KategoriPotensi` will be added. If there are existing duplicate values, this will fail.
|
|
||||||
- A unique constraint covering the columns `[name]` on the table `PotensiDesa` will be added. If there are existing duplicate values, this will fail.
|
|
||||||
- Made the column `kategoriId` on table `PotensiDesa` required. This step will fail if there are existing NULL values in that column.
|
|
||||||
|
|
||||||
*/
|
|
||||||
-- DropForeignKey
|
|
||||||
ALTER TABLE "DataPerpustakaan" DROP CONSTRAINT "DataPerpustakaan_imageId_fkey";
|
|
||||||
|
|
||||||
-- DropForeignKey
|
|
||||||
ALTER TABLE "DesaDigital" DROP CONSTRAINT "DesaDigital_imageId_fkey";
|
|
||||||
|
|
||||||
-- DropForeignKey
|
|
||||||
ALTER TABLE "InfoTekno" DROP CONSTRAINT "InfoTekno_imageId_fkey";
|
|
||||||
|
|
||||||
-- DropForeignKey
|
|
||||||
ALTER TABLE "KegiatanDesa" DROP CONSTRAINT "KegiatanDesa_imageId_fkey";
|
|
||||||
|
|
||||||
-- DropForeignKey
|
|
||||||
ALTER TABLE "PengaduanMasyarakat" DROP CONSTRAINT "PengaduanMasyarakat_imageId_fkey";
|
|
||||||
|
|
||||||
-- DropForeignKey
|
|
||||||
ALTER TABLE "PotensiDesa" DROP CONSTRAINT "PotensiDesa_kategoriId_fkey";
|
|
||||||
|
|
||||||
-- DropForeignKey
|
|
||||||
ALTER TABLE "ProfileDesaImage" DROP CONSTRAINT "ProfileDesaImage_imageId_fkey";
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "CaraMemperolehInformasi" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "CaraMemperolehSalinanInformasi" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "DaftarInformasiPublik" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "DasarHukumPPID" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "DataPerpustakaan" ALTER COLUMN "imageId" DROP NOT NULL;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "DesaDigital" ALTER COLUMN "imageId" DROP NOT NULL;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "FormulirPermohonanKeberatan" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "InfoTekno" ALTER COLUMN "imageId" DROP NOT NULL;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "JenisInformasiDiminta" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "JenisKelaminResponden" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "KategoriPotensi" ALTER COLUMN "nama" SET DATA TYPE VARCHAR(100),
|
|
||||||
ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "KategoriPrestasiDesa" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "KegiatanDesa" ALTER COLUMN "imageId" DROP NOT NULL;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "LambangDesa" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "MaskotDesa" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PegawaiPPID" ADD COLUMN "deletedAt" TIMESTAMP(3);
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PengaduanMasyarakat" ALTER COLUMN "imageId" DROP NOT NULL;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PermohonanInformasiPublik" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PilihanRatingResponden" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PosisiOrganisasiPPID" ADD COLUMN "deletedAt" TIMESTAMP(3);
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PotensiDesa" ALTER COLUMN "name" SET DATA TYPE VARCHAR(255),
|
|
||||||
ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT,
|
|
||||||
ALTER COLUMN "kategoriId" SET NOT NULL,
|
|
||||||
ALTER COLUMN "kategoriId" SET DATA TYPE VARCHAR(36);
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PrestasiDesa" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "ProfileDesaImage" ALTER COLUMN "imageId" DROP NOT NULL;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "ProfilePPID" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "Responden" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "SejarahDesa" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "UmurResponden" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "VisiMisiDesa" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "VisiMisiPPID" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "KategoriPotensi_nama_key" ON "KategoriPotensi"("nama");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "PotensiDesa_name_key" ON "PotensiDesa"("name");
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "ProfileDesaImage" ADD CONSTRAINT "ProfileDesaImage_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "PotensiDesa" ADD CONSTRAINT "PotensiDesa_kategoriId_fkey" FOREIGN KEY ("kategoriId") REFERENCES "KategoriPotensi"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "DesaDigital" ADD CONSTRAINT "DesaDigital_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "InfoTekno" ADD CONSTRAINT "InfoTekno_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "PengaduanMasyarakat" ADD CONSTRAINT "PengaduanMasyarakat_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "KegiatanDesa" ADD CONSTRAINT "KegiatanDesa_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "DataPerpustakaan" ADD CONSTRAINT "DataPerpustakaan_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
||||||
@@ -236,7 +236,7 @@ model PrestasiDesa {
|
|||||||
imageId String?
|
imageId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ model KategoriPrestasiDesa {
|
|||||||
name String @unique
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
PrestasiDesa PrestasiDesa[]
|
PrestasiDesa PrestasiDesa[]
|
||||||
}
|
}
|
||||||
@@ -263,7 +263,7 @@ model Responden {
|
|||||||
kelompokUmurId String
|
kelompokUmurId String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +272,7 @@ model JenisKelaminResponden {
|
|||||||
name String @unique
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
Responden Responden[]
|
Responden Responden[]
|
||||||
}
|
}
|
||||||
@@ -282,7 +282,7 @@ model PilihanRatingResponden {
|
|||||||
name String @unique
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
Responden Responden[]
|
Responden Responden[]
|
||||||
}
|
}
|
||||||
@@ -292,7 +292,7 @@ model UmurResponden {
|
|||||||
name String @unique
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
Responden Responden[]
|
Responden Responden[]
|
||||||
}
|
}
|
||||||
@@ -326,7 +326,6 @@ model PosisiOrganisasiPPID {
|
|||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
|
||||||
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
||||||
children PosisiOrganisasiPPID[] @relation("Parent")
|
children PosisiOrganisasiPPID[] @relation("Parent")
|
||||||
StrukturOrganisasiPPID StrukturOrganisasiPPID[]
|
StrukturOrganisasiPPID StrukturOrganisasiPPID[]
|
||||||
@@ -346,7 +345,6 @@ model PegawaiPPID {
|
|||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
|
||||||
posisi PosisiOrganisasiPPID @relation(fields: [posisiId], references: [id])
|
posisi PosisiOrganisasiPPID @relation(fields: [posisiId], references: [id])
|
||||||
strukturOrganisasi StrukturPPID[] // Relasi balik
|
strukturOrganisasi StrukturPPID[] // Relasi balik
|
||||||
StrukturOrganisasiPPID StrukturOrganisasiPPID[]
|
StrukturOrganisasiPPID StrukturOrganisasiPPID[]
|
||||||
@@ -372,7 +370,7 @@ model VisiMisiPPID {
|
|||||||
misi String @db.Text
|
misi String @db.Text
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,7 +381,7 @@ model DasarHukumPPID {
|
|||||||
content String @db.Text
|
content String @db.Text
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +398,7 @@ model ProfilePPID {
|
|||||||
imageId String?
|
imageId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +410,7 @@ model DaftarInformasiPublik {
|
|||||||
tanggal DateTime @db.Date
|
tanggal DateTime @db.Date
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,7 +431,7 @@ model PermohonanInformasiPublik {
|
|||||||
caraMemperolehSalinanInformasiId String?
|
caraMemperolehSalinanInformasiId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,7 +440,7 @@ model JenisInformasiDiminta {
|
|||||||
name String @unique
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
PermohonanInformasiPublik PermohonanInformasiPublik[]
|
PermohonanInformasiPublik PermohonanInformasiPublik[]
|
||||||
}
|
}
|
||||||
@@ -452,7 +450,7 @@ model CaraMemperolehInformasi {
|
|||||||
name String @unique
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
PermohonanInformasiPublik PermohonanInformasiPublik[]
|
PermohonanInformasiPublik PermohonanInformasiPublik[]
|
||||||
}
|
}
|
||||||
@@ -462,7 +460,7 @@ model CaraMemperolehSalinanInformasi {
|
|||||||
name String @unique
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
PermohonanInformasiPublik PermohonanInformasiPublik[]
|
PermohonanInformasiPublik PermohonanInformasiPublik[]
|
||||||
}
|
}
|
||||||
@@ -476,7 +474,7 @@ model FormulirPermohonanKeberatan {
|
|||||||
alasan String
|
alasan String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +531,7 @@ model SejarahDesa {
|
|||||||
deskripsi String @db.Text
|
deskripsi String @db.Text
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,7 +541,7 @@ model VisiMisiDesa {
|
|||||||
misi String @db.Text
|
misi String @db.Text
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,7 +551,7 @@ model LambangDesa {
|
|||||||
deskripsi String @db.Text
|
deskripsi String @db.Text
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,7 +562,7 @@ model MaskotDesa {
|
|||||||
images ProfileDesaImage[]
|
images ProfileDesaImage[]
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,25 +631,25 @@ model KategoriBerita {
|
|||||||
// ========================================= POTENSI DESA ========================================= //
|
// ========================================= POTENSI DESA ========================================= //
|
||||||
model PotensiDesa {
|
model PotensiDesa {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique @db.VarChar(255)
|
name String
|
||||||
deskripsi String @db.Text
|
deskripsi String
|
||||||
kategori KategoriPotensi? @relation(fields: [kategoriId], references: [id])
|
kategori KategoriPotensi? @relation(fields: [kategoriId], references: [id])
|
||||||
kategoriId String @db.VarChar(36)
|
kategoriId String?
|
||||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||||
imageId String?
|
imageId String?
|
||||||
content String @db.Text
|
content String @db.Text
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
model KategoriPotensi {
|
model KategoriPotensi {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
nama String @unique @db.VarChar(100)
|
nama String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
PotensiDesa PotensiDesa[]
|
PotensiDesa PotensiDesa[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ import { seedProfilPpd } from "./_seeder_list/ppid/profil-ppid/seed_profil_ppd";
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
// Always run seedAssets to handle new images without duplication
|
// Always run seedAssets to handle new images without duplication
|
||||||
console.log("📂 Checking for new assets to seed...");
|
// console.log("📂 Checking for new assets to seed...");
|
||||||
await seedAssets();
|
// await seedAssets();
|
||||||
|
|
||||||
// // =========== FILE STORAGE ===========
|
// // =========== FILE STORAGE ===========
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ function ListKategoriBerita({ search }: { search: string }) {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={3}> {/* ✅ Match column count (3 columns) */}
|
<TableTd colSpan={4}>
|
||||||
<Center py={24}>
|
<Center py={24}>
|
||||||
<Text c="dimmed" fz="sm" lh={1.4}>
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
Tidak ada data kategori berita yang cocok
|
Tidak ada data kategori berita yang cocok
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ function ListBerita({ search }: { search: string }) {
|
|||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
onChange={(newPage) => {
|
onChange={(newPage) => {
|
||||||
load(newPage, 10, debouncedSearch); // ✅ Include search parameter
|
load(newPage, 10);
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
}}
|
}}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react';
|
|||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import DOMPurify from 'dompurify';
|
|
||||||
|
|
||||||
export default function DetailPotensi() {
|
export default function DetailPotensi() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -78,17 +77,7 @@ export default function DetailPotensi() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||||
<Text
|
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}></Text>
|
||||||
fz="md"
|
|
||||||
c="dimmed"
|
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: DOMPurify.sanitize(data.deskripsi || '-', {
|
|
||||||
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
|
|
||||||
ALLOWED_ATTR: []
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
></Text>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
@@ -113,12 +102,7 @@ export default function DetailPotensi() {
|
|||||||
<Text
|
<Text
|
||||||
fz="md"
|
fz="md"
|
||||||
c="dimmed"
|
c="dimmed"
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{ __html: data.content || '-' }}
|
||||||
__html: DOMPurify.sanitize(data.content || '-', {
|
|
||||||
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
|
|
||||||
ALLOWED_ATTR: []
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import { useProxy } from 'valtio/utils';
|
|||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import potensiDesaState from '../../../_state/desa/potensi';
|
import potensiDesaState from '../../../_state/desa/potensi';
|
||||||
import { useDebouncedValue } from '@mantine/hooks';
|
import { useDebouncedValue } from '@mantine/hooks';
|
||||||
import DOMPurify from 'dompurify';
|
|
||||||
|
|
||||||
function Potensi() {
|
function Potensi() {
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
@@ -138,12 +137,7 @@ function ListPotensi({ search }: { search: string }) {
|
|||||||
fz="sm"
|
fz="sm"
|
||||||
lh={1.5}
|
lh={1.5}
|
||||||
lineClamp={2}
|
lineClamp={2}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
__html: DOMPurify.sanitize(item.deskripsi, {
|
|
||||||
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
|
|
||||||
ALLOWED_ATTR: []
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
style={{ wordBreak: 'break-word' }}
|
style={{ wordBreak: 'break-word' }}
|
||||||
/>
|
/>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
@@ -205,12 +199,7 @@ function ListPotensi({ search }: { search: string }) {
|
|||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz="sm"
|
||||||
lh={1.5}
|
lh={1.5}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
__html: DOMPurify.sanitize(item.deskripsi, {
|
|
||||||
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
|
|
||||||
ALLOWED_ATTR: []
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
style={{ wordBreak: 'break-word' }}
|
style={{ wordBreak: 'break-word' }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ function Page() {
|
|||||||
fz={{ base: 'md', md: 'lg' }}
|
fz={{ base: 'md', md: 'lg' }}
|
||||||
lh={{ base: 1.4, md: 1.4 }}
|
lh={{ base: 1.4, md: 1.4 }}
|
||||||
>
|
>
|
||||||
{perbekel.nama || "I.B. Surya Prabhawa Manuaba, S.H., M.H."}
|
I.B. Surya Prabhawa Manuaba, S.H., M.H.
|
||||||
</Text>
|
</Text>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -354,8 +354,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
borderLeft: `2px solid ${tokens.colors.primary}`,
|
borderLeft: `2px solid ${tokens.colors.primary}`,
|
||||||
}),
|
}),
|
||||||
...(mounted && isChildActive && !isDark && {
|
...(mounted && isChildActive && !isDark && {
|
||||||
backgroundColor: 'rgba(25, 113, 194, 0.1)',
|
backgroundColor: tokens.colors.bg.hover,
|
||||||
borderLeft: `2px solid ${tokens.colors.primary}`,
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -2,50 +2,15 @@ import prisma from "@/lib/prisma";
|
|||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function kategoriBeritaDelete(context: Context) {
|
export default async function kategoriBeritaDelete(context: Context) {
|
||||||
try {
|
const id = context.params.id as string;
|
||||||
const id = context.params?.id as string;
|
|
||||||
|
|
||||||
if (!id) {
|
await prisma.kategoriBerita.delete({
|
||||||
return Response.json({
|
where: { id },
|
||||||
success: false,
|
});
|
||||||
message: "ID tidak boleh kosong",
|
|
||||||
}, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Cek apakah kategori masih digunakan oleh berita
|
return {
|
||||||
const beritaCount = await prisma.berita.count({
|
status: 200,
|
||||||
where: {
|
success: true,
|
||||||
kategoriBeritaId: id,
|
message: "Sukses Menghapus kategori berita",
|
||||||
isActive: true,
|
};
|
||||||
deletedAt: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (beritaCount > 0) {
|
|
||||||
return Response.json({
|
|
||||||
success: false,
|
|
||||||
message: `Kategori tidak dapat dihapus karena masih digunakan oleh ${beritaCount} berita`,
|
|
||||||
}, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Soft delete (bukan hard delete)
|
|
||||||
await prisma.kategoriBerita.update({
|
|
||||||
where: { id },
|
|
||||||
data: {
|
|
||||||
deletedAt: new Date(),
|
|
||||||
isActive: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: "Kategori berita berhasil dihapus",
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Delete kategori error:", error);
|
|
||||||
return Response.json({
|
|
||||||
success: false,
|
|
||||||
message: "Gagal menghapus kategori: " + (error instanceof Error ? error.message : 'Unknown error'),
|
|
||||||
}, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -21,13 +21,8 @@ export default async function findUnique(
|
|||||||
}, { status: 400 });
|
}, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ Filter by isActive and deletedAt
|
const data = await prisma.potensiDesa.findUnique({
|
||||||
const data = await prisma.potensiDesa.findFirst({
|
where: { id },
|
||||||
where: {
|
|
||||||
id,
|
|
||||||
isActive: true,
|
|
||||||
deletedAt: null,
|
|
||||||
},
|
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
kategori: true
|
kategori: true
|
||||||
|
|||||||
@@ -2,50 +2,15 @@ import prisma from "@/lib/prisma";
|
|||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function kategoriPotensiDelete(context: Context) {
|
export default async function kategoriPotensiDelete(context: Context) {
|
||||||
try {
|
const id = context.params.id as string;
|
||||||
const id = context.params?.id as string;
|
|
||||||
|
|
||||||
if (!id) {
|
await prisma.kategoriPotensi.delete({
|
||||||
return Response.json({
|
where: { id },
|
||||||
success: false,
|
});
|
||||||
message: "ID tidak boleh kosong",
|
|
||||||
}, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Cek apakah kategori masih digunakan oleh potensi desa
|
return {
|
||||||
const existingPotensi = await prisma.potensiDesa.findFirst({
|
status: 200,
|
||||||
where: {
|
success: true,
|
||||||
kategoriId: id,
|
message: "Sukses Menghapus kategori potensi",
|
||||||
isActive: true,
|
};
|
||||||
deletedAt: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existingPotensi) {
|
|
||||||
return Response.json({
|
|
||||||
success: false,
|
|
||||||
message: "Kategori masih digunakan oleh potensi desa. Tidak dapat dihapus.",
|
|
||||||
}, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Soft delete
|
|
||||||
await prisma.kategoriPotensi.update({
|
|
||||||
where: { id },
|
|
||||||
data: {
|
|
||||||
deletedAt: new Date(),
|
|
||||||
isActive: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: "Kategori potensi berhasil dihapus",
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Delete kategori error:", error);
|
|
||||||
return Response.json({
|
|
||||||
success: false,
|
|
||||||
message: "Gagal menghapus kategori: " + (error instanceof Error ? error.message : 'Unknown error'),
|
|
||||||
}, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import prisma from "@/lib/prisma";
|
|
||||||
import { requireAuth } from "@/lib/api-auth";
|
|
||||||
|
|
||||||
export default async function sejarahDesaFindFirst(request: Request) {
|
|
||||||
// ✅ Authentication check
|
|
||||||
const headers = new Headers(request.url);
|
|
||||||
const authResult = await requireAuth({ headers });
|
|
||||||
if (!authResult.authenticated) {
|
|
||||||
return authResult.response;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get the first active record
|
|
||||||
const data = await prisma.sejarahDesa.findFirst({
|
|
||||||
where: {
|
|
||||||
isActive: true,
|
|
||||||
deletedAt: null
|
|
||||||
},
|
|
||||||
orderBy: { createdAt: 'asc' } // Get the oldest one first
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
return Response.json({
|
|
||||||
success: false,
|
|
||||||
message: "Data tidak ditemukan",
|
|
||||||
}, {status: 404})
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.json({
|
|
||||||
success: true,
|
|
||||||
data,
|
|
||||||
}, {status: 200})
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Gagal mengambil data sejarah desa:", error)
|
|
||||||
return Response.json({
|
|
||||||
success: false,
|
|
||||||
message: "Terjadi kesalahan saat mengambil data",
|
|
||||||
}, {status: 500})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
import Elysia, { t } from "elysia";
|
import Elysia, { t } from "elysia";
|
||||||
import sejarahDesaFindById from "./find-by-id";
|
import sejarahDesaFindById from "./find-by-id";
|
||||||
import sejarahDesaUpdate from "./update";
|
import sejarahDesaUpdate from "./update";
|
||||||
import sejarahDesaFindFirst from "./find-first";
|
|
||||||
|
|
||||||
const SejarahDesa = new Elysia({
|
const SejarahDesa = new Elysia({
|
||||||
prefix: "/sejarah",
|
prefix: "/sejarah",
|
||||||
tags: ["Desa/Profile"],
|
tags: ["Desa/Profile"],
|
||||||
})
|
})
|
||||||
.get("/first", async (context) => {
|
|
||||||
const response = await sejarahDesaFindFirst(new Request(context.request));
|
|
||||||
return response;
|
|
||||||
})
|
|
||||||
.get("/:id", async (context) => {
|
.get("/:id", async (context) => {
|
||||||
const response = await sejarahDesaFindById(new Request(context.request));
|
const response = await sejarahDesaFindById(new Request(context.request));
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { requireAuth } from "@/lib/api-auth";
|
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function sejarahDesaUpdate(context: Context) {
|
export default async function sejarahDesaUpdate(context: Context) {
|
||||||
// ✅ Authentication check
|
|
||||||
const authResult = await requireAuth(context);
|
|
||||||
if (!authResult.authenticated) {
|
|
||||||
return authResult.response;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const id = context.params?.id as string;
|
const id = context.params?.id as string;
|
||||||
const body = await context.body as {
|
const body = await context.body as {
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import {
|
|||||||
SimpleGrid,
|
SimpleGrid,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
Stack,
|
Stack,
|
||||||
Text
|
Text,
|
||||||
|
useMantineColorScheme
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useShallowEffect } from "@mantine/hooks";
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
@@ -23,6 +24,8 @@ type ProgramInovasiItem = Prisma.ProgramInovasiGetPayload<{ include: { image: tr
|
|||||||
|
|
||||||
function ModuleItem({ data }: { data: ProgramInovasiItem }) {
|
function ModuleItem({ data }: { data: ProgramInovasiItem }) {
|
||||||
const router = useTransitionRouter();
|
const router = useTransitionRouter();
|
||||||
|
const { colorScheme } = useMantineColorScheme();
|
||||||
|
const isDark = colorScheme === "dark";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div whileHover={{ scale: 1.03 }}>
|
<motion.div whileHover={{ scale: 1.03 }}>
|
||||||
@@ -34,7 +37,7 @@ function ModuleItem({ data }: { data: ProgramInovasiItem }) {
|
|||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className="cursor-pointer transition-all"
|
className="cursor-pointer transition-all"
|
||||||
bg="white"
|
bg={isDark ? "dark.6" : "white"}
|
||||||
>
|
>
|
||||||
<Center h={160}>
|
<Center h={160}>
|
||||||
{data.image?.link ? (
|
{data.image?.link ? (
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import colors from "@/con/colors";
|
import colors from "@/con/colors";
|
||||||
import { Box, Space, Stack } from "@mantine/core";
|
import { Box, Space, Stack } from "@mantine/core";
|
||||||
|
|
||||||
@@ -7,20 +5,21 @@ import { Navbar } from "@/app/darmasaba/_com/Navbar";
|
|||||||
import Footer from "./_com/Footer";
|
import Footer from "./_com/Footer";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<Stack gap={0} bg={colors.grey[1]}>
|
<Stack gap={0} bg={colors.grey[1]}>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<Space h={{
|
<Space h={{
|
||||||
base: "3.9rem",
|
base: "3.9rem",
|
||||||
md: "2.5rem"
|
md: "2.5rem"
|
||||||
}} />
|
}} />
|
||||||
<Box style={{
|
<Box style={{
|
||||||
overflow: "scroll"
|
overflow: "scroll"
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
<Footer />
|
<Footer />
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -98,10 +98,10 @@ export default function RootLayout({
|
|||||||
<html lang="id" {...mantineHtmlProps}>
|
<html lang="id" {...mantineHtmlProps}>
|
||||||
<head>
|
<head>
|
||||||
<meta charSet="utf-8" />
|
<meta charSet="utf-8" />
|
||||||
<ColorSchemeScript defaultColorScheme="light" />
|
<ColorSchemeScript />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<MantineProvider theme={theme} defaultColorScheme="light">
|
<MantineProvider theme={theme}>
|
||||||
{children}
|
{children}
|
||||||
<LoadDataFirstClient />
|
<LoadDataFirstClient />
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
/**
|
|
||||||
* Authentication helper untuk API endpoints
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* import { requireAuth } from "@/lib/api-auth";
|
|
||||||
*
|
|
||||||
* export default async function myEndpoint(context: Context) {
|
|
||||||
* const authResult = await requireAuth(context);
|
|
||||||
* if (!authResult.authenticated) {
|
|
||||||
* return authResult.response;
|
|
||||||
* }
|
|
||||||
* // Lanjut proses dengan authResult.user
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { getSession } from "@/lib/session";
|
|
||||||
|
|
||||||
export type AuthResult =
|
|
||||||
| { authenticated: true; user: any }
|
|
||||||
| { authenticated: false; response: Response };
|
|
||||||
|
|
||||||
export async function requireAuth(context: any): Promise<AuthResult> {
|
|
||||||
try {
|
|
||||||
// Cek session dari cookies
|
|
||||||
const session = await getSession();
|
|
||||||
|
|
||||||
if (!session || !session.user) {
|
|
||||||
return {
|
|
||||||
authenticated: false,
|
|
||||||
response: new Response(JSON.stringify({
|
|
||||||
success: false,
|
|
||||||
message: "Unauthorized - Silakan login terlebih dahulu"
|
|
||||||
}), {
|
|
||||||
status: 401,
|
|
||||||
headers: { 'Content-Type': 'application/json' }
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check jika user masih aktif
|
|
||||||
if (!session.user.isActive) {
|
|
||||||
return {
|
|
||||||
authenticated: false,
|
|
||||||
response: new Response(JSON.stringify({
|
|
||||||
success: false,
|
|
||||||
message: "Akun Anda tidak aktif. Hubungi administrator."
|
|
||||||
}), {
|
|
||||||
status: 403,
|
|
||||||
headers: { 'Content-Type': 'application/json' }
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
authenticated: true,
|
|
||||||
user: session.user
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Auth error:", error);
|
|
||||||
return {
|
|
||||||
authenticated: false,
|
|
||||||
response: new Response(JSON.stringify({
|
|
||||||
success: false,
|
|
||||||
message: "Authentication error"
|
|
||||||
}), {
|
|
||||||
status: 500,
|
|
||||||
headers: { 'Content-Type': 'application/json' }
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional auth - tidak error jika tidak authenticated
|
|
||||||
* Berguna untuk endpoint yang bisa diakses public atau private
|
|
||||||
*/
|
|
||||||
export async function optionalAuth(context: any): Promise<any> {
|
|
||||||
try {
|
|
||||||
const session = await getSession();
|
|
||||||
return session?.user || null;
|
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/**
|
|
||||||
* Session helper menggunakan iron-session
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* import { getSession } from "@/lib/session";
|
|
||||||
*
|
|
||||||
* const session = await getSession();
|
|
||||||
* if (session?.user) {
|
|
||||||
* // User authenticated
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { getIronSession } from 'iron-session';
|
|
||||||
import { cookies } from 'next/headers';
|
|
||||||
|
|
||||||
export type SessionData = {
|
|
||||||
user?: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
roleId: number;
|
|
||||||
menuIds?: string[] | null;
|
|
||||||
isActive?: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Session = SessionData & {
|
|
||||||
save: () => Promise<void>;
|
|
||||||
destroy: () => Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SESSION_OPTIONS = {
|
|
||||||
cookieName: 'desa-session',
|
|
||||||
password: process.env.SESSION_PASSWORD || 'default-password-change-in-production',
|
|
||||||
cookieOptions: {
|
|
||||||
secure: process.env.NODE_ENV === 'production',
|
|
||||||
httpOnly: true,
|
|
||||||
sameSite: 'lax' as const,
|
|
||||||
maxAge: 60 * 60 * 24 * 7, // 7 days
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function getSession(): Promise<SessionData | null> {
|
|
||||||
try {
|
|
||||||
const cookieStore = await cookies();
|
|
||||||
const session = await getIronSession<SessionData>(
|
|
||||||
cookieStore,
|
|
||||||
SESSION_OPTIONS
|
|
||||||
);
|
|
||||||
|
|
||||||
return session;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Session error:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function destroySession(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const cookieStore = await cookies();
|
|
||||||
const session = await getIronSession<SessionData>(
|
|
||||||
cookieStore,
|
|
||||||
SESSION_OPTIONS
|
|
||||||
);
|
|
||||||
await session.destroy();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Destroy session error:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,7 +21,7 @@ import { proxy, useSnapshot } from 'valtio';
|
|||||||
|
|
||||||
const STORAGE_KEY = 'darmasaba-admin-dark-mode';
|
const STORAGE_KEY = 'darmasaba-admin-dark-mode';
|
||||||
|
|
||||||
// Initialize from localStorage or default to light mode
|
// Initialize from localStorage or system preference
|
||||||
const getInitialDarkMode = (): boolean => {
|
const getInitialDarkMode = (): boolean => {
|
||||||
if (typeof window === 'undefined') return false;
|
if (typeof window === 'undefined') return false;
|
||||||
|
|
||||||
@@ -30,9 +30,8 @@ const getInitialDarkMode = (): boolean => {
|
|||||||
return stored === 'true';
|
return stored === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to light mode for first-time users
|
// Fallback to system preference
|
||||||
// System preference is NOT used as default to ensure consistent UX
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DarkModeStore {
|
class DarkModeStore {
|
||||||
|
|||||||
Reference in New Issue
Block a user