diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9421ad0..eba8a9d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -113,7 +113,6 @@ model User { Announcement Announcement[] Project Project[] ProjectMember ProjectMember[] - ProjectComment ProjectComment[] UserLog UserLog[] Division Division[] DivisionMember DivisionMember[] @@ -184,24 +183,25 @@ model AnnouncementMember { } model Project { - id String @id @default(cuid()) - Village Village @relation(fields: [idVillage], references: [id]) - idVillage String - Group Group @relation(fields: [idGroup], references: [id]) - idGroup String - title String - status Int @default(0) // 0 = pending, 1 = ongoing, 2 = done, 3 = cancelled - desc String? @db.Text - reason String? @db.Text - isActive Boolean @default(true) - User User @relation(fields: [createdBy], references: [id]) - createdBy String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - ProjectMember ProjectMember[] - ProjectFile ProjectFile[] - ProjectComment ProjectComment[] - ProjectTask ProjectTask[] + id String @id @default(cuid()) + Village Village @relation(fields: [idVillage], references: [id]) + idVillage String + Group Group @relation(fields: [idGroup], references: [id]) + idGroup String + title String + status Int @default(0) // 0 = pending, 1 = ongoing, 2 = done, 3 = cancelled + desc String? @db.Text + reason String? @db.Text + report String? @db.Text + isActive Boolean @default(true) + User User @relation(fields: [createdBy], references: [id]) + createdBy String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + ProjectMember ProjectMember[] + ProjectFile ProjectFile[] + ProjectTask ProjectTask[] + ProjectLink ProjectLink[] } model ProjectMember { @@ -228,33 +228,44 @@ model ProjectFile { updatedAt DateTime @updatedAt } -model ProjectTask { - id String @id @default(cuid()) - Project Project @relation(fields: [idProject], references: [id]) - idProject String - title String - desc String? - status Int @default(0) // 0 = todo, 1 = done - notifikasi Boolean @default(false) - dateStart DateTime @db.Date - dateEnd DateTime @db.Date - isActive Boolean @default(true) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} - -model ProjectComment { +model ProjectLink { id String @id @default(cuid()) Project Project @relation(fields: [idProject], references: [id]) idProject String - User User @relation(fields: [createdBy], references: [id]) - createdBy String - comment String @db.Text + link String @db.Text isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } +model ProjectTask { + id String @id @default(cuid()) + Project Project @relation(fields: [idProject], references: [id]) + idProject String + title String + desc String? + status Int @default(0) // 0 = todo, 1 = done + notifikasi Boolean @default(false) + dateStart DateTime @db.Date + dateEnd DateTime @db.Date + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + ProjectTaskDetail ProjectTaskDetail[] +} + +model ProjectTaskDetail { + id String @id @default(cuid()) + ProjectTask ProjectTask @relation(fields: [idTask], references: [id]) + idTask String + date DateTime @db.Date + timeStart DateTime? @db.Time() + timeEnd DateTime? @db.Time() + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + model Division { id String @id @default(cuid()) Village Village @relation(fields: [idVillage], references: [id]) @@ -280,6 +291,7 @@ model Division { DivisionCalendar DivisionCalendar[] DivisionCalendarReminder DivisionCalendarReminder[] ContainerFileDivision ContainerFileDivision[] + DivisionProjectLink DivisionProjectLink[] } model DivisionMember { @@ -302,6 +314,7 @@ model DivisionProject { title String desc String? @db.Text reason String? @db.Text + report String? @db.Text status Int @default(0) // 0 = pending, 1 = ongoing, 2 = done, 3 = cancelled isActive Boolean @default(true) createdAt DateTime @default(now()) @@ -309,6 +322,19 @@ model DivisionProject { DivisionProjectTask DivisionProjectTask[] DivisionProjectMember DivisionProjectMember[] DivisionProjectFile DivisionProjectFile[] + DivisionProjectLink DivisionProjectLink[] +} + +model DivisionProjectLink { + id String @id @default(cuid()) + Division Division @relation(fields: [idDivision], references: [id]) + idDivision String + DivisionProject DivisionProject @relation(fields: [idProject], references: [id]) + idProject String + link String @db.Text + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model DivisionProjectTask { @@ -326,6 +352,19 @@ model DivisionProjectTask { isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + DivisionProjectTaskDetail DivisionProjectTaskDetail[] +} + +model DivisionProjectTaskDetail { + id String @id @default(cuid()) + DivisionProjectTask DivisionProjectTask @relation(fields: [idTask], references: [id]) + idTask String + date DateTime @db.Date + timeStart DateTime? @db.Time() + timeEnd DateTime? @db.Time() + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model DivisionProjectMember { diff --git a/src/app/(application)/division/[id]/(fitur-division)/task/[detail]/page.tsx b/src/app/(application)/division/[id]/(fitur-division)/task/[detail]/page.tsx index 293102f..f964f3b 100644 --- a/src/app/(application)/division/[id]/(fitur-division)/task/[detail]/page.tsx +++ b/src/app/(application)/division/[id]/(fitur-division)/task/[detail]/page.tsx @@ -1,4 +1,4 @@ -import { NavbarDetailDivisionTask, ProgressDetailTask, ListTugasDetailTask, ListFileDetailTask, ListAnggotaDetailTask } from "@/module/task" +import { ListAnggotaDetailTask, ListFileDetailTask, ListLinkDetailTask, ListReportDetailTask, ListTugasDetailTask, NavbarDetailDivisionTask, ProgressDetailTask } from "@/module/task" import { Box } from "@mantine/core" function Page() { @@ -7,8 +7,10 @@ function Page() { + + diff --git a/src/app/(application)/division/[id]/(fitur-division)/task/[detail]/report/page.tsx b/src/app/(application)/division/[id]/(fitur-division)/task/[detail]/report/page.tsx new file mode 100644 index 0000000..9da9b27 --- /dev/null +++ b/src/app/(application)/division/[id]/(fitur-division)/task/[detail]/report/page.tsx @@ -0,0 +1,8 @@ +import { AddReportTask } from "@/module/task" + +function Page() { + return ( + + ) +} +export default Page diff --git a/src/app/(application)/project/[id]/page.tsx b/src/app/(application)/project/[id]/page.tsx index 26dfc03..715f53a 100644 --- a/src/app/(application)/project/[id]/page.tsx +++ b/src/app/(application)/project/[id]/page.tsx @@ -1,6 +1,5 @@ -import { ListAnggotaDetailProject, ListFileDetailProject, ListTugasDetailProject, NavbarDetailProject, ProgressDetailProject } from '@/module/project'; +import { ListAnggotaDetailProject, ListFileDetailProject, ListLinkDetailProject, ListReportDetailProject, ListTugasDetailProject, NavbarDetailProject, ProgressDetailProject } from '@/module/project'; import { Box } from '@mantine/core'; -import React from 'react'; function Page() { return ( @@ -8,8 +7,10 @@ function Page() { + + diff --git a/src/app/(application)/project/[id]/report/page.tsx b/src/app/(application)/project/[id]/report/page.tsx new file mode 100644 index 0000000..c3b9021 --- /dev/null +++ b/src/app/(application)/project/[id]/report/page.tsx @@ -0,0 +1,9 @@ +import { AddReportProject } from "@/module/project"; + +function Page() { + return ( + + ); +} + +export default Page; diff --git a/src/app/api/mobile/discussion-general/[id]/comment/route.ts b/src/app/api/mobile/discussion-general/[id]/comment/route.ts index da842a6..6df4622 100644 --- a/src/app/api/mobile/discussion-general/[id]/comment/route.ts +++ b/src/app/api/mobile/discussion-general/[id]/comment/route.ts @@ -70,7 +70,9 @@ export async function POST(request: Request, context: { params: { id: string } } } }) - const dataFCM = member.map((v: any) => ({ + const memberFilter = member.filter((v: any) => v.idUser != userMobile.id) + + const dataFCM = memberFilter.map((v: any) => ({ ..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]), tokens: v.User.TokenDeviceUser.map((v: any) => v.token) })) @@ -106,7 +108,7 @@ export async function POST(request: Request, context: { params: { id: string } } token: tokenUnique, title: "Komentar Baru", body: `${userSent?.name}: ${data.comment}`, - data: { id: data.id, category: "discussion", content: id } + data: { id: data.id, category: "discussion-general", content: id } }) // create log user diff --git a/src/app/api/mobile/discussion/[id]/comment/route.ts b/src/app/api/mobile/discussion/[id]/comment/route.ts index 52216af..e1b0fbc 100644 --- a/src/app/api/mobile/discussion/[id]/comment/route.ts +++ b/src/app/api/mobile/discussion/[id]/comment/route.ts @@ -86,7 +86,9 @@ export async function POST(request: Request, context: { params: { id: string } } } }) - const dataFCM = member.map((v: any) => ({ + const memberFilter = member.filter((v: any) => v.idUser != userMobile.id) + + const dataFCM = memberFilter.map((v: any) => ({ ..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]), tokens: v.User.TokenDeviceUser.map((v: any) => v.token) })) @@ -122,7 +124,7 @@ export async function POST(request: Request, context: { params: { id: string } } token: tokenUnique, title: "Komentar Baru", body: `${userSent?.name}: ${comment}`, - data: { id: data.id, category: `division/${dataDivision?.idDivision}/discussion/`, content: id } + data: { id: data.id, category: `division/${dataDivision?.idDivision}/discussion`, content: id } }) // create log user diff --git a/src/app/api/mobile/project/[id]/lainnya/route.ts b/src/app/api/mobile/project/[id]/lainnya/route.ts index d6a8260..48de186 100644 --- a/src/app/api/mobile/project/[id]/lainnya/route.ts +++ b/src/app/api/mobile/project/[id]/lainnya/route.ts @@ -47,4 +47,51 @@ export async function DELETE(request: Request, context: { params: { id: string } console.error(error); return NextResponse.json({ success: false, message: "Gagal menghapus kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); } +} + +// EDIT PROJECT REPORT +export async function PUT(request: Request, context: { params: { id: string } }) { + try { + const { id } = context.params + const { report, user } = await request.json() + + const userMobile = await funGetUserById({ id: String(user) }) + + if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 }); + } + + const data = await prisma.project.count({ + where: { + id: id + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", + }, + { status: 200 } + ); + } + + const dataCreate = await prisma.project.update({ + where: { + id + }, + data: { + report: report + } + }) + + // create log user + const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate laporan kegiatan', table: 'project', data: String(id), user: userMobile.id }) + + return NextResponse.json({ success: true, message: "Laporan kegiatan berhasil diupdate" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mengupdate kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } } \ No newline at end of file diff --git a/src/app/api/mobile/project/[id]/link/route.ts b/src/app/api/mobile/project/[id]/link/route.ts new file mode 100644 index 0000000..c42ffde --- /dev/null +++ b/src/app/api/mobile/project/[id]/link/route.ts @@ -0,0 +1,95 @@ +import { prisma } from "@/module/_global"; +import { funGetUserById } from "@/module/auth"; +import { createLogUserMobile } from "@/module/user"; +import { NextResponse } from "next/server"; + +// ADD LINK PROJECT +export async function POST(request: Request, context: { params: { id: string } }) { + try { + const { id } = context.params + const { link, user } = (await request.json()) + + const userMobile = await funGetUserById({ id: String(user) }) + + if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 }); + } + + const data = await prisma.project.count({ + where: { + id: id + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", + }, + { status: 200 } + ); + } + + + const insertLink = await prisma.projectLink.create({ + data: { + idProject: id, + link: link + } + }) + + // create log user + const log = await createLogUserMobile({ act: 'CREATE', desc: 'User menambah link kegiatan', table: 'projectLink', data: insertLink.id, user: userMobile.id }) + return NextResponse.json({ success: true, message: "Berhasil menambahkan link kegiatan" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menambah link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} + + +// DELETE LINK PROJECT +export async function DELETE(request: Request, context: { params: { id: string } }) { + try { + const { idLink, user } = (await request.json()) + + const userMobile = await funGetUserById({ id: String(user) }) + + if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 }); + } + + const data = await prisma.projectLink.count({ + where: { + id: idLink + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan link, data tidak ditemukan", + }, + { status: 200 } + ); + } + + const deleteLink = await prisma.projectLink.update({ + where: { + id: idLink + }, + data: { + isActive: false + } + }) + + // create log user + const log = await createLogUserMobile({ act: 'DELETE', desc: 'User menghapus link kegiatan', table: 'projectLink', data: String(idLink), user: userMobile.id }) + return NextResponse.json({ success: true, message: "Berhasil menghapus link kegiatan" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menghapus link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} diff --git a/src/app/api/mobile/project/[id]/route.ts b/src/app/api/mobile/project/[id]/route.ts index e261dae..7c09849 100644 --- a/src/app/api/mobile/project/[id]/route.ts +++ b/src/app/api/mobile/project/[id]/route.ts @@ -136,6 +136,18 @@ export async function GET(request: Request, context: { params: { id: string } }) })) allData = fix + } else if (kategori == "link") { + const dataLink = await prisma.projectLink.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + createdAt: 'asc' + } + }) + + allData = dataLink } return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: allData, }, { status: 200 }); @@ -150,7 +162,7 @@ export async function GET(request: Request, context: { params: { id: string } }) export async function POST(request: Request, context: { params: { id: string } }) { try { const { id } = context.params - const { name, dateStart, dateEnd, user } = await request.json() + const { name, dateStart, dateEnd, user, dataDetail } = await request.json() const userMobile = await funGetUserById({ id: String(user) }) @@ -185,6 +197,51 @@ export async function POST(request: Request, context: { params: { id: string } } } }) + if (dataDetail.length > 0) { + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: dataCreate.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + + const dataDetailCreate = await prisma.projectTaskDetail.createMany({ + data: dataDetailFix + }) + } + + // const cek progress + const dataTask = await prisma.projectTask.findMany({ + where: { + isActive: true, + idProject: id, + } + }) + + const semua = dataTask.length + const selesai = dataTask.filter((item) => item.status == 1).length + const prosess = Math.ceil((selesai / semua) * 100) + let statusProject = 1 + + if (prosess == 100) { + statusProject = 2 + } else if (prosess == 0) { + statusProject = 0 + } + + + const update = await prisma.project.update({ + where: { + id: id + }, + data: { + status: statusProject + } + }) + + // create log user const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat data tahapan kegiatan', table: 'projectTask', data: String(dataCreate.id), user: userMobile.id }) diff --git a/src/app/api/mobile/project/detail/[id]/route.ts b/src/app/api/mobile/project/detail/[id]/route.ts index 8a550da..73630a8 100644 --- a/src/app/api/mobile/project/detail/[id]/route.ts +++ b/src/app/api/mobile/project/detail/[id]/route.ts @@ -171,12 +171,14 @@ export async function GET(request: Request, context: { params: { id: string } }) const { id } = context.params; const { searchParams } = new URL(request.url); const user = searchParams.get("user"); + const kategori = searchParams.get("cat"); const userMobile = await funGetUserById({ id: String(user) }) if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 }); } + let dataFix const data = await prisma.projectTask.findUnique({ where: { id: String(id), @@ -195,7 +197,29 @@ export async function GET(request: Request, context: { params: { id: string } }) ); } - return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data: fixData }, { status: 200 }); + if (kategori == "detailTask") { + const dataDetail = await prisma.projectTaskDetail.findMany({ + where: { + idTask: String(id) + }, + orderBy: { + date: "asc" + } + }) + + const dataDetailFix = dataDetail.map((data: any) => ({ + ...data, + date: moment(data?.date).format('DD-MM-YYYY'), + timeStart: data.timeStart == null ? "" : moment.utc(data.timeStart).format("HH:mm"), + timeEnd: data.timeEnd == null ? "" : moment.utc(data.timeEnd).format("HH:mm") + })) + + dataFix = dataDetailFix + } else { + dataFix = fixData + } + + return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data: dataFix }, { status: 200 }); } catch (error) { console.error(error); return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); @@ -207,7 +231,7 @@ export async function GET(request: Request, context: { params: { id: string } }) export async function POST(request: Request, context: { params: { id: string } }) { try { const { id } = context.params; - const { title, dateStart, dateEnd, user } = (await request.json()); + const { title, dateStart, dateEnd, user, dataDetail } = (await request.json()); const userMobile = await funGetUserById({ id: String(user) }) if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { @@ -240,6 +264,26 @@ export async function POST(request: Request, context: { params: { id: string } } } }) + const dataDetailDelete = await prisma.projectTaskDetail.deleteMany({ + where: { + idTask: id + } + }) + + if (dataDetail.length > 0) { + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + const dataDetailCreate = await prisma.projectTaskDetail.createMany({ + data: dataDetailFix + }) + } + // create log user const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate tahapan kegiatan', table: 'projectTask', data: String(id), user: userMobile.id }) diff --git a/src/app/api/mobile/project/route.ts b/src/app/api/mobile/project/route.ts index 1950782..5a2c8a8 100644 --- a/src/app/api/mobile/project/route.ts +++ b/src/app/api/mobile/project/route.ts @@ -179,16 +179,33 @@ export async function POST(request: Request) { if (task.length > 0) { const dataProject = task.map((v: any) => ({ - ..._.omit(v, ["dateStart", "dateEnd", "name", "dateEndFix", "dateStartFix"]), + ..._.omit(v, ["dateStart", "dateEnd", "name", "dateEndFix", "dateStartFix", "dataDetail"]), idProject: data.id, title: v.title, dateStart: new Date(v.dateStartFix), dateEnd: new Date(v.dateEndFix), })) + let dataDetailFix = [] + for (let i = 0; i < dataProject.length; i++) { + const insertTask = await prisma.projectTask.create({ + data: dataProject[i], + select: { + id: true + } + }) + const dataDetail = task[i].dataDetail.map((v: any) => ({ + ...v, + idTask: insertTask.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + dataDetailFix.push(...dataDetail) + } - const insertTask = await prisma.projectTask.createMany({ - data: dataProject + const insertDetail = await prisma.projectTaskDetail.createMany({ + data: dataDetailFix }) } diff --git a/src/app/api/mobile/task/[id]/lainnya/route.ts b/src/app/api/mobile/task/[id]/lainnya/route.ts index 4dc98e5..ef33d75 100644 --- a/src/app/api/mobile/task/[id]/lainnya/route.ts +++ b/src/app/api/mobile/task/[id]/lainnya/route.ts @@ -46,4 +46,51 @@ export async function DELETE(request: Request, context: { params: { id: string } console.error(error); return NextResponse.json({ success: false, message: "Gagal menghapus tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); } +} + +// EDIT TASK REPORT +export async function PUT(request: Request, context: { params: { id: string } }) { + try { + const { id } = context.params + const { report, user } = await request.json() + + const userMobile = await funGetUserById({ id: String(user) }) + if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 }); + } + + + const data = await prisma.divisionProject.count({ + where: { + id: id + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", + }, + { status: 200 } + ); + } + + const dataCreate = await prisma.divisionProject.update({ + where: { + id + }, + data: { + report: report + } + }) + + // create log user + const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate laporan tugas divisi', table: 'divisionProject', data: String(id), user: userMobile.id }) + + return NextResponse.json({ success: true, message: "Laporan tugas divisi berhasil diupdate" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mengupdate laporan tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } } \ No newline at end of file diff --git a/src/app/api/mobile/task/[id]/link/route.ts b/src/app/api/mobile/task/[id]/link/route.ts new file mode 100644 index 0000000..067394a --- /dev/null +++ b/src/app/api/mobile/task/[id]/link/route.ts @@ -0,0 +1,98 @@ +import { prisma } from "@/module/_global"; +import { funGetUserById } from "@/module/auth"; +import { createLogUserMobile } from "@/module/user"; +import { NextResponse } from "next/server"; + +// ADD LINK TASK DIVISI +export async function POST(request: Request, context: { params: { id: string } }) { + try { + const { id } = context.params; + const { link, idDivision, user } = (await request.json()); + + const userMobile = await funGetUserById({ id: String(user) }) + if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 }); + } + + const data = await prisma.divisionProject.count({ + where: { + id: id, + }, + }); + + if (data == 0) { + return NextResponse.json( + { + success: false, + message: "Tambah link tugas gagal, data tugas tidak ditemukan", + }, + { status: 200 } + ); + } + + + + const insertlink = await prisma.divisionProjectLink.create({ + data: { + idProject: id, + link, + idDivision, + } + }) + + + // create log user + const log = await createLogUserMobile({ act: 'CREATE', desc: 'User menambahkan link tugas divisi', table: 'divisionProjectLink', data: insertlink.id, user: userMobile.id }) + + + return NextResponse.json({ success: true, message: "Berhasil menambahkan link tugas", }, { status: 200 }); + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menambah link tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} + + +// DELETE LINK TASK DIVISI +export async function DELETE(request: Request, context: { params: { id: string } }) { + try { + const { idLink, user } = (await request.json()) + + const userMobile = await funGetUserById({ id: String(user) }) + if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 }); + } + + const data = await prisma.divisionProjectLink.count({ + where: { + id: idLink + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan link, data tidak ditemukan", + }, + { status: 200 } + ); + } + + const deleteLink = await prisma.divisionProjectLink.update({ + where: { + id: idLink + }, + data: { + isActive: false + } + }) + + // create log user + const log = await createLogUserMobile({ act: 'DELETE', desc: 'User menghapus link tugas divisi', table: 'divisionProjectLink', data: String(idLink), user: userMobile.id }) + return NextResponse.json({ success: true, message: "Berhasil menghapus link tugas divisi" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menghapus link tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/mobile/task/[id]/route.ts b/src/app/api/mobile/task/[id]/route.ts index 8328320..a7260f0 100644 --- a/src/app/api/mobile/task/[id]/route.ts +++ b/src/app/api/mobile/task/[id]/route.ts @@ -151,6 +151,18 @@ export async function GET(request: Request, context: { params: { id: string } }) })) allData = fix + } else if (kategori == "link") { + const dataLink = await prisma.divisionProjectLink.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + createdAt: 'asc' + } + }) + + allData = dataLink } return NextResponse.json({ success: true, message: "Berhasil mendapatkan tugas divisi", data: allData }, { status: 200 }); @@ -167,7 +179,7 @@ export async function GET(request: Request, context: { params: { id: string } }) export async function POST(request: Request, context: { params: { id: string } }) { try { const { id } = context.params; - const { title, dateStart, dateEnd, idDivision, user } = (await request.json()); + const { title, dateStart, dateEnd, idDivision, user, dataDetail } = (await request.json()); const userMobile = await funGetUserById({ id: String(user) }) if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { @@ -203,6 +215,20 @@ export async function POST(request: Request, context: { params: { id: string } } } }); + if (dataDetail.length > 0) { + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: create.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({ + data: dataDetailFix + }) + } + // const cek progress const dataTask = await prisma.divisionProjectTask.findMany({ where: { diff --git a/src/app/api/mobile/task/detail/[id]/route.ts b/src/app/api/mobile/task/detail/[id]/route.ts index cc53e39..e5c1423 100644 --- a/src/app/api/mobile/task/detail/[id]/route.ts +++ b/src/app/api/mobile/task/detail/[id]/route.ts @@ -2,6 +2,7 @@ import { prisma } from "@/module/_global"; import { funGetUserById } from "@/module/auth"; import { createLogUserMobile } from "@/module/user"; import _ from "lodash"; +import moment from "moment"; import { NextResponse } from "next/server"; @@ -166,6 +167,7 @@ export async function GET(request: Request, context: { params: { id: string } }) const { id } = context.params; const { searchParams } = new URL(request.url); const user = searchParams.get("user"); + const kategori = searchParams.get("cat"); const userMobile = await funGetUserById({ id: String(user) }) if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { @@ -183,7 +185,30 @@ export async function GET(request: Request, context: { params: { id: string } }) return NextResponse.json({ success: false, message: "Gagal mendapatkan detail tugas, data tidak ditemukan" }, { status: 200 }); } - return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data }, { status: 200 }); + let dataFix + if (kategori == "detailTask") { + const dataDetail = await prisma.divisionProjectTaskDetail.findMany({ + where: { + idTask: String(id) + }, + orderBy: { + date: "asc" + } + }) + + const dataDetailFix = dataDetail.map((data: any) => ({ + ...data, + date: moment(data?.date).format('DD-MM-YYYY'), + timeStart: data.timeStart == null ? "" : moment.utc(data.timeStart).format("HH:mm"), + timeEnd: data.timeEnd == null ? "" : moment.utc(data.timeEnd).format("HH:mm") + })) + + dataFix = dataDetailFix + } else { + dataFix = data + } + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data: dataFix }, { status: 200 }); } catch (error) { @@ -198,7 +223,7 @@ export async function GET(request: Request, context: { params: { id: string } }) export async function POST(request: Request, context: { params: { id: string } }) { try { const { id } = context.params; - const { title, dateStart, dateEnd, user } = (await request.json()); + const { title, dateStart, dateEnd, user, dataDetail } = (await request.json()); const userMobile = await funGetUserById({ id: String(user) }) if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") { @@ -232,6 +257,26 @@ export async function POST(request: Request, context: { params: { id: string } } }, }); + const dataDetailDelete = await prisma.divisionProjectTaskDetail.deleteMany({ + where: { + idTask: id + } + }) + + if (dataDetail.length > 0) { + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({ + data: dataDetailFix + }) + } + // create log user const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate data detail task divisi', table: 'divisionProjectTask', data: id, user: userMobile.id }) diff --git a/src/app/api/mobile/task/route.ts b/src/app/api/mobile/task/route.ts index ebaf027..479f4ea 100644 --- a/src/app/api/mobile/task/route.ts +++ b/src/app/api/mobile/task/route.ts @@ -142,7 +142,7 @@ export async function POST(request: Request) { if (task.length > 0) { const dataTask = task.map((v: any) => ({ - ..._.omit(v, ["dateStart", "dateEnd", "title", "dateStartFix", "dateEndFix"]), + ..._.omit(v, ["dateStart", "dateEnd", "title", "dateStartFix", "dateEndFix", "dataDetail"]), idDivision: idDivision, idProject: data.id, title: v.title, @@ -150,9 +150,26 @@ export async function POST(request: Request) { dateEnd: new Date(v.dateEndFix), })) + let dataDetailFix = [] + for (let i = 0; i < dataTask.length; i++) { + const insertTask = await prisma.divisionProjectTask.create({ + data: dataTask[i], + select: { + id: true + } + }) + const dataDetail = task[i].dataDetail.map((v: any) => ({ + ...v, + idTask: insertTask.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + dataDetailFix.push(...dataDetail) + } - const insertTask = await prisma.divisionProjectTask.createMany({ - data: dataTask + const insertDetail = await prisma.divisionProjectTaskDetail.createMany({ + data: dataDetailFix }) } @@ -350,7 +367,7 @@ export async function POST(request: Request) { token: tokenUnique, title: "Tugas Baru", body: "Anda memiliki tugas baru. Silahkan periksa detailnya.", - data: { id: data.id, category:'division/' + idDivision + '/task', content: data.id } + data: { id: data.id, category: 'division/' + idDivision + '/task', content: data.id } }) // create log user diff --git a/src/app/api/project/[id]/lainnya/route.ts b/src/app/api/project/[id]/lainnya/route.ts index bf3f042..1e28df9 100644 --- a/src/app/api/project/[id]/lainnya/route.ts +++ b/src/app/api/project/[id]/lainnya/route.ts @@ -45,4 +45,50 @@ export async function DELETE(request: Request, context: { params: { id: string } console.error(error); return NextResponse.json({ success: false, message: "Gagal menghapus kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); } +} + +// EDIT PROJECT REPORT +export async function PUT(request: Request, context: { params: { id: string } }) { + try { + const user = await funGetUserByCookies() + if (user.id == undefined) { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); + } + + const { id } = context.params + const { report } = await request.json() + + const data = await prisma.project.count({ + where: { + id: id + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", + }, + { status: 404 } + ); + } + + const dataCreate = await prisma.project.update({ + where: { + id + }, + data: { + report: report + } + }) + + // create log user + const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate laporan kegiatan', table: 'project', data: String(id) }) + + return NextResponse.json({ success: true, message: "Laporan kegiatan berhasil diupdate" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mengupdate kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } } \ No newline at end of file diff --git a/src/app/api/project/[id]/link/route.ts b/src/app/api/project/[id]/link/route.ts new file mode 100644 index 0000000..eb642e4 --- /dev/null +++ b/src/app/api/project/[id]/link/route.ts @@ -0,0 +1,93 @@ +import { prisma } from "@/module/_global"; +import { funGetUserByCookies } from "@/module/auth"; +import { createLogUser } from "@/module/user"; +import { NextResponse } from "next/server"; + +// ADD LINK PROJECT +export async function POST(request: Request, context: { params: { id: string } }) { + try { + const user = await funGetUserByCookies() + if (user.id == undefined) { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); + } + + const { id } = context.params + const { link } = (await request.json()) + + const data = await prisma.project.count({ + where: { + id: id + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", + }, + { status: 404 } + ); + } + + + const insertLink = await prisma.projectLink.create({ + data: { + idProject: id, + link: link + } + }) + + // create log user + const log = await createLogUser({ act: 'CREATE', desc: 'User menambah link kegiatan', table: 'projectLink', data: insertLink.id }) + return NextResponse.json({ success: true, message: "Berhasil menambahkan link kegiatan" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menambah link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} + + +// DELETE LINK PROJECT +export async function DELETE(request: Request, context: { params: { id: string } }) { + try { + const user = await funGetUserByCookies() + if (user.id == undefined) { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); + } + + const { idLink } = (await request.json()) + + const data = await prisma.projectLink.count({ + where: { + id: idLink + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan link, data tidak ditemukan", + }, + { status: 404 } + ); + } + + const deleteLink = await prisma.projectLink.update({ + where: { + id: idLink + }, + data: { + isActive: false + } + }) + + // create log user + const log = await createLogUser({ act: 'DELETE', desc: 'User menghapus link kegiatan', table: 'projectLink', data: String(idLink) }) + return NextResponse.json({ success: true, message: "Berhasil menghapus link kegiatan" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menghapus link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} diff --git a/src/app/api/project/[id]/route.ts b/src/app/api/project/[id]/route.ts index 19bc836..df7e87f 100644 --- a/src/app/api/project/[id]/route.ts +++ b/src/app/api/project/[id]/route.ts @@ -133,6 +133,17 @@ export async function GET(request: Request, context: { params: { id: string } }) })) allData = fix + } else if (kategori == "link") { + const dataLink = await prisma.projectLink.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + createdAt: 'asc' + } + }) + allData = dataLink } return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: allData, }, { status: 200 }); @@ -152,7 +163,7 @@ export async function POST(request: Request, context: { params: { id: string } } } const { id } = context.params - const { name, dateStart, dateEnd, } = await request.json() + const { name, dateStart, dateEnd, dataDetail } = await request.json() const data = await prisma.project.count({ where: { @@ -181,6 +192,50 @@ export async function POST(request: Request, context: { params: { id: string } } } }) + if (dataDetail.length > 0) { + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: dataCreate.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + const dataDetailCreate = await prisma.projectTaskDetail.createMany({ + data: dataDetailFix + }) + } + + // const cek progress + const dataTask = await prisma.projectTask.findMany({ + where: { + isActive: true, + idProject: id, + } + }) + + const semua = dataTask.length + const selesai = dataTask.filter((item) => item.status == 1).length + const prosess = Math.ceil((selesai / semua) * 100) + let statusProject = 1 + + if (prosess == 100) { + statusProject = 2 + } else if (prosess == 0) { + statusProject = 0 + } + + + const update = await prisma.project.update({ + where: { + id: id + }, + data: { + status: statusProject + } + }) + + // create log user const log = await createLogUser({ act: 'CREATE', desc: 'User membuat data tahapan kegiatan', table: 'projectTask', data: String(dataCreate.id) }) diff --git a/src/app/api/project/detail/[id]/route.ts b/src/app/api/project/detail/[id]/route.ts index abd5571..d29ed5e 100644 --- a/src/app/api/project/detail/[id]/route.ts +++ b/src/app/api/project/detail/[id]/route.ts @@ -1,6 +1,7 @@ import { prisma } from "@/module/_global"; import { funGetUserByCookies } from "@/module/auth"; import { createLogUser } from "@/module/user"; +import moment from "moment"; import { NextResponse } from "next/server"; @@ -171,7 +172,11 @@ export async function GET(request: Request, context: { params: { id: string } }) return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); } + const { searchParams } = new URL(request.url); + const kategori = searchParams.get("cat"); const { id } = context.params; + + let dataFix const data = await prisma.projectTask.findUnique({ where: { id: String(id), @@ -188,7 +193,28 @@ export async function GET(request: Request, context: { params: { id: string } }) ); } - return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data }, { status: 200 }); + if (kategori == "detailTask") { + const dataDetail = await prisma.projectTaskDetail.findMany({ + where: { + idTask: String(id) + }, + orderBy: { + date: "asc" + } + }) + + const dataDetailFix = dataDetail.map((data: any) => ({ + ...data, + timeStart: moment.utc(data.timeStart).format("HH:mm"), + timeEnd: moment.utc(data.timeEnd).format("HH:mm") + })) + + dataFix = dataDetailFix + } else { + dataFix = data + } + + return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data: dataFix }, { status: 200 }); } catch (error) { console.error(error); return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); @@ -205,17 +231,17 @@ export async function POST(request: Request, context: { params: { id: string } } } const { id } = context.params; - const { title, dateStart, dateEnd } = (await request.json()); + const { title, dateStart, dateEnd, dataDetail } = (await request.json()); - const dataTask = await prisma.projectTask.count({ + const dataTaskLama = await prisma.projectTask.findUnique({ where: { id } }) - if (dataTask == 0) { + if (dataTaskLama?.title == undefined) { return NextResponse.json( { success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", @@ -235,6 +261,26 @@ export async function POST(request: Request, context: { params: { id: string } } } }) + const dataDetailDelete = await prisma.projectTaskDetail.deleteMany({ + where: { + idTask: id + } + }) + + if (dataDetail.length > 0) { + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + const dataDetailCreate = await prisma.projectTaskDetail.createMany({ + data: dataDetailFix + }) + } + // create log user const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate tahapan kegiatan', table: 'projectTask', data: String(id) }) diff --git a/src/app/api/project/route.ts b/src/app/api/project/route.ts index ee2a96b..d4e6652 100644 --- a/src/app/api/project/route.ts +++ b/src/app/api/project/route.ts @@ -169,15 +169,34 @@ export async function POST(request: Request) { if (task.length > 0) { const dataProject = task.map((v: any) => ({ - ..._.omit(v, ["dateStart", "dateEnd", "name"]), + ..._.omit(v, ["dateStart", "dateEnd", "name", "dataDetail"]), idProject: data.id, title: v.title, dateStart: new Date(v.dateStart), dateEnd: new Date(v.dateEnd), })) - const insertTask = await prisma.projectTask.createMany({ - data: dataProject + let dataDetailFix = [] + + for (let i = 0; i < dataProject.length; i++) { + const insertTask = await prisma.projectTask.create({ + data: dataProject[i], + select:{ + id: true + } + }) + const dataDetail = task[i].dataDetail.map((v: any) => ({ + ...v, + idTask: insertTask.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + dataDetailFix.push(...dataDetail) + } + + const insertDetail = await prisma.projectTaskDetail.createMany({ + data: dataDetailFix }) } diff --git a/src/app/api/task/[id]/lainnya/route.ts b/src/app/api/task/[id]/lainnya/route.ts index cc67eeb..585a0ac 100644 --- a/src/app/api/task/[id]/lainnya/route.ts +++ b/src/app/api/task/[id]/lainnya/route.ts @@ -45,4 +45,52 @@ export async function DELETE(request: Request, context: { params: { id: string } console.error(error); return NextResponse.json({ success: false, message: "Gagal menghapus tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); } +} + + +// EDIT TASK REPORT +export async function PUT(request: Request, context: { params: { id: string } }) { + try { + const user = await funGetUserByCookies() + if (user.id == undefined) { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); + } + + const { id } = context.params + const { report } = await request.json() + + + const data = await prisma.divisionProject.count({ + where: { + id: id + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", + }, + { status: 404 } + ); + } + + const dataCreate = await prisma.divisionProject.update({ + where: { + id + }, + data: { + report: report + } + }) + + // create log user + const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate laporan tugas divisi', table: 'divisionProject', data: String(id) }) + + return NextResponse.json({ success: true, message: "Laporan tugas divisi berhasil diupdate" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mengupdate laporan tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } } \ No newline at end of file diff --git a/src/app/api/task/[id]/link/route.ts b/src/app/api/task/[id]/link/route.ts new file mode 100644 index 0000000..25b927b --- /dev/null +++ b/src/app/api/task/[id]/link/route.ts @@ -0,0 +1,98 @@ +import { prisma } from "@/module/_global"; +import { funGetUserByCookies } from "@/module/auth"; +import { createLogUser } from "@/module/user"; +import { NextResponse } from "next/server"; + +// ADD LINK TASK DIVISI +export async function POST(request: Request, context: { params: { id: string } }) { + try { + const user = await funGetUserByCookies() + if (user.id == undefined) { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); + } + + const { id } = context.params; + const { link, idDivision } = (await request.json()); + + const data = await prisma.divisionProject.count({ + where: { + id: id, + }, + }); + + if (data == 0) { + return NextResponse.json( + { + success: false, + message: "Tambah link tugas gagal, data tugas tidak ditemukan", + }, + { status: 404 } + ); + } + + + + const insertlink = await prisma.divisionProjectLink.create({ + data: { + idProject: id, + link, + idDivision, + } + }) + + + // create log user + const log = await createLogUser({ act: 'CREATE', desc: 'User menambahkan link tugas divisi', table: 'divisionProjectLink', data: insertlink.id }) + + + return NextResponse.json({ success: true, message: "Berhasil menambahkan link tugas", }, { status: 200 }); + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menambah link tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} + + +// DELETE LINK TASK DIVISI +export async function DELETE(request: Request, context: { params: { id: string } }) { + try { + const user = await funGetUserByCookies() + if (user.id == undefined) { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); + } + + const { idLink } = (await request.json()) + + const data = await prisma.divisionProjectLink.count({ + where: { + id: idLink + } + }) + + if (data == 0) { + return NextResponse.json( + { + success: false, message: "Gagal mendapatkan link, data tidak ditemukan", + }, + { status: 404 } + ); + } + + const deleteLink = await prisma.divisionProjectLink.update({ + where: { + id: idLink + }, + data: { + isActive: false + } + }) + + // create log user + const log = await createLogUser({ act: 'DELETE', desc: 'User menghapus link tugas divisi', table: 'divisionProjectLink', data: String(idLink) }) + return NextResponse.json({ success: true, message: "Berhasil menghapus link tugas divisi" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menghapus link tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/task/[id]/route.ts b/src/app/api/task/[id]/route.ts index 07e9dc2..7ef6090 100644 --- a/src/app/api/task/[id]/route.ts +++ b/src/app/api/task/[id]/route.ts @@ -150,6 +150,18 @@ export async function GET(request: Request, context: { params: { id: string } }) })) allData = fix + } else if (kategori == "link") { + const dataLink = await prisma.divisionProjectLink.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + createdAt: 'asc' + } + }) + + allData = dataLink } return NextResponse.json({ success: true, message: "Berhasil mendapatkan tugas divisi", data: allData }, { status: 200 }); @@ -171,7 +183,8 @@ export async function POST(request: Request, context: { params: { id: string } } } const { id } = context.params; - const { title, dateStart, dateEnd, idDivision } = (await request.json()); + const { title, dateStart, dateEnd, idDivision, dataDetail } = (await request.json()); + const data = await prisma.divisionProject.count({ where: { id: id, @@ -201,6 +214,20 @@ export async function POST(request: Request, context: { params: { id: string } } } }); + if(dataDetail.length>0){ + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: create.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({ + data: dataDetailFix + }) + } + // const cek progress const dataTask = await prisma.divisionProjectTask.findMany({ where: { diff --git a/src/app/api/task/detail/[id]/route.ts b/src/app/api/task/detail/[id]/route.ts index ddaa1f0..7a55930 100644 --- a/src/app/api/task/detail/[id]/route.ts +++ b/src/app/api/task/detail/[id]/route.ts @@ -2,6 +2,7 @@ import { prisma } from "@/module/_global"; import { funGetUserByCookies } from "@/module/auth"; import { createLogUser } from "@/module/user"; import _ from "lodash"; +import moment from "moment"; import { NextResponse } from "next/server"; @@ -155,12 +156,15 @@ export async function PUT(request: Request, context: { params: { id: string } }) export async function GET(request: Request, context: { params: { id: string } }) { try { const { id } = context.params; + const { searchParams } = new URL(request.url); + const kategori = searchParams.get("cat"); const user = await funGetUserByCookies() if (user.id == undefined) { return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); } + let dataFix const data = await prisma.divisionProjectTask.findUnique({ where: { id: String(id), @@ -172,7 +176,28 @@ export async function GET(request: Request, context: { params: { id: string } }) return NextResponse.json({ success: false, message: "Gagal mendapatkan detail tugas, data tidak ditemukan", }, { status: 404 }); } - return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data }, { status: 200 }); + if (kategori == "detailTask") { + const dataDetail = await prisma.divisionProjectTaskDetail.findMany({ + where: { + idTask: String(id) + }, + orderBy: { + date: "asc" + } + }) + + const dataDetailFix = dataDetail.map((data: any) => ({ + ...data, + timeStart: moment.utc(data.timeStart).format("HH:mm"), + timeEnd: moment.utc(data.timeEnd).format("HH:mm") + })) + + dataFix = dataDetailFix + } else { + dataFix = data + } + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data: dataFix }, { status: 200 }); } catch (error) { @@ -192,7 +217,7 @@ export async function POST(request: Request, context: { params: { id: string } } } const { id } = context.params; - const { title, dateStart, dateEnd } = (await request.json()); + const { title, dateStart, dateEnd, dataDetail } = (await request.json()); const data = await prisma.divisionProjectTask.count({ where: { id: id, @@ -220,6 +245,26 @@ export async function POST(request: Request, context: { params: { id: string } } }, }); + const dataDetailDelete = await prisma.divisionProjectTaskDetail.deleteMany({ + where: { + idTask: id + } + }) + + if (dataDetail.length > 0) { + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + idTask: id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + + const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({ + data: dataDetailFix + }) + } + // create log user const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate data detail task divisi', table: 'divisionProjectTask', data: id }) diff --git a/src/app/api/task/route.ts b/src/app/api/task/route.ts index b55940e..976b941 100644 --- a/src/app/api/task/route.ts +++ b/src/app/api/task/route.ts @@ -140,7 +140,7 @@ export async function POST(request: Request) { if (task.length > 0) { const dataTask = task.map((v: any) => ({ - ..._.omit(v, ["dateStart", "dateEnd", "title"]), + ..._.omit(v, ["dateStart", "dateEnd", "title", "dataDetail"]), idDivision: idDivision, idProject: data.id, title: v.title, @@ -148,8 +148,26 @@ export async function POST(request: Request) { dateEnd: new Date(v.dateEnd), })) - const insertTask = await prisma.divisionProjectTask.createMany({ - data: dataTask + let dataDetailFix = [] + for (let i = 0; i < dataTask.length; i++) { + const insertTask = await prisma.divisionProjectTask.create({ + data: dataTask[i], + select: { + id: true + } + }) + const dataDetail = task[i].dataDetail.map((v: any) => ({ + ...v, + idTask: insertTask.id, + date: new Date(v.date), + timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(), + timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(), + })) + dataDetailFix.push(...dataDetail) + } + + const insertDetail = await prisma.divisionProjectTaskDetail.createMany({ + data: dataDetailFix }) } diff --git a/src/app/api/version-app/route.ts b/src/app/api/version-app/route.ts index b3eae59..f14e0ef 100644 --- a/src/app/api/version-app/route.ts +++ b/src/app/api/version-app/route.ts @@ -2,7 +2,7 @@ import { NextResponse } from "next/server"; export async function GET(request: Request) { try { - return NextResponse.json({ success: true, version: "1.5.8", tahap: "beta", update: "-update notif komen diskusi" }, { status: 200 }); + return NextResponse.json({ success: true, version: "1.7.0", tahap: "beta", update: "-api mobile; -tambah laporan pada project dan tugas divisi; -tambah upload link pada project dan tugas divisi; -tambah detail tanggal dan jam pada project dan tugas divisi" }, { status: 200 }); } catch (error) { console.error(error); return NextResponse.json({ success: false, version: "Gagal mendapatkan version, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); diff --git a/src/lib/getDatesInRange.ts b/src/lib/getDatesInRange.ts new file mode 100644 index 0000000..c706968 --- /dev/null +++ b/src/lib/getDatesInRange.ts @@ -0,0 +1,9 @@ +export function getDatesInRange(startDate: Date, endDate: Date) { + const dates = []; + const currentDate = new Date(startDate); + while (currentDate <= endDate) { + dates.push(new Date(currentDate)); + currentDate.setDate(currentDate.getDate() + 1); + } + return dates; +} \ No newline at end of file diff --git a/src/lib/urlCompleted.ts b/src/lib/urlCompleted.ts new file mode 100644 index 0000000..2af7aad --- /dev/null +++ b/src/lib/urlCompleted.ts @@ -0,0 +1,7 @@ +export function urlCompleted(url: string) { + if (url.startsWith("http://") || url.startsWith("https://")) { + return url + } else { + return `https://${url}` + } +} \ No newline at end of file diff --git a/src/module/project/index.ts b/src/module/project/index.ts index 1c33e04..35107a1 100644 --- a/src/module/project/index.ts +++ b/src/module/project/index.ts @@ -5,7 +5,6 @@ import NavbarDetailProject from "./ui/navbar_detail_project"; import ProgressDetailProject from "./ui/progress_detail_project"; import ListTugasDetailProject from "./ui/list_tugas_detail_project"; import ListFileDetailProject from "./ui/list_file_detail_project"; -import LiatAnggotaDetailProject from "./ui/list_anggota_detail_project"; import EditTaskProject from "./ui/edit_task_project"; import EditDetailTaskProject from "./ui/edit_detail_task_project"; import ListAnggotaDetailProject from "./ui/list_anggota_detail_project"; @@ -15,6 +14,9 @@ import AddMemberDetailProject from "./ui/add_member_detail_project"; import CreateProject from "./ui/create_project"; import AddFileDetailProject from "./ui/add_file_detail_project"; import WrapLayoutProject from "./ui/wrap_project"; +import ListLinkDetailProject from "./ui/list_link_detail_project"; +import AddReportProject from "./ui/add_report_project"; +import ListReportDetailProject from "./ui/list_report_project"; export { ViewDateEndTask } export { CreateUsersProject } @@ -31,4 +33,7 @@ export { CancelProject } export { AddMemberDetailProject } export { CreateProject } export { AddFileDetailProject } -export { WrapLayoutProject } \ No newline at end of file +export { WrapLayoutProject } +export { ListLinkDetailProject } +export { AddReportProject } +export { ListReportDetailProject } \ No newline at end of file diff --git a/src/module/project/lib/api_project.ts b/src/module/project/lib/api_project.ts index 255faae..d4dc5cc 100644 --- a/src/module/project/lib/api_project.ts +++ b/src/module/project/lib/api_project.ts @@ -1,4 +1,4 @@ -import { IFormAddDetailproject, IFormAddMemberProject, IFormDateProject, NewIFormDateProject } from "./type_project"; +import { IFormAddDetailproject, IFormAddMemberProject, NewIFormDateProject } from "./type_project"; export const funGetAllProject = async (path?: string) => { @@ -49,8 +49,8 @@ export const funUpdateStatusProject = async (path: string, data: { status: numbe } -export const funGetDetailProject = async (path: string) => { - const response = await fetch(`/api/project/detail/${path}`); +export const funGetDetailProject = async (path: string, kat?: string) => { + const response = await fetch(`/api/project/detail/${path}${(kat) ? `?cat=${kat}` : ''}`); return await response.json().catch(() => null); } @@ -122,6 +122,17 @@ export const funEditProject = async (path: string, data: { name: string }) => { return await response.json().catch(() => null); } +export const funEditReportProject = async (path: string, data: { report: string }) => { + const response = await fetch(`/api/project/${path}/lainnya`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + return await response.json().catch(() => null); +} + export const funDeleteFileProject = async (path: string) => { const response = await fetch(`/api/project/file/${path}`, { @@ -149,6 +160,17 @@ export const funAddFileProject = async (path: string, data: FormData) => { return await response.json().catch(() => null); }; +export const funDeleteLinkProject = async (path: string, data: { idLink: string }) => { + const response = await fetch(`/api/project/${path}/link`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + return await response.json().catch(() => null); +}; + export const funDeleteProject = async (path: string) => { const response = await fetch(`/api/project/${path}/lainnya`, { method: "DELETE", @@ -159,3 +181,14 @@ export const funDeleteProject = async (path: string) => { return await response.json().catch(() => null); }; + +export const funAddLinkProject = async (path: string, data: { link: string }) => { + const response = await fetch(`/api/project/${path}/link`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + return await response.json().catch(() => null); +} diff --git a/src/module/project/lib/type_project.ts b/src/module/project/lib/type_project.ts index 8c1bb4c..8adb847 100644 --- a/src/module/project/lib/type_project.ts +++ b/src/module/project/lib/type_project.ts @@ -20,7 +20,13 @@ export interface IDataFileProject { id: string name: string extension: string - idStorage:string + idStorage: string +} + + +export interface IDataLinkProject { + id: string + link: string } export interface IDataMemberProject { @@ -46,10 +52,11 @@ export interface IFormDateProject { title: string, } -export interface NewIFormDateProject{ +export interface NewIFormDateProject { dateStart: string, dateEnd: string, title: string, + dataDetail: any[] } export interface IFormMemberProject { @@ -62,7 +69,8 @@ export interface IFormMemberProject { export interface IFormAddDetailproject { dateStart: string, dateEnd: string, - name: string + name: string, + dataDetail: any[] } diff --git a/src/module/project/ui/add_detail_task_project.tsx b/src/module/project/ui/add_detail_task_project.tsx index abc9bce..1dbc9f0 100644 --- a/src/module/project/ui/add_detail_task_project.tsx +++ b/src/module/project/ui/add_detail_task_project.tsx @@ -1,4 +1,5 @@ "use client" +import { getDatesInRange } from '@/lib/getDatesInRange'; import { keyWibu, LayoutNavbarNew, TEMA } from '@/module/_global'; import LayoutModal from '@/module/_global/layout/layout_modal'; import { useHookstate } from '@hookstate/core'; @@ -11,6 +12,7 @@ import { useState } from 'react'; import toast from 'react-hot-toast'; import { useWibuRealtime } from 'wibu-realtime'; import { funCreateDetailProject } from '../lib/api_project'; +import { ModalAddDetailTaskProject } from './modal_add_detail_task_project'; export default function AddDetailTaskProject() { const [value, setValue] = useState<[Date | null, Date | null]>([null, null]); @@ -21,6 +23,8 @@ export default function AddDetailTaskProject() { const param = useParams<{ id: string }>() const tema = useHookstate(TEMA) const [acuan, setAcuan] = useState(false) + const [openModalDetailTask, setOpenModalDetailTask] = useState(false) + const [dataDetail, setDataDetail] = useState([]) const [touched, setTouched] = useState({ title: false, date: false @@ -33,10 +37,16 @@ export default function AddDetailTaskProject() { async function onSubmit() { try { setLoadingModal(true) + const dataDetailFix = dataDetail.map((v: any) => ({ + ...v, + date: moment(v.date).format("YYYY-MM-DD"), + })) + const res = await funCreateDetailProject(param.id, { name, dateStart: (value[0] != null) ? moment(value[0]).format('YYYY-MM-DD') : moment(new Date).format('YYYY-MM-DD'), dateEnd: (value[1] != null) ? moment(value[1]).format('YYYY-MM-DD') : moment(new Date).format('YYYY-MM-DD'), + dataDetail: dataDetailFix }) if (res.success) { @@ -94,8 +104,15 @@ export default function AddDetailTaskProject() { const array = val.split(",") if (array[0] == '' || array[1] == '') { setTouched({ ...touched, date: true }) + setDataDetail([]) } else { setTouched({ ...touched, date: false }) + const datanya = getDatesInRange(value[0]!, value[1]!) + setDataDetail(datanya.map((data: any) => ({ + date: data, + timeStart: null, + timeEnd: null + }))) } } } @@ -119,7 +136,6 @@ export default function AddDetailTaskProject() { style={{ borderRadius: 10, border: `1px solid ${"#D6D8F6"}` }} > Tanggal Tidak Boleh Kosong : <> } + + setOpenModalDetailTask(false)} + data={dataDetail} + onSubmit={(data) => { + setDataDetail(data) + setOpenModalDetailTask(false) + }} + /> setOpenModal(false)} description="Apakah Anda yakin ingin menambahkan tugas?" diff --git a/src/module/project/ui/add_report_project.tsx b/src/module/project/ui/add_report_project.tsx new file mode 100644 index 0000000..593e4b0 --- /dev/null +++ b/src/module/project/ui/add_report_project.tsx @@ -0,0 +1,157 @@ +"use client" +import { keyWibu, LayoutNavbarNew, TEMA } from '@/module/_global'; +import LayoutModal from '@/module/_global/layout/layout_modal'; +import { useHookstate } from '@hookstate/core'; +import { Box, Button, rem, Skeleton, Stack, Textarea } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { useParams, useRouter } from 'next/navigation'; +import { useState } from 'react'; +import toast from 'react-hot-toast'; +import { useWibuRealtime } from 'wibu-realtime'; +import { funEditReportProject, funGetOneProjectById } from '../lib/api_project'; + +export default function AddReportProject() { + const router = useRouter() + const [report, setReport] = useState("") + const [openModal, setOpenModal] = useState(false) + const param = useParams<{ id: string }>() + const [loading, setLoading] = useState(true) + const [loadingSubmit, setLoadingSubmit] = useState(false) + const tema = useHookstate(TEMA) + const [touched, setTouched] = useState({ + report: false, + }); + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) + + async function onSubmit() { + try { + setLoadingSubmit(true) + const res = await funEditReportProject(param.id, { report }) + if (res.success) { + setDataRealtime([{ + category: "project-report", + id: param.id, + }]) + toast.success(res.message) + router.push("./") + } else { + toast.error(res.message) + } + } catch (error) { + console.error(error) + toast.error("Gagal mengedit Laporan Kegiatan, coba lagi nanti") + } finally { + setLoadingSubmit(false) + setOpenModal(false) + } + } + + function onCheck() { + if (report == "") { + setTouched({ ...touched, report: true }) + return false + } + setOpenModal(true) + } + + + + function onValidation(kategori: string, val: string) { + if (kategori == 'report') { + setReport(val) + if (val === "") { + setTouched({ ...touched, report: true }) + } else { + setTouched({ ...touched, report: false }) + } + } + } + + async function getOneData() { + try { + setLoading(true) + const res = await funGetOneProjectById(param.id, 'data'); + if (res.success) { + setReport(res.data.report); + } else { + toast.error(res.message); + } + setLoading(false); + } catch (error) { + console.error(error); + toast.error("Gagal mendapatkan data Kegiatan, coba lagi nanti"); + } finally { + setLoading(false); + } + } + + useShallowEffect(() => { + getOneData(); + }, [param.id]) + + + return ( + + + + + {loading ? + + : +