diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b8427da..af6264d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -274,7 +274,7 @@ model DivisionProjectTask { DivisionProject DivisionProject @relation(fields: [idProject], references: [id]) idProject String title String - desc String @db.Text + desc String? @db.Text status Int @default(0) // 0 = todo, 1 = done dateStart DateTime @db.Date dateEnd DateTime @db.Date diff --git a/src/app/(application)/division/[id]/(fitur-division)/task/create/page.tsx b/src/app/(application)/division/[id]/(fitur-division)/task/create/page.tsx index e5660a0..e6ce908 100644 --- a/src/app/(application)/division/[id]/(fitur-division)/task/create/page.tsx +++ b/src/app/(application)/division/[id]/(fitur-division)/task/create/page.tsx @@ -1,16 +1,11 @@ -import { ViewCreateTaskDivision } from "@/module/division_new"; -import { ViewDateEndTask, CreateUsersProject, ViewFileSave } from "@/module/project"; +import { CreateTask, FileSave } from "@/module/task"; function Page({ searchParams }: { searchParams: any }) { - if (searchParams.page == "task") - return ; - if (searchParams.page == "create-users") - return - if (searchParams.page == "file-save") - return - return + if (searchParams.page == "file-save") + return + + return } -export default Page -// onClick={() => router.push('/document?page=list-document')} \ No newline at end of file +export default Page \ No newline at end of file diff --git a/src/app/api/calender/[id]/route.ts b/src/app/api/calender/[id]/route.ts index fc9117e..70cdeb0 100644 --- a/src/app/api/calender/[id]/route.ts +++ b/src/app/api/calender/[id]/route.ts @@ -1,3 +1,4 @@ + import { prisma } from "@/module/_global"; import { funGetUserByCookies } from "@/module/auth"; import _, { result } from "lodash"; @@ -91,3 +92,4 @@ export async function GET(request: Request, context: { params: { id: string } }) ); } } + diff --git a/src/app/api/task/route.ts b/src/app/api/task/route.ts index 9b053bd..28da9ee 100644 --- a/src/app/api/task/route.ts +++ b/src/app/api/task/route.ts @@ -67,9 +67,6 @@ export async function GET(request: Request) { member: v.DivisionProjectMember.length })) - console.log('amalia', formatData) - - return NextResponse.json({ success: true, message: "Berhasil mendapatkan divisi", data, }, { status: 200 }); } catch (error) { diff --git a/src/module/division_new/_division_fitur/task/view/view_create_division_task.tsx b/src/module/division_new/_division_fitur/task/view/view_create_division_task.tsx deleted file mode 100644 index da3acf8..0000000 --- a/src/module/division_new/_division_fitur/task/view/view_create_division_task.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import CreateTask from "../component/create_task"; - -export default function ViewCreateTaskDivision({ searchParams }: { searchParams: any }) { - return ( - - ); -} \ No newline at end of file diff --git a/src/module/division_new/index.ts b/src/module/division_new/index.ts index 341aabf..3a45a9f 100644 --- a/src/module/division_new/index.ts +++ b/src/module/division_new/index.ts @@ -9,7 +9,6 @@ import ViewDivisionCalender from "./_division_fitur/calender/view/view_division_ import ViewHistoryDivisionCalender from "./_division_fitur/calender/view/view_history_division_calender"; import ViewUpdateDivisionCalender from "./_division_fitur/calender/view/view_update_division_calender"; import ViewDocumentDivision from "./_division_fitur/document/view/view_document_division"; -import ViewCreateTaskDivision from "./_division_fitur/task/view/view_create_division_task"; import ViewDetailDivisionTask from "./_division_fitur/task/view/view_detail_division_task"; import ViewUpdateProgressDivisionTask from "./_division_fitur/task/view/view_update_progress_division_task"; import CreateAdminDivision from "./ui/create_admin_division"; @@ -27,6 +26,7 @@ import CreateAnggotaDivision from './ui/create_anggota_division'; import EditDivision from './ui/edit_division'; import CreateReport from './ui/create_report'; import ReportDivisionId from './ui/report_division_id'; +import { funGetDivisionById } from './lib/api_division'; export { CreateUsers }; export { CreateAdminDivision }; @@ -34,7 +34,6 @@ export { ViewDetailDivisionTask }; export { ViewUpdateProgressDivisionTask }; export { ViewDivisionCalender }; export { ViewCreateDivisionCalender }; -export { ViewCreateTaskDivision }; export { UlangiEvent }; export { CreateUserDivisionCalender }; export { ViewHistoryDivisionCalender }; @@ -57,3 +56,4 @@ export { CreateAnggotaDivision } export { EditDivision } export { CreateReport } export { ReportDivisionId } +export { funGetDivisionById } diff --git a/src/module/task/index.ts b/src/module/task/index.ts index 31eceb8..8b34a28 100644 --- a/src/module/task/index.ts +++ b/src/module/task/index.ts @@ -1,5 +1,13 @@ +import ViewDateEndTask from "./ui/create_date_end_task"; +import CreateTask from "./ui/create_task"; +import CreateUsersProject from "./ui/create_users_project"; +import FileSave from "./ui/file_save"; import NavbarDivisionTask from "./ui/navbar_division_task"; import TabsDivisionTask from "./ui/tabs_division_task"; export { NavbarDivisionTask } -export { TabsDivisionTask } \ No newline at end of file +export { TabsDivisionTask } +export { CreateTask } +export { ViewDateEndTask } +export { CreateUsersProject } +export { FileSave } \ No newline at end of file diff --git a/src/module/task/lib/type_task.ts b/src/module/task/lib/type_task.ts index e69de29..4521724 100644 --- a/src/module/task/lib/type_task.ts +++ b/src/module/task/lib/type_task.ts @@ -0,0 +1,20 @@ +export interface IDataTask { + id: string + title: string + desc: string, + status: number, + progress: number, + member: number +} + +export interface IFormMemberTask { + idUser: string, + name: string +} + + +export interface IFormDateTask { + dateStart: Date, + dateEnd: Date, + title: string +} \ No newline at end of file diff --git a/src/module/task/lib/val_task.ts b/src/module/task/lib/val_task.ts new file mode 100644 index 0000000..eaea013 --- /dev/null +++ b/src/module/task/lib/val_task.ts @@ -0,0 +1,4 @@ +import { hookstate } from "@hookstate/core"; +import { IFormMemberTask } from "./type_task"; + +export const globalMemberTask = hookstate([]); \ No newline at end of file diff --git a/src/module/task/ui/create_date_end_task.tsx b/src/module/task/ui/create_date_end_task.tsx new file mode 100644 index 0000000..a74c4be --- /dev/null +++ b/src/module/task/ui/create_date_end_task.tsx @@ -0,0 +1,116 @@ +"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 { useRouter } from "next/navigation"; +import toast from "react-hot-toast"; +import { IFormDateTask } from "../lib/type_task"; +import moment from "moment"; + + +export default function ViewDateEndTask({ onClose }: { onClose: (val: IFormDateTask) => void }) { + const [value, setValue] = useState<[Date | null, Date | null]>([null, null]); + const router = useRouter() + const [title, setTitle] = useState("") + + 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") + + onClose( + { + dateStart: value[0], + dateEnd: value[1], + title: title + } + ) + + } + + 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)} + /> + + + + + + + ); +} diff --git a/src/module/task/ui/create_task.tsx b/src/module/task/ui/create_task.tsx new file mode 100644 index 0000000..1e30cff --- /dev/null +++ b/src/module/task/ui/create_task.tsx @@ -0,0 +1,205 @@ +"use client"; +import { LayoutDrawer, LayoutNavbarNew, WARNA } from "@/module/_global"; +import { Avatar, Box, Button, Center, Flex, Group, Input, Stack, Text } from "@mantine/core"; +import { useRouter } from "next/navigation"; +import React, { useState } from "react"; +import { IoIosArrowDropright } from "react-icons/io"; +import { BsFiletypeCsv } from "react-icons/bs"; +import CreateUsersProject from "./create_users_project"; +import ResultsDateAndTask from "./results_date-and_task"; +import ResultsFile from "./results_file"; +import { useHookstate } from "@hookstate/core"; +import { globalMemberTask } from "../lib/val_task"; +import ViewDateEndTask from "./create_date_end_task"; +import { IFormDateTask } from "../lib/type_task"; + +export default function CreateTask() { + const router = useRouter(); + const [openDrawer, setOpenDrawer] = useState(false) + const [openMember, setOpenMember] = useState(false) + const [openTugas, setOpenTugas] = useState(false) + const member = useHookstate(globalMemberTask) + const [dataTask, setDataTask] = useState([]) + + + if (openTugas) return { + setDataTask([...dataTask, val]) + setOpenTugas(false) + }} />; + if (openMember) return setOpenMember(false)} /> + + + return ( + + + + + + { setOpenTugas(true) }}> + + Tambah Tanggal & Tugas + + + + setOpenDrawer(true)} + > + Upload File + + + setOpenMember(true)}> + + Tambah Anggota + + + + + { + dataTask.length > 0 && + + Tanggal & Tugas + { + dataTask.map((v, i) => { + return ( + + + + ) + }) + } + + } + + {/* */} + + { + member.length > 0 && + + + Anggota Terpilih + Total {member.length} Anggota + + + + + {member.get().map((v: any, i: any) => { + return ( + + + + + + {v.name} + + + + + Anggota + + + ); + })} + + + + + } + + + + + + + + + + setOpenDrawer(false)} + title={"Pilih File"} + > + + ""}> + +
+ +
+
+ + Pilih file + + diperangkat +
+ router.push("/task/create?page=file-save")}> + +
+ +
+
+ + Pilih file yang + + sudah ada +
+
+
+
+ ); +} diff --git a/src/module/task/ui/create_users_project.tsx b/src/module/task/ui/create_users_project.tsx new file mode 100644 index 0000000..57bf146 --- /dev/null +++ b/src/module/task/ui/create_users_project.tsx @@ -0,0 +1,166 @@ +"use client" +import { LayoutNavbarNew, WARNA } from "@/module/_global"; +import { funGetDivisionById, IDataMemberDivision } from "@/module/division_new"; +import { useHookstate } from "@hookstate/core"; +import { + Anchor, + Avatar, + Box, + Button, + Checkbox, + Divider, + Flex, + Group, + Text, + TextInput, +} from "@mantine/core"; +import { useShallowEffect } from "@mantine/hooks"; +import { useParams, useRouter } from "next/navigation"; +import React, { useState } from "react"; +import toast from "react-hot-toast"; +import { globalMemberTask } from "../lib/val_task"; +import { FaCheck } from "react-icons/fa6"; + +export default function CreateUsersProject({ onClose }: { onClose: (val: any) => void }) { + const router = useRouter() + const param = useParams<{ id: string }>() + const [selectedFiles, setSelectedFiles] = useState([]) + const [isData, setData] = useState([]) + const member = useHookstate(globalMemberTask) + const [selectAll, setSelectAll] = useState(false) + + + async function getData() { + try { + const response = await funGetDivisionById(param.id) + if (response.success) { + setData(response.data.member) + if (member.length > 0) { + setSelectedFiles(JSON.parse(JSON.stringify(member.get()))) + } + } else { + toast.error(response.message) + } + } catch (error) { + console.log(error) + toast.error("Gagal mendapatkan anggota, coba lagi nanti"); + } + } + + + useShallowEffect(() => { + getData() + }, []); + + const handleFileClick = (index: number) => { + if (selectedFiles.some((i: any) => i.idUser == isData[index].idUser)) { + setSelectedFiles(selectedFiles.filter((i: any) => i.idUser != isData[index].idUser)) + } else { + setSelectedFiles([...selectedFiles, { idUser: isData[index].idUser, name: isData[index].name }]) + } + }; + + + + const handleSelectAll = () => { + setSelectAll(!selectAll); + if (!selectAll) { + for (let index = 0; index < isData.length; index++) { + if (!selectedFiles.some((i: any) => i.idUser == isData[index].idUser)) { + const newArr = { + idUser: isData[index].idUser, name: isData[index].name + } + setSelectedFiles((selectedFiles: any) => [...selectedFiles, newArr]) + } + + } + } else { + setSelectedFiles([]); + } + }; + + + function onSubmit() { + if (selectedFiles.length == 0) { + return toast.error("Error! silahkan pilih anggota") + } + member.set(selectedFiles) + onClose(true) + } + + + return ( + + + + {/* } + placeholder="Pencarian" + /> */} + + + Pilih Semua Anggota + + {selectAll ? : ""} + + + {isData.map((v, i) => { + const isSelected = selectedFiles.some((i: any) => i?.idUser == v.idUser); + return ( + handleFileClick(i)}> + + + + + {v.name} + + + + {isSelected ? : ""} + + + + + ); + })} + + + + + + + ); +} diff --git a/src/module/task/ui/drawer_division_task.tsx b/src/module/task/ui/drawer_division_task.tsx index e9037da..8820692 100644 --- a/src/module/task/ui/drawer_division_task.tsx +++ b/src/module/task/ui/drawer_division_task.tsx @@ -9,7 +9,7 @@ export default function DrawerDivisionTask() { - window.location.href = "/task/create"} justify={'center'} align={'center'} direction={'column'} > + window.location.href = "task/create"} justify={'center'} align={'center'} direction={'column'} > diff --git a/src/module/task/ui/file_save.tsx b/src/module/task/ui/file_save.tsx new file mode 100644 index 0000000..741061c --- /dev/null +++ b/src/module/task/ui/file_save.tsx @@ -0,0 +1,88 @@ +'use client' +import { LayoutNavbarNew, WARNA } from "@/module/_global"; +import { Box, Button, Center, SimpleGrid, Text } from "@mantine/core"; +import { useRouter } from "next/navigation"; +import React, { useState } from "react"; +import { BsFiletypeCsv } from "react-icons/bs"; + +const dataFile = [ + { + id: 1, + name: "Semua_Proyek.csv", + }, + { + id: 2, + name: "Proyek_Dinas.csv", + }, + { + id: 3, + name: "Proyek_Lpd.csv", + }, + { + id: 4, + name: "Proyek_Lembaga1.csv", + }, + { + id: 5, + name: "Proyek_Lembaga2.csv", + }, + { + id: 6, + name: "Proyek_Lembaga3.csv", + }, +]; + + +export default function FileSave({ kategori }: { kategori: string }) { + const router = useRouter() + const [selectedFiles, setSelectedFiles] = useState>({}); + + const handleFileClick = (index: number) => { + setSelectedFiles((prevSelectedFiles) => ({ + ...prevSelectedFiles, + [index]: !prevSelectedFiles[index], + })); + }; + + return ( + + + + + {dataFile.map((file, index) => { + const isSelected = selectedFiles[index]; + return ( + + handleFileClick(index)} + > +
+ +
+
+ + {file.name} + +
+ ); + })} +
+ + + +
+
+ ); +} diff --git a/src/module/task/ui/list_division_task.tsx b/src/module/task/ui/list_division_task.tsx index b6b7595..c5dd0be 100644 --- a/src/module/task/ui/list_division_task.tsx +++ b/src/module/task/ui/list_division_task.tsx @@ -1,9 +1,13 @@ import { WARNA } from "@/module/_global"; import { ActionIcon, Avatar, Badge, Box, Card, Center, Divider, Flex, Grid, Group, Progress, Text, TextInput, Title } from "@mantine/core"; -import { useRouter } from "next/navigation"; +import { useParams, useRouter, useSearchParams } from "next/navigation"; import { useState } from "react"; import { HiMagnifyingGlass, HiMiniPresentationChartBar, HiOutlineListBullet, HiSquares2X2 } from "react-icons/hi2"; import { MdAccountCircle } from "react-icons/md"; +import { IDataTask } from "../lib/type_task"; +import { funGetAllTask } from "../lib/api_task"; +import toast from "react-hot-toast"; +import { useShallowEffect } from "@mantine/hooks"; const dataProject = [ @@ -51,14 +55,47 @@ const dataProject = [ }, ] -export default function ListDivisionTask({ status }: { status: string }) { +export default function ListDivisionTask() { const [isList, setIsList] = useState(false) const router = useRouter() + const [isData, setData] = useState([]) + const param = useParams<{ id: string }>() + const searchParams = useSearchParams() + const status = searchParams.get('status') + const [searchQuery, setSearchQuery] = useState('') + const [loading, setLoading] = useState(true); const handleList = () => { setIsList(!isList) } + const fetchData = async () => { + try { + setData([]); + setLoading(true); + + const response = await funGetAllTask('?division=' + param.id + '&status=' + status + '&search=' + searchQuery) + + if (response.success) { + setData(response?.data) + } else { + toast.error(response.message); + } + + setLoading(false); + } catch (error) { + toast.error("Gagal mendapatkan tugas divisi, coba lagi nanti"); + console.error(error); + } finally { + setLoading(false); + } + }; + + + useShallowEffect(() => { + fetchData(); + }, [status, searchQuery]); + return ( @@ -91,12 +128,12 @@ export default function ListDivisionTask({ status }: { status: string }) { Total Proyek - 35 + {isData.length} {isList ? ( - {dataProject.map((v, i) => { + {isData.map((v, i) => { return ( router.push(`/task/${v.id}`)}> @@ -118,9 +155,6 @@ export default function ListDivisionTask({ status }: { status: string }) { {v.title} - {/* - - */} @@ -129,7 +163,7 @@ export default function ListDivisionTask({ status }: { status: string }) { ) : ( - {dataProject.map((v, i) => { + {isData.map((v: any, i: any) => { return ( router.push(`/task/${v.id}`)}> @@ -146,7 +180,7 @@ export default function ListDivisionTask({ status }: { status: string }) { {(status == 'segera') ? 0 : (status == 'dikerjakan') ? 42 : (status == 'selesai') ? 100 : 0}% - {v.description} + {v.desc} {status} diff --git a/src/module/task/ui/results_date-and_task.tsx b/src/module/task/ui/results_date-and_task.tsx new file mode 100644 index 0000000..61f7e6f --- /dev/null +++ b/src/module/task/ui/results_date-and_task.tsx @@ -0,0 +1,56 @@ +import { WARNA } from '@/module/_global'; +import { Box, Group, SimpleGrid, Text } from '@mantine/core'; +import React from 'react'; +import { AiOutlineFileSync } from "react-icons/ai"; +import { IFormDateTask } from '../lib/type_task'; +import moment from 'moment'; + +export default function ResultsDateAndTask(data: IFormDateTask) { + return ( + + + + + + {data.title} + + + + + + Tanggal Mulai + + {moment(data.dateStart).format('DD-MM-YYYY')} + + + + Tanggal Berakhir + + {moment(data.dateEnd).format('DD-MM-YYYY')} + + + + + + + ); +} + diff --git a/src/module/task/ui/results_file.tsx b/src/module/task/ui/results_file.tsx new file mode 100644 index 0000000..1a3c0d3 --- /dev/null +++ b/src/module/task/ui/results_file.tsx @@ -0,0 +1,38 @@ +import { WARNA } from '@/module/_global'; +import { Box, Group, Text } from '@mantine/core'; +import React from 'react'; +import { BsFiletypeCsv } from 'react-icons/bs'; + +export default function ResultsFile() { + return ( + + File + + + + + Proyek Laporan Permasyarakatan + + + + + + Proyek Laporan Permasyarakatan + + + + + ); +} \ No newline at end of file diff --git a/src/module/task/ui/tabs_division_task.tsx b/src/module/task/ui/tabs_division_task.tsx index de627df..ac2151c 100644 --- a/src/module/task/ui/tabs_division_task.tsx +++ b/src/module/task/ui/tabs_division_task.tsx @@ -5,11 +5,11 @@ import { IoCloseCircleOutline } from "react-icons/io5"; import { RiProgress3Line } from "react-icons/ri"; import { TbClockPause } from "react-icons/tb"; import ListDivisionTask from "./list_division_task"; -import { useParams, useSearchParams } from "next/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; export default function TabsDivisionTask() { const iconStyle = { width: rem(20), height: rem(20) }; - const param = useParams<{ id: string }>() + const router = useRouter() const searchParams = useSearchParams() const status = searchParams.get('status') @@ -21,21 +21,28 @@ export default function TabsDivisionTask() { padding: 5, borderRadius: 100 }}> - }> + } + onClick={() => { router.push("?status=0") }}> Segera - }> + } + onClick={() => { router.push("?status=1") }}> Dikerjakan - }> + } + onClick={() => { router.push("?status=2") }}> Selesai - }> + } + onClick={() => { router.push("?status=3") }}> Batal - - + )