Merge pull request 'amalia/17-sept-25' (#42) from amalia/17-sept-25 into join

Reviewed-on: bip/sistem-desa-mandiri#42
This commit is contained in:
2025-09-17 17:33:33 +08:00
5 changed files with 661 additions and 351 deletions

View File

@@ -41,6 +41,14 @@ components:
status:
type: integer
BaseResponse:
type: object
properties:
success:
type: boolean
message:
type: string
@@ -329,6 +337,176 @@ components:
$ref: '#/components/schemas/DiscussionComment'
# Discussion General
DiskusiUmumListResponse:
allOf:
- $ref: '#/components/schemas/BaseResponse'
- type: object
properties:
data:
type: array
items:
type: object
properties:
id:
type: string
title:
type: string
desc:
type: string
createdAt:
type: string
format: date-time
totalKomentar:
type: integer
status:
type: string
group:
type: string
DiskusiUmumDetailResponse:
allOf:
- $ref: '#/components/schemas/BaseResponse'
- type: object
properties:
data:
type: object
properties:
id:
type: string
isActive:
type: boolean
idGroup:
type: string
group:
type: string
title:
type: string
desc:
type: string
status:
type: string
createdAt:
type: string
format: date-time
DiskusiUmumMemberResponse:
allOf:
- $ref: '#/components/schemas/BaseResponse'
- type: object
properties:
data:
type: array
items:
type: object
properties:
idUser:
type: string
name:
type: string
img:
type: string
nullable: true
DiskusiUmumCommentResponse:
allOf:
- $ref: '#/components/schemas/BaseResponse'
- type: object
properties:
data:
type: array
items:
type: object
properties:
id:
type: string
comment:
type: string
createdAt:
type: string
format: date-time
idUser:
type: string
username:
type: string
img:
type: string
nullable: true
# Division (mirip Project, disederhanakan)
DivisiListResponse:
allOf:
- $ref: '#/components/schemas/BaseResponse'
- type: object
properties:
data:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
desc:
type: string
idGroup:
type: string
group:
type: string
jumlahMember:
type: integer
DivisiDetailResponse:
allOf:
- $ref: '#/components/schemas/BaseResponse'
- type: object
properties:
data:
type: object
properties:
id:
type: string
idVillage:
type: string
idGroup:
type: string
name:
type: string
desc:
type: string
isActive:
type: boolean
createdBy:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
member:
type: array
items:
type: object
properties:
id:
type: string
isAdmin:
type: boolean
idUser:
type: string
name:
type: string
img:
type: string
nullable: true
# Group
Group:
type: object
@@ -363,28 +541,6 @@ components:
- id
- name
# Discussion General
DiscussionGeneral:
type: object
properties:
id:
type: string
title:
type: string
desc:
type: string
user:
type: string
status:
type: integer
member:
type: array
items:
$ref: '#/components/schemas/User'
required:
- id
- title
# Project
Project:
type: object
@@ -405,28 +561,6 @@ components:
- id
- name
# Division (mirip Project, disederhanakan)
Division:
type: object
properties:
id:
type: string
name:
type: string
desc:
type: string
user:
type: string
isActive:
type: boolean
member:
type: array
items:
$ref: '#/components/schemas/User'
required:
- id
- name
# Task (mirip Project)
Task:
type: object
@@ -720,6 +854,153 @@ paths:
$ref: '#/components/schemas/DiscussionDetailResponse'
# Discussion General
/discussion-general:
get:
tags:
- DiscussionGeneral
summary: Get discussion general
parameters:
- name: desa
in: query
required: true
schema:
type: string
- name: group
in: query
schema:
type: string
- name: search
in: query
schema:
type: string
- name: status
in: query
schema:
type: string
enum: [open, close]
- name: active
in: query
schema:
type: boolean
- name: page
in: query
schema:
type: integer
- name: get
in: query
schema:
type: integer
responses:
'200':
description: List of discussions
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DiskusiUmumListResponse'
/discussion-general/{id}:
get:
tags:
- DiscussionGeneral
summary: Get one discussion general
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: desa
in: query
required: true
schema:
type: string
- name: cat
in: query
schema:
type: string
enum: [detail, member, comment]
responses:
'200':
description: Discussion details
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/DiskusiUmumDetailResponse'
- $ref: '#/components/schemas/DiskusiUmumMemberResponse'
- $ref: '#/components/schemas/DiskusiUmumCommentResponse'
# Division
/division:
get:
tags:
- Division
summary: Get divisions
parameters:
- name: desa
in: query
required: true
schema:
type: string
- name: active
in: query
schema:
type: boolean
- name: group
in: query
schema:
type: string
- name: search
in: query
schema:
type: string
- name: page
in: query
schema:
type: integer
- name: get
in: query
schema:
type: integer
responses:
'200':
description: List of divisions
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DivisiListResponse'
/division/{id}:
get:
tags:
- Division
summary: Get one division detail
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: desa
in: query
required: true
schema:
type: string
responses:
'200':
description: Division details
content:
application/json:
schema:
$ref: '#/components/schemas/DivisiDetailResponse'
# Home Data
/home:
get:
@@ -924,75 +1205,6 @@ paths:
schema:
$ref: '#/components/schemas/User'
# Discussion General
/discussion-general:
get:
tags:
- DiscussionGeneral
summary: Get discussion general
parameters:
- name: user
in: query
required: true
schema:
type: string
- name: active
in: query
required: true
schema:
type: string
- name: group
in: query
schema:
type: string
- name: search
in: query
required: true
schema:
type: string
- name: page
in: query
schema:
type: integer
responses:
'200':
description: List of discussions
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DiscussionGeneral'
/discussion-general/{id}:
get:
tags:
- DiscussionGeneral
summary: Get one discussion general
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: user
in: query
required: true
schema:
type: string
- name: cat
in: query
required: true
schema:
type: string
responses:
'200':
description: Discussion details
content:
application/json:
schema:
$ref: '#/components/schemas/DiscussionGeneral'
# Project
/project:
get:
@@ -1067,208 +1279,6 @@ paths:
schema:
$ref: '#/components/schemas/Project'
# Division
/division:
get:
tags:
- Division
summary: Get divisions
parameters:
- name: user
in: query
required: true
schema:
type: string
- name: active
in: query
schema:
type: string
- name: group
in: query
schema:
type: string
- name: search
in: query
required: true
schema:
type: string
- name: cat
in: query
schema:
type: string
- name: page
in: query
schema:
type: integer
responses:
'200':
description: List of divisions
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Division'
/division/{id}:
get:
tags:
- Division
summary: Get one division detail
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: user
in: query
required: true
schema:
type: string
responses:
'200':
description: Division details
content:
application/json:
schema:
$ref: '#/components/schemas/Division'
/division/{id}/detail:
get:
tags:
- Division
summary: Get division one feature
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: user
in: query
required: true
schema:
type: string
- name: cat
in: query
required: true
schema:
type: string
enum: [jumlah, today-task, new-file, new-discussion, check-member, check-admin]
responses:
'200':
description: Feature data
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/division/{id}/member:
get:
tags:
- Division
summary: Get division members
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: user
in: query
required: true
schema:
type: string
- name: search
in: query
required: true
schema:
type: string
responses:
'200':
description: List of members
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
/division/report:
get:
tags:
- Division
summary: Get division report
parameters:
- name: user
in: query
required: true
schema:
type: string
- name: cat
in: query
required: true
schema:
type: string
enum: [table-progress, lainnya]
- name: date
in: query
required: true
schema:
type: string
- name: date-end
in: query
required: true
schema:
type: string
- name: division
in: query
required: true
schema:
type: string
- name: group
in: query
schema:
type: string
responses:
'200':
description: Report data
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/division/more:
get:
tags:
- Division
summary: Get list division by id division
parameters:
- name: user
in: query
required: true
schema:
type: string
- name: search
in: query
required: true
schema:
type: string
- name: division
in: query
required: true
schema:
type: string
responses:
'200':
description: List of divisions
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Division'
# Task
/task:
get:
@@ -1449,6 +1459,10 @@ tags:
description: Calendar events
- name: Discussion
description: Division discussions
- name: DiscussionGeneral
description: General discussions
- name: Division
description: Division management
- name: Home
description: Home and search
@@ -1458,12 +1472,8 @@ tags:
description: Position management
- name: User
description: User management
- name: DiscussionGeneral
description: General discussions
- name: Project
description: Project management
- name: Division
description: Division management
- name: Task
description: Task management
- name: Document

View File

@@ -1,7 +1,5 @@
import { prisma } from "@/module/_global";
import _ from "lodash";
import moment from "moment";
import "moment/locale/id";
import { NextResponse } from "next/server";
@@ -10,12 +8,15 @@ export async function GET(request: Request, context: { params: { id: string } })
try {
let dataFix
const { id } = context.params
const { searchParams } = new URL(request.url);
const kategori = searchParams.get("cat");
const idVillage = searchParams.get("desa");
const cek = await prisma.discussion.count({
where: {
id,
idVillage: String(idVillage)
}
})
@@ -23,33 +24,7 @@ export async function GET(request: Request, context: { params: { id: string } })
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" }, { status: 404 });
}
if (kategori == "detail") {
const data = await prisma.discussion.findUnique({
where: {
id,
},
select: {
isActive: true,
id: true,
title: true,
idGroup: true,
desc: true,
status: true,
createdAt: true,
}
})
dataFix = {
id: data?.id,
isActive: data?.isActive,
idGroup: data?.idGroup,
title: data?.title,
desc: data?.desc,
status: data?.status,
createdAt: moment(data?.createdAt).format("ll"),
}
} else if (kategori == "komentar") {
if (kategori == "comment") {
const data = await prisma.discussionComment.findMany({
where: {
idDiscussion: id,
@@ -70,13 +45,12 @@ export async function GET(request: Request, context: { params: { id: string } })
})
dataFix = data.map((v: any) => ({
..._.omit(v, ["createdAt", "User",]),
createdAt: moment(v.createdAt).format("lll").replace('pukul', ''),
..._.omit(v, ["User",]),
username: v.User.name,
img: v.User.img
}))
} else if (kategori == "anggota") {
} else if (kategori == "member") {
const data = await prisma.discussionMember.findMany({
where: {
idDiscussion: id,
@@ -98,6 +72,38 @@ export async function GET(request: Request, context: { params: { id: string } })
name: v.User.name,
img: v.User.img
}))
} else {
const data = await prisma.discussion.findUnique({
where: {
id,
idVillage: String(idVillage)
},
select: {
isActive: true,
id: true,
title: true,
idGroup: true,
desc: true,
status: true,
createdAt: true,
Group: {
select: {
name: true,
}
}
}
})
dataFix = {
id: data?.id,
isActive: data?.isActive,
idGroup: data?.idGroup,
group: data?.Group.name,
title: data?.title,
desc: data?.desc,
status: data?.status == 1 ? "Open" : "Close",
createdAt: data?.createdAt
}
}

View File

@@ -0,0 +1,63 @@
import { prisma } from "@/module/_global";
import _ from "lodash";
import { NextResponse } from "next/server";
// GET ONE DATA DIVISI :: UNTUK TAMPIL DATA DI HALAMAN EDIT DAN INFO
export async function GET(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params;
const { searchParams } = new URL(request.url);
const idVillage = searchParams.get("desa");
const data = await prisma.division.findUnique({
where: {
id: String(id),
idVillage: String(idVillage)
}
});
if (!data) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan", }, { status: 404 });
}
const member = await prisma.divisionMember.findMany({
where: {
idDivision: String(id),
isActive: true,
},
select: {
id: true,
isAdmin: true,
idUser: true,
User: {
select: {
name: true,
img: true
}
}
},
orderBy: {
isAdmin: 'desc',
}
})
const fixMember = member.map((v: any) => ({
..._.omit(v, ["User"]),
name: v.User.name,
img: v.User.img
}))
const dataFix = {
...data,
member: fixMember
}
return NextResponse.json({ success: true, message: "Berhasil mendapatkan divisi", data: dataFix, }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -0,0 +1,84 @@
import { prisma } from "@/module/_global";
import _ from "lodash";
import { NextResponse } from "next/server";
// GET ALL DATA DIVISI == LIST DATA DIVISI
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const idVillage = searchParams.get("desa");
const idGroup = searchParams.get("group");
const name = searchParams.get('search');
const page = searchParams.get('page');
const active = searchParams.get("active");
const get = searchParams.get('get')
let getFix = 10;
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
getFix = 10;
} else {
getFix = Number(get);
}
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
let kondisi: any = {
isActive: active == 'false' ? false : true,
idVillage: String(idVillage),
name: {
contains: (name == undefined || name == "null") ? "" : name,
mode: "insensitive"
}
}
if (idGroup != "null" && idGroup != undefined && idGroup != "") {
kondisi = {
...kondisi,
idGroup: String(idGroup)
}
}
const data = await prisma.division.findMany({
skip: dataSkip,
take: getFix,
where: kondisi,
select: {
id: true,
name: true,
desc: true,
idGroup: true,
Group: {
select: {
name: true
}
},
DivisionMember: {
where: {
isActive: true
},
select: {
idUser: true
}
}
},
orderBy: {
createdAt: 'desc'
}
});
const allData = data.map((v: any) => ({
..._.omit(v, ["DivisionMember", "Group"]),
group: v.Group.name,
jumlahMember: v.DivisionMember.length,
}))
return NextResponse.json({ success: true, message: "Berhasil mendapatkan divisi", data: allData }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -0,0 +1,147 @@
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";
// GET ALL DOCUMENT
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const idDivision = searchParams.get("division");
const villageId = searchParams.get("desa");
const path = searchParams.get("path");
const category = searchParams.get("category");
const active = searchParams.get("active");
const search = searchParams.get("search");
const page = searchParams.get("page");
const get = searchParams.get("get");
let kondisi: any = {
isActive: true,
idDivision: String(idDivision),
path: (path == "undefined" || path == "null" || path == "" || path == null) ? "home" : path
}
let formatDataShare: any[] = [];
if (category == "folder") {
kondisi = {
isActive: true,
idDivision: String(idDivision),
path: (path == "undefined" || path == "null" || path == "" || path == null) ? "home" : path,
category: "FOLDER"
}
} else {
if (path == "home" || path == "null" || path == "undefined") {
const dataShare = await prisma.divisionDocumentShare.findMany({
where: {
isActive: true,
idDivision: String(idDivision),
DivisionDocumentFolderFile: {
isActive: true
}
},
select: {
DivisionDocumentFolderFile: {
select: {
idStorage: true,
id: true,
category: true,
name: true,
extension: true,
path: true,
User: {
select: {
name: true
}
},
createdAt: true,
updatedAt: true
}
}
},
orderBy: {
DivisionDocumentFolderFile: {
createdAt: 'desc'
}
}
})
formatDataShare = dataShare.map((v: any) => ({
..._.omit(v, ["DivisionDocumentFolderFile"]),
idStorage: v.DivisionDocumentFolderFile.idStorage,
id: v.DivisionDocumentFolderFile.id,
category: v.DivisionDocumentFolderFile.category,
name: v.DivisionDocumentFolderFile.name,
extension: v.DivisionDocumentFolderFile.extension,
path: v.DivisionDocumentFolderFile.path,
createdBy: v.DivisionDocumentFolderFile.User.name,
createdAt: v.DivisionDocumentFolderFile.createdAt,
updatedAt: v.DivisionDocumentFolderFile.updatedAt,
share: true
}))
} else {
kondisi = {
isActive: true,
path: (path == "undefined" || path == "null" || path == null) ? "home" : path
}
}
}
const data = await prisma.divisionDocumentFolderFile.findMany({
where: kondisi,
select: {
id: true,
category: true,
name: true,
extension: true,
idStorage: true,
path: true,
User: {
select: {
name: true
}
},
createdAt: true,
updatedAt: true
},
orderBy: {
createdAt: 'desc'
}
})
const allData = data.map((v: any) => ({
..._.omit(v, ["User", "createdAt", "updatedAt"]),
createdBy: v.User.name,
createdAt: v.createdAt,
updatedAt: v.updatedAt,
share: false
}))
if (formatDataShare.length > 0) {
allData.push(...formatDataShare)
}
const formatData = _.orderBy(allData, ['category', 'createdAt'], ['desc', 'desc']);
const fixData = formatData.map((v: any) => ({
..._.omit(v, ["createdAt", "updatedAt"]),
createdAt: moment(v.createdAt).format("DD-MM-YYYY HH:mm"),
updatedAt: moment(v.updatedAt).format("DD-MM-YYYY HH:mm"),
}))
return NextResponse.json({ success: true, message: "Berhasil mendapatkan item", data: fixData }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan item, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
}