From c654fd439dc8d6b5457728ca1db18a0ce38e963b Mon Sep 17 00:00:00 2001 From: amel Date: Fri, 10 Jan 2025 12:04:05 +0800 Subject: [PATCH 1/2] rev: report divisi Deskripsi: - api chart progres tugas - api chart dokumen - api chart acara - ui chart acara No Issues --- src/app/api/division/report/route.ts | 163 +++++++++++++----- .../division_new/ui/echart_bar_calender.tsx | 93 ++++++++++ .../division_new/ui/echart_bar_report.tsx | 13 +- .../division_new/ui/report_division_id.tsx | 12 +- 4 files changed, 224 insertions(+), 57 deletions(-) create mode 100644 src/module/division_new/ui/echart_bar_calender.tsx diff --git a/src/app/api/division/report/route.ts b/src/app/api/division/report/route.ts index ef775e5..b83578c 100644 --- a/src/app/api/division/report/route.ts +++ b/src/app/api/division/report/route.ts @@ -27,8 +27,6 @@ export async function GET(request: Request) { if (kat == "table-progress") { let kondisiProgress - const dateStart = date - const dateEnd = dateAkhir if (division == "undefined") { kondisiProgress = { isActive: true, @@ -38,10 +36,10 @@ export async function GET(request: Request) { DivisionProjectTask: { some: { dateStart: { - gte: new Date(String(dateStart)) + gte: new Date(String(date)) }, dateEnd: { - lte: new Date(String(dateEnd)) + lte: new Date(String(dateAkhir)) } } } @@ -54,10 +52,10 @@ export async function GET(request: Request) { DivisionProjectTask: { some: { dateStart: { - gte: new Date(String(dateStart)) + gte: new Date(String(date)) }, dateEnd: { - lte: new Date(String(dateEnd)) + lte: new Date(String(dateAkhir)) } } } @@ -96,20 +94,34 @@ export async function GET(request: Request) { if (division == "undefined") { kondisiProgress = { isActive: true, - updatedAt: { - lte: new Date(String(date)) - }, Division: { idGroup: String(grup) + }, + DivisionProjectTask: { + some: { + dateStart: { + gte: new Date(String(date)) + }, + dateEnd: { + lte: new Date(String(dateAkhir)) + } + } } } } else { kondisiProgress = { isActive: true, idDivision: String(division), - updatedAt: { - lte: new Date(String(date)) - }, + DivisionProjectTask: { + some: { + dateStart: { + gte: new Date(String(date)) + }, + dateEnd: { + lte: new Date(String(dateAkhir)) + } + } + } } } @@ -153,7 +165,8 @@ export async function GET(request: Request) { idGroup: String(grup) }, createdAt: { - lte: new Date(String(date)) + gte: new Date(String(date)), + lte: new Date(String(dateAkhir)) }, } } else { @@ -162,7 +175,8 @@ export async function GET(request: Request) { category: 'FILE', idDivision: String(division), createdAt: { - lte: new Date(String(date)) + gte: new Date(String(date)), + lte: new Date(String(dateAkhir)) }, } } @@ -207,53 +221,112 @@ export async function GET(request: Request) { // CHART EVENT - let kondisiEvent + let kondisiEvent, kondisiSelesai, kondisiComingSoon if (division == "undefined") { kondisiEvent = { isActive: true, Division: { idGroup: String(grup) }, - dateStart: new Date(String(date)) + DivisionCalendarReminder: { + some: { + dateStart: { + gte: new Date(String(date)), + lte: new Date(String(dateAkhir)) + } + } + } } } else { kondisiEvent = { isActive: true, idDivision: String(division), - dateStart: new Date(String(date)) + DivisionCalendarReminder: { + some: { + dateStart: { + gte: new Date(String(date)), + lte: new Date(String(dateAkhir)) + } + } + } + } + + kondisiSelesai = { + isActive: true, + idDivision: String(division), + DivisionCalendarReminder: { + some: { + dateStart: { + gte: new Date(String(date)), + lte: new Date() + } + } + } + } + + kondisiComingSoon = { + isActive: true, + idDivision: String(division), + DivisionCalendarReminder: { + some: { + dateStart: { + gt: new Date(), + lte: new Date(String(dateAkhir)) + } + } + } } } - const dataEvent = await prisma.divisionCalendar.findMany({ - where: kondisiEvent, - select: { - id: true, - idDivision: true, - title: true, - desc: true, - status: true, - timeStart: true, - dateStart: true, - timeEnd: true, - dateEnd: true, - createdAt: true, - User: { - select: { - name: true - } - } - }, - orderBy: { - createdAt: 'desc' - } + const eventSelesai = await prisma.divisionCalendar.count({ + where: kondisiSelesai }) - const hasilEvent = dataEvent.map((v: any) => ({ - ..._.omit(v, ["User"]), - user_name: v.User.name, - timeStart: moment.utc(v.timeStart).format('HH:mm'), - timeEnd: moment.utc(v.timeEnd).format('HH:mm') - })) + const eventComingSoon = await prisma.divisionCalendar.count({ + where: kondisiComingSoon + }) + + const hasilEvent = [ + { + name: 'Selesai', + value: eventSelesai + }, + { + name: 'Akan Datang', + value: eventComingSoon + } + ] + + // const dataEvent = await prisma.divisionCalendar.findMany({ + // where: kondisiEvent, + // select: { + // id: true, + // idDivision: true, + // title: true, + // desc: true, + // status: true, + // timeStart: true, + // dateStart: true, + // timeEnd: true, + // dateEnd: true, + // createdAt: true, + // User: { + // select: { + // name: true + // } + // } + // }, + // orderBy: { + // createdAt: 'desc' + // } + // }) + + // const hasilEvent = dataEvent.map((v: any) => ({ + // ..._.omit(v, ["User"]), + // user_name: v.User.name, + // timeStart: moment.utc(v.timeStart).format('HH:mm'), + // timeEnd: moment.utc(v.timeEnd).format('HH:mm') + // })) const allData = { diff --git a/src/module/division_new/ui/echart_bar_calender.tsx b/src/module/division_new/ui/echart_bar_calender.tsx new file mode 100644 index 0000000..2d585ae --- /dev/null +++ b/src/module/division_new/ui/echart_bar_calender.tsx @@ -0,0 +1,93 @@ +import { TEMA, } from '@/module/_global'; +import { useHookstate } from '@hookstate/core'; +import { Box } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { EChartsOption } from "echarts"; +import EChartsReact from "echarts-for-react"; +import { useState } from 'react'; + +export default function EchartBarReportCalender({ data }: { data: any }) { + const [options, setOptions] = useState({}); + const color = ["#5971C0", "#868e96", "#9EC97F"] + const tema = useHookstate(TEMA) + + useShallowEffect(() => { + loadData(data) + }, [data]) + + const loadData = (value: any) => { + const option: EChartsOption = { + title: { + text: "ACARA DIVISI", + top: '2%', + left: 'center', + textStyle: { + color: tema.get().utama + } + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: [ + { + type: 'category', + data: value.map(({ name }: any) => name), + axisLabel: { + fontSize: 14 + }, + axisTick: { + alignWithLabel: true + }, + axisLine: { + show: true, + }, + } + ], + yAxis: [ + { + type: 'value', + show: true, + splitLine: { + lineStyle: { + color: "gray", + opacity: 0.1 + } + }, + } + ], + series: [ + { + name: 'Data', + type: 'bar', + barWidth: '70%', + data: value.map( + (v: any, i: any) => + ({ + name: v.name, + value: v.value, + itemStyle: { + color: color[i] + }, + }) + ), + } + ] + }; + setOptions(option); + } + + return ( + + + + ); +} diff --git a/src/module/division_new/ui/echart_bar_report.tsx b/src/module/division_new/ui/echart_bar_report.tsx index b145dc3..87e4e40 100644 --- a/src/module/division_new/ui/echart_bar_report.tsx +++ b/src/module/division_new/ui/echart_bar_report.tsx @@ -1,11 +1,10 @@ -import React, { useState } from 'react'; -import { EChartsOption, color } from "echarts"; -import EChartsReact from "echarts-for-react"; -import { useShallowEffect } from '@mantine/hooks'; -import * as echarts from 'echarts'; -import { Box } from '@mantine/core'; -import { TEMA, } from '@/module/_global'; +import { TEMA, } from '@/module/_global'; import { useHookstate } from '@hookstate/core'; +import { Box } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { EChartsOption } from "echarts"; +import EChartsReact from "echarts-for-react"; +import { useState } from 'react'; export default function EchartBarReport({ data }: { data: any }) { const [options, setOptions] = useState({}); diff --git a/src/module/division_new/ui/report_division_id.tsx b/src/module/division_new/ui/report_division_id.tsx index 5e7c841..00fa246 100644 --- a/src/module/division_new/ui/report_division_id.tsx +++ b/src/module/division_new/ui/report_division_id.tsx @@ -13,6 +13,7 @@ import { funGetReportDivision } from '../lib/api_division'; import EchartBarReport from './echart_bar_report'; import EchartPaiReport from './echart_pai_report'; import EventReport from './event_report'; +import EchartBarReportCalender from './echart_bar_calender'; export default function ReportDivisionId() { @@ -36,7 +37,7 @@ export default function ReportDivisionId() { end_date: false }) - async function onReport(date: any) { + async function onReport(awal: any, akhir: any) { try { setReport({ progress: [], @@ -45,7 +46,7 @@ export default function ReportDivisionId() { }) setTampil(true) setLoading(true) - const res = await funGetReportDivision(`?division=${param.id}&date=${moment(date).format("YYYY-MM-DD")}`) + const res = await funGetReportDivision(`?division=${param.id}&date=${moment(awal).format("YYYY-MM-DD")}&date-end=${moment(akhir).format("YYYY-MM-DD")}`) if (res.success) { setReport(res.data) } else { @@ -84,7 +85,7 @@ export default function ReportDivisionId() { setTampil(false) } else { setTouched({ ...touched, end_date: false }) - onReport(val) + onReport(val, valueAkhir) onReportTable(val, valueAkhir) } } @@ -96,7 +97,7 @@ export default function ReportDivisionId() { setTampil(false) } else { setTouched({ ...touched, end_date: false }) - onReport(val) + onReport(value, val) onReportTable(value, val) } } @@ -231,7 +232,8 @@ export default function ReportDivisionId() { padding: 10, }} > - + + {/* */} From 266073bfef594e94bb12d0f894b8dce29761744d Mon Sep 17 00:00:00 2001 From: amel Date: Fri, 10 Jan 2025 17:04:57 +0800 Subject: [PATCH 2/2] rev : report divisi Deskripsi: - report semua divisi api - report semua divisi ui No Issues --- src/app/api/division/report/route.ts | 56 ++++-- src/module/division_new/ui/create_report.tsx | 168 ++++++++++++++---- .../division_new/ui/report_division_id.tsx | 1 - 3 files changed, 180 insertions(+), 45 deletions(-) diff --git a/src/app/api/division/report/route.ts b/src/app/api/division/report/route.ts index b83578c..6c28b1e 100644 --- a/src/app/api/division/report/route.ts +++ b/src/app/api/division/report/route.ts @@ -223,7 +223,22 @@ export async function GET(request: Request) { // CHART EVENT let kondisiEvent, kondisiSelesai, kondisiComingSoon if (division == "undefined") { - kondisiEvent = { + // kondisiEvent = { + // isActive: true, + // Division: { + // idGroup: String(grup) + // }, + // DivisionCalendarReminder: { + // some: { + // dateStart: { + // gte: new Date(String(date)), + // lte: new Date(String(dateAkhir)) + // } + // } + // } + // } + + kondisiSelesai = { isActive: true, Division: { idGroup: String(grup) @@ -232,24 +247,39 @@ export async function GET(request: Request) { some: { dateStart: { gte: new Date(String(date)), + lte: new Date() + } + } + } + } + + kondisiComingSoon = { + isActive: true, + Division: { + idGroup: String(grup) + }, + DivisionCalendarReminder: { + some: { + dateStart: { + gt: new Date(), lte: new Date(String(dateAkhir)) } } } } } else { - kondisiEvent = { - isActive: true, - idDivision: String(division), - DivisionCalendarReminder: { - some: { - dateStart: { - gte: new Date(String(date)), - lte: new Date(String(dateAkhir)) - } - } - } - } + // kondisiEvent = { + // isActive: true, + // idDivision: String(division), + // DivisionCalendarReminder: { + // some: { + // dateStart: { + // gte: new Date(String(date)), + // lte: new Date(String(dateAkhir)) + // } + // } + // } + // } kondisiSelesai = { isActive: true, diff --git a/src/module/division_new/ui/create_report.tsx b/src/module/division_new/ui/create_report.tsx index 59d50fe..8ef8a9e 100644 --- a/src/module/division_new/ui/create_report.tsx +++ b/src/module/division_new/ui/create_report.tsx @@ -2,7 +2,7 @@ import { globalRole, LayoutNavbarNew, TEMA } from "@/module/_global"; import { funGetAllGroup, IDataGroup } from "@/module/group"; import { useHookstate } from "@hookstate/core"; -import { Box, Select, Skeleton, Stack } from "@mantine/core"; +import { Badge, Box, Select, Skeleton, Stack, Table } from "@mantine/core"; import { DateInput } from "@mantine/dates"; import { useShallowEffect } from "@mantine/hooks"; import moment from "moment"; @@ -13,21 +13,32 @@ import { funGetReportDivision } from "../lib/api_division"; import EchartBarReport from "./echart_bar_report"; import EchartPaiReport from "./echart_pai_report"; import EventReport from "./event_report"; +import _ from "lodash"; +import router from "next/router"; +import EchartBarReportCalender from "./echart_bar_calender"; export default function CreateReport() { const [value, setValue] = useState(null); + const [valueAkhir, setValueAkhir] = useState(null); const [dataGroup, setDataGroup] = useState([]); const [loading, setLoading] = useState(false); + const [loadingTable, setLoadingTable] = useState(false); const [tampil, setTampil] = useState(false); const [isGroup, setIsGroup] = useState(""); const param = useParams<{ id: string }>() const tema = useHookstate(TEMA) const roleLogin = useHookstate(globalRole) + const [reportTable, setReportTable] = useState([]) const [report, setReport] = useState({ progress: [], dokumen: [], event: [], }) + const [touched, setTouched] = useState({ + grup: false, + start_date: false, + end_date: false + }) async function loadData() { const loadGroup = await funGetAllGroup('?active=true') @@ -38,7 +49,7 @@ export default function CreateReport() { } } - async function onReport(group: string, date: any) { + async function onReport(group: string, awal: any, akhir: any) { try { setReport({ progress: [], @@ -47,7 +58,7 @@ export default function CreateReport() { }) setTampil(true) setLoading(true) - const res = await funGetReportDivision(`?group=${group}&division=${param.id}&date=${moment(date).format("YYYY-MM-DD")}`) + const res = await funGetReportDivision(`?group=${group}&division=${param.id}&date=${moment(awal).format("YYYY-MM-DD")}&date-end=${moment(akhir).format("YYYY-MM-DD")}`) if (res.success) { setReport(res.data) } else { @@ -61,36 +72,71 @@ export default function CreateReport() { } } - function onChooseGroup(val: any) { - if (val != null && val != "" && value != null && value != undefined) { - onReport(val, value) + async function onReportTable(group: string, awal: any, akhir: any) { + try { + setLoadingTable(true) + const res = await funGetReportDivision(`?cat=table-progress&group=${group}&division=${param.id}&date=${moment(awal).format("YYYY-MM-DD")}&date-end=${moment(akhir).format("YYYY-MM-DD")}`) + if (res.success) { + setReportTable(res.data) + } else { + toast.error(res.message) + } + } catch (error) { + console.error(error) + } finally { + setLoadingTable(false) } - - if (val == null || val == "") { - setTampil(false) - toast.error("Error! harus memilih grup") - } - setIsGroup(String(val)) } - function onChangeDate(val: any) { - if (roleLogin.get() == "supadmin") { - if (val != null && val != "" && isGroup != "" && isGroup != "null") { - onReport(isGroup, val) - } - - if (isGroup == null || isGroup == "") { + function onChangeDate(val: any, kat: string) { + if (kat == "grup") { + setIsGroup(val) + if (val == null || val == "") { setTampil(false) - toast.error("Error! harus memilih grup") + setTouched({ ...touched, grup: true }) + } else { + setIsGroup(String(val)) + setTouched({ ...touched, grup: false }) + + if (value != null && value != undefined && valueAkhir != null && valueAkhir != undefined && !touched.end_date) { + onReport(String(val), value, valueAkhir) + onReportTable(String(val), value, valueAkhir) + } } - } else { - if (val != null && val != "") { - onReport(isGroup, val) + } else if (kat == "start-date") { + setValue(val) + if (valueAkhir != null && valueAkhir != undefined) { + if (val >= valueAkhir) { + setTouched({ ...touched, end_date: true }) + setTampil(false) + } else { + setTouched({ ...touched, end_date: false }) + if (roleLogin.get() == "supadmin" && (isGroup == "" || isGroup == null || isGroup == undefined)) { + setTampil(false) + } else { + onReport(isGroup, val, valueAkhir) + onReportTable(isGroup, val, valueAkhir) + } + } + } + } else if (kat == "end-date") { + setValueAkhir(val) + if (value != null && value != undefined) { + if (value >= val) { + setTouched({ ...touched, end_date: true }) + setTampil(false) + } else { + setTouched({ ...touched, end_date: false }) + if (roleLogin.get() == "supadmin" && (isGroup == "" || isGroup == null || isGroup == undefined)) { + setTampil(false) + } else { + onReport(isGroup, value, val) + onReportTable(isGroup, value, val) + } + } } } - - setValue(val) } useShallowEffect(() => { @@ -113,19 +159,32 @@ export default function CreateReport() { value: String(pro.id), label: pro.name }))} - onChange={(val) => { onChooseGroup(val) }} + onChange={(val) => { onChangeDate(val, 'grup') }} + error={touched.grup && "Grup tidak boleh kosong"} /> } { onChangeDate(val) }} + onChange={(val) => { onChangeDate(val, 'start-date') }} radius={10} size="md" required - label="Tanggal" - placeholder="Tanggal" + label="Tanggal Awal" + placeholder="Tanggal Awal" + /> + + { onChangeDate(val, 'end-date') }} + radius={10} + size="md" + required + label="Tanggal Akhir" + placeholder="Tanggal Akhir" + error={touched.end_date && "Tanggal akhir harus lebih besar dari tanggal awal"} /> { tampil && @@ -158,6 +217,52 @@ export default function CreateReport() { }} > + { + !loadingTable ? + + + Tugas + Progres + Status + + { + reportTable.length == 0 ? + + Data kosong + + : + reportTable.map((item: any, i: number) => { + return ( + { router.push(`/division/${param.id}/task/${item.id}`) }}> + {item.title} + + {_.isNull(item.progress) ? 0 : item.progress}% + + + + { + item.status === 0 ? 'Segera' : + item.status === 1 ? 'Dikerjakan' : + item.status === 2 ? 'Selesai' : + item.status === 3 ? 'Dibatalkan' : + "Segera" + } + + + + ) + }) + } + +
+ : <> + } @@ -181,7 +286,8 @@ export default function CreateReport() { padding: 10, }} > - + + {/* */} diff --git a/src/module/division_new/ui/report_division_id.tsx b/src/module/division_new/ui/report_division_id.tsx index 00fa246..48d9c00 100644 --- a/src/module/division_new/ui/report_division_id.tsx +++ b/src/module/division_new/ui/report_division_id.tsx @@ -31,7 +31,6 @@ export default function ReportDivisionId() { event: [], }) const [reportTable, setReportTable] = useState([]) - const [touched, setTouched] = useState({ start_date: false, end_date: false