diff --git a/src/app/(application)/division/[id]/(fitur-division)/task/edit/[detail]/page.tsx b/src/app/(application)/division/[id]/(fitur-division)/task/edit/[detail]/page.tsx
new file mode 100644
index 0000000..fe6054e
--- /dev/null
+++ b/src/app/(application)/division/[id]/(fitur-division)/task/edit/[detail]/page.tsx
@@ -0,0 +1,9 @@
+import { EditDetailTask } from "@/module/task"
+
+function Page() {
+ return (
+
+ )
+}
+
+export default Page
\ 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 24409ed..0817ebe 100644
--- a/src/app/api/task/[id]/route.ts
+++ b/src/app/api/task/[id]/route.ts
@@ -36,7 +36,7 @@ export async function GET(request: Request, context: { params: { id: string } })
isActive: true,
idProject: String(id)
},
- orderBy:{
+ orderBy: {
updatedAt: 'desc'
}
})
@@ -61,6 +61,9 @@ export async function GET(request: Request, context: { params: { id: string } })
status: true,
dateStart: true,
dateEnd: true,
+ },
+ orderBy: {
+ status: 'desc'
}
})
diff --git a/src/app/api/task/detail/[id]/route.ts b/src/app/api/task/detail/[id]/route.ts
new file mode 100644
index 0000000..1fb2f37
--- /dev/null
+++ b/src/app/api/task/detail/[id]/route.ts
@@ -0,0 +1,187 @@
+import { prisma } from "@/module/_global";
+import { funGetUserByCookies } from "@/module/auth";
+import moment from "moment";
+import { NextResponse } from "next/server";
+
+
+// HAPUS DETAIL TASK
+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 { id } = context.params;
+ const data = await prisma.divisionProjectTask.count({
+ where: {
+ id: id,
+ },
+ });
+
+ if (data == 0) {
+ return NextResponse.json(
+ {
+ success: false,
+ message: "Hapus tugas gagal, data tidak ditemukan",
+ },
+ { status: 404 }
+ );
+ }
+
+ const update = await prisma.divisionProjectTask.update({
+ where: {
+ id: id,
+ },
+ data: {
+ isActive: false,
+ },
+ });
+
+ return NextResponse.json(
+ {
+ success: true,
+ message: "Tugas berhasil dihapus",
+ data,
+ },
+ { status: 200 }
+ );
+ } catch (error) {
+ console.log(error);
+ return NextResponse.json({ success: false, message: "Gagal menghapus tugas divisi, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
+ }
+}
+
+
+
+// EDIT STATUS DETAIL TASK
+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 { status } = (await request.json());
+ const data = await prisma.divisionProjectTask.count({
+ where: {
+ id: id,
+ },
+ });
+
+ if (data == 0) {
+ return NextResponse.json(
+ {
+ success: false,
+ message: "Update status detail tugas gagal, data tidak ditemukan",
+ },
+ { status: 404 }
+ );
+ }
+
+ const update = await prisma.divisionProjectTask.update({
+ where: {
+ id: id,
+ },
+ data: {
+ status: status,
+ },
+ });
+
+ return NextResponse.json(
+ {
+ success: true,
+ message: "Status detail tugas berhasil diupdate",
+ data,
+ },
+ { status: 200 }
+ );
+ } catch (error) {
+ console.log(error);
+ return NextResponse.json({ success: false, message: "Gagal mengupdate status detail tugas, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
+ }
+}
+
+
+// GET ONE DETAIL TASK
+export async function GET(request: Request, context: { params: { id: string } }) {
+ try {
+ const { id } = context.params;
+ const user = await funGetUserByCookies()
+
+ if (user.id == undefined) {
+ return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
+ }
+
+ const data = await prisma.divisionProjectTask.findUnique({
+ where: {
+ id: String(id),
+ isActive: true
+ }
+ });
+
+ if (!data) {
+ 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 });
+
+ }
+ catch (error) {
+ console.log(error);
+ return NextResponse.json({ success: false, message: "Gagal mendapatkan detail tugas divisi, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
+ }
+}
+
+
+
+// EDIT DETAIL TASK
+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 { title, dateStart, dateEnd } = (await request.json());
+ const data = await prisma.divisionProjectTask.count({
+ where: {
+ id: id,
+ },
+ });
+
+ if (data == 0) {
+ return NextResponse.json(
+ {
+ success: false,
+ message: "Edit detail tugas gagal, data tidak ditemukan",
+ },
+ { status: 404 }
+ );
+ }
+
+ const update = await prisma.divisionProjectTask.update({
+ where: {
+ id: id,
+ },
+ data: {
+ title,
+ dateStart: new Date(moment(dateStart).format('YYYY-MM-DD')),
+ dateEnd: new Date(moment(dateEnd).format('YYYY-MM-DD')),
+ },
+ });
+
+ return NextResponse.json(
+ {
+ success: true,
+ message: "Detail tugas berhasil diedit",
+ data,
+ },
+ { status: 200 }
+ );
+ } catch (error) {
+ console.log(error);
+ return NextResponse.json({ success: false, message: "Gagal mengedit detail tugas, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
+ }
+}
\ No newline at end of file
diff --git a/src/app/api/task/route.ts b/src/app/api/task/route.ts
index e5939da..558cabb 100644
--- a/src/app/api/task/route.ts
+++ b/src/app/api/task/route.ts
@@ -1,6 +1,7 @@
import { funUploadFile, prisma } from "@/module/_global";
import { funGetUserByCookies } from "@/module/auth";
import _, { ceil } from "lodash";
+import moment from "moment";
import { NextResponse } from "next/server";
@@ -115,8 +116,8 @@ export async function POST(request: Request) {
idDivision: idDivision,
idProject: data.id,
title: v.title,
- dateStart: new Date(v.dateStart),
- dateEnd: new Date(v.dateEnd),
+ dateStart: new Date(moment(v.dateStart).format('YYYY-MM-DD')),
+ dateEnd: new Date(moment(v.dateEnd).format('YYYY-MM-DD')),
}))
const insertTask = await prisma.divisionProjectTask.createMany({
@@ -139,7 +140,6 @@ export async function POST(request: Request) {
let fileFix: any[] = []
- console.log("amalia",file)
if (file.length > 0) {
file.map((v: any, index: any) => {
@@ -158,7 +158,6 @@ export async function POST(request: Request) {
fileFix.push(dataFile)
})
- console.log(fileFix)
const insertFile = await prisma.divisionProjectFile.createMany({
data: fileFix
})
@@ -170,6 +169,6 @@ export async function POST(request: Request) {
} catch (error) {
console.log(error);
- return NextResponse.json({ success: false, message: "Gagal membuat tugas divisiii, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
+ return NextResponse.json({ success: false, message: "Gagal membuat tugas divisi, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}
\ No newline at end of file
diff --git a/src/module/task/index.ts b/src/module/task/index.ts
index 5a6dd34..afbcfd7 100644
--- a/src/module/task/index.ts
+++ b/src/module/task/index.ts
@@ -5,6 +5,7 @@ import ListAnggotaDetailTask from "./ui/detail_list_anggota_task";
import ListFileDetailTask from "./ui/detail_list_file_task";
import ListTugasDetailTask from "./ui/detail_list_tugas_task";
import ProgressDetailTask from "./ui/detail_progress_task";
+import EditDetailTask from "./ui/edit_detail_task";
import FileSave from "./ui/file_save";
import NavbarDetailDivisionTask from "./ui/navbar_detail_division_task";
import NavbarDivisionTask from "./ui/navbar_division_task";
@@ -20,4 +21,5 @@ export { NavbarDetailDivisionTask }
export { ListTugasDetailTask }
export { ProgressDetailTask }
export { ListFileDetailTask }
-export { ListAnggotaDetailTask }
\ No newline at end of file
+export { ListAnggotaDetailTask }
+export { EditDetailTask }
\ No newline at end of file
diff --git a/src/module/task/lib/api_task.ts b/src/module/task/lib/api_task.ts
index 7fe36fd..5aec7e2 100644
--- a/src/module/task/lib/api_task.ts
+++ b/src/module/task/lib/api_task.ts
@@ -1,4 +1,4 @@
-import { IFormTaskDivision } from "./type_task";
+import { IFormDateTask, IFormTaskDivision } from "./type_task";
export const funGetAllTask = async (path?: string) => {
const response = await fetch(`/api/task${(path) ? path : ''}`, { next: { tags: ['task'] } });
@@ -23,4 +23,45 @@ export const funCreateTask = async (data: IFormTaskDivision) => {
export const funGetTaskDivisionById = async (path: string, kategori: string) => {
const response = await fetch(`/api/task/${path}?cat=${kategori}`);
return await response.json().catch(() => null);
-}
\ No newline at end of file
+}
+
+
+export const funDeleteDetailTask = async (path: string) => {
+ const response = await fetch(`/api/task/detail/${path}`, {
+ method: "DELETE",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ return await response.json().catch(() => null);
+};
+
+
+export const funUpdateStatusDetailTask = async (path: string, data: { status: number }) => {
+ const response = await fetch(`/api/task/detail/${path}`, {
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data),
+ });
+ return await response.json().catch(() => null);
+};
+
+
+export const funGetDetailTask = async (path: string) => {
+ const response = await fetch(`/api/task/detail/${path}`);
+ return await response.json().catch(() => null);
+}
+
+
+export const funEditDetailTask = async (path: string, data: IFormDateTask) => {
+ const response = await fetch(`/api/task/detail/${path}`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data),
+ });
+ return await response.json().catch(() => null);
+};
\ No newline at end of file
diff --git a/src/module/task/lib/val_task.ts b/src/module/task/lib/val_task.ts
index eaea013..0412ddc 100644
--- a/src/module/task/lib/val_task.ts
+++ b/src/module/task/lib/val_task.ts
@@ -1,4 +1,16 @@
import { hookstate } from "@hookstate/core";
import { IFormMemberTask } from "./type_task";
-export const globalMemberTask = hookstate([]);
\ No newline at end of file
+export const globalMemberTask = hookstate([]);
+export const globalRefreshTask = hookstate(false);
+
+export const valStatusDetailTask = [
+ {
+ name: "Belum Dikerjakan",
+ value: 0
+ },
+ {
+ name: "Selesai",
+ value: 1
+ }
+]
\ No newline at end of file
diff --git a/src/module/task/ui/detail_list_tugas_task.tsx b/src/module/task/ui/detail_list_tugas_task.tsx
index 7218595..4170bbe 100644
--- a/src/module/task/ui/detail_list_tugas_task.tsx
+++ b/src/module/task/ui/detail_list_tugas_task.tsx
@@ -1,18 +1,29 @@
'use client'
-import { WARNA } from "@/module/_global"
-import { Box, Grid, Center, Checkbox, Group, SimpleGrid, Text } from "@mantine/core"
+import { LayoutDrawer, WARNA } from "@/module/_global"
+import { Box, Grid, Center, Checkbox, Group, SimpleGrid, Text, Stack, Flex, Divider } from "@mantine/core"
import { useShallowEffect } from "@mantine/hooks"
-import { useParams } from "next/navigation"
+import { useParams, useRouter } from "next/navigation"
import toast from "react-hot-toast"
-import { AiOutlineFileSync } from "react-icons/ai"
-import { funGetTaskDivisionById } from "../lib/api_task"
+import { AiOutlineFileDone, AiOutlineFileSync } from "react-icons/ai"
+import { funDeleteDetailTask, funGetTaskDivisionById, funUpdateStatusDetailTask } from "../lib/api_task"
import { useState } from "react"
import { IDataListTaskDivision } from "../lib/type_task"
+import { FaCheck, FaPencil, FaTrash } from "react-icons/fa6"
+import LayoutModal from "@/module/_global/layout/layout_modal"
+import { globalRefreshTask, valStatusDetailTask } from "../lib/val_task"
+import { useHookstate } from "@hookstate/core"
export default function ListTugasDetailTask() {
+ const [openDrawer, setOpenDrawer] = useState(false)
+ const [openDrawerStatus, setOpenDrawerStatus] = useState(false)
+ const [isOpenModal, setOpenModal] = useState(false)
const [isData, setData] = useState([])
const [loading, setLoading] = useState(true)
const param = useParams<{ id: string, detail: string }>()
+ const [idData, setIdData] = useState('')
+ const [statusData, setStatusData] = useState(0)
+ const router = useRouter()
+ const refresh = useHookstate(globalRefreshTask)
async function getOneData() {
try {
setLoading(true)
@@ -35,6 +46,45 @@ export default function ListTugasDetailTask() {
getOneData();
}, [param.detail])
+
+ async function onDelete() {
+ try {
+ const res = await funDeleteDetailTask(idData);
+ if (res.success) {
+ toast.success(res.message);
+ refresh.set(true)
+ getOneData();
+ setIdData("")
+ setOpenDrawer(false)
+ } else {
+ toast.error(res.message);
+ }
+ } catch (error) {
+ console.error(error);
+ toast.error("Gagal menghapus tugas divisi, coba lagi nanti");
+ }
+
+ }
+
+ async function onUpdateStatus(val: number) {
+ try {
+ const res = await funUpdateStatusDetailTask(idData, { status: val });
+ if (res.success) {
+ toast.success(res.message);
+ refresh.set(true)
+ getOneData();
+ setIdData("")
+ setOpenDrawerStatus(false)
+ setOpenDrawer(false)
+ } else {
+ toast.error(res.message);
+ }
+ } catch (error) {
+ console.error(error);
+ toast.error("Gagal mengubah status tugas divisi, coba lagi nanti");
+ }
+ }
+
return (
@@ -53,7 +103,13 @@ export default function ListTugasDetailTask() {
isData.length === 0 ? Tidak ada tugas :
isData.map((item, index) => {
return (
-
+ {
+ setIdData(item.id)
+ setStatusData(item.status)
+ setOpenDrawer(true)
+ }}
+ >
@@ -109,8 +165,92 @@ export default function ListTugasDetailTask() {
)
})
}
-
+
+ setOpenDrawer(false)}>
+
+
+
+ { setOpenDrawerStatus(true) }} justify={'center'} align={'center'} direction={'column'} >
+
+
+
+
+ Update status
+
+
+
+ { router.push('edit/' + idData) }} justify={'center'} align={'center'} direction={'column'} >
+
+
+
+
+ Edit tugas
+
+
+
+ { setOpenModal(true) }} justify={'center'} align={'center'} direction={'column'} >
+
+
+
+
+ Hapus tugas
+
+
+
+
+
+
+
+ setOpenModal(false)}
+ description="Apakah Anda yakin ingin menghapus tugas ini?"
+ onYes={(val) => {
+ if (val) {
+ onDelete()
+ }
+ setOpenModal(false)
+ }} />
+
+
+ setOpenDrawerStatus(false)}>
+
+
+ {
+ valStatusDetailTask.map((item, index) => {
+ return (
+ { onUpdateStatus(item.value) }}>
+
+
+
+ {item.name}
+
+
+
+ {statusData === item.value ? : ""}
+
+
+
+
+ )
+ })
+ }
+
+
+
+
)
}
\ No newline at end of file
diff --git a/src/module/task/ui/detail_progress_task.tsx b/src/module/task/ui/detail_progress_task.tsx
index 51fb1b6..af14cbb 100644
--- a/src/module/task/ui/detail_progress_task.tsx
+++ b/src/module/task/ui/detail_progress_task.tsx
@@ -6,12 +6,16 @@ import { useParams } from "next/navigation";
import toast from "react-hot-toast";
import { HiMiniPresentationChartBar } from "react-icons/hi2";
import { funGetTaskDivisionById } from "../lib/api_task";
-import { useState } from "react";
+import { useEffect, useState } from "react";
+import { globalRefreshTask } from "../lib/val_task";
+import { useHookstate } from "@hookstate/core";
export default function ProgressDetailTask() {
const [valProgress, setValProgress] = useState(0)
const [valLastUpdate, setValLastUpdate] = useState('')
const param = useParams<{ id: string, detail: string }>()
+ const refresh = useHookstate(globalRefreshTask)
+
async function getOneData() {
try {
const res = await funGetTaskDivisionById(param.detail, 'progress');
@@ -28,6 +32,19 @@ export default function ProgressDetailTask() {
}
}
+ function onRefresh() {
+ if (refresh.get()) {
+ getOneData()
+ refresh.set(false)
+ }
+ }
+
+
+
+ useEffect(() => {
+ onRefresh()
+ }, [refresh.get()])
+
useShallowEffect(() => {
getOneData();
}, [param.detail])
@@ -66,7 +83,7 @@ export default function ProgressDetailTask() {
size="xl"
value={valProgress}
/>
- {valLastUpdate}
+ {/* Update terakhir : {valLastUpdate} */}
diff --git a/src/module/task/ui/edit_detail_task.tsx b/src/module/task/ui/edit_detail_task.tsx
new file mode 100644
index 0000000..23717f6
--- /dev/null
+++ b/src/module/task/ui/edit_detail_task.tsx
@@ -0,0 +1,162 @@
+"use client";
+import { LayoutNavbarNew, WARNA } from "@/module/_global";
+import {
+ Avatar,
+ Box,
+ Button,
+ Flex,
+ Group,
+ Input,
+ SimpleGrid,
+ Stack,
+ Text,
+} from "@mantine/core";
+import React, { useState } from "react";
+import { DatePicker } from "@mantine/dates";
+import { useParams, useRouter } from "next/navigation";
+import toast from "react-hot-toast";
+import moment from "moment";
+import { funEditDetailTask, funGetDetailTask } from "../lib/api_task";
+import { useShallowEffect } from "@mantine/hooks";
+import LayoutModal from "@/module/_global/layout/layout_modal";
+
+
+export default function EditDetailTask() {
+ const [value, setValue] = useState<[Date | null, Date | null]>([null, null]);
+ const router = useRouter()
+ const [title, setTitle] = useState("")
+ const param = useParams<{ id: string, detail: string }>()
+ const [openModal, setOpenModal] = useState(false)
+
+ async function onSubmit() {
+ if (value[0] == null || value[1] == null)
+ return toast.error("Error! harus memilih tanggal")
+
+ if (title == "")
+ return toast.error("Error! harus memasukkan judul tugas")
+
+ try {
+ const res = await funEditDetailTask(param.detail, {
+ title: title,
+ dateStart: value[0],
+ dateEnd: value[1],
+ })
+
+ if (res.success) {
+ toast.success(res.message);
+ } else {
+ toast.error(res.message);
+ }
+ } catch (error) {
+ console.error(error);
+ toast.error("Gagal edit detail tugas divisi, coba lagi nanti");
+ }
+
+ }
+
+ async function getOneData() {
+ try {
+ const res = await funGetDetailTask(param.detail);
+ if (res.success) {
+ setTitle(res.data.title)
+ setValue([
+ new Date(moment(res.data.dateStart).format('YYYY-MM-DD')),
+ new Date(moment(res.data.dateEnd).format('YYYY-MM-DD')),
+ ])
+ } else {
+ toast.error(res.message);
+ }
+
+ } catch (error) {
+ console.error(error);
+ toast.error("Gagal mendapatkan detail tugas divisi, coba lagi nanti");
+ }
+ }
+
+ useShallowEffect(() => {
+ getOneData();
+ }, [param.detail])
+
+
+ return (
+
+
+
+
+
+
+
+
+ Tanggal Mulai
+
+ {value[0] ? `${moment(value[0]).format('DD-MM-YYYY')}` : ""}
+
+
+
+ Tanggal Berakhir
+
+ {value[1] ? `${moment(value[1]).format('DD-MM-YYYY')}` : ""}
+
+
+
+
+ { setTitle(e.target.value) }}
+ />
+
+
+
+
+
+
+ setOpenModal(false)}
+ description="Apakah Anda yakin ingin mengubah data?"
+ onYes={(val) => {
+ if (val) {
+ onSubmit()
+ }
+ setOpenModal(false)
+ }} />
+
+ );
+}
diff --git a/src/module/task/ui/navbar_detail_division_task.tsx b/src/module/task/ui/navbar_detail_division_task.tsx
index e06b78c..512d4da 100644
--- a/src/module/task/ui/navbar_detail_division_task.tsx
+++ b/src/module/task/ui/navbar_detail_division_task.tsx
@@ -41,7 +41,7 @@ export default function NavbarDetailDivisionTask() {
size="lg"
radius="lg"
aria-label="Settings"
- onClick={() => router.push("/task/update/1")}
+ onClick={() => router.push("update/clzwclyjc00072sqq4sbr5iz4")}
>