Merge pull request #164 from bipproduction/join

First merge to staging
This commit is contained in:
Bagasbanuna02
2024-12-06 13:55:36 +08:00
committed by GitHub
167 changed files with 4843 additions and 9546 deletions

View File

@@ -2,6 +2,73 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
## [1.2.19](https://github.com/bipproduction/hipmi/compare/v1.2.18...v1.2.19) (2024-12-06)
## [1.2.18](https://github.com/bipproduction/hipmi/compare/v1.2.17...v1.2.18) (2024-12-04)
## [1.2.17](https://github.com/bipproduction/hipmi/compare/v1.2.16...v1.2.17) (2024-12-04)
## [1.2.16](https://github.com/bipproduction/hipmi/compare/v1.2.15...v1.2.16) (2024-12-03)
## [1.2.15](https://github.com/bipproduction/hipmi/compare/v1.2.14...v1.2.15) (2024-12-03)
## [1.2.14](https://github.com/bipproduction/hipmi/compare/v1.2.13...v1.2.14) (2024-12-03)
## [1.2.13](https://github.com/bipproduction/hipmi/compare/v1.2.12...v1.2.13) (2024-12-03)
### Bug Fixes
* event ([fc38813](https://github.com/bipproduction/hipmi/commit/fc388133a638d4288314dd3faeddfcce61fe7292))
* version 1.2.12 ([932735f](https://github.com/bipproduction/hipmi/commit/932735f9238db07b331b1b26328624247371c3d6))
## [1.2.12](https://github.com/bipproduction/hipmi/compare/v1.2.11...v1.2.12) (2024-12-02)
### Bug Fixes
* version 1.2.11 ([7afcc9c](https://github.com/bipproduction/hipmi/commit/7afcc9ced02eafab1df669fd71fdbcd4556bb322))
## [1.2.11](https://github.com/bipproduction/hipmi/compare/v1.2.10...v1.2.11) (2024-12-02)
### Bug Fixes
* version 1.2.10 ([08eed15](https://github.com/bipproduction/hipmi/commit/08eed15b798d549146b035ffd9a44cea5e55b283))
## [1.2.10](https://github.com/bipproduction/hipmi/compare/v1.2.9...v1.2.10) (2024-12-02)
## [1.2.9](https://github.com/bipproduction/hipmi/compare/v1.2.8...v1.2.9) (2024-12-02)
### Bug Fixes
* version 1.2.8 ([378b2c1](https://github.com/bipproduction/hipmi/commit/378b2c19ff7a7fb07647c6a093d803d299c091f7))
* version 1.2.8 ([23edb2d](https://github.com/bipproduction/hipmi/commit/23edb2d6317f2a8344ac3190f492f718c05b65c9))
## [1.2.8](https://github.com/bipproduction/hipmi/compare/v1.2.7...v1.2.8) (2024-12-02)
### Bug Fixes
* version 1.2.7 ([1b83de0](https://github.com/bipproduction/hipmi/commit/1b83de0189b4581a8511cc58af2de0d5c613646b))
## [1.2.7](https://github.com/bipproduction/hipmi/compare/v1.2.6...v1.2.7) (2024-12-02)
### Bug Fixes
* version 1.2.6 ([13142f2](https://github.com/bipproduction/hipmi/commit/13142f283d804fead233cf6bff6a41e4732a3ec0))
## [1.2.6](https://github.com/bipproduction/hipmi/compare/v1.2.5...v1.2.6) (2024-12-02)
### Bug Fixes
* Donasi ([517b2bb](https://github.com/bipproduction/hipmi/commit/517b2bb9b0e256d31d7a10332a6e7880c58ad48f))
* Event ([45279cd](https://github.com/bipproduction/hipmi/commit/45279cd37fb4b2a293012c9cb1a8d6e977d0edb3))
* middleware ([31124c5](https://github.com/bipproduction/hipmi/commit/31124c5500d10a4d831c45c0da1a46a1dee995db))
## [1.2.5](https://github.com/bipproduction/hipmi/compare/v1.2.4...v1.2.5) (2024-11-28)

BIN
bun.lockb Executable file

Binary file not shown.

View File

@@ -1,10 +1,10 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
experimental: {
serverActions: true
},
}
reactStrictMode: false,
experimental: {
serverActions: true,
},
output: "standalone"
};
module.exports = nextConfig
module.exports = nextConfig;

View File

@@ -1,16 +1,17 @@
{
"name": "hipmi",
"version": "1.2.5",
"version": "1.2.19",
"private": true,
"prisma": {
"seed": "npx tsx prisma/seed.ts --yes"
"seed": "npx tsx prisma/seed.ts --yes"
},
"scripts": {
"dev": "next dev --experimental-https",
"build": "next build",
"start": "next start",
"lint": "next lint",
"ver": "npx commit-and-tag-version -- --prerelease"
"dev": "bun --bun run next dev --experimental-https",
"build": "NODE_OPTIONS='--max-old-space-size=2048' bun --bun run next build",
"build:dev": "bun --bun run next build",
"start": "bun --bun run next start",
"lint": "bun --bun run next lint",
"ver": "bunx commit-and-tag-version -- --prerelease"
},
"dependencies": {
"@bounceapp/iframe": "^0.3.0",
@@ -79,6 +80,7 @@
"react-international-phone": "^4.2.6",
"react-map-gl": "^7.1.7",
"react-pdf": "^9.1.0",
"react-qr-code": "^2.0.15",
"react-quill": "^2.0.0",
"react-responsive-carousel": "^3.2.23",
"react-toastify": "^9.1.3",
@@ -89,6 +91,7 @@
"utf-8-validate": "^6.0.3",
"uuid": "^9.0.1",
"wibu": "bipproduction/wibu",
"wibu-cli": "^1.0.91",
"wibu-pkg": "^1.0.3",
"yaml": "^2.3.2"
}

View File

@@ -15,7 +15,7 @@ model User {
id String @id @default(cuid())
username String @unique
nomor String @unique
active Boolean @default(true)
active Boolean @default(false)
createdAt DateTime? @default(now())
updatedAt DateTime? @updatedAt
MasterUserRole MasterUserRole @relation(fields: [masterUserRoleId], references: [id])
@@ -573,16 +573,19 @@ model Donasi_PencairanDana {
// ========================================= EVENT ========================================= //
model Event {
id String @id @default(cuid())
id String @id @default(cuid())
title String
lokasi String
tanggal DateTime
tanggal DateTime?
deskripsi String
active Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
active Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
catatan String?
tanggalSelesai DateTime?
isArsip Boolean? @default(false)
Author User? @relation(fields: [authorId], references: [id])
authorId String?
EventMaster_Status EventMaster_Status? @relation(fields: [eventMaster_StatusId], references: [id])
@@ -615,6 +618,7 @@ model Event_Peserta {
active Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
isPresent Boolean @default(false)
Event Event? @relation(fields: [eventId], references: [id])
eventId String?

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View File

@@ -1,4 +1,4 @@
import { funCheckCookies } from "@/app_modules/_global/fun/get/fun_check_cookies";
import { Login } from "@/app_modules/auth";
import versionUpdate from "../../../../package.json";

View File

@@ -1,8 +0,0 @@
import { Register } from "@/app_modules/auth";
import { auth_getCodeOtpByNumber } from "@/app_modules/auth/fun/get_kode_otp_by_id";
export default async function Page({ params }: { params: { id: string } }) {
let otpId = params.id;
const dataOtp = await auth_getCodeOtpByNumber({ kodeId: otpId });
return <Register dataOtp={dataOtp} />;
}

View File

@@ -0,0 +1,5 @@
import { Register } from "@/app_modules/auth";
export default async function Page() {
return <Register />;
}

View File

@@ -0,0 +1,7 @@
import { SplashScreen } from "@/app_modules/auth";
export default async function Page() {
return <>
<SplashScreen/>
</>
}

View File

@@ -1,9 +0,0 @@
import { Validasi } from "@/app_modules/auth";
import { auth_getCodeOtpByNumber } from "@/app_modules/auth/fun/get_kode_otp_by_id";
export default async function Page({ params }: { params: { id: string } }) {
let kodeId = params.id;
const dataOtp = await auth_getCodeOtpByNumber({ kodeId: kodeId });
return <Validasi dataOtp={dataOtp as any} />;
}

View File

@@ -0,0 +1,5 @@
import { Validasi } from "@/app_modules/auth";
export default async function Page() {
return <Validasi />;
}

View File

@@ -0,0 +1,19 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { funGlobal_checkActivationUseById } from "@/app_modules/_global/fun/get/fun_check_activation_use_by_id";
import WaitingRoom_View from "@/app_modules/waiting_room/view";
export default async function Page() {
const userLoginId = await funGetUserIdByToken();
const activationUser = await funGlobal_checkActivationUseById({
userId: userLoginId as string,
});
return (
<>
<WaitingRoom_View
activationUser={activationUser as boolean}
userLoginId={userLoginId as string}
/>
</>
);
}

View File

@@ -0,0 +1,21 @@
import { prisma } from "@/app/lib";
import { data } from "autoprefixer";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get("id");
try {
const data = await prisma.kodeOtp.findFirst({
where: {
id: id as string,
},
});
return new Response(JSON.stringify({ data }), { status: 200 });
} catch (error) {
console.log(error);
}
return new Response(JSON.stringify({ data: null }), { status: 404 });
}

View File

@@ -1,31 +1,64 @@
import { prisma } from "@/app/lib";
import { randomOTP } from "@/app_modules/auth/fun/rondom_otp";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
if (req.method === "POST") {
const codeOtp = randomOTP();
const body = await req.json();
// console.log(body);
const { nomor } = body;
if (body.nomor === "1234567890") {
return NextResponse.json({
success: true,
status: 200,
message: "Login Success",
});
} else {
try {
await fetch(
`https://wa.wibudev.com/code?nom=${body.nomor}&text=Masukan Kode OTP:${body.otp}`
try {
const res = await fetch(
`https://wa.wibudev.com/code?nom=${nomor}&text=HIPMI - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPADA SIAPAPUN, termasuk anggota ataupun pengurus HIPMI lainnya.
\n
>> Kode OTP anda: ${codeOtp}.
`
);
const sendWa = await res.json();
if (sendWa.status !== "success")
return new Response(
JSON.stringify({
success: false,
message: "Nomor Whatsapp Tidak Aktif",
}),
{ status: 400 }
);
return NextResponse.json({
body,
status: 200,
message: "Login Success",
});
} catch (error) {
return NextResponse.json({ status: 500, message: "Server Error !!!" });
}
const createOtpId = await prisma.kodeOtp.create({
data: {
nomor: nomor,
otp: codeOtp,
},
});
if (!createOtpId)
return new Response(
JSON.stringify({
success: false,
message: "Gagal Membuat Kode OTP",
}),
{ status: 400 }
);
return new Response(
JSON.stringify({
success: true,
message: "Kode Verifikasi Dikirim",
kodeId: createOtpId.id,
}),
{ status: 200 }
);
} catch (error) {
console.log(error);
return new Response(
JSON.stringify({
success: false,
message: "Server Whatsapp Error !!",
}),
{ status: 500 }
);
}
}
return NextResponse.json({ success: false });

View File

@@ -1,12 +1,28 @@
import { prisma } from "@/app/lib";
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get("id");
export async function GET() {
cookies().set({
name: "mySession",
value: "",
maxAge: 0,
});
const delToken = await prisma.userSession.delete({
where: {
userId: id as string,
},
});
return NextResponse.json({ status: 200, message: "Logout" });
const del = cookies().delete(process.env.NEXT_PUBLIC_BASE_SESSION_KEY!);
return new Response(JSON.stringify({ success: true, message: "Logout Berhasil" }), {status: 200});
}
// import { cookies } from "next/headers";
// import { NextResponse } from "next/server";
// export async function GET() {
// cookies().set({
// name: "mySession",
// value: "",
// maxAge: 0,
// });
// return NextResponse.json({ status: 200, message: "Logout" });
// }

View File

@@ -1,51 +1,70 @@
import { sessionCreate } from "@/app/auth/_lib/session_create";
import prisma from "@/app/lib/prisma";
import { ServerEnv } from "@/app/lib/server_env";
import { sealData } from "iron-session";
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
if (req.method === "POST") {
const body = await req.json();
// MyConsole(body);
const { data } = await req.json();
const cekUsername = await prisma.user.findUnique({
where: {
username: body.username,
username: data.username,
},
});
if (cekUsername)
return NextResponse.json({ status: 400, message: "Username sudah ada" });
return new Response(
JSON.stringify({
success: false,
message: "Username sudah digunakan",
}),
{ status: 400 }
);
const data = await prisma.user.create({
const createUser = await prisma.user.create({
data: {
username: body.username,
nomor: body.nomor,
username: data.username,
nomor: data.nomor,
active: true,
},
});
if (data) {
const seal = await sealData(
JSON.stringify({
id: data.id,
username: data.username,
}),
{
password: ServerEnv.value?.WIBU_PWD as string,
}
);
const token = await sessionCreate({
sessionKey: process.env.NEXT_PUBLIC_BASE_SESSION_KEY!,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
user: createUser as any,
});
cookies().set({
name: "mySession",
value: seal,
maxAge: 60 * 60 * 24 * 7,
try {
const createUserSession = await prisma.userSession.create({
data: {
token: token as string,
userId: createUser.id,
},
});
return NextResponse.json({ status: 201 });
if (!createUserSession)
return new Response(
JSON.stringify({
success: false,
message: "Gagal Membuat Session",
}),
{ status: 400 }
);
} catch (error) {
console.log(error);
}
return NextResponse.json({ success: true });
return new Response(
JSON.stringify({
success: true,
message: "Berhasil Login",
}),
{ status: 200 }
);
}
return NextResponse.json({ success: false });
return new Response(
JSON.stringify({ success: false, message: "Method Not Allowed" }),
{ status: 405 }
);
}

View File

@@ -0,0 +1,65 @@
import { prisma } from "@/app/lib";
import { randomOTP } from "@/app_modules/auth/fun/rondom_otp";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
if (req.method === "POST") {
const codeOtp = randomOTP();
const body = await req.json();
const { nomor } = body;
try {
const res = await fetch(
`https://wa.wibudev.com/code?nom=${nomor}&text=HIPMI - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPADA SIAPAPUN, termasuk anggota ataupun pengurus HIPMI lainnya.
\n
>> Kode OTP anda: ${codeOtp}.
`
);
const sendWa = await res.json();
if (sendWa.status !== "success")
return new Response(
JSON.stringify({
success: false,
message: "Nomor Whatsapp Tidak Aktif",
}),
{ status: 400 }
);
const createOtpId = await prisma.kodeOtp.create({
data: {
nomor: nomor,
otp: codeOtp,
},
});
if (!createOtpId)
return new Response(
JSON.stringify({
success: false,
message: "Gagal Membuat Kode OTP",
}),
{ status: 400 }
);
return new Response(
JSON.stringify({
success: true,
message: "Kode Verifikasi Dikirim",
kodeId: createOtpId.id,
}),
{ status: 200 }
);
} catch (error) {
console.log(error);
return new Response(
JSON.stringify({
success: false,
message: "Server Whatsapp Error !!",
}),
{ status: 500 }
);
}
}
return NextResponse.json({ success: false });
}

View File

@@ -1,3 +1,4 @@
import { sessionCreate } from "@/app/auth/_lib/session_create";
import prisma from "@/app/lib/prisma";
import { ServerEnv } from "@/app/lib/server_env";
import { sealData } from "iron-session";
@@ -7,45 +8,100 @@ import { NextResponse } from "next/server";
export async function POST(req: Request) {
if (req.method === "POST") {
const body = await req.json();
const { nomor } = await req.json();
const data = await prisma.user.findUnique({
const dataUser = await prisma.user.findUnique({
where: {
nomor: body.nomor,
nomor: nomor,
},
select: {
id: true,
nomor: true,
username: true,
active: true,
masterUserRoleId: true,
},
});
if (!data) return NextResponse.json({ status: 404 });
if (data) {
const res = await sealData(
JSON.stringify({
id: data.id,
username: data.username,
}),
{
password: ServerEnv.value?.WIBU_PWD as string,
}
if (dataUser === null)
return new Response(
JSON.stringify({ success: false, message: "Nomor Belum Terdaftar" }),
{ status: 404 }
);
cookies().set({
name: "mySession",
value: res,
maxAge: 60 * 60 * 24 * 7,
const token = await sessionCreate({
sessionKey: process.env.NEXT_PUBLIC_BASE_SESSION_KEY!,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
user: dataUser as any,
});
const cekSessionUser = await prisma.userSession.findFirst({
where: {
userId: dataUser.id,
},
});
if (cekSessionUser !== null) {
await prisma.userSession.delete({
where: {
userId: dataUser.id,
},
});
revalidatePath("/dev/home");
return NextResponse.json({ status: 200, data });
}
return NextResponse.json({ success: true });
try {
const createUserSession = await prisma.userSession.create({
data: {
token: token as string,
userId: dataUser.id,
},
});
if (!createUserSession)
return new Response(
JSON.stringify({ success: false, message: "Gagal Membuat Session" }),
{ status: 400 }
);
} catch (error) {
console.log(error);
}
// if (data) {
// const res = await sealData(
// JSON.stringify({
// id: data.id,
// username: data.username,
// }),
// {
// password: ServerEnv.value?.WIBU_PWD as string,
// }
// );
// cookies().set({
// name: "mySession",
// value: res,
// maxAge: 60 * 60 * 24 * 7,
// });
// revalidatePath("/dev/home");
// return NextResponse.json({ status: 200, data });
// }
// return NextResponse.json({ success: true });
return new Response(
JSON.stringify({
success: true,
message: "Berhasil Login",
roleId: dataUser.masterUserRoleId,
active: dataUser.active,
}),
{ status: 200 }
);
}
return NextResponse.json({ success: false });
return new Response(
JSON.stringify({ success: false, message: "Method Not Allowed" }),
{ status: 405 }
);
}

View File

@@ -0,0 +1,15 @@
import { event_funCheckKehadiran } from "@/app_modules/event/fun";
import { NextResponse } from "next/server";
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const userId = searchParams.get("userId");
const eventId = searchParams.get("eventId");
const res = await event_funCheckKehadiran({
eventId: eventId as string,
userId: userId as string,
});
return NextResponse.json(res, { status: 200 });
}

View File

@@ -0,0 +1,15 @@
import { event_funCheckPesertaByUserId } from "@/app_modules/event/fun";
import { NextResponse } from "next/server";
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const userId = searchParams.get("userId");
const eventId = searchParams.get("eventId");
const res = await event_funCheckPesertaByUserId({
eventId: eventId as string,
userId: userId as string,
});
return NextResponse.json(res, { status: 200 });
}

View File

@@ -0,0 +1,12 @@
import { event_getListAllPublish } from "@/app_modules/event/fun/get/get_list_all_publish";
import { toNumber } from "lodash";
import { NextResponse } from "next/server";
export async function GET(params: Request) {
const { searchParams } = new URL(params.url);
const page = searchParams.get("page");
const data = await event_getListAllPublish({ page: toNumber(page) });
return NextResponse.json({ data });
}

View File

@@ -0,0 +1,21 @@
import { event_getOneById } from "@/app_modules/event/fun/get/get_one_by_id";
import { NextResponse } from "next/server";
export async function GET(params: Request) {
const { searchParams } = new URL(params.url);
const eventId = searchParams.get("eventId");
const res = await event_getOneById(eventId as string);
if (!res) {
return NextResponse.json(
{ message: "Event Not Found", data: null },
{ status: 404 }
);
}
return NextResponse.json(
{ message: "Event Found", data: res },
{ status: 200 }
);
}

View File

@@ -0,0 +1,16 @@
import { event_newGetListPesertaById } from "@/app_modules/event/fun";
import { toNumber } from "lodash";
import { NextResponse } from "next/server";
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const eventId = searchParams.get("eventId");
const page = searchParams.get("page");
const res = await event_newGetListPesertaById({
eventId: eventId as string,
page: toNumber(page),
});
return NextResponse.json(res, { status: 200 });
}

View File

@@ -0,0 +1,68 @@
import { prisma } from "@/app/lib";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { NextResponse } from "next/server";
// GET DATA HOME
export async function GET(request: Request) {
try {
let fixData
const { searchParams } = new URL(request.url)
const kategori = searchParams.get("cat")
const userLoginId = await funGetUserIdByToken()
if (userLoginId == null) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan data, user id tidak ada" }, { status: 500 });
}
if (kategori == "job") {
fixData = await prisma.job.findMany({
take: 2,
orderBy: {
createdAt: "desc",
},
where: {
isActive: true,
masterStatusId: "1"
},
select: {
id: true,
Author: {
select: {
id: true,
username: true,
},
},
title: true,
deskripsi: true
},
});
} else if (kategori == "cek_profile") {
const data = await prisma.user.findUnique({
where: {
id: userLoginId,
},
select: {
Profile: {
select: {
id: true,
imageId: true,
}
}
}
});
fixData = {
profile: data?.Profile?.id,
imageId: data?.Profile?.imageId
}
}
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: fixData }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan data, coba lagi nanti ", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -0,0 +1,59 @@
import { prisma } from "@/app/lib";
import { NextResponse } from "next/server";
// GET ALL DATA PORTOFOLIO BY PROFILE ID
export async function GET(request: Request) {
try {
let fixData
const { searchParams } = new URL(request.url)
const profile = searchParams.get("profile")
const kategori_halaman = searchParams.get("cat")
const page = searchParams.get("page")
const dataSkip = Number(page) * 10 - 10;
if (kategori_halaman == "profile") {
fixData = await prisma.portofolio.findMany({
take: 2,
orderBy: {
createdAt: "desc",
},
where: {
profileId: profile,
active: true,
},
select: {
id: true,
id_Portofolio: true,
namaBisnis: true,
profileId: true,
},
});
} else if (kategori_halaman == "portofolio") {
fixData = await prisma.portofolio.findMany({
skip: dataSkip,
take: 10,
orderBy: {
createdAt: "desc",
},
where: {
profileId: profile,
active: true,
},
select: {
id: true,
id_Portofolio: true,
namaBisnis: true,
profileId: true,
},
});
}
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: fixData }, { status: 200 });
}
catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan data, coba lagi nanti ", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -0,0 +1,58 @@
import { prisma } from "@/app/lib";
import { NextResponse } from "next/server";
// GET ONE DATA USER PROFILE BY PROFILE ID
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url)
const profile = searchParams.get("profile")
const data = await prisma.profile.findUnique({
where: {
id: String(profile),
},
select: {
id: true,
name: true,
email: true,
alamat: true,
jenisKelamin: true,
imageId: true,
imageBackgroundId: true,
userId: true,
User: {
select: {
username: true,
nomor: true,
active: true,
masterUserRoleId: true
}
}
}
});
const dataFix = {
id: data?.userId,
username: data?.User?.username,
nomor: data?.User?.nomor,
active: data?.User?.active,
masterUserRoleId: data?.User?.masterUserRoleId,
idProfile: data?.id,
name: data?.name,
email: data?.email,
alamat: data?.alamat,
jenisKelamin: data?.jenisKelamin,
imageId: data?.imageId,
imageBackgroundId: data?.imageBackgroundId
}
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: dataFix, }, { status: 200 });
}
catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan data, coba lagi nanti ", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -0,0 +1,6 @@
import { headers } from "next/headers";
export async function GET(req: Request) {
const origin = new URL(req.url).origin;
return new Response(JSON.stringify({ success: true, origin }));
}

41
src/app/api/user/route.ts Normal file
View File

@@ -0,0 +1,41 @@
import { jwtVerify } from "jose";
import _ from "lodash";
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
export async function GET() {
// const data = await req.text();
// console.log(data);
const c = cookies().get(process.env.NEXT_PUBLIC_BASE_SESSION_KEY!);
if (!c || !c?.value || _.isEmpty(c?.value) || _.isUndefined(c?.value)) {
return NextResponse.json({ status: 401, message: "Unauthorized" });
}
const token = c.value;
const dataUser = await decrypt({
token: token,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
});
return NextResponse.json({ status: 200, message: "OK", data: dataUser });
}
async function decrypt({
token,
encodedKey,
}: {
token: string;
encodedKey: string;
}): Promise<Record<string, any> | null> {
try {
const enc = new TextEncoder().encode(encodedKey);
const { payload } = await jwtVerify(token, enc, {
algorithms: ["HS256"],
});
return (payload.user as Record<string, any>) || null;
} catch (error) {
console.error("Gagal verifikasi session", error);
return null;
}
}

View File

@@ -0,0 +1,7 @@
export async function GET(req: Request) {
const auth = req.headers.get("Authorization");
const token = auth?.split(" ")[1];
if (!token)
return new Response(JSON.stringify({ success: false }), { status: 401 });
return new Response(JSON.stringify({ success: true }));
}

View File

@@ -0,0 +1,22 @@
import { jwtVerify } from "jose";
export async function decrypt({
token,
encodedKey,
}: {
token: string;
encodedKey: string;
}): Promise<Record<string, any> | null> {
try {
const enc = new TextEncoder().encode(encodedKey);
const { payload } = await jwtVerify(token, enc, {
algorithms: ["HS256"],
});
return (payload.user as Record<string, any>) || null;
} catch (error) {
console.error("Gagal verifikasi session", error);
return null;
}
}
// wibu:0.2.82

View File

@@ -0,0 +1,25 @@
import { SignJWT } from "jose";
export async function encrypt({
user,
exp = "7 year",
encodedKey,
}: {
user: Record<string, any>;
exp?: string;
encodedKey: string;
}): Promise<string | null> {
try {
const enc = new TextEncoder().encode(encodedKey);
return new SignJWT({ user })
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime(exp)
.sign(enc);
} catch (error) {
console.error("Gagal mengenkripsi", error);
return null;
}
}
// wibu:0.2.82

View File

@@ -0,0 +1,35 @@
import { cookies } from "next/headers";
import { encrypt } from "./encrypt";
export async function sessionCreate({
sessionKey,
exp = "7 year",
encodedKey,
user,
}: {
sessionKey: string;
exp?: string;
encodedKey: string;
user: Record<string, unknown>;
}) {
const token = await encrypt({
exp,
encodedKey,
user,
});
const cookie: any = {
key: sessionKey,
value: token,
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
},
};
cookies().set(cookie.key, cookie.value, { ...cookie.options });
return token;
}
// wibu:0.2.82

View File

@@ -0,0 +1,27 @@
import { prisma } from "@/app/lib";
import { sessionCreate } from "../../_lib/session_create";
export async function POST(req: Request) {
const user = await prisma.user.findUnique({
where: {
nomor: "6281339158911",
},
select: {
id: true,
nomor: true,
},
});
if (!user)
return new Response(
JSON.stringify({ success: false, message: "User not found" }), {status: 404}
);
const token = await sessionCreate({
sessionKey: process.env.NEXT_PUBLIC_BASE_SESSION_KEY!,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
user: user as any,
});
return new Response(JSON.stringify({ success: true, token }));
}

View File

@@ -0,0 +1,5 @@
import { cookies } from "next/headers";
export async function GET() {
const del = cookies().delete(process.env.NEXT_PUBLIC_BASE_SESSION_KEY!);
return new Response(JSON.stringify({ success: true }));
}

View File

@@ -0,0 +1,39 @@
"use client";
import { Button } from "@mantine/core";
import { useState } from "react";
export default function Page() {
const [loading, setLoading] = useState(false);
async function login() {
setLoading(true);
try {
const res = await fetch("/auth/api/login", {
method: "POST",
});
const dataText = await res.text();
if (!res.ok) {
console.error(dataText);
throw new Error(res.statusText);
}
const dataJson = JSON.parse(dataText);
console.log(dataJson);
// window.location.replace("/dev/home");
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
return (
<>
<Button loading={loading} onClick={login}>
Login
</Button>
</>
);
}

View File

@@ -0,0 +1,21 @@
import { HomeViewNew } from "@/app_modules/home";
import notifikasi_countUserNotifikasi from "@/app_modules/notifikasi/fun/count/fun_count_by_id";
export default async function PageHome() {
// const userLoginId = await funGetUserIdByToken();
// const dataUser = await user_getOneByUserId(userLoginId as string);
// const dataJob = await job_getTwoForHomeView();
const countNotifikasi = await notifikasi_countUserNotifikasi();
return (
<>
{/* <HomeView
dataUser={dataUser as any}
dataJob={dataJob as any}
countNotifikasi={countNotifikasi}
/> */}
<HomeViewNew countNotifikasi={countNotifikasi} />
</>
);
}

View File

@@ -1,9 +1,8 @@
import { AdminEvent_TablePublish } from "@/app_modules/admin/event";
import { adminEvent_funGetListPublish } from "@/app_modules/admin/event/fun";
import { AdminEvent_getListTableByStatusId } from "@/app_modules/admin/event/fun/get/get_list_table_by_status_id";
export default async function Page() {
const listPublish = await adminEvent_funGetListPublish({page: 1});
async function Page() {
const listPublish = await adminEvent_funGetListPublish({ page: 1 });
return (
<>
@@ -11,3 +10,5 @@ export default async function Page() {
</>
);
}
export default Page;

View File

@@ -5,8 +5,9 @@ import adminNotifikasi_countNotifikasi from "@/app_modules/admin/notifikasi/fun/
import adminNotifikasi_getByUserId from "@/app_modules/admin/notifikasi/fun/get/get_notifikasi_by_user_id";
import React from "react";
import versionUpdate from "../../../../package.json";
import { redirect } from "next/navigation";
export default async function Layout({
export default async function Layout({
children,
}: {
children: React.ReactNode;
@@ -14,10 +15,14 @@ export default async function Layout({
const userLoginId = await funGetUserIdByToken();
const version = versionUpdate.version;
const dataUser = await funGlobal_getUserById({ userId: userLoginId as string});
const listNotifikasi = await adminNotifikasi_getByUserId({page: 1});
const dataUser = await funGlobal_getUserById({
userId: userLoginId as string,
});
const listNotifikasi = await adminNotifikasi_getByUserId({ page: 1 });
const countNotifikasi = await adminNotifikasi_countNotifikasi();
if (dataUser?.masterUserRoleId == "1") return redirect("/dev/home");
return (
<>
<Admin_NewLayout

View File

@@ -6,9 +6,9 @@ import { redirect } from "next/navigation";
export default async function Page() {
const version = versionUpdate.version;
const checkCookies = await funCheckCookies();
console.log(checkCookies, "ini halaman login");
if (!checkCookies) return redirect("/");
// const checkCookies = await funCheckCookies();
// console.log(checkCookies, "ini halaman login");
// if (!checkCookies) return redirect("/");
return (
<>

View File

@@ -4,5 +4,5 @@ import { auth_getCodeOtpByNumber } from "@/app_modules/auth/fun/get_kode_otp_by_
export default async function Page({ params }: { params: { id: string } }) {
let otpId = params.id;
const dataOtp = await auth_getCodeOtpByNumber({ kodeId: otpId });
return <Register dataOtp={dataOtp} />;
return <Register />;
}

View File

@@ -3,7 +3,7 @@ import { SplashScreen } from "@/app_modules/auth";
export default async function PageSplash() {
return (
<>
<SplashScreen checkCookies/>
<SplashScreen />
</>
);
}

View File

@@ -5,6 +5,5 @@ export default async function Page({ params }: { params: { id: string } }) {
let kodeId = params.id;
const dataOtp = await auth_getCodeOtpByNumber({ kodeId: kodeId });
return <Validasi dataOtp={dataOtp as any} />;
return <Validasi />;
}

View File

@@ -6,16 +6,16 @@ import { CheckCookies_UiView } from "@/app_modules/check_cookies";
import { redirect } from "next/navigation";
export default async function Page() {
const userLoginId = await funGetUserIdByToken();
const dataUser = await funGlobal_getUserById({ userId: userLoginId });
// const userLoginId = await funGetUserIdByToken();
// const dataUser = await funGlobal_getUserById({ userId: userLoginId });
if (dataUser?.masterUserRoleId === "1") {
return redirect(RouterHome.main_home);
}
// if (dataUser?.masterUserRoleId === "1") {
// return redirect(RouterHome.main_home);
// }
if (dataUser?.masterUserRoleId !== "1") {
return redirect(RouterAdminDashboard.splash_admin);
}
// if (dataUser?.masterUserRoleId !== "1") {
// return redirect(RouterAdminDashboard.splash_admin);
// }
// return <CheckCookies_UiView />;
}

View File

@@ -1,9 +1,9 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { newFunGetUserId } from "@/app/lib/new_fun_user_id";
import { Event_Create } from "@/app_modules/event";
import { Event_getMasterTipeAcara } from "@/app_modules/event/fun/master/get_tipe_acara";
export default async function Page() {
const userLoginId = await funGetUserIdByToken();
const userLoginId = await newFunGetUserId();
const listTipeAcara = await Event_getMasterTipeAcara();
return (

View File

@@ -11,8 +11,7 @@ export default async function Page({ params }: { params: { id: string } }) {
return (
<>
<Event_DetailKontribusi
dataEvent={dataEvent as any}
listKontributor={listKontributor as any}
eventId={eventId}
totalPeserta={totalPeserta}
/>
</>

View File

@@ -1,27 +1,18 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { newFunGetUserId } from "@/app/lib/new_fun_user_id";
import { Event_DetailMain } from "@/app_modules/event";
import { Event_countTotalPesertaById } from "@/app_modules/event/fun/count/count_total_peserta_by_id";
import { Event_CekUserJoinById } from "@/app_modules/event/fun/get/cek_user_join_by_id";
import { Event_getListPesertaById } from "@/app_modules/event/fun/get/get_list_peserta_by_id";
import { event_getOneById } from "@/app_modules/event/fun/get/get_one_by_id";
export default async function Page({ params }: { params: { id: string } }) {
let eventId = params.id;
const userLoginId : any= await funGetUserIdByToken();
const dataEvent = await event_getOneById(eventId);
const listPeserta = await Event_getListPesertaById(eventId);
const isJoin = await Event_CekUserJoinById(eventId, userLoginId);
const userLoginId = await newFunGetUserId();
const totalPeserta = await Event_countTotalPesertaById(eventId);
return (
<>
<Event_DetailMain
dataEvent={dataEvent as any}
listPeserta={listPeserta as any}
userLoginId={userLoginId as string}
isJoin={isJoin}
totalPeserta={totalPeserta as any}
eventId={eventId}
/>
</>
);

View File

@@ -6,15 +6,14 @@ import { event_getOneById } from "@/app_modules/event/fun/get/get_one_by_id";
export default async function Page({ params }: { params: { id: string } }) {
let eventId = params.id;
const dataEvent = await event_getOneById(eventId);
const listPeserta = await Event_getListPesertaById(eventId);
const totalPeserta = await Event_countTotalPesertaById(eventId);
return (
<Event_DetailPublish
dataEvent={dataEvent as any}
listPeserta={listPeserta}
totalPeserta={totalPeserta}
eventId={eventId}
/>
);
}

View File

@@ -1,21 +1,15 @@
import { Event_DetailRiwayat } from "@/app_modules/event";
import { Event_countTotalPesertaById } from "@/app_modules/event/fun/count/count_total_peserta_by_id";
import { Event_getListPesertaById } from "@/app_modules/event/fun/get/get_list_peserta_by_id";
import { event_getOneById } from "@/app_modules/event/fun/get/get_one_by_id";
export default async function Page({ params }: { params: { id: string } }) {
let eventId = params.id;
const dataEvent = await event_getOneById(eventId);
const listPeserta = await Event_getListPesertaById(eventId);
const totalPeserta = await Event_countTotalPesertaById(eventId);
return (
<>
<Event_DetailRiwayat
dataEvent={dataEvent as any}
listPeserta={listPeserta as any}
totalPeserta={totalPeserta as any}
eventId={eventId}
/>
</>
);

View File

@@ -0,0 +1,22 @@
import { newFunGetUserId } from "@/app/lib/new_fun_user_id";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import Ui_Konfirmasi from "@/app_modules/event/_ui/konfirmasi";
import { event_funCheckPesertaByUserId } from "@/app_modules/event/fun";
import { event_getOneById } from "@/app_modules/event/fun/get/get_one_by_id";
import moment from "moment";
import { redirect } from "next/navigation";
export default async function Page({
params,
}: {
params: Promise<{ id: string }>;
}) {
const eventId = (await params).id;
const userLoginId = await newFunGetUserId();
return (
<>
<Ui_Konfirmasi userLoginId={userLoginId as string} eventId={eventId} />
</>
);
}

View File

@@ -1,12 +1,10 @@
import { Event_Beranda } from "@/app_modules/event";
import { event_getListAllPublish } from "@/app_modules/event/fun/get/get_list_all_publish";
export default async function Page() {
const dataEvent = await event_getListAllPublish({ page: 1 });
return (
<>
<Event_Beranda dataEvent={dataEvent as any} />
<Event_Beranda />
</>
);
}

View File

@@ -16,7 +16,7 @@ export default async function Page({ params }: { params: { id: string } }) {
page: 1,
});
dataPosting?.isActive === false && redirect(RouterForum.beranda);
// dataPosting?.isActive === false && redirect(RouterForum.beranda);
const countKomentar = await forum_countTotalKomenById(postingId);

View File

@@ -1,31 +0,0 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { HomeView } from "@/app_modules/home";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { job_getTwoForHomeView } from "@/app_modules/job/fun/get/get_two_for_home_view";
import notifikasi_countUserNotifikasi from "@/app_modules/notifikasi/fun/count/fun_count_by_id";
export default async function Page() {
const userLoginId = await funGetUserIdByToken();
const dataUser = await user_getOneByUserId(userLoginId as string);
const dataJob = await job_getTwoForHomeView();
const countNotifikasi = await notifikasi_countUserNotifikasi();
// console.log(userLoginId, "ini di home");
// console.log(dataUser, "ini di home");
// if (dataUser?.active === false) {
// return redirect(RouterHome.home_user_non_active);
// }
// if (dataUser?.masterUserRoleId === "2" || dataUser?.masterUserRoleId === "3")
// return redirect(RouterAdminDashboard.splash_admin);
return (
<>
<HomeView
dataUser={dataUser as any}
dataJob={dataJob as any}
countNotifikasi={countNotifikasi}
/>
</>
);
}

View File

@@ -1,29 +1,24 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { KatalogLayout } from "@/app_modules/katalog/main";
import { Profile_getOneProfileAndUserById } from "@/app_modules/katalog/profile/fun/get/get_one_user_profile";
import { LayoutKatalogNew } from "@/app_modules/katalog/main";
export default async function Layout({
children,
params,
}: {
children: any;
params: { id: string };
}) {
const profileId = params.id;
const dataProfile = await Profile_getOneProfileAndUserById(profileId);
const authorId = dataProfile?.userId;
export default async function Layout({ children, params, }: { children: any; params: { id: string } }) {
// const profileId = params.id;
// const dataProfile = await Profile_getOneProfileAndUserById(profileId);
// const authorId = dataProfile?.userId;
const userLoginId = await funGetUserIdByToken();
// const userLoginId = await funGetUserIdByToken();
// const userRoleId = dataProfile?.User?.masterUserRoleId;
return (
<>
<KatalogLayout
{/* <KatalogLayout
profileId={profileId}
userLoginId={userLoginId as string}
authorId={authorId as any}
userRoleId={userRoleId as string}
>
{children}
</KatalogLayout>
</KatalogLayout> */}
<LayoutKatalogNew>{children}</LayoutKatalogNew>
</>
);
}

View File

@@ -1,22 +1,21 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { Katalog_MainView } from "@/app_modules/katalog";
import { funGetListPortofolio } from "@/app_modules/katalog/portofolio/fun/get/get_list_portofolio";
import { Profile_getOneProfileAndUserById } from "@/app_modules/katalog/profile/fun/get/get_one_user_profile";
import { ViewKatalogNew } from "@/app_modules/katalog";
export default async function Page({ params }: { params: { id: string } }) {
let profileId = params.id;
const userLoginId = await funGetUserIdByToken();
// let profileId = params.id;
// const userLoginId = await funGetUserIdByToken();
const listPorto = await funGetListPortofolio(profileId);
const dataProfile = await Profile_getOneProfileAndUserById(profileId);
// const listPorto = await funGetListPortofolio(profileId);
// const dataProfile = await Profile_getOneProfileAndUserById(profileId);
return (
<>
<Katalog_MainView
{/* <Katalog_MainView
profile={dataProfile as any}
listPorto={listPorto as any}
userLoginId={userLoginId as any}
/>
/> */}
<ViewKatalogNew />
</>
);
}

View File

@@ -1,38 +1,21 @@
import { CheckCookies_UiLayout } from "@/app_modules/check_cookies";
import { RealtimeProvider } from "../lib";
import { funCheckCookies } from "@/app_modules/_global/fun/get/fun_check_cookies";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { newFunGetUserId } from "../lib/new_fun_user_id";
import { ServerEnv } from "../lib/server_env";
import { funGlobal_getUserById } from "@/app_modules/_global/fun/get/fun_get_user_by_id";
import { RouterHome } from "../lib/router_hipmi/router_home";
import { RouterAdminDashboard } from "../lib/router_hipmi/router_admin";
import { redirect } from "next/navigation";
export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
const checkCookies = await funCheckCookies();
if (!checkCookies) return redirect("/");
const userLoginId = await funGetUserIdByToken();
const WIBU_REALTIME_TOKEN = process.env.NEXT_PUBLIC_WIBU_REALTIME_TOKEN;
// console.log(WIBU_REALTIME_TOKEN, "check cookies di layout dalam");
return (
<>
<RealtimeProvider
userLoginId={userLoginId as string}
WIBU_REALTIME_TOKEN={
ServerEnv.value?.NEXT_PUBLIC_WIBU_REALTIME_TOKEN as string
}
/>
{children}
{/* <CheckCookies_UiLayout dataUser={dataUser as any}>
{children}
</CheckCookies_UiLayout> */}
</>
);
}

View File

@@ -1,17 +1,17 @@
import { Portofolio_ViewListDetail } from "@/app_modules/katalog/portofolio";
import { portofolio_funGetAllDaftarByid } from "@/app_modules/katalog/portofolio/fun/get/get_all_portofolio";
import { ListDetailPortofolioNew } from "@/app_modules/katalog/portofolio";
export default async function Page({ params }: { params: { id: string } }) {
const profileId = params.id;
const dataPortofolio = await portofolio_funGetAllDaftarByid({
profileId,
page: 1,
});
// const profileId = params.id;
// const dataPortofolio = await portofolio_funGetAllDaftarByid({
// profileId,
// page: 1,
// });
return (
<>
<Portofolio_ViewListDetail dataPortofolio={dataPortofolio as any} profileId={profileId} />
{/* <Portofolio_ViewListDetail dataPortofolio={dataPortofolio as any} profileId={profileId} /> */}
<ListDetailPortofolioNew />
</>
);
}

View File

@@ -1,18 +1,5 @@
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { Home_UserNonActive } from "@/app_modules/home";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
// import { redirect } from "next/navigation";
export default async function Page() {
const userLoginId = await funGetUserIdByToken();
const dataUser = await user_getOneByUserId(userLoginId as string);
// if (dataUser?.active === true) {
// return redirect(RouterHome.main_home);
// }
return (
<>
<Home_UserNonActive />

View File

@@ -16,7 +16,7 @@ export default async function Layout({
<>
<LayoutVote_DetailSemuaRiwayat
votingId={votingId}
userLoginId={userLoginId}
userLoginId={userLoginId as string}
>
{children}
</LayoutVote_DetailSemuaRiwayat>

View File

@@ -1,13 +1,8 @@
import MqttLoader from "@/util/mqtt_loader";
import RootStyleRegistry from "./emotion";
// import "./globals.css";
import { TokenProvider } from "./lib/token";
import dotenv from "dotenv";
import { ServerEnv } from "./lib/server_env";
import { RealtimeProvider } from "./lib";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { funCheckCookies } from "@/app_modules/_global/fun/get/fun_check_cookies";
import { redirect } from "next/navigation";
import { TokenProvider } from "./lib/token";
dotenv.config({
path: ".env",
});

View File

@@ -0,0 +1,10 @@
export const API_RouteEvent = {
get_all: ({ page }: { page: number }) => `/api/event/get-all?page=${page}`,
get_one_by_id: ({ eventId }: { eventId: string }) =>
`/api/event/get-one-by-id?eventId=${eventId}`,
check_kehadiran: ({ eventId, userId }: { eventId: string; userId: string }) =>
`/api/event/check-kehadiran?eventId=${eventId}&userId=${userId}`,
check_peserta: ({ eventId, userId }: { eventId: string; userId: string }) =>
`/api/event/check-peserta?eventId=${eventId}&userId=${userId}`,
list_peserta: ({ eventId, page }: { eventId: string, page: number }) => `/api/event/list-peserta?eventId=${eventId}&page=${page}`,
};

View File

@@ -0,0 +1,21 @@
"use server"
import _ from "lodash";
import { cookies } from "next/headers";
import { decrypt } from "../auth/_lib/decrypt";
export async function newFunGetUserId() {
const c = cookies().get(process.env.NEXT_PUBLIC_BASE_SESSION_KEY!);
if (!c || !c?.value || _.isEmpty(c?.value) || _.isUndefined(c?.value)) {
return null;
}
const token = c.value;
const dataUser = await decrypt({
token: token,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
});
return dataUser?.id;
}

View File

@@ -1,17 +1,26 @@
import { PrismaClient } from '@prisma/client'
const prismaClientSingleton = () => {
return new PrismaClient()
}
type PrismaClientSingleton = ReturnType<typeof prismaClientSingleton>
import { PrismaClient } from '@prisma/client';
// Singleton PrismaClient untuk pengembangan
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClientSingleton | undefined
__prisma__: PrismaClient | undefined;
};
export const prisma = globalForPrisma.__prisma__ ?? new PrismaClient({
// log: process.env.NODE_ENV === 'development' ? ['query', 'info', 'warn', 'error'] : [],
});
// Gunakan PrismaClient yang sama jika sudah ada
if (process.env.NODE_ENV !== 'production') {
if (!globalForPrisma.__prisma__) {
console.log('PrismaClient initialized in development mode');
}
globalForPrisma.__prisma__ = prisma;
}
const prisma = globalForPrisma.prisma ?? prismaClientSingleton()
process.on('SIGINT', async () => {
console.log('Disconnecting PrismaClient...');
await prisma.$disconnect();
process.exit(0);
});
export default prisma
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
export default prisma;

View File

@@ -17,6 +17,8 @@ import {
gs_votingTiggerBeranda,
IRealtimeData,
} from "./global_state";
import { newFunGetUserId } from "./new_fun_user_id";
import { useState } from "react";
// const WIBU_REALTIME_TOKEN: string | undefined =
// process.env.NEXT_PUBLIC_WIBU_REALTIME_TOKEN;
@@ -30,12 +32,11 @@ export type TypeNotification = {
};
export default function RealtimeProvider({
userLoginId,
WIBU_REALTIME_TOKEN,
}: {
userLoginId: string;
WIBU_REALTIME_TOKEN: string;
}) {
const [userLoginId, setUserLoginId] = useState("");
const [dataRealtime, setDataRealtime] = useAtom(gs_realtimeData);
const [newAdminNtf, setNewAdminNtf] = useAtom(gs_admin_ntf);
const [newUserNtf, setNewUserNtf] = useAtom(gs_user_ntf);
@@ -71,8 +72,15 @@ export default function RealtimeProvider({
gs_donasiTriggerBeranda
);
async function loadUserId() {
const userId = await newFunGetUserId();
setUserLoginId(userId as string);
}
useShallowEffect(() => {
// if (WIBU_REALTIME_TOKEN === undefined) return alert("gak dapet key");
loadUserId();
try {
WibuRealtime.init({
project: "hipmi",
@@ -201,7 +209,7 @@ export default function RealtimeProvider({
},
});
} catch (error) {
console.log(error);
console.log("Error!:", error);
}
}, []);

View File

@@ -1,24 +1,14 @@
import { funCheckCookies } from "@/app_modules/_global/fun/get/fun_check_cookies";
import PageSplash from "./dev/auth/splash/page";
import { redirect } from "next/navigation";
import { Login, SplashScreen } from "@/app_modules/auth";
import { RouterAuth } from "./lib/router_hipmi/router_auth";
import versionUpdate from "../../package.json";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { funGlobal_getUserById } from "@/app_modules/_global/fun/get/fun_get_user_by_id";
import { RouterHome } from "./lib/router_hipmi/router_home";
import { RouterAdminDashboard } from "./lib/router_hipmi/router_admin";
"use client";
export default async function Page() {
const version = versionUpdate.version;
import { SplashScreen } from "@/app_modules/auth";
import { useShallowEffect } from "@mantine/hooks";
const checkCookies = await funCheckCookies();
// console.log(checkCookies, "ini check cookies di page awal");
if (checkCookies) return redirect("/dev/check-cookies");
return redirect("/login");
// const WIBU_REALTIME_TOKEN = process.env.NEXT_PUBLIC_WIBU_REALTIME_TOKEN;
export default function Page() {
useShallowEffect(() => {
setTimeout(() => {
window.location.replace("/dev/home");
}, 1000);
}, []);
// return <Login version={version} />;
// return <SplashScreen checkCookies={checkCookies} />;
return <PageSplash />;
return <SplashScreen />;
}

View File

@@ -51,7 +51,7 @@ export function ComponentGlobal_AvatarAndUsername({
</Avatar>
) : (
<ComponentGlobal_LoaderAvatar
fileId={profile.imageId as any}
fileId={profile?.imageId as any}
sizeAvatar={sizeAvatar}
/>
)}

View File

@@ -52,11 +52,13 @@ export async function generate_seeder() {
nomor: i.nomor,
username: i.name,
masterUserRoleId: i.masterUserRoleId,
active: i.active,
},
update: {
nomor: i.nomor,
username: i.name,
masterUserRoleId: i.masterUserRoleId,
active: i.active,
},
});
}

View File

@@ -0,0 +1,22 @@
"use server";
import { prisma } from "@/app/lib";
import { RouterAuth } from "@/app/lib/router_hipmi/router_auth";
import { permanentRedirect } from "next/navigation";
export async function funGlobal_checkActivationUseById({
userId,
}: {
userId: string;
}) {
const data = await prisma.user.findFirst({
where: {
id: userId,
},
select: {
active: true,
},
});
return data?.active;
}

View File

@@ -1,20 +1,31 @@
"use server";
import { prisma } from "@/app/lib";
import { ServerEnv } from "@/app/lib/server_env";
import { unsealData } from "iron-session";
import { jwtVerify } from "jose";
import { cookies } from "next/headers";
export async function funGetUserIdByToken() {
const c = cookies().get("mySession");
const SESSION_KEY = process.env.NEXT_PUBLIC_BASE_SESSION_KEY!;
// console.log("SESSION_KEY", SESSION_KEY);
const c = cookies().get("hipmi-key");
const token = JSON.parse(
await unsealData(c?.value as string, {
password: process.env.WIBU_PWD as string,
})
);
const cekUser = await decrypt({
token: c?.value as string,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
});
return token.id;
// const token = c?.value
// console.log("userid" , cekUser?.id)
// const token = JSON.parse(
// await unsealData(c?.value as string, {
// password: process.env.WIBU_PWD as string,
// })
// );
// return token.id;
// const token = c?.value;
// const cekToken = await prisma.userSession.findFirst({
// where: {
// token: token,
@@ -22,5 +33,24 @@ export async function funGetUserIdByToken() {
// });
// if (cekToken === null) return null
// return cekToken.userId;
return cekUser?.id;
}
async function decrypt({
token,
encodedKey,
}: {
token: string;
encodedKey: string;
}): Promise<Record<string, any> | null> {
try {
const enc = new TextEncoder().encode(encodedKey);
const { payload } = await jwtVerify(token, enc, {
algorithms: ["HS256"],
});
return (payload.user as Record<string, any>) || null;
} catch (error) {
console.error("Gagal verifikasi session", error);
return null;
}
}

View File

@@ -1,14 +1,8 @@
"use client";
import { RouterAuth } from "@/app/lib/router_hipmi/router_auth";
import { Warna } from "@/app/lib/warna";
import { AccentColor } from "@/app_modules/_global/color";
import {
ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global";
import { auth_Logout } from "@/app_modules/auth/fun/fun_logout";
import { gs_kodeId } from "@/app_modules/auth/state/state";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global";
import { MODEL_USER } from "@/app_modules/home/model/interface";
import {
ActionIcon,
@@ -20,12 +14,12 @@ import {
Menu,
Modal,
Popover,
SimpleGrid,
Stack,
Text,
Title,
} from "@mantine/core";
import { IconPhone, IconUser, IconUserCircle } from "@tabler/icons-react";
import { useAtom } from "jotai";
import { useRouter } from "next/navigation";
import { useState } from "react";
@@ -38,21 +32,18 @@ export function Admin_ComponentButtonUserCircle({
const [isOpenMenuUser, setOpenMenuUser] = useState(false);
const [openPop, setOpenPop] = useState(false);
const [openModal, setOpenModal] = useState(false);
const [loading, setLoading] = useState(false);
const [kodeId, setKodeId] = useAtom(gs_kodeId);
const [loadingLogout, setLoadingLogout] = useState(false);
async function onClickLogout() {
const res = await auth_Logout();
setLoadingLogout(true);
const res = await fetch(`/api/auth/logout?id=${dataUser.id}`, {
method: "GET",
});
const result = await res.json();
if (res.status === 200) {
console.log(res);
setLoadingLogout(true);
ComponentGlobal_NotifikasiBerhasil(res.message);
setKodeId("");
setOpenModal(false);
router.push(RouterAuth.login, { scroll: false });
} else {
ComponentGlobal_NotifikasiPeringatan(res.message);
ComponentGlobal_NotifikasiBerhasil(result.message);
router.push("/", { scroll: false });
}
}
@@ -92,11 +83,21 @@ export function Admin_ComponentButtonUserCircle({
<Divider />
<Center>
<Button radius={"xl"} onClick={() => setOpenModal(true)}>
<SimpleGrid cols={2}>
<Button
radius={"xl"}
onClick={() => router.push("/dev/home", { scroll: false })}
>
User Access
</Button>
<Button
radius={"xl"}
color="red"
onClick={() => setOpenModal(true)}
>
Keluar
</Button>
</Center>
</SimpleGrid>
</Stack>
</Popover.Dropdown>
</Popover>
@@ -114,7 +115,6 @@ export function Admin_ComponentButtonUserCircle({
<Button
onClick={() => {
setOpenModal(false);
setLoading(false);
}}
radius={50}
>

View File

@@ -45,6 +45,8 @@ import adminNotifikasi_funCreateToUser from "../../notifikasi/fun/create/fun_cre
import { adminEvent_funGetListReview } from "../fun";
import { AdminEvent_funEditStatusPublishById } from "../fun/edit/fun_edit_status_publish_by_id";
import { AdminEvent_funEditCatatanById } from "../fun/edit/fun_edit_status_reject_by_id";
import { event_checkStatus } from "@/app_modules/event/fun/get/fun_check_status_by_id";
import { ComponentAdminGlobal_NotifikasiPeringatan } from "../../_admin_global/admin_notifikasi/notifikasi_peringatan";
export default function AdminEvent_ComponentTableReview({
listData,
@@ -104,51 +106,65 @@ export default function AdminEvent_ComponentTableReview({
setIsAdminTriggerReview(false);
}
async function onPublish(eventId: string, tanggal: Date) {
if (moment(tanggal).diff(Date.now(), "minutes") < 0)
return ComponentGlobal_NotifikasiPeringatan(
"Waktu acara telah lewat, Report untuk memberitahu user !"
);
async function onPublish({
eventId,
tanggal,
}: {
eventId: string;
tanggal: Date;
}) {
const checkStatus = await event_checkStatus({ id: eventId });
const res = await AdminEvent_funEditStatusPublishById(eventId, "1");
if (res.status === 200) {
const dataNotifikasi: IRealtimeData = {
appId: res.data?.id as any,
status: res.data?.EventMaster_Status?.name as any,
userId: res.data?.authorId as any,
pesan: res.data?.title as any,
kategoriApp: "EVENT",
title: "Event publish",
};
if (checkStatus) {
if (moment(tanggal).diff(Date.now(), "minutes") < 0)
return ComponentGlobal_NotifikasiPeringatan(
"Waktu acara telah lewat, Report untuk memberitahu user !"
);
const notif = await adminNotifikasi_funCreateToUser({
data: dataNotifikasi as any,
});
const res = await AdminEvent_funEditStatusPublishById(eventId, "1");
if (res.status === 200) {
const dataNotifikasi: IRealtimeData = {
appId: res.data?.id as any,
status: res.data?.EventMaster_Status?.name as any,
userId: res.data?.authorId as any,
pesan: res.data?.title as any,
kategoriApp: "EVENT",
title: "Event publish",
};
if (notif.status === 201) {
WibuRealtime.setData({
type: "notification",
pushNotificationTo: "USER",
dataMessage: dataNotifikasi,
const notif = await adminNotifikasi_funCreateToUser({
data: dataNotifikasi as any,
});
WibuRealtime.setData({
type: "trigger",
pushNotificationTo: "USER",
dataMessage: dataNotifikasi,
if (notif.status === 201) {
WibuRealtime.setData({
type: "notification",
pushNotificationTo: "USER",
dataMessage: dataNotifikasi,
});
WibuRealtime.setData({
type: "trigger",
pushNotificationTo: "USER",
dataMessage: dataNotifikasi,
});
}
const loadData = await adminEvent_funGetListReview({
search: isSearch,
page: isActivePage,
});
setData(loadData.data as any);
setNPage(loadData.nPage);
ComponentAdminGlobal_NotifikasiBerhasil("Berhasil update status");
} else {
ComponentAdminGlobal_NotifikasiGagal(res.message);
}
const loadData = await adminEvent_funGetListReview({
search: isSearch,
page: isActivePage,
});
setData(loadData.data as any);
setNPage(loadData.nPage);
ComponentAdminGlobal_NotifikasiBerhasil("Berhasil update status");
} else {
ComponentAdminGlobal_NotifikasiGagal(res.message);
ComponentAdminGlobal_NotifikasiPeringatan(
"Review di batalkan oleh user, reload halaman review !"
);
}
}
@@ -218,19 +234,40 @@ export default function AdminEvent_ComponentTableReview({
<Text>{e.EventMaster_TipeAcara.name}</Text>
</Center>
</td>
<td>
<Center w={200}>
{e.tanggal.toLocaleString("id-ID", { dateStyle: "full" })}
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggal)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggal)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={200}>
{e.tanggal.toLocaleTimeString([], {
timeStyle: "short",
hourCycle: "h24",
})}
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggalSelesai)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggalSelesai)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={400}>
<Spoiler hideLabel="sembunyikan" maxHeight={50} showLabel="tampilkan">
@@ -246,7 +283,12 @@ export default function AdminEvent_ComponentTableReview({
color={"green"}
leftIcon={<IconCircleCheck />}
radius={"xl"}
onClick={() => onPublish(e.id, e.tanggal)}
onClick={() =>
onPublish({
eventId: e.id,
tanggal: e.tanggal,
})
}
>
Publish
</Button>
@@ -254,9 +296,17 @@ export default function AdminEvent_ComponentTableReview({
color={"red"}
leftIcon={<IconBan />}
radius={"xl"}
onClick={() => {
open();
setEventId(e.id);
onClick={async () => {
const checkStatus = await event_checkStatus({ id: e.id });
if (checkStatus) {
open();
setEventId(e.id);
} else {
ComponentAdminGlobal_NotifikasiPeringatan(
"Review di batalkan oleh user, muat kembali halaman ini !"
);
}
}}
>
Reject
@@ -334,10 +384,10 @@ export default function AdminEvent_ComponentTableReview({
<Center>Tipe Acara</Center>
</th>
<th>
<Center>Tanggal</Center>
<Center>Tanggal & Waktu Mulai</Center>
</th>
<th>
<Center>Jam</Center>
<Center>Tanggal & Waktu Selesai</Center>
</th>
<th>
<Center>Deskripsi</Center>

View File

@@ -1,19 +1,11 @@
"use client";
import { RouterAdminEvent } from "@/app/lib/router_admin/router_admin_event";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import { MODEL_EVENT } from "@/app_modules/event/model/interface";
import {
MODEL_EVENT,
MODEL_EVENT_PESERTA,
} from "@/app_modules/event/model/interface";
import {
Avatar,
Button,
Center,
Divider,
Grid,
Group,
Modal,
Pagination,
Paper,
ScrollArea,
@@ -24,7 +16,6 @@ import {
TextInput,
Title,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { IconCircleCheck, IconSearch } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
@@ -80,11 +71,14 @@ function DetailRiwayat({ listRiwayat }: { listRiwayat: any }) {
<tr key={i}>
<td>
<Button
loaderPosition="center"
loading={e.id === eventId && loading ? true : false}
color={"green"}
leftIcon={<IconCircleCheck />}
radius={"xl"}
onClick={() => {
setEventId(e.id);
setLoading(true);
router.push(RouterAdminEvent.detail_peserta + e.id);
}}
>
@@ -112,19 +106,40 @@ function DetailRiwayat({ listRiwayat }: { listRiwayat: any }) {
<Text>{e.EventMaster_TipeAcara.name}</Text>
</Center>
</td>
<td>
<Center w={200}>
{e.tanggal.toLocaleString("id-ID", { dateStyle: "full" })}
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggal)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggal)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={200}>
{e.tanggal.toLocaleTimeString([], {
timeStyle: "short",
hourCycle: "h24",
})}
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggalSelesai)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggalSelesai)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={400}>
<Spoiler hideLabel="sembunyikan" maxHeight={50} showLabel="tampilkan">
@@ -183,10 +198,10 @@ function DetailRiwayat({ listRiwayat }: { listRiwayat: any }) {
<Center>Tipe Acara</Center>
</th>
<th>
<Center>Tanggal</Center>
<Center>Tanggal & Waktu Mulai</Center>
</th>
<th>
<Center>Jam</Center>
<Center>Tanggal & Waktu Selesai</Center>
</th>
<th>
<Center>Deskripsi</Center>

View File

@@ -12,9 +12,7 @@ export default async function AdminEvent_funCountByStatusId(statusId: string) {
const count = await prisma.event.count({
where: {
eventMaster_StatusId: "1",
tanggal: {
gte: new Date
}
isArsip: false
},
});
return count;

View File

@@ -6,9 +6,7 @@ export async function AdminEvent_funCountRiwayat() {
const data = await prisma.event.count({
where: {
eventMaster_StatusId: "1",
tanggal: {
lte: new Date(),
},
isArsip: true,
},
});

View File

@@ -21,9 +21,7 @@ export async function adminEvent_funGetListAllRiwayat({
},
where: {
eventMaster_StatusId: "1",
tanggal: {
lte: new Date(),
},
isArsip: true,
title: {
contains: search,
mode: "insensitive",
@@ -49,9 +47,7 @@ export async function adminEvent_funGetListAllRiwayat({
const nCount = await prisma.event.count({
where: {
eventMaster_StatusId: "1",
tanggal: {
lte: new Date(),
},
isArsip: true,
title: {
contains: search,
mode: "insensitive",

View File

@@ -1,146 +0,0 @@
"use server";
import prisma from "@/app/lib/prisma";
export async function AdminEvent_getListTableByStatusId(statudId: string) {
if (statudId === "1") {
const getPublish = await prisma.event.findMany({
orderBy: {
tanggal: "desc",
},
where: {
eventMaster_StatusId: "1",
tanggal: {
gte: new Date(),
},
},
select: {
id: true,
title: true,
lokasi: true,
tanggal: true,
deskripsi: true,
Author: {
select: {
id: true,
username: true,
Profile: {
select: {
name: true,
},
},
},
},
EventMaster_Status: {
select: {
id: true,
name: true,
},
},
EventMaster_TipeAcara: {
select: {
id: true,
name: true,
},
},
Event_Peserta: true,
},
});
return getPublish;
}
if (statudId === "2") {
const getReview = await prisma.event.findMany({
orderBy: {
updatedAt: "desc",
},
where: {
eventMaster_StatusId: "2",
active: true,
},
select: {
id: true,
title: true,
lokasi: true,
tanggal: true,
deskripsi: true,
Author: {
select: {
id: true,
username: true,
Profile: {
select: {
name: true,
},
},
},
},
EventMaster_Status: {
select: {
id: true,
name: true,
},
},
EventMaster_TipeAcara: {
select: {
id: true,
name: true,
},
},
},
});
return getReview;
}
if (statudId === "3") {
const getDraft = await prisma.event.findMany({
orderBy: {
updatedAt: "desc",
},
where: {
eventMaster_StatusId: "3",
},
});
return getDraft;
}
if (statudId === "4") {
const getReject = await prisma.event.findMany({
orderBy: {
updatedAt: "desc",
},
where: {
eventMaster_StatusId: "4",
},
select: {
id: true,
title: true,
lokasi: true,
tanggal: true,
deskripsi: true,
Author: {
select: {
id: true,
username: true,
Profile: {
select: {
name: true,
},
},
},
},
EventMaster_Status: {
select: {
id: true,
name: true,
},
},
EventMaster_TipeAcara: {
select: {
id: true,
name: true,
},
},
catatan: true,
},
});
return getReject;
}
}

View File

@@ -1,7 +1,9 @@
"use server";
import prisma from "@/app/lib/prisma";
import { ComponentAdminGlobal_NotifikasiPeringatan } from "@/app_modules/admin/_admin_global/admin_notifikasi/notifikasi_peringatan";
import { ceil } from "lodash";
import moment from "moment";
export async function adminEvent_funGetListPublish({
page,
@@ -10,6 +12,27 @@ export async function adminEvent_funGetListPublish({
page: number;
search?: string;
}) {
const getAllData = await prisma.event.findMany({
where: {
active: true,
eventMaster_StatusId: "1",
isArsip: false,
},
});
for (let i of getAllData) {
if (moment(i.tanggalSelesai).diff(moment(), "minutes") < 0) {
await prisma.event.update({
where: {
id: i.id,
},
data: {
isArsip: true,
},
});
}
}
let takeData = 10;
let skipData = page * takeData - takeData;
@@ -21,9 +44,7 @@ export async function adminEvent_funGetListPublish({
},
where: {
eventMaster_StatusId: "1",
tanggal: {
gte: new Date(),
},
isArsip: false,
title: {
contains: search,
mode: "insensitive",
@@ -49,9 +70,7 @@ export async function adminEvent_funGetListPublish({
const nCount = await prisma.event.count({
where: {
eventMaster_StatusId: "1",
tanggal: {
gte: new Date(),
},
isArsip: false,
title: {
contains: search,
mode: "insensitive",

View File

@@ -1,14 +1,12 @@
"use client";
import { RouterAdminEvent } from "@/app/lib/router_admin/router_admin_event";
import { MODEL_EVENT } from "@/app_modules/event/model/interface";
import {
Avatar,
Box,
Button,
Center,
Divider,
Grid,
Group,
Modal,
Pagination,
Paper,
ScrollArea,
@@ -19,20 +17,14 @@ import {
TextInput,
Title,
} from "@mantine/core";
import { IconCircleCheck, IconEyeShare, IconSearch } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import { useDisclosure } from "@mantine/hooks";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import {
MODEL_EVENT,
MODEL_EVENT_PESERTA,
} from "@/app_modules/event/model/interface";
import { IconCircleCheck, IconSearch } from "@tabler/icons-react";
import _ from "lodash";
import { useRouter } from "next/navigation";
import { useState } from "react";
import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate";
import { adminEvent_getListPesertaById } from "../fun/get/get_list_peserta_by_id";
import { adminEvent_funGetListPublish } from "../fun";
import { RouterAdminEvent } from "@/app/lib/router_admin/router_admin_event";
import QRCode from "react-qr-code";
import { useShallowEffect } from "@mantine/hooks";
export default function AdminEvent_TablePublish({
listPublish,
@@ -58,6 +50,21 @@ function TableStatus({ listPublish }: { listPublish: any }) {
const [eventId, setEventId] = useState("");
const [loading, setLoading] = useState(false);
const [origin, setOrigin] = useState("");
useShallowEffect(() => {
if (typeof window !== "undefined") {
console.log(window.location.origin);
setOrigin(window.location.origin);
}
}, [setOrigin]);
// async function onLoadOrigin(setOrigin: any) {
// const res = await fetch("/api/origin-url");
// const result = await res.json();
// setOrigin(result.origin);
// }
async function onSearch(s: string) {
setSearch(s);
const loadData = await adminEvent_funGetListPublish({
@@ -78,64 +85,137 @@ function TableStatus({ listPublish }: { listPublish: any }) {
setNPage(loadData.nPage);
}
const TableRows = data.map((e, i) => (
<tr key={i}>
<td>
<Center w={200}>
<Text>{e?.Author?.username}</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text lineClamp={2}>{e.title}</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text>{e.lokasi}</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text>{e.EventMaster_TipeAcara.name}</Text>
</Center>
</td>
<td>
<Center w={200}>
{e.tanggal.toLocaleString("id-ID", { dateStyle: "full" })}
</Center>
</td>
<td>
<Center w={200}>
{e.tanggal.toLocaleTimeString([], {
timeStyle: "short",
hourCycle: "h24",
})}
</Center>
</td>
<td>
<Center w={400}>
<Spoiler hideLabel="sembunyikan" maxHeight={50} showLabel="tampilkan">
{e.deskripsi}
</Spoiler>
</Center>
</td>
<td>
<Button
loading={e.id === eventId ? (loading === true ? true : false) : false}
color={"green"}
leftIcon={<IconCircleCheck />}
radius={"xl"}
onClick={async () => {
router.push(RouterAdminEvent.detail_peserta + e.id);
}}
>
Lihat Peserta
</Button>
const TableRows = _.isEmpty(data) ? (
<tr>
<td colSpan={12}>
<Center>Belum Ada Data</Center>
</td>
</tr>
));
) : (
data.map((e, i) => (
<tr key={i}>
<td>
<Center w={200}>
<QRCode
id={e.id}
style={{ height: 70, width: 70 }}
value={`${origin}/dev/event/konfirmasi/${e.id}`}
/>
</Center>
</td>
<td>
<Center w={200}>
<input
type="button"
value="Download QR"
onClick={() => {
const svg: any = document.getElementById(e.id);
const svgData = new XMLSerializer().serializeToString(svg);
const canvas = document.createElement("canvas");
const ctx: any = canvas.getContext("2d");
const img = new Image();
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const pngFile = canvas.toDataURL("image/png");
const downloadLink = document.createElement("a");
downloadLink.download = `QRCode ${e.title}`;
downloadLink.href = `${pngFile}`;
downloadLink.click();
};
img.src = `data:image/svg+xml;base64,${btoa(svgData)}`;
}}
/>
</Center>
</td>
<td>
<Center w={200}>
<Text>{e?.Author?.username}</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text lineClamp={2}>{e.title}</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text>{e.lokasi}</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text>{e.EventMaster_TipeAcara.name}</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggal)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggal)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={200}>
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggalSelesai)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggalSelesai)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={400}>
<Spoiler
hideLabel="sembunyikan"
maxHeight={50}
showLabel="tampilkan"
>
{e.deskripsi}
</Spoiler>
</Center>
</td>
<td>
<Button
loaderPosition="center"
loading={
e.id === eventId ? (loading === true ? true : false) : false
}
color={"green"}
leftIcon={<IconCircleCheck />}
radius={"xl"}
onClick={async () => {
setEventId(e.id);
setLoading(true);
router.push(RouterAdminEvent.detail_peserta + e.id);
}}
>
Lihat Peserta
</Button>
</td>
</tr>
))
);
return (
<>
@@ -169,6 +249,13 @@ function TableStatus({ listPublish }: { listPublish: any }) {
>
<thead>
<tr>
<th>
<Center>QR Code</Center>
</th>
<th>
<Center>Download QR</Center>
</th>
<th>
<Center>Username</Center>
</th>
@@ -182,11 +269,12 @@ function TableStatus({ listPublish }: { listPublish: any }) {
<Center>Tipe Acara</Center>
</th>
<th>
<Center>Tanggal</Center>
<Center>Tanggal & Waktu Mulai</Center>
</th>
<th>
<Center>Jam</Center>
<Center>Tanggal & Waktu Selesai</Center>
</th>
<th>
<Center>Deskripsi</Center>
</th>

View File

@@ -11,6 +11,7 @@ import {
Spoiler,
Stack,
Table,
Text,
Textarea,
TextInput,
Title,
@@ -106,19 +107,40 @@ function TableStatus({ listReject }: { listReject: any }) {
<td>
<Center w={200}>{e.EventMaster_TipeAcara.name}</Center>
</td>
<td>
<Center w={200}>
{e.tanggal.toLocaleString("id-ID", { dateStyle: "full" })}
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggal)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggal)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={100}>
{e.tanggal.toLocaleTimeString([], {
timeStyle: "short",
hourCycle: "h24",
})}
<Center w={200}>
<Text align="center">
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(e?.tanggalSelesai)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(e?.tanggalSelesai)}
</Text>
</Text>
</Center>
</td>
<td>
<Center w={500}>
<Spoiler hideLabel="sembunyikan" maxHeight={50} showLabel="tampilkan">
@@ -197,10 +219,10 @@ function TableStatus({ listReject }: { listReject: any }) {
<Center>Tipe Acara</Center>
</th>
<th>
<Center>Tanggal</Center>
<Center>Tanggal & Waktu Mulai</Center>
</th>
<th>
<Center>Jam</Center>
<Center>Tanggal & Waktu Selesai</Center>
</th>
<th>
<Center>Cacatan</Center>

View File

@@ -4,6 +4,7 @@ import { gs_admin_ntf } from "@/app/lib/global_state";
import {
ActionIcon,
AppShell,
Button,
Divider,
Drawer,
Grid,
@@ -18,8 +19,10 @@ import {
import { useMediaQuery, useShallowEffect } from "@mantine/hooks";
import { IconBell } from "@tabler/icons-react";
import { useAtom } from "jotai";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { AccentColor } from "../_global/color";
import { ComponentGlobal_NotifikasiBerhasil } from "../_global/notif_global";
import { MODEL_USER } from "../home/model/interface";
import { MODEL_NOTIFIKASI } from "../notifikasi/model/interface";
import {
@@ -47,6 +50,7 @@ export function Admin_NewLayout({
listNotifikasi: MODEL_NOTIFIKASI[];
version: string;
}) {
const router = useRouter();
const matches = useMediaQuery("(min-width: 1024px)");
const [dataUser, setDataUser] = useState(user);
const userRoleId = dataUser.masterUserRoleId;
@@ -72,6 +76,20 @@ export function Admin_NewLayout({
setDrawerNotifikasi(true);
}
const [loadingLogout, setLoadingLogout] = useState(false);
async function onClickLogout() {
setLoadingLogout(true);
const res = await fetch(`/api/auth/logout?id=${user.id}`, {
method: "GET",
});
const result = await res.json();
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(result.message);
router.push("/", { scroll: false });
}
}
return (
<>
<AppShell
@@ -168,6 +186,7 @@ export function Admin_NewLayout({
<Title order={4} align="center">
View Only Available For Desktop
</Title>
<Button onClick={() => onClickLogout()}>Logout</Button>
</Stack>
) : (
children

View File

@@ -2,12 +2,15 @@
import prisma from "@/app/lib/prisma";
export async function auth_funDeleteAktivasiKodeOtpById({
export async function auth_funDeleteAktivasiKodeOtpByNomor({
nomor,
}: {
nomor: string;
}) {
// console.log(otpId);
const updt = await prisma.kodeOtp.deleteMany({
where: {
nomor: nomor,

View File

@@ -2,12 +2,12 @@ import SplashScreen from "./splash/view";
import Login from "./login/view";
import Validasi from "./validasi/view";
import Register from "./register/view";
import Component_Logout from "./logout/view";
import Component_ButtonLogout from "./logout/view";
export {
SplashScreen,
Login,
Validasi,
Register,
Component_Logout as Logout,
Component_ButtonLogout as Logout,
};

View File

@@ -1,6 +1,5 @@
"use client";
import { RouterAuth } from "@/app/lib/router_hipmi/router_auth";
import {
AccentColor,
MainColor,
@@ -8,10 +7,10 @@ import {
import ComponentGlobal_ErrorInput from "@/app_modules/_global/component/error_input";
import {
ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal,
ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global";
import { UIGlobal_LayoutDefault } from "@/app_modules/_global/ui";
import { auth_funLogin } from "@/app_modules/auth/fun/fun_login";
import { Box, Button, Center, Stack, Text, Title } from "@mantine/core";
import { useRouter } from "next/navigation";
import { useState } from "react";
@@ -28,23 +27,28 @@ export default function Login({ version }: { version: string }) {
const nomor = phone.substring(1);
if (nomor.length <= 4) return setError(true);
const res = await auth_funLogin({ nomor: nomor });
if (res.status === 200) {
setLoading(true);
ComponentGlobal_NotifikasiBerhasil(res.message, 2000);
// router.push(RouterAuth.validasi + res.kodeId, { scroll: false });
router.push("/validasi/" + res.kodeId, { scroll: false });
} else {
ComponentGlobal_NotifikasiPeringatan(res.message);
}
setLoading(true);
try {
const res = await fetch("/api/auth/login", {
method: "POST",
body: JSON.stringify({ nomor: nomor }),
headers: {
"Content-Type": "application/json",
},
});
// await fetch(ApiHipmi.login, {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(body),
// })
const result = await res.json();
if (res.status === 200) {
localStorage.setItem("hipmi_auth_code_id", result.kodeId);
ComponentGlobal_NotifikasiBerhasil(result.message, 2000);
router.push("/validasi", { scroll: false });
} else {
ComponentGlobal_NotifikasiPeringatan(result.message);
}
} catch (error) {
console.error(error);
ComponentGlobal_NotifikasiGagal("Terjadi Kesalahan");
}
}
return (
@@ -96,16 +100,11 @@ export default function Login({ version }: { version: string }) {
<Box pos={"fixed"} bottom={10}>
<Text fw={"bold"} c={"white"} fs={"italic"} fz={"xs"}>
V.{version}
v {version}
</Text>
</Box>
</Stack>
</UIGlobal_LayoutDefault>
{/* <BackgroundImage
src={"/aset/global/main_background.png"}
h={"100vh"}
// pos={"static"}
></BackgroundImage> */}
</>
);
}

View File

@@ -11,18 +11,21 @@ import { useState } from "react";
import { auth_Logout } from "../fun/fun_logout";
import { RouterAuth } from "@/app/lib/router_hipmi/router_auth";
export default function Component_Logout() {
export default function Component_ButtonLogout({userId}: {userId: string}) {
const router = useRouter();
const [opened, setOpened] = useState(false);
const [loading, setLoading] = useState(false);
async function onClickLogout() {
const res = await auth_Logout();
setLoading(true);
const res = await fetch(`/api/auth/logout?id=${userId}`, {
method: "GET",
});
const result = await res.json();
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message);
router.push("/login", { scroll: false });
} else {
ComponentGlobal_NotifikasiPeringatan(res.message);
ComponentGlobal_NotifikasiBerhasil(result.message);
router.push("/", { scroll: false });
}
}
@@ -49,7 +52,6 @@ export default function Component_Logout() {
bg={Warna.merah}
color="red"
onClick={() => {
setLoading(true);
onClickLogout();
}}
>

View File

@@ -0,0 +1,19 @@
import { Stack, Skeleton } from "@mantine/core";
export default function Register_SkeletonView() {
return (
<>
<Stack h={"100vh"} align="center" justify="center" spacing={50}>
<Skeleton h={30} w={250} radius={"xl"} />
<Skeleton h={100} w={100} radius={"50%"} />
<Stack spacing={"sm"}>
<Skeleton h={20} w={300} radius={"xl"} />
<Skeleton h={50} w={300} radius={"sm"} />
<Skeleton h={50} w={300} radius={"sm"} />
</Stack>
</Stack>
</>
);
}

View File

@@ -1,76 +1,95 @@
"use client";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { GlobalEnv } from "@/app/lib/token";
import {
AccentColor,
MainColor,
} from "@/app_modules/_global/color/color_pallet";
import { MainColor } from "@/app_modules/_global/color/color_pallet";
import ComponentGlobal_ErrorInput from "@/app_modules/_global/component/error_input";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan";
import { UIGlobal_LayoutDefault } from "@/app_modules/_global/ui";
import {
Button,
Center,
Stack,
Text,
TextInput,
Title
} from "@mantine/core";
import { useFocusTrap } from "@mantine/hooks";
import { Button, Stack, Text, TextInput, Title } from "@mantine/core";
import { useFocusTrap, useShallowEffect } from "@mantine/hooks";
import { IconUserCircle } from "@tabler/icons-react";
import _ from "lodash";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { auth_funDeleteAktivasiKodeOtpById } from "../fun/fun_edit_aktivasi_kode_otp_by_id";
import { Auth_funRegister } from "../fun/fun_register";
import { auth_funDeleteAktivasiKodeOtpByNomor } from "../fun/fun_edit_aktivasi_kode_otp_by_id";
import Register_SkeletonView from "./skeleton";
export default function Register({ dataOtp }: { dataOtp: any }) {
export default function Register() {
const router = useRouter();
const [nomor, setNomor] = useState(dataOtp.nomor);
const [nomor, setNomor] = useState("");
const [value, setValue] = useState("");
const [isValue, setIsValue] = useState(false);
const focusTrapRef = useFocusTrap();
const [loading, setLoading] = useState(false);
useShallowEffect(() => {
const kodeId = localStorage.getItem("hipmi_auth_code_id");
if (kodeId != null) {
onCheckAuthCode({ kodeId: kodeId as string, onSetData: setNomor });
} else {
console.log("code id not found");
}
}, [setNomor]);
async function onCheckAuthCode({
kodeId,
onSetData,
}: {
kodeId: string;
onSetData: any;
}) {
const res = await fetch(`/api/auth/check?id=${kodeId}`);
const result = await res.json();
onSetData(result.data.nomor);
}
async function onRegistarsi() {
const body = {
const data = {
username: value,
nomor: nomor,
};
if (body.username === "") {
setIsValue(true);
return null;
}
if (body.username.length < 5) return null;
if (_.values(body.username).includes(" ")) return null;
const res = await Auth_funRegister({
data: body,
HIPMI_PWD: GlobalEnv.value?.WIBU_PWD as string,
});
if (res.status === 200) {
await auth_funDeleteAktivasiKodeOtpById({ nomor: nomor }).then((val) => {
if (val.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message);
setLoading(true);
router.push(RouterHome.main_home, { scroll: false });
} else {
ComponentGlobal_NotifikasiPeringatan(val.message);
}
try {
setLoading(true);
const res = await fetch("/api/auth/register", {
method: "POST",
body: JSON.stringify({
data,
}),
headers: {
"Content-Type": "application/json",
},
});
} else {
ComponentGlobal_NotifikasiPeringatan(res.message);
const result = await res.json();
if (res.status === 200) {
localStorage.removeItem("hipmi_auth_code_id");
ComponentGlobal_NotifikasiBerhasil(result.message);
router.push("/dev/home", { scroll: false });
await auth_funDeleteAktivasiKodeOtpByNomor({
nomor: data.nomor,
});
}
if (res.status === 400) {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan(result.message);
}
} catch (error) {
console.log(error);
}
}
return (
<>
<UIGlobal_LayoutDefault>
<Center h={"100vh"}>
<Stack h={"100%"} align="center" justify="center" spacing={70}>
{nomor == "" ? (
<Register_SkeletonView />
) : (
<Stack h={"100vh"} align="center" justify="center" spacing={50}>
<Title order={2} c={MainColor.yellow}>
REGISTRASI
</Title>
@@ -78,7 +97,7 @@ export default function Register({ dataOtp }: { dataOtp: any }) {
<IconUserCircle size={100} color="white" />
<Stack spacing={"sm"} w={300}>
<Text fz={10} c={"white"}>
<Text align="center" c={"white"}>
Anda akan terdaftar dengan nomor berikut{" "}
<Text inherit span fw={"bold"}>
+{nomor}
@@ -109,6 +128,11 @@ export default function Register({ dataOtp }: { dataOtp: any }) {
/>
<Stack>
<Button
disabled={
value === "" ||
value.length < 5 ||
_.values(value).includes(" ")
}
loading={loading ? true : false}
loaderPosition="center"
radius={"md"}
@@ -117,9 +141,6 @@ export default function Register({ dataOtp }: { dataOtp: any }) {
c={"black"}
bg={MainColor.yellow}
color={"yellow"}
style={{
borderColor: AccentColor.yellow,
}}
onClick={() => {
onRegistarsi();
}}
@@ -129,7 +150,7 @@ export default function Register({ dataOtp }: { dataOtp: any }) {
</Stack>
</Stack>
</Stack>
</Center>
)}
</UIGlobal_LayoutDefault>
</>
);

View File

@@ -1,63 +1,22 @@
"use client";
import { RouterAdminDashboard } from "@/app/lib/router_hipmi/router_admin";
import { RouterAuth } from "@/app/lib/router_hipmi/router_auth";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { funGlobal_getUserById } from "@/app_modules/_global/fun/get/fun_get_user_by_id";
import { MODEL_USER } from "@/app_modules/home/model/interface";
import { UIGlobal_LayoutDefault } from "@/app_modules/_global/ui";
import { Avatar, BackgroundImage, Center, Image, Stack } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation";
export default function SplashScreen({
checkCookies,
}: {
checkCookies: boolean;
}) {
export default function SplashScreen() {
const router = useRouter();
useShallowEffect(() => {
// if (!checkCookies) return router.push(RouterAuth.login, { scroll: false });
// onCheckUser();
// setTimeout(() => {
// router.push(RouterAuth.login, { scroll: false });
// }, 1000);
// if (!userLoginId) {
// setTimeout(() => {
// router.push(RouterAuth.login, { scroll: false });
// }, 1000);
// } else {
// dataUser.masterUserRoleId === "1"
// ? setTimeout(() => {
// return router.push(RouterHome.main_home, { scroll: false });
// }, 1000)
// : setTimeout(() => {
// return router.push(RouterAdminDashboard.splash_admin, {
// scroll: false,
// });
// }, 1000);
// }
}, []);
// async function onCheckUser() {
// const userLoginId = await funGetUserIdByToken();
// const dataUser = await funGlobal_getUserById({ userId: userLoginId });
// if (dataUser?.masterUserRoleId == "1")
// return router.push(RouterHome.main_home);
// return router.push(RouterAdminDashboard.splash_admin);
// }
// useShallowEffect(() => {
// setTimeout(() => {
// router.push("/dev/home", { scroll: false });
// }, 1000);
// }, []);
return (
<>
<BackgroundImage
src={"/aset/global/main_background.png"}
h={"100vh"}
// pos={"static"}
>
<UIGlobal_LayoutDefault>
<Center h={"100vh"}>
<Stack align="center" justify="center" p={"md"}>
{/* <Title c={"#002e59"}>Welcome to</Title> */}
@@ -71,7 +30,7 @@ export default function SplashScreen({
</Avatar>
</Stack>
</Center>
</BackgroundImage>
</UIGlobal_LayoutDefault>
</>
);
}

View File

@@ -0,0 +1,25 @@
import { Stack, Skeleton, Group } from "@mantine/core";
export default function Validasi_SkeletonView() {
return (
<>
<Stack align="center" justify="center" h={"100vh"} spacing={50}>
<Skeleton h={30} w={250} radius={"xl"} />
<Stack>
<Skeleton h={20} w={250} radius={"xl"} />
<Skeleton h={20} w={250} radius={"xl"} />
</Stack>
<Group>
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} h={50} w={50} radius={"sm"} />
))}
</Group>
<Skeleton h={20} w={250} radius={"xl"} />
<Skeleton h={50} w={250} radius={"sm"} />
</Stack>
</>
);
}

View File

@@ -1,9 +1,7 @@
"use client";
import { RouterAdminDashboard } from "@/app/lib/router_hipmi/router_admin";
import { RouterAuth } from "@/app/lib/router_hipmi/router_auth";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { GlobalEnv } from "@/app/lib/token";
import {
AccentColor,
MainColor,
@@ -12,107 +10,175 @@ import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan";
import { UIGlobal_LayoutDefault } from "@/app_modules/_global/ui";
import {
ActionIcon,
Box,
Button,
Center,
Loader,
PinInput,
Stack,
Text,
Title,
} from "@mantine/core";
import { useFocusTrap, useShallowEffect } from "@mantine/hooks";
import { Prisma } from "@prisma/client";
import { IconChevronLeft } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { auth_funResendCode } from "../fun";
import { auth_funDeleteAktivasiKodeOtpById } from "../fun/fun_edit_aktivasi_kode_otp_by_id";
import { auth_funValidasi } from "../fun/fun_validasi";
import { useEffect, useState } from "react";
export default function Validasi({
dataOtp,
}: {
dataOtp: Prisma.KodeOtpSelect;
}) {
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global";
import { auth_funDeleteAktivasiKodeOtpByNomor } from "../fun/fun_edit_aktivasi_kode_otp_by_id";
import Validasi_SkeletonView from "./skeleton";
export default function Validasi() {
const router = useRouter();
const nomor = dataOtp.nomor as any;
const code = dataOtp.otp as any;
const [inputCode, setInputOtp] = useState("");
const focusTrapRef = useFocusTrap();
const [loading, setLoading] = useState(false);
const [counter, setCounter] = useState(60);
const [loadingResend, setLoadingResend] = useState(false);
const [triggerOtp, setTriggerOtp] = useState(false);
const [data, setData] = useState({
nomor: "",
code: "",
});
useShallowEffect(() => {
const kodeId = localStorage.getItem("hipmi_auth_code_id");
if (kodeId != null) {
onCheckAuthCode({ kodeId: kodeId as string, onSetData: setData });
} else {
console.log("code id not found");
}
if (triggerOtp) {
const kodeId = localStorage.getItem("hipmi_auth_code_id");
if (kodeId != null) {
onCheckAuthCode({ kodeId: kodeId as string, onSetData: setData });
} else {
console.log("code id not found");
}
setTriggerOtp(false);
}
}, [triggerOtp, setData, setTriggerOtp]);
async function onCheckAuthCode({
kodeId,
onSetData,
}: {
kodeId: string;
onSetData: any;
}) {
const res = await fetch(`/api/auth/check?id=${kodeId}`);
const result = await res.json();
onSetData({
nomor: result.data.nomor,
code: result.data.otp,
});
}
useEffect(() => {
counter > 0 && setTimeout(() => setCounter(counter - 1), 1000);
}, [counter]);
async function onVerifikasi() {
if (!inputCode)
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Kode");
if (code != inputCode)
if (data.code != inputCode)
return ComponentGlobal_NotifikasiPeringatan("Kode Salah");
const res = await auth_funValidasi({
nomor: nomor,
HIPMI_PWD: GlobalEnv.value?.WIBU_PWD as string,
});
if (res.status === 200) {
const resAktivasi = await auth_funDeleteAktivasiKodeOtpById(
dataOtp.id as any
);
if (resAktivasi.status === 200) {
if (res.role === "1") {
ComponentGlobal_NotifikasiBerhasil(res.message);
setLoading(true);
try {
setLoading(true);
const res = await fetch("/api/auth/validasi", {
method: "POST",
body: JSON.stringify({
nomor: data.nomor,
}),
headers: {
"Content-Type": "application/json",
},
});
const result = await res.json();
if (res.status === 200) {
localStorage.removeItem("hipmi_auth_code_id");
if (result.roleId === "1") {
ComponentGlobal_NotifikasiBerhasil(result.message);
router.push(RouterHome.main_home, { scroll: false });
// if (result.active === true) {
// } else {
// ComponentGlobal_NotifikasiBerhasil(result.message);
// router.push("/waiting-room", { scroll: false });
// }
} else {
ComponentGlobal_NotifikasiBerhasil("Admin Logged in");
setLoading(true);
router.push(RouterAdminDashboard.splash_admin, { scroll: false });
}
} else {
ComponentGlobal_NotifikasiPeringatan(resAktivasi.message);
}
}
if (res.status === 400) {
ComponentGlobal_NotifikasiBerhasil(res.message);
router.push("/register/" + dataOtp.id, { scroll: false });
}
if (res.status === 401) {
const resAktivasi = await auth_funDeleteAktivasiKodeOtpById({
nomor: nomor,
});
if (resAktivasi.status === 200) {
ComponentGlobal_NotifikasiPeringatan(res.message);
router.push("/login", { scroll: false });
await auth_funDeleteAktivasiKodeOtpByNomor({
nomor: data.nomor,
});
}
if (res.status === 404) {
ComponentGlobal_NotifikasiBerhasil(result.message);
router.push("/register", { scroll: false });
}
if (res.status === 400) {
ComponentGlobal_NotifikasiPeringatan(result.message);
}
} catch (error) {
console.error(error);
}
}
async function onBack() {
await auth_funDeleteAktivasiKodeOtpById({ nomor: nomor });
localStorage.removeItem("hipmi_auth_code_id");
await auth_funDeleteAktivasiKodeOtpByNomor({ nomor: data.nomor });
router.back();
}
async function onResendCode() {
const res = await auth_funResendCode({ nomor: nomor });
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message, 2000);
router.push("/validasi/" + res.kodeId, { scroll: false });
} else {
ComponentGlobal_NotifikasiPeringatan(res.message);
setLoadingResend(true);
localStorage.removeItem("hipmi_auth_code_id");
try {
const res = await fetch("/api/auth/resend", {
method: "POST",
body: JSON.stringify({ nomor: data.nomor }),
headers: {
"Content-Type": "application/json",
},
});
const result = await res.json();
if (res.status === 200) {
localStorage.setItem("hipmi_auth_code_id", result.kodeId);
ComponentGlobal_NotifikasiBerhasil("Kode Berhasil Dikirim", 2000);
setTriggerOtp(true);
setCounter(60);
setLoadingResend(false);
// router.push("/validasi", { scroll: false });
} else {
setLoadingResend(false);
ComponentGlobal_NotifikasiPeringatan(result.message);
}
} catch (error) {
console.error(error);
setLoadingResend(false);
ComponentGlobal_NotifikasiGagal("Terjadi Kesalahan");
}
}
// console.log(data.code);
return (
<>
<UIGlobal_LayoutDefault>
<Stack h={"100vh"}>
<Box
{/* <Box
pt={"md"}
px={"md"}
style={{
@@ -123,70 +189,84 @@ export default function Validasi({
<ActionIcon variant="transparent" onClick={() => onBack()}>
<IconChevronLeft color="white" />
</ActionIcon>
</Box>
</Box> */}
{data.nomor == "" && data.code == "" ? (
<Validasi_SkeletonView />
) : (
<Stack align="center" justify="center" h={"100vh"} spacing={50}>
<Title order={2} color={MainColor.yellow}>
Verifikasi Kode OTP
</Title>
<Stack align="center" justify="center" h={"100vh"} spacing={50}>
<Title order={2} color={MainColor.yellow}>
Verifikasi Kode OTP
</Title>
<Stack spacing={"md"} align="center">
<Stack spacing={0} align="center">
<Text c={"white"}>Masukan 4 digit kode otp</Text>
<Text c={"white"}>
Yang dikirim ke{" "}
<Text span inherit fw={"bold"}>
{" "}
+{nomor}
<Stack spacing={"md"} align="center">
<Stack spacing={0} align="center">
<Text c={"white"}>Masukan 4 digit kode otp</Text>
<Text c={"white"}>
Yang dikirim ke{" "}
<Text span inherit fw={"bold"}>
{" "}
+{data.nomor}
</Text>
</Text>
</Text>
</Stack>
<Center>
<PinInput
size="xl"
type={"number"}
ref={focusTrapRef}
spacing={"md"}
mt={"md"}
onChange={(val) => {
setInputOtp(val);
}}
/>
</Center>
<Stack h={"5vh"} align="center" justify="center">
<Text fs="italic" c={"white"}>
Tidak menerima kode ?{" "}
{counter > 0 ? (
<Text fw={"bold"} inherit span>
{counter + "s"}
</Text>
) : loadingResend ? (
<Loader ml={"sm"} size={"xs"} color="yellow" />
) : (
<Text
inherit
span
onClick={() => {
onResendCode();
}}
fw={"bold"}
>
Kirim ulang
</Text>
)}
</Text>
</Stack>
</Stack>
<Center>
<PinInput
size="xl"
type={"number"}
ref={focusTrapRef}
spacing={"md"}
mt={"md"}
onChange={(val) => {
setInputOtp(val);
}}
/>
</Center>
<Text fs="italic" mt={"sm"} c={"white"}>
Tidak menerima kode ?{" "}
{counter > 0 ? (
<Text fw={"bold"} inherit span>
{counter + "s"}
</Text>
) : (
<Text inherit span onClick={() => onResendCode()}>
Kirim ulang
</Text>
)}
</Text>
<Button
w={300}
loading={loading ? true : false}
loaderPosition="center"
radius={"md"}
compact
h={40}
c={"black"}
bg={MainColor.yellow}
color={"yellow"}
style={{
borderColor: AccentColor.yellow,
}}
onClick={() => {
onVerifikasi();
}}
>
<Text>VERIFIKASI</Text>
</Button>
</Stack>
<Button
w={300}
loading={loading ? true : false}
loaderPosition="center"
radius={"md"}
compact
h={40}
c={"black"}
bg={MainColor.yellow}
color={"yellow"}
style={{
borderColor: AccentColor.yellow,
}}
onClick={() => {
onVerifikasi();
}}
>
<Text>VERIFIKASI</Text>
</Button>
</Stack>
)}
</Stack>
</UIGlobal_LayoutDefault>
</>

View File

@@ -2,7 +2,7 @@
import { RouterAuth } from "@/app/lib/router_hipmi/router_auth";
import { useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import { redirect, useRouter } from "next/navigation";
import { MODEL_USER } from "../home/model/interface";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { RouterAdminDashboard } from "@/app/lib/router_hipmi/router_admin";
@@ -16,6 +16,12 @@ export function CheckCookies_UiLayout({
}) {
const router = useRouter();
// if (dataUser.active == false){
// router.push(RouterHome.home_user_non_active, { scroll: false });
// return children
// }
// useShallowEffect(() => {
// onCheckCookies();
// }, []);
@@ -38,5 +44,5 @@ export function CheckCookies_UiLayout({
// router.push(RouterAdminDashboard.splash_admin, { scroll: false });
// }
return children;
return <>{children}</>;
}

View File

@@ -0,0 +1,451 @@
"use client";
import {
UIGlobal_LayoutDefault,
UIGlobal_LayoutTamplate,
} from "@/app_modules/_global/ui";
import {
Button,
Card,
Center,
Group,
Paper,
Skeleton,
Stack,
Text,
Title,
} from "@mantine/core";
import { MODEL_EVENT } from "../model/interface";
import { useShallowEffect } from "@mantine/hooks";
import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { event_funCheckKehadiran, event_funUpdateKehadiran } from "../fun";
import {
ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal,
} from "@/app_modules/_global/notif_global";
import { redirect, useRouter } from "next/navigation";
import { RouterEvent } from "@/app/lib/router_hipmi/router_event";
import { useState } from "react";
import { API_RouteEvent } from "@/app/lib/api_user_router/route_api_event";
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import moment from "moment";
import { gs_event_hotMenu } from "../global_state";
import { useAtom } from "jotai";
import { Event_funJoinEvent } from "../fun/create/fun_join_event";
import { Event_funJoinAndConfirmEvent } from "../fun/create/fun_join_and_confirm";
export default function Ui_Konfirmasi({
userLoginId,
eventId,
}: {
userLoginId: string;
eventId: string;
}) {
// console.log(dataEvent);
const router = useRouter();
const [data, setData] = useState<MODEL_EVENT | null>(null);
const [isJoin, setIsJoin] = useState<boolean | null>(null);
const [isPresent, setIsPresent] = useState<boolean | null>(null);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
const data = await fetch(
API_RouteEvent.get_one_by_id({ eventId: eventId })
);
const res = await data.json();
setData(res.data);
}
// CEK PESERTA
useShallowEffect(() => {
onCheckPeserta();
}, []);
async function onCheckPeserta() {
const res = await fetch(
API_RouteEvent.check_peserta({ eventId: eventId, userId: userLoginId })
);
const data = await res.json();
console.log("cek peserta", data);
setIsJoin(data);
}
// CEK KEHADIRAN
useShallowEffect(() => {
onLoadKehadiran();
}, []);
async function onLoadKehadiran() {
const res = await fetch(
API_RouteEvent.check_kehadiran({ eventId: eventId, userId: userLoginId })
);
const data = await res.json();
setIsPresent(data);
}
// console.log("kehadiran:", isPresent);
// console.log("data:", data);
if (data == null && isPresent == null) {
return <SkeletonIsDataNull />;
}
if (data == null) {
return (
<>
<DataNotFound />
</>
);
}
if (moment(data?.tanggal).diff(moment(), "minute") < 0) {
return (
<>
<EventAlreadyDone title={data?.title} eventId={eventId} />
</>
);
}
if (isJoin == false) {
return (
<>
<UserNotJoin
title={data?.title}
eventId={eventId}
userLoginId={userLoginId}
/>
</>
);
}
if (isPresent && data) {
return <UserAlreadyConfirm title={data.title} />;
}
if (isPresent == false && data) {
return (
<UserNotConfirm
title={data.title}
eventId={eventId}
userLoginId={userLoginId}
/>
);
}
// const tgl = moment(data?.tanggal).diff(moment(), "minute") < 0;
// return (
// <>
// <UIGlobal_LayoutDefault>
// <Stack h={"100vh"} justify="center" c={"white"}>
// {JSON.stringify(tgl)}
// </Stack>
// </UIGlobal_LayoutDefault>
// </>
// );
}
function DataNotFound() {
const router = useRouter();
const [isLoading, setLoading] = useState(false);
const [hotMenu, setHotMenu] = useAtom(gs_event_hotMenu);
return (
<>
<UIGlobal_LayoutDefault>
<Stack h={"100vh"} justify="center">
<ComponentGlobal_CardStyles>
<Stack>
<Text fw={"bold"} align="center">
Data Event Tidak Ditemukan
</Text>
<Button
loading={isLoading}
loaderPosition="center"
radius={"xl"}
color="green"
c={"black"}
onClick={() => {
setHotMenu(0);
setLoading(true);
router.push(RouterEvent.beranda, { scroll: false });
}}
>
Kembali Ke Beranda
</Button>
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</UIGlobal_LayoutDefault>
</>
);
}
function SkeletonIsDataNull() {
return (
<>
<UIGlobal_LayoutDefault>
<Stack h={"100vh"} justify="center">
<ComponentGlobal_CardStyles>
<Stack>
<Skeleton height={20} width={"100%"} radius={"xl"} />{" "}
<Skeleton height={20} width={"100%"} radius={"xl"} />{" "}
<Skeleton height={20} width={"100%"} radius={"xl"} />
<Center>
<Skeleton height={40} width={"40%"} radius={"sm"} />
</Center>
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</UIGlobal_LayoutDefault>
</>
);
}
function UserNotJoin({
title,
eventId,
userLoginId,
}: {
title: string;
eventId: string;
userLoginId: string;
}) {
const router = useRouter();
const [isLoading, setLoading] = useState(false);
async function onJoinAndKonfirmasi() {
setLoading(true);
const body = {
eventId: eventId,
userId: userLoginId,
};
const res = await Event_funJoinAndConfirmEvent(body as any);
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message, 2000);
router.push(RouterEvent.detail_main + eventId);
} else {
setLoading(false);
ComponentGlobal_NotifikasiGagal(res.message);
}
}
return (
<>
<UIGlobal_LayoutDefault>
<Stack h={"100vh"} justify="center">
<ComponentGlobal_CardStyles>
<Stack align="center" justify="center">
<Text align="center">
Halo, Bapak/Ibu. Kami mencatat bahwa Anda belum melakukan
registrasi melalui aplikasi untuk mengikuti acara{" "}
<Text inherit span fw={"bold"}>
{title}.
</Text>{" "}
Mohon segera lakukan registrasi melalui Event App agar dapat
mengikuti acara ini. Jika membutuhkan bantuan, jangan ragu untuk
menghubungi tim kami. Terima kasih Terima kasih atas kehadiran
Anda di acara pada hari ini. Mohon untuk mengonfirmasi kehadiran
Anda dengan menekan tombol {"Join & Konfirmasi"}
atau fitur konfirmasi yang tersedia di bawah. Terima kasih dan
selamat menikmati acara.
</Text>
<Button
loading={isLoading}
loaderPosition="center"
radius={"xs"}
bg={MainColor.yellow}
color="yellow"
c={"black"}
onClick={() => {
onJoinAndKonfirmasi();
}}
>
Join & Konfirmasi
</Button>
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</UIGlobal_LayoutDefault>
</>
);
}
function EventAlreadyDone({
title,
eventId,
}: {
title: string;
eventId: string;
}) {
const router = useRouter();
const [isLoading, setLoading] = useState(false);
const [isLoadingDetail, setLoadingDetail] = useState(false);
const [hotMenu, setHotMenu] = useAtom(gs_event_hotMenu);
return (
<>
<UIGlobal_LayoutDefault>
<Stack h={"100vh"} justify="center">
<ComponentGlobal_CardStyles>
<Stack align="center" justify="center">
<Text align="center">
Kami mohon maaf, Bapak/Ibu, acara{" "}
<Text inherit span fw={"bold"}>
{title}
</Text>{" "}
telah selesai, sehingga konfirmasi kehadiran sudah tidak dapat
dilakukan. Terima kasih atas perhatian dan minat Anda. Kami
berharap dapat bertemu di acara kami berikutnya. Terima kasih,
Bapak/Ibu, kehadiran Anda di acara.
</Text>
</Stack>
<Group grow mt={"lg"}>
<Button
loading={isLoading}
loaderPosition="center"
radius={"xl"}
color="green"
c={"black"}
onClick={() => {
setHotMenu(0);
setLoading(true);
router.push(RouterEvent.beranda, { scroll: false });
}}
>
Beranda
</Button>
<Button
loading={isLoadingDetail}
loaderPosition="center"
radius={"xl"}
c={"black"}
onClick={() => {
setHotMenu(3);
setLoadingDetail(true);
router.push(RouterEvent.detail_riwayat + eventId, {
scroll: false,
});
}}
>
Riwayat Event
</Button>
</Group>
</ComponentGlobal_CardStyles>
</Stack>
</UIGlobal_LayoutDefault>
</>
);
}
function UserNotConfirm({
title,
eventId,
userLoginId,
}: {
title: string;
eventId: string;
userLoginId: string;
}) {
const router = useRouter();
const [isLoading, setLoading] = useState(false);
async function onUpdateKonfirmasi() {
setLoading(true);
const res = await event_funUpdateKehadiran({
eventId: eventId,
userId: userLoginId,
});
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message, 2000);
router.push(RouterEvent.detail_main + eventId);
} else {
setLoading(false);
ComponentGlobal_NotifikasiGagal(res.message);
}
}
return (
<>
<UIGlobal_LayoutDefault>
<Stack h={"100vh"} justify="center">
<ComponentGlobal_CardStyles>
<Stack align="center" justify="center">
<Text align="center">
Terima kasih atas kehadiran Anda di acara{" "}
<Text inherit span fw={"bold"}>
{title}
</Text>{" "}
pada hari ini. Mohon untuk mengonfirmasi kehadiran Anda dengan
menekan tombol {"Hadir"} atau fitur konfirmasi yang tersedia di
bawah. Terima kasih dan selamat menikmati acara.
</Text>
<Button
loading={isLoading}
loaderPosition="center"
radius={"xs"}
bg={MainColor.yellow}
color="yellow"
c={"black"}
onClick={() => {
onUpdateKonfirmasi();
}}
>
HADIR
</Button>
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</UIGlobal_LayoutDefault>
</>
);
}
function UserAlreadyConfirm({ title }: { title: string }) {
const router = useRouter();
const [isLoading, setLoading] = useState(false);
const [hotMenu, setHotMenu] = useAtom(gs_event_hotMenu);
return (
<>
<UIGlobal_LayoutDefault>
<Stack h={"100vh"} justify="center">
<ComponentGlobal_CardStyles>
<Stack align="center" justify="center">
<Text align="center">
Terima kasih, Bapak/Ibu, kehadiran Anda di acara{" "}
<Text inherit span fw={"bold"}>
{title}
</Text>{" "}
telah berhasil dikonfirmasi. Kami senang menyambut Anda dan
semoga acara ini memberikan manfaat yang maksimal. Selamat
mengikuti kegiatan.
</Text>
<Button
loading={isLoading}
loaderPosition="center"
radius={"xl"}
color="green"
c={"black"}
onClick={() => {
setHotMenu(0);
setLoading(true);
router.push(RouterEvent.beranda, { scroll: false });
}}
>
Beranda
</Button>
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</UIGlobal_LayoutDefault>
</>
);
}

View File

@@ -4,6 +4,7 @@ import { MainColor } from "@/app_modules/_global/color";
import {
ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal,
ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global";
import { notifikasiToAdmin_funCreate } from "@/app_modules/notifikasi/fun";
import { Button } from "@mantine/core";
@@ -14,13 +15,23 @@ import { useState } from "react";
import { WibuRealtime } from "wibu-pkg";
import { Event_funCreate } from "../../fun/create/fun_create";
import { gs_event_hotMenu } from "../../global_state";
import { event_checkStatus } from "../../fun/get/fun_check_status_by_id";
export default function Event_ComponentCreateButton({ value }: { value: any }) {
export default function Event_ComponentCreateButton({
value,
diffTimeStart,
diffTimeEnd,
}: {
value: any;
diffTimeStart: number;
diffTimeEnd: number;
}) {
const router = useRouter();
const [hotMenu, setHotMenu] = useAtom(gs_event_hotMenu);
const [isLoading, setLoading] = useState(false);
async function onSave() {
const res = await Event_funCreate(value);
if (res.status === 201) {
@@ -71,7 +82,8 @@ export default function Event_ComponentCreateButton({ value }: { value: any }) {
value.deskripsi === "" ||
value.eventMaster_TipeAcaraId === 0 ||
value.tanggal === "function Date() { [native code] }" ||
moment(value.tanggal).diff(moment(), "minutes") < 0
// moment(value.tanggal).diff(moment(), "minutes") < 0
diffTimeEnd - 1 < diffTimeStart
}
loaderPosition="center"
loading={isLoading ? true : false}

View File

@@ -34,11 +34,11 @@ export function ComponentEvent_CardBeranda({ data }: { data: any }) {
<Title order={5} lineClamp={1}>
{data.title}
</Title>
<Text align="right" fz={"sm"} lineClamp={1}>
{/* <Text align="right" fz={"sm"} lineClamp={1}>
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "medium",
}).format(data.tanggal)}
</Text>
}).format(data?.tanggal)}
</Text> */}
</Group>
<Text fz={"sm"} lineClamp={2}>

View File

@@ -9,26 +9,16 @@ export default function ComponentEvent_DetailData({
}: {
data: MODEL_EVENT;
}) {
const tgl = data.tanggal;
const hari = tgl.toLocaleString("id-ID", { dateStyle: "full" });
const jam = tgl.toLocaleTimeString([], {
timeStyle: "short",
hourCycle: "h24",
});
return (
<>
<ComponentGlobal_CardStyles marginBottom={"16px"}>
<Stack px={"sm"} spacing={"lg"}>
<Stack px={"sm"} spacing={"xl"}>
<Title lineClamp={2} align="center" w={"100%"} order={4}>
{data ? data?.title : null}
</Title>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Lokasi
</Text>
<Text fw={"bold"}>Lokasi</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
@@ -37,37 +27,59 @@ export default function ComponentEvent_DetailData({
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Tipe Acara
</Text>
<Text fw={"bold"}>Tipe Acara</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{data ? data.EventMaster_TipeAcara?.name : null}</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Tanggal
</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>{hari ? hari : ""}</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Jam
</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>{jam ? jam : ""}</Grid.Col>
</Grid>
<Stack spacing={"xs"}>
<Text fw={"bold"}>Tanggal & Waktu</Text>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"}>Mulai</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(data?.tanggal)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(data?.tanggal)}
</Text>
</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"}>Selesai</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{" "}
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "full",
}).format(data?.tanggalSelesai)}
,{" "}
<Text span inherit>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "short",
}).format(data?.tanggalSelesai)}
</Text>
</Text>
</Grid.Col>
</Grid>
</Stack>
<Stack spacing={2}>
<Text fw={"bold"} fz={"sm"}>
Deskripsi
</Text>
<Text fw={"bold"}>Deskripsi</Text>
<Text>{data ? data?.deskripsi : null}</Text>
</Stack>
</Stack>

View File

@@ -4,83 +4,110 @@ import {
ComponentGlobal_AvatarAndUsername,
ComponentGlobal_CardStyles,
} from "@/app_modules/_global/component";
import { Grid, Stack, Text, Title } from "@mantine/core";
import { Center, Grid, Skeleton, Stack, Text, Title } from "@mantine/core";
import { MODEL_EVENT } from "../../model/interface";
import { useShallowEffect } from "@mantine/hooks";
import { useState } from "react";
import { API_RouteEvent } from "@/app/lib/api_user_router/route_api_event";
import { Event_ComponentSkeletonDetail } from "../skeleton/comp_skeleton_detail";
import moment from "moment";
import "moment/locale/id";
export default function ComponentEvent_DetailMainData({
data,
eventId,
}: {
data: MODEL_EVENT;
eventId: string;
}) {
const tgl = data.tanggal;
const hari = tgl.toLocaleString("id-ID", { dateStyle: "full" });
const [data, setData] = useState<MODEL_EVENT | null>(null);
const jam = tgl.toLocaleTimeString([], {
timeStyle: "short",
hourCycle: "h24",
});
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
const data = await fetch(
API_RouteEvent.get_one_by_id({ eventId: eventId })
);
const res = await data.json();
setData(res.data);
}
return (
<>
<ComponentGlobal_CardStyles>
<Stack px={"xs"} spacing={"xl"}>
<ComponentGlobal_AvatarAndUsername
profile={data?.Author?.Profile as any}
/>
{data == null ? (
<Event_ComponentSkeletonDetail />
) : (
<ComponentGlobal_CardStyles>
<Stack px={"xs"} spacing={"xl"}>
<ComponentGlobal_AvatarAndUsername
profile={data?.Author?.Profile as any}
/>
<Stack>
<Title align="center" order={4}>
{data ? data.title : null}
</Title>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Lokasi
</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{data ? data.lokasi : null}</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Tipe Acara
</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{data ? data.EventMaster_TipeAcara.name : null}</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Tanggal
</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>{hari}</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"} fz={"sm"}>
Jam
</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>{jam}</Grid.Col>
</Grid>
<Stack spacing={2}>
<Text fw={"bold"} fz={"sm"}>
Deskripsi
</Text>
<Text>{data ? data?.deskripsi : null}</Text>
<Stack spacing={"xl"}>
<Title align="center" order={4}>
{data ? data.title : null}
</Title>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"}>Lokasi</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{data ? data.lokasi : null}</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"}>Tipe Acara</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{data ? data.EventMaster_TipeAcara.name : null}</Text>
</Grid.Col>
</Grid>
<Stack spacing={"xs"}>
<Text fw={"bold"}>Tanggal & Waktu</Text>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"}>Mulai</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{moment(
data.tanggal?.toLocaleString("id-ID", {
dateStyle: "full",
})
).format("dddd, DD MMMM YYYY, LT")}
</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={4}>
<Text fw={"bold"}>Selesai</Text>
</Grid.Col>
<Grid.Col span={1}>:</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{moment(
data.tanggalSelesai?.toLocaleString("id-ID", {
dateStyle: "full",
})
).format("dddd, DD MMMM YYYY, LT")}
</Text>
</Grid.Col>
</Grid>
</Stack>
<Stack spacing={2}>
<Text fw={"bold"}>Deskripsi</Text>
<Text>{data ? data?.deskripsi : null}</Text>
</Stack>
</Stack>
</Stack>
</Stack>
</ComponentGlobal_CardStyles>
</ComponentGlobal_CardStyles>
)}
</>
);
}

View File

@@ -1,58 +1,202 @@
"use client";
import {
ActionIcon,
Avatar,
Center,
Grid,
Group,
Skeleton,
Stack,
Text,
Title
Title,
} from "@mantine/core";
import _ from "lodash";
import {
ComponentGlobal_AvatarAndUsername,
ComponentGlobal_CardStyles,
ComponentGlobal_LoaderAvatar,
} from "@/app_modules/_global/component";
import { useRouter } from "next/navigation";
import { MODEL_EVENT_PESERTA } from "../../model/interface";
import { Prisma } from "@prisma/client";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
import { funGlobal_CheckProfile } from "@/app_modules/_global/fun/get";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
import { useState } from "react";
import moment from "moment";
import { useShallowEffect } from "@mantine/hooks";
import { API_RouteEvent } from "@/app/lib/api_user_router/route_api_event";
import Event_ComponentSkeletonListPeserta from "../skeleton/comp_skeleton_list_peserta";
export default function ComponentEvent_ListPeserta({
listPeserta,
total,
eventId,
isNewPeserta,
}: {
listPeserta: MODEL_EVENT_PESERTA[];
total: number;
eventId: string;
isNewPeserta?: boolean | null;
}) {
const router = useRouter();
const [data, setData] = useState<MODEL_EVENT_PESERTA[] | null>(null);
useShallowEffect(() => {
onLoadPeserta();
}, []);
useShallowEffect(() => {
if (isNewPeserta !== null && isNewPeserta === true) {
onLoadPeserta();
}
}, [isNewPeserta]);
async function onLoadPeserta() {
const res = await fetch(
API_RouteEvent.list_peserta({ eventId: eventId, page: 1 })
);
const data = await res.json();
setData(data);
}
return (
<>
<ComponentGlobal_CardStyles>
<Stack spacing={"md"} px={"sm"}>
<Center>
<Title order={5}>Daftar Peserta ({total})</Title>
</Center>
{_.isEmpty(listPeserta) ? (
{data === null ? (
<Event_ComponentSkeletonListPeserta />
) : (
<ComponentGlobal_CardStyles>
<Stack spacing={"md"} px={"sm"}>
<Center>
<Text fz={"xs"} fw={"bold"}>
- Tidak ada peserta -
</Text>
<Title order={5}>Daftar Peserta ({total})</Title>
</Center>
) : (
<Stack>
{listPeserta.map((e, i) => (
<Stack key={i} spacing={"sm"}>
<ComponentGlobal_AvatarAndUsername
profile={e.User.Profile as any}
sizeAvatar={30}
fontSize={"sm"}
/>
{/* <Divider /> */}
</Stack>
))}
</Stack>
)}
</Stack>
</ComponentGlobal_CardStyles>
{_.isEmpty(data) ? (
<Center>
<Text fz={"xs"} fw={"bold"}>
- Tidak ada peserta -
</Text>
</Center>
) : (
<Stack>
{data.map((e, i) => (
<Stack key={i} spacing={"sm"}>
<ComponentEvent_AvatarAndUsername
profile={e?.User?.Profile as any}
sizeAvatar={30}
fontSize={"sm"}
tanggalMulai={e?.Event?.tanggal}
tanggalSelesai={e?.Event?.tanggalSelesai}
isPresent={e?.isPresent}
/>
{/* <Divider /> */}
</Stack>
))}
</Stack>
)}
</Stack>
</ComponentGlobal_CardStyles>
)}
</>
);
}
type IFontSize = "xs" | "sm" | "md" | "lg" | "xl";
function ComponentEvent_AvatarAndUsername({
profile,
component,
sizeAvatar,
fontSize,
tanggalMulai,
tanggalSelesai,
isPresent,
}: {
profile: Prisma.ProfileSelect;
component?: React.ReactNode;
sizeAvatar?: number;
fontSize?: IFontSize | {};
tanggalMulai?: Date;
tanggalSelesai?: Date;
isPresent?: boolean;
}) {
const router = useRouter();
const [visible, setVisible] = useState(false);
async function onCheckProfile() {
const res = await funGlobal_CheckProfile({ profileId: profile.id as any });
if (res !== null) {
setVisible(true);
router.push(RouterProfile.katalog({ id: profile.id as any }));
} else {
ComponentGlobal_NotifikasiPeringatan("Id tidak ditemukan");
}
}
const tglMulai = moment(tanggalMulai).diff(moment(), "minutes");
const tglSelesai = moment(tanggalSelesai).diff(moment(), "minutes");
// console.log("mulai:", tglMulai, "selesai:", tglSelesai);
return (
<>
<Grid align="flex-start" justify="space-around">
<Grid.Col span={2} style={{ minHeight: 50 }}>
<ActionIcon
radius={"xl"}
variant="transparent"
onClick={() => onCheckProfile()}
>
{visible ? (
<Avatar radius={"xl"} size={40}>
<ComponentGlobal_Loader />
</Avatar>
) : (
<ComponentGlobal_LoaderAvatar
fileId={profile?.imageId as any}
sizeAvatar={sizeAvatar}
/>
)}
</ActionIcon>
</Grid.Col>
<Grid.Col span={"auto"} style={{ minHeight: 50 }}>
<Stack justify="center" h={30}>
<Text
fw={"bold"}
fz={fontSize ? fontSize : "sm"}
lineClamp={1}
onClick={() => onCheckProfile()}
>
{profile?.name}
</Text>
</Stack>
</Grid.Col>
{/* {component && (
<Grid.Col span={"auto"} style={{ minHeight: 50 }}>
<Stack justify="center" h={30}>
{component}
</Stack>
</Grid.Col>
)} */}
{tglMulai < 0 && (
<Grid.Col span={3} style={{ minHeight: 50 }}>
<Group position="right">
<Stack justify="center" h={30}>
<Text fw={"bold"} fz={fontSize ? fontSize : "sm"}>
{isPresent ? "Hadir" : "-"}
</Text>
</Stack>
</Group>
</Grid.Col>
)}
</Grid>
</>
);
}

View File

@@ -1,5 +1,11 @@
import Event_ComponentCreateButton from "./button/button_create_event";
import Event_ComponentSkeletonBeranda from "./skeleton/comp_skeleton_beranda";
import { Event_ComponentSkeletonDetail } from "./skeleton/comp_skeleton_detail";
import { Event_ComponentSkeletonDetailData } from "./skeleton/comp_skeleton_detail_data";
import Event_ComponentSkeletonListPeserta from "./skeleton/comp_skeleton_list_peserta";
export { Event_ComponentSkeletonDetailData };
export { Event_ComponentCreateButton };
export { Event_ComponentSkeletonBeranda };
export { Event_ComponentSkeletonDetail };
export { Event_ComponentSkeletonListPeserta };

View File

@@ -0,0 +1,29 @@
import { AccentColor } from "@/app_modules/_global/color";
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { Grid, Group, Paper, Skeleton, Stack, Text } from "@mantine/core";
export default function Event_ComponentSkeletonBeranda() {
return (
<>
{Array.from({ length: 10 }).map((_, index) => (
<ComponentGlobal_CardStyles key={index} marginBottom={"16px"}>
<Stack>
<Grid align="center">
<Grid.Col span={"content"}>
<Skeleton radius={"100%"} h={50} w={50} />
</Grid.Col>
<Grid.Col span={"auto"}>
<Skeleton h={20} w={"50%"} />
</Grid.Col>
</Grid>
<Stack>
<Skeleton h={20} w={"100%"} />
<Skeleton h={20} w={"100%"} />
</Stack>
</Stack>
</ComponentGlobal_CardStyles>
))}
</>
);
}

View File

@@ -0,0 +1,36 @@
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { Stack, Center, Skeleton, Grid } from "@mantine/core";
export function Event_ComponentSkeletonDetail() {
return (
<>
<ComponentGlobal_CardStyles>
<Stack>
<Grid align="center">
<Grid.Col span={"content"}>
<Skeleton radius={"100%"} h={50} w={50} />
</Grid.Col>
<Grid.Col span={"auto"}>
<Skeleton h={20} w={"50%"} />
</Grid.Col>
</Grid>
</Stack>
<Stack spacing={"xl"}>
<Center>
<Skeleton h={20} w={"50%"} />
</Center>
<Skeleton h={20} w={"100%"} />
<Skeleton h={20} w={"100%"} />
<Skeleton h={20} w={"50%"} />
<Skeleton h={20} w={"100%"} />
<Skeleton h={20} w={"100%"} />
<Stack>
<Skeleton h={20} w={"50%"} />
<Skeleton h={20} w={"100%"} />
<Skeleton h={20} w={"100%"} />
</Stack>
</Stack>
</ComponentGlobal_CardStyles>
</>
);
}

View File

@@ -0,0 +1,32 @@
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { Stack, Center, Skeleton, Grid } from "@mantine/core";
export default function Event_ComponentSkeletonListPeserta() {
return (
<>
<ComponentGlobal_CardStyles>
<Stack spacing={"lg"}>
<Center>
<Skeleton height={20} width={"50%"} />
</Center>
<Stack>
{Array.from(new Array(3)).map((e, i) => (
<Grid key={i} align="center">
<Grid.Col span={"content"}>
<Skeleton radius={"100%"} h={30} w={30} />
</Grid.Col>
<Grid.Col span={"auto"}>
<Skeleton h={20} w={"50%"} />
</Grid.Col>
<Grid.Col span={2}>
<Skeleton h={20} w={"50%"} />
</Grid.Col>
</Grid>
))}
</Stack>
</Stack>
</ComponentGlobal_CardStyles>
</>
);
}

Some files were not shown because too many files have changed in this diff Show More