feat(noc): implement NOC API module and sync strategy task
This commit is contained in:
@@ -17,3 +17,4 @@ LOG_LEVEL=info
|
|||||||
|
|
||||||
# Public URL
|
# Public URL
|
||||||
VITE_PUBLIC_URL="http://localhost:3000"
|
VITE_PUBLIC_URL="http://localhost:3000"
|
||||||
|
NOC_API_URL="https://darmasaba.muku.id/api/noc/docs/json"
|
||||||
|
|||||||
68
__tests__/api/noc.test.ts
Normal file
68
__tests__/api/noc.test.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { describe, expect, it } from "bun:test";
|
||||||
|
import api from "@/api";
|
||||||
|
|
||||||
|
describe("NOC API Module", () => {
|
||||||
|
const idDesa = "darmasaba";
|
||||||
|
|
||||||
|
it("should return active divisions", async () => {
|
||||||
|
const response = await api.handle(
|
||||||
|
new Request(`http://localhost/api/noc/active-divisions?idDesa=${idDesa}`),
|
||||||
|
);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
const data = await response.json();
|
||||||
|
expect(Array.isArray(data.data)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return latest projects", async () => {
|
||||||
|
const response = await api.handle(
|
||||||
|
new Request(`http://localhost/api/noc/latest-projects?idDesa=${idDesa}`),
|
||||||
|
);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
const data = await response.json();
|
||||||
|
expect(Array.isArray(data.data)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return upcoming events", async () => {
|
||||||
|
const response = await api.handle(
|
||||||
|
new Request(`http://localhost/api/noc/upcoming-events?idDesa=${idDesa}`),
|
||||||
|
);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
const data = await response.json();
|
||||||
|
expect(Array.isArray(data.data)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return diagram jumlah document", async () => {
|
||||||
|
const response = await api.handle(
|
||||||
|
new Request(`http://localhost/api/noc/diagram-jumlah-document?idDesa=${idDesa}`),
|
||||||
|
);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
const data = await response.json();
|
||||||
|
expect(Array.isArray(data.data)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return diagram progres kegiatan", async () => {
|
||||||
|
const response = await api.handle(
|
||||||
|
new Request(`http://localhost/api/noc/diagram-progres-kegiatan?idDesa=${idDesa}`),
|
||||||
|
);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
const data = await response.json();
|
||||||
|
expect(Array.isArray(data.data)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return latest discussion", async () => {
|
||||||
|
const response = await api.handle(
|
||||||
|
new Request(`http://localhost/api/noc/latest-discussion?idDesa=${idDesa}`),
|
||||||
|
);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
const data = await response.json();
|
||||||
|
expect(Array.isArray(data.data)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return 400 for missing idDesa in active-divisions", async () => {
|
||||||
|
const response = await api.handle(
|
||||||
|
new Request("http://localhost/api/noc/active-divisions"),
|
||||||
|
);
|
||||||
|
// Elysia returns 400 or 422 for validation errors
|
||||||
|
expect([400, 422]).toContain(response.status);
|
||||||
|
});
|
||||||
|
});
|
||||||
371
generated/api.ts
371
generated/api.ts
@@ -457,6 +457,102 @@ export interface paths {
|
|||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
"/api/noc/active-divisions": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations["getApiNocActive-divisions"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/noc/latest-projects": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations["getApiNocLatest-projects"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/noc/upcoming-events": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations["getApiNocUpcoming-events"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/noc/diagram-jumlah-document": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations["getApiNocDiagram-jumlah-document"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/noc/diagram-progres-kegiatan": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations["getApiNocDiagram-progres-kegiatan"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/noc/latest-discussion": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations["getApiNocLatest-discussion"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
export type webhooks = Record<string, never>;
|
export type webhooks = Record<string, never>;
|
||||||
export interface components {
|
export interface components {
|
||||||
@@ -1974,4 +2070,279 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
"getApiNocActive-divisions": {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
idDesa: string;
|
||||||
|
limit?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
activityCount: number;
|
||||||
|
color: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"multipart/form-data": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
activityCount: number;
|
||||||
|
color: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"text/plain": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
activityCount: number;
|
||||||
|
color: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"getApiNocLatest-projects": {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
idDesa: string;
|
||||||
|
limit?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
status: string;
|
||||||
|
progress: number;
|
||||||
|
divisionName: string;
|
||||||
|
createdAt: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"multipart/form-data": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
status: string;
|
||||||
|
progress: number;
|
||||||
|
divisionName: string;
|
||||||
|
createdAt: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"text/plain": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
status: string;
|
||||||
|
progress: number;
|
||||||
|
divisionName: string;
|
||||||
|
createdAt: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"getApiNocUpcoming-events": {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
idDesa: string;
|
||||||
|
limit?: string;
|
||||||
|
filter?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
startDate: string;
|
||||||
|
location: (string | null) | null;
|
||||||
|
eventType: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"multipart/form-data": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
startDate: string;
|
||||||
|
location: (string | null) | null;
|
||||||
|
eventType: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"text/plain": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
startDate: string;
|
||||||
|
location: (string | null) | null;
|
||||||
|
eventType: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"getApiNocDiagram-jumlah-document": {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
idDesa: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
data: {
|
||||||
|
category: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"multipart/form-data": {
|
||||||
|
data: {
|
||||||
|
category: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"text/plain": {
|
||||||
|
data: {
|
||||||
|
category: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"getApiNocDiagram-progres-kegiatan": {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
idDesa: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
data: {
|
||||||
|
status: string;
|
||||||
|
avgProgress: number;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"multipart/form-data": {
|
||||||
|
data: {
|
||||||
|
status: string;
|
||||||
|
avgProgress: number;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"text/plain": {
|
||||||
|
data: {
|
||||||
|
status: string;
|
||||||
|
avgProgress: number;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"getApiNocLatest-discussion": {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
idDesa: string;
|
||||||
|
limit?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
message: string;
|
||||||
|
senderName: string;
|
||||||
|
senderImage: (string | null) | null;
|
||||||
|
divisionName: string;
|
||||||
|
createdAt: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"multipart/form-data": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
message: string;
|
||||||
|
senderName: string;
|
||||||
|
senderImage: (string | null) | null;
|
||||||
|
divisionName: string;
|
||||||
|
createdAt: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
"text/plain": {
|
||||||
|
data: {
|
||||||
|
id: string;
|
||||||
|
message: string;
|
||||||
|
senderName: string;
|
||||||
|
senderImage: (string | null) | null;
|
||||||
|
divisionName: string;
|
||||||
|
createdAt: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4022,6 +4022,892 @@
|
|||||||
},
|
},
|
||||||
"operationId": "getApiDashboardSatisfaction"
|
"operationId": "getApiDashboardSatisfaction"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/api/noc/active-divisions": {
|
||||||
|
"get": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "idDesa",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "limit",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"activityCount",
|
||||||
|
"color"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"activityCount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"activityCount",
|
||||||
|
"color"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"activityCount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"activityCount",
|
||||||
|
"color"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"activityCount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operationId": "getApiNocActive-divisions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/noc/latest-projects": {
|
||||||
|
"get": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "idDesa",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "limit",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"status",
|
||||||
|
"progress",
|
||||||
|
"divisionName",
|
||||||
|
"createdAt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"progress": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"divisionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"status",
|
||||||
|
"progress",
|
||||||
|
"divisionName",
|
||||||
|
"createdAt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"progress": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"divisionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"status",
|
||||||
|
"progress",
|
||||||
|
"divisionName",
|
||||||
|
"createdAt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"progress": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"divisionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operationId": "getApiNocLatest-projects"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/noc/upcoming-events": {
|
||||||
|
"get": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "idDesa",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "limit",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "filter",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"startDate",
|
||||||
|
"location",
|
||||||
|
"eventType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"startDate": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"nullable": true,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"eventType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"startDate",
|
||||||
|
"location",
|
||||||
|
"eventType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"startDate": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"nullable": true,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"eventType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"startDate",
|
||||||
|
"location",
|
||||||
|
"eventType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"startDate": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"nullable": true,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"eventType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operationId": "getApiNocUpcoming-events"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/noc/diagram-jumlah-document": {
|
||||||
|
"get": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "idDesa",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"category",
|
||||||
|
"count"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"category": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"category",
|
||||||
|
"count"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"category": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"category",
|
||||||
|
"count"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"category": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operationId": "getApiNocDiagram-jumlah-document"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/noc/diagram-progres-kegiatan": {
|
||||||
|
"get": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "idDesa",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"status",
|
||||||
|
"avgProgress",
|
||||||
|
"count"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avgProgress": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"status",
|
||||||
|
"avgProgress",
|
||||||
|
"count"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avgProgress": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"status",
|
||||||
|
"avgProgress",
|
||||||
|
"count"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avgProgress": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operationId": "getApiNocDiagram-progres-kegiatan"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/noc/latest-discussion": {
|
||||||
|
"get": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "idDesa",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "limit",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"message",
|
||||||
|
"senderName",
|
||||||
|
"senderImage",
|
||||||
|
"divisionName",
|
||||||
|
"createdAt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"senderName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"senderImage": {
|
||||||
|
"nullable": true,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"divisionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"message",
|
||||||
|
"senderName",
|
||||||
|
"senderImage",
|
||||||
|
"divisionName",
|
||||||
|
"createdAt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"senderName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"senderImage": {
|
||||||
|
"nullable": true,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"divisionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"message",
|
||||||
|
"senderName",
|
||||||
|
"senderImage",
|
||||||
|
"divisionName",
|
||||||
|
"createdAt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"senderName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"senderImage": {
|
||||||
|
"nullable": true,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"divisionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operationId": "getApiNocLatest-discussion"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { division } from "./division";
|
|||||||
import { event } from "./event";
|
import { event } from "./event";
|
||||||
import { profile } from "./profile";
|
import { profile } from "./profile";
|
||||||
import { resident } from "./resident";
|
import { resident } from "./resident";
|
||||||
|
import { noc } from "./noc";
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === "production";
|
const isProduction = process.env.NODE_ENV === "production";
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ const api = new Elysia({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
.use(noc)
|
||||||
.use(apiMiddleware)
|
.use(apiMiddleware)
|
||||||
.use(apikey)
|
.use(apikey)
|
||||||
.use(profile)
|
.use(profile)
|
||||||
|
|||||||
276
src/api/noc.ts
Normal file
276
src/api/noc.ts
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
import { Elysia, t } from "elysia";
|
||||||
|
import { prisma } from "../utils/db";
|
||||||
|
|
||||||
|
export const noc = new Elysia({ prefix: "/noc" })
|
||||||
|
.get(
|
||||||
|
"/active-divisions",
|
||||||
|
async ({ query }) => {
|
||||||
|
const { idDesa, limit } = query;
|
||||||
|
// TODO: Filter by idDesa once schema supports it
|
||||||
|
const data = await prisma.division.findMany({
|
||||||
|
include: {
|
||||||
|
_count: {
|
||||||
|
select: { activities: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
activities: {
|
||||||
|
_count: "desc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
take: limit ? Number.parseInt(limit) : 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data.map((d) => ({
|
||||||
|
id: d.id,
|
||||||
|
name: d.name,
|
||||||
|
activityCount: d._count.activities,
|
||||||
|
color: d.color,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: t.Object({
|
||||||
|
idDesa: t.String(),
|
||||||
|
limit: t.Optional(t.String()),
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: t.Object({
|
||||||
|
data: t.Array(
|
||||||
|
t.Object({
|
||||||
|
id: t.String(),
|
||||||
|
name: t.String(),
|
||||||
|
activityCount: t.Number(),
|
||||||
|
color: t.String(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.get(
|
||||||
|
"/latest-projects",
|
||||||
|
async ({ query }) => {
|
||||||
|
const { idDesa, limit } = query;
|
||||||
|
// TODO: Filter by idDesa once schema supports it
|
||||||
|
const data = await prisma.activity.findMany({
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
take: limit ? Number.parseInt(limit) : 5,
|
||||||
|
include: { division: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data.map((a) => ({
|
||||||
|
id: a.id,
|
||||||
|
title: a.title,
|
||||||
|
status: a.status,
|
||||||
|
progress: a.progress,
|
||||||
|
divisionName: a.division.name,
|
||||||
|
createdAt: a.createdAt.toISOString(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: t.Object({
|
||||||
|
idDesa: t.String(),
|
||||||
|
limit: t.Optional(t.String()),
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: t.Object({
|
||||||
|
data: t.Array(
|
||||||
|
t.Object({
|
||||||
|
id: t.String(),
|
||||||
|
title: t.String(),
|
||||||
|
status: t.String(),
|
||||||
|
progress: t.Number(),
|
||||||
|
divisionName: t.String(),
|
||||||
|
createdAt: t.String(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.get(
|
||||||
|
"/upcoming-events",
|
||||||
|
async ({ query }) => {
|
||||||
|
const { idDesa, limit, filter } = query;
|
||||||
|
// TODO: Filter by idDesa once schema supports it
|
||||||
|
const now = new Date();
|
||||||
|
const where: any = {};
|
||||||
|
|
||||||
|
if (filter === "today") {
|
||||||
|
const startOfDay = new Date(now.setHours(0, 0, 0, 0));
|
||||||
|
const endOfDay = new Date(now.setHours(23, 59, 59, 999));
|
||||||
|
where.startDate = {
|
||||||
|
gte: startOfDay,
|
||||||
|
lte: endOfDay,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
where.startDate = {
|
||||||
|
gte: now,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await prisma.event.findMany({
|
||||||
|
where,
|
||||||
|
orderBy: { startDate: "asc" },
|
||||||
|
take: limit ? Number.parseInt(limit) : 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data.map((e) => ({
|
||||||
|
id: e.id,
|
||||||
|
title: e.title,
|
||||||
|
startDate: e.startDate.toISOString(),
|
||||||
|
location: e.location,
|
||||||
|
eventType: e.eventType,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: t.Object({
|
||||||
|
idDesa: t.String(),
|
||||||
|
limit: t.Optional(t.String()),
|
||||||
|
filter: t.Optional(t.String()), // today/upcoming
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: t.Object({
|
||||||
|
data: t.Array(
|
||||||
|
t.Object({
|
||||||
|
id: t.String(),
|
||||||
|
title: t.String(),
|
||||||
|
startDate: t.String(),
|
||||||
|
location: t.Nullable(t.String()),
|
||||||
|
eventType: t.String(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.get(
|
||||||
|
"/diagram-jumlah-document",
|
||||||
|
async ({ query }) => {
|
||||||
|
const { idDesa } = query;
|
||||||
|
// TODO: Filter by idDesa once schema supports it
|
||||||
|
const data = await prisma.document.groupBy({
|
||||||
|
by: ["category"],
|
||||||
|
_count: {
|
||||||
|
_all: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data.map((d) => ({
|
||||||
|
category: d.category,
|
||||||
|
count: d._count._all,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: t.Object({
|
||||||
|
idDesa: t.String(),
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: t.Object({
|
||||||
|
data: t.Array(
|
||||||
|
t.Object({
|
||||||
|
category: t.String(),
|
||||||
|
count: t.Number(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.get(
|
||||||
|
"/diagram-progres-kegiatan",
|
||||||
|
async ({ query }) => {
|
||||||
|
const { idDesa } = query;
|
||||||
|
// TODO: Filter by idDesa once schema supports it
|
||||||
|
const data = await prisma.activity.groupBy({
|
||||||
|
by: ["status"],
|
||||||
|
_avg: {
|
||||||
|
progress: true,
|
||||||
|
},
|
||||||
|
_count: {
|
||||||
|
_all: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data.map((d) => ({
|
||||||
|
status: d.status,
|
||||||
|
avgProgress: d._avg.progress || 0,
|
||||||
|
count: d._count._all,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: t.Object({
|
||||||
|
idDesa: t.String(),
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: t.Object({
|
||||||
|
data: t.Array(
|
||||||
|
t.Object({
|
||||||
|
status: t.String(),
|
||||||
|
avgProgress: t.Number(),
|
||||||
|
count: t.Number(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.get(
|
||||||
|
"/latest-discussion",
|
||||||
|
async ({ query }) => {
|
||||||
|
const { idDesa, limit } = query;
|
||||||
|
// TODO: Filter by idDesa once schema supports it
|
||||||
|
const data = await prisma.discussion.findMany({
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
take: limit ? Number.parseInt(limit) : 5,
|
||||||
|
include: {
|
||||||
|
sender: {
|
||||||
|
select: { name: true, image: true },
|
||||||
|
},
|
||||||
|
division: {
|
||||||
|
select: { name: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data.map((d) => ({
|
||||||
|
id: d.id,
|
||||||
|
message: d.message,
|
||||||
|
senderName: d.sender.name || "Anonymous",
|
||||||
|
senderImage: d.sender.image,
|
||||||
|
divisionName: d.division?.name || "General",
|
||||||
|
createdAt: d.createdAt.toISOString(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: t.Object({
|
||||||
|
idDesa: t.String(),
|
||||||
|
limit: t.Optional(t.String()),
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: t.Object({
|
||||||
|
data: t.Array(
|
||||||
|
t.Object({
|
||||||
|
id: t.String(),
|
||||||
|
message: t.String(),
|
||||||
|
senderName: t.String(),
|
||||||
|
senderImage: t.Nullable(t.String()),
|
||||||
|
divisionName: t.String(),
|
||||||
|
createdAt: t.String(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -45,6 +45,7 @@ export function ActivityCard({
|
|||||||
backgroundColor: dark ? "#334155" : "white",
|
backgroundColor: dark ? "#334155" : "white",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
|
h={"100%"}
|
||||||
>
|
>
|
||||||
{/* 🔵 HEADER */}
|
{/* 🔵 HEADER */}
|
||||||
<Box
|
<Box
|
||||||
|
|||||||
Reference in New Issue
Block a user