Merge pull request 'feat: tambah endpoint kalender umum village' (#45) from amalia/11-mei-26 into join

Reviewed-on: #45
This commit is contained in:
2026-05-11 17:36:03 +08:00
2 changed files with 205 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import { prisma } from "@/module/_global";
import { funGetUserById } from "@/module/auth";
import _ from "lodash";
import moment from "moment";
import { NextResponse } from "next/server";
// GET indicator dot per bulan (tanggal mana saja yang ada event)
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const user = searchParams.get("user");
const date = searchParams.get("date");
const userMobile = await funGetUserById({ id: String(user) });
if (!userMobile.id || userMobile.id === "null") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const idVillage = userMobile.idVillage;
const awalDate = moment(date).format("YYYY-MM") + "-01";
const akhirDate = moment(awalDate).add(1, "M").format("YYYY-MM-DD");
// Tanggal dengan event kalender divisi
const calendarDates = await prisma.divisionCalendarReminder.findMany({
where: {
isActive: true,
dateStart: {
gte: new Date(awalDate),
lt: new Date(akhirDate),
},
Division: {
idVillage,
isActive: true,
},
DivisionCalendar: {
isActive: true,
},
},
select: { dateStart: true },
});
// Tanggal dengan task project se-village (ambil semua task yang overlap dengan bulan ini)
const taskDates = await prisma.projectTask.findMany({
where: {
isActive: true,
dateStart: { lt: new Date(akhirDate) },
dateEnd: { gte: new Date(awalDate) },
Project: {
isActive: true,
idVillage: String(idVillage),
},
},
select: { dateStart: true, dateEnd: true },
});
// Expand setiap task menjadi array tanggal per hari dalam range bulan
const taskExpandedDates: string[] = [];
for (const task of taskDates) {
let cur = moment(task.dateStart);
const end = moment(task.dateEnd);
const monthStart = moment(awalDate);
const monthEnd = moment(akhirDate);
while (cur.isSameOrBefore(end)) {
if (cur.isSameOrAfter(monthStart) && cur.isBefore(monthEnd)) {
taskExpandedDates.push(cur.format("YYYY-MM-DD"));
}
cur.add(1, 'day');
}
}
const calendarResult = _.uniq(calendarDates.map((v) => moment(v.dateStart).format("YYYY-MM-DD"))).sort();
const taskResult = _.uniq(taskExpandedDates).sort();
return NextResponse.json({
success: true,
message: "Berhasil mendapatkan indicator kalender",
data: { calendar: calendarResult, task: taskResult }
}, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan indicator kalender (error: 500)" }, { status: 500 });
}
}

View File

@@ -0,0 +1,122 @@
import { prisma } from "@/module/_global";
import { funGetUserById } from "@/module/auth";
import _ from "lodash";
import moment from "moment";
import "moment/locale/id";
import { NextResponse } from "next/server";
// GET events per tanggal (DivisionCalendarReminder + ProjectTask)
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const user = searchParams.get("user");
const date = searchParams.get("date");
const userMobile = await funGetUserById({ id: String(user) });
if (!userMobile.id || userMobile.id === "null") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const targetDate = new Date(String(date));
const idVillage = userMobile.idVillage;
// Ambil semua event kalender divisi se-village pada tanggal tersebut
const calendarData = await prisma.divisionCalendarReminder.findMany({
where: {
isActive: true,
dateStart: targetDate,
Division: {
idVillage,
isActive: true,
},
DivisionCalendar: {
isActive: true,
},
},
select: {
id: true,
idCalendar: true,
dateStart: true,
dateEnd: true,
timeStart: true,
timeEnd: true,
Division: {
select: {
id: true,
name: true,
},
},
DivisionCalendar: {
select: {
title: true,
desc: true,
},
},
},
orderBy: [{ timeStart: "asc" }, { timeEnd: "asc" }],
});
// Ambil semua task project se-village yang mencakup tanggal tersebut (dateStart <= target <= dateEnd)
const taskData = await prisma.projectTask.findMany({
where: {
isActive: true,
dateStart: { lte: targetDate },
dateEnd: { gte: targetDate },
Project: {
isActive: true,
idVillage: String(idVillage),
},
},
select: {
id: true,
title: true,
desc: true,
dateStart: true,
dateEnd: true,
Project: {
select: {
id: true,
title: true,
},
},
},
orderBy: { dateStart: "asc" },
});
const calendarResult = calendarData.map((v) => ({
id: v.id,
type: "calendar",
title: v.DivisionCalendar.title,
desc: v.DivisionCalendar.desc,
dateStart: moment(v.dateStart).format("YYYY-MM-DD"),
dateEnd: v.dateEnd ? moment(v.dateEnd).format("YYYY-MM-DD") : null,
timeStart: moment.utc(v.timeStart).format("HH:mm"),
timeEnd: moment.utc(v.timeEnd).format("HH:mm"),
divisionName: v.Division.name,
projectName: null,
idDivision: v.Division.id,
idRef: v.Division.id,
}));
const taskResult = taskData.map((v) => ({
id: v.id,
type: "task",
title: v.title,
desc: v.desc ?? "",
dateStart: moment(v.dateStart).format("YYYY-MM-DD"),
dateEnd: moment(v.dateEnd).format("YYYY-MM-DD"),
timeStart: null,
timeEnd: null,
divisionName: null,
projectName: v.Project.title,
idRef: v.Project.id,
}));
const data = [...calendarResult, ...taskResult];
return NextResponse.json({ success: true, message: "Berhasil mendapatkan kalender umum", data }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan kalender umum (error: 500)" }, { status: 500 });
}
}