diff --git a/src/app/api/calender/[id]/route.ts b/src/app/api/calender/[id]/route.ts index 70cdeb0..02b0d7e 100644 --- a/src/app/api/calender/[id]/route.ts +++ b/src/app/api/calender/[id]/route.ts @@ -93,3 +93,50 @@ export async function GET(request: Request, context: { params: { id: string } }) } } +// DELETE CALENDER BY ID +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 cek = await prisma.divisionCalendar.count({ + where: { + id: id + } + }) + + if (cek == 0) { + return NextResponse.json( + { + success: false, + message: "Gagal menghapus calender, data tidak ditemukan", + }, + { status: 404 } + ); + } + + const data = await prisma.divisionCalendar.update({ + where: { + id: id + }, + data: { + isActive: false + } + }); + + return NextResponse.json({ success: true, message: "Berhasil menghapus calender", data }, { status: 200 }); + + } catch (error) { + return NextResponse.json( + { + success: false, + message: "Gagal menghapus calender, coba lagi nanti", + }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/src/app/api/calender/route.ts b/src/app/api/calender/route.ts index cf48258..302f9a5 100644 --- a/src/app/api/calender/route.ts +++ b/src/app/api/calender/route.ts @@ -81,7 +81,9 @@ export async function POST(request: Request) { return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); } - const { idDivision, title, desc, timeStart, timeEnd, dateStart, dateEnd, reminderInterval, repeatEventTyper } = (await request.json()); + const { idDivision, title, desc, timeStart, timeEnd, dateStart, dateEnd, repeatEventTyper, member, linkMeet } = (await request.json()); + + const userId = user.id const cekDivision = await prisma.division.count({ where: { @@ -94,25 +96,61 @@ export async function POST(request: Request) { return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 404 }); } + if (timeStart > timeEnd) { + return NextResponse.json({ success: false, message: "Gagal mendapatkan calender, waktu mulai harus lebih kecil dari waktu berakhir" }, { status: 404 }); + } + + if (dateStart > dateEnd) { + return NextResponse.json({ success: false, message: "Gagal mendapatkan calender, Tanggal mulai harus lebih kecil dari Tanggal berakhir" }, { status: 404 }); + } + + if (dateStart < moment().format("YYYY-MM-DD")) { + return NextResponse.json({ success: false, message: "Gagal mendapatkan calender, Tanggal mulai harus lebih kecil dari Tanggal sekarang" }, { status: 404 }); + } + + if (dateEnd < moment().format("YYYY-MM-DD")) { + return NextResponse.json({ success: false, message: "Gagal mendapatkan calender, Tanggal berakhir harus lebih kecil dari Tanggal sekarang" }, { status: 404 }); + } + + const statusCalender = 0 + + const y = new Date('1970-01-01 ' + timeStart) + const x = new Date('1970-01-01 ' + timeEnd) + const timeStartFix = new Date(y.getTime() - (y.getTimezoneOffset() * 60000)).toISOString() + const timeEndFix = new Date(x.getTime() - (x.getTimezoneOffset() * 60000)).toISOString() + const data = await prisma.divisionCalendar.create({ data: { idDivision, - createdBy:String(userId), + createdBy: String(userId), title, - timeStart, - timeEnd, - dateStart, - dateEnd, - reminderInterval, + dateStart: new Date(dateStart), + timeStart: timeStartFix, + timeEnd: timeEndFix, + linkMeet, repeatEventTyper, desc, + status: statusCalender }, select: { - id: true + id: true, + } }); - return NextResponse.json({ success: true, message: "Berhasil mendapatkan calender", data: data }, { status: 200 }); + const omitMember = member.map((v: any) => ({ + ..._.omit(v, ["name", "idUser"]), + idCalendar: data.id, + idUser: v.idUser + })) + + const insertMember = await prisma.divisionCalendarMember.createMany({ + data: omitMember + }); + + + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan calender" }, { status: 200 }); } catch (error) { console.error(error); diff --git a/src/module/calender/lib/api_calender.ts b/src/module/calender/lib/api_calender.ts index 54301c7..55b6a95 100644 --- a/src/module/calender/lib/api_calender.ts +++ b/src/module/calender/lib/api_calender.ts @@ -1,10 +1,29 @@ +import { IFormCreateCalender } from "./type_calender"; + export const funGetAllCalender = async (path?: string) => { const response = await fetch(`/api/calender${(path) ? path : ''}`, { next: { tags: ['calender'] } }); return await response.json().catch(() => null); } - export const funGetOneCalender = async (path: string) => { const response = await fetch(`/api/calender/${path}`); return await response.json().catch(() => null); +} + +export const funCreateCalender = async (data: IFormCreateCalender) => { + const response = await fetch("/api/calender", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + return await response.json().catch(() => null); +} + +export const funDeleteCalenderById = async (path: string) => { + const response = await fetch(`/api/calender/${path}`, { + method: "DELETE", + }); + return await response.json().catch(() => null); } \ No newline at end of file diff --git a/src/module/calender/lib/type_calender.ts b/src/module/calender/lib/type_calender.ts index a8f38d7..3ae044a 100644 --- a/src/module/calender/lib/type_calender.ts +++ b/src/module/calender/lib/type_calender.ts @@ -27,4 +27,24 @@ export interface IDataDetailByIdMember { idUser: string name: string email: string +} + +export interface IFormCreateCalender { + idDivision: string + title: string + dateStart: String + timeStart: string + timeEnd: string + linkMeet: string + repeatEventTyper: string + desc: string, + member: IFormMemberCalender[] +} + +export interface IFormMemberCalender { + idCalender: string + idUser: { + id: string + name: string + }[] } \ No newline at end of file diff --git a/src/module/calender/lib/val_calender.ts b/src/module/calender/lib/val_calender.ts new file mode 100644 index 0000000..e43de78 --- /dev/null +++ b/src/module/calender/lib/val_calender.ts @@ -0,0 +1,5 @@ +import { hookstate } from "@hookstate/core"; +import { IFormMemberCalender } from "./type_calender"; + + +export const globalCalender = hookstate([]) \ No newline at end of file diff --git a/src/module/calender/ui/create_user_calender.tsx b/src/module/calender/ui/create_user_calender.tsx new file mode 100644 index 0000000..ced9764 --- /dev/null +++ b/src/module/calender/ui/create_user_calender.tsx @@ -0,0 +1,139 @@ +import React, { useState } from 'react'; +import { globalCalender } from '../lib/val_calender'; +import { useParams, useRouter } from 'next/navigation'; +import { funGetDivisionById, IDataMemberDivision } from '@/module/division_new'; +import { useHookstate } from '@hookstate/core'; +import toast from 'react-hot-toast'; +import { useShallowEffect } from '@mantine/hooks'; +import { LayoutNavbarNew, WARNA } from '@/module/_global'; +import { Avatar, Box, Button, Divider, Flex, Group, Text } from '@mantine/core'; +import { FaCheck } from 'react-icons/fa6'; + +export default function CreateUserCalender({ onClose }: { onClose: (val: any) => void }) { + const router = useRouter() + const param = useParams<{ id: string }>() + const [selectedFiles, setSelectedFiles] = useState([]) + const [isData, setData] = useState([]) + const member = useHookstate(globalCalender) + 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 ( + + + + + + 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/calender/ui/drawer_detail_event.tsx b/src/module/calender/ui/drawer_detail_event.tsx index 74ac1fe..8188a9c 100644 --- a/src/module/calender/ui/drawer_detail_event.tsx +++ b/src/module/calender/ui/drawer_detail_event.tsx @@ -2,30 +2,49 @@ import { WARNA } from '@/module/_global'; import LayoutModal from '@/module/_global/layout/layout_modal'; import { Box, Flex, SimpleGrid, Stack, Text } from '@mantine/core'; -import { useRouter } from 'next/navigation'; +import { useParams, useRouter } from 'next/navigation'; import React, { useState } from 'react'; import toast from 'react-hot-toast'; import { AiOutlineFileSearch } from 'react-icons/ai'; import { IoAddCircle } from 'react-icons/io5'; import { MdDelete, MdEdit } from 'react-icons/md'; +import { funDeleteCalenderById } from '../lib/api_calender'; export default function DrawerDetailEvent() { const router = useRouter() const [isModal, setModal] = useState(false) + const param = useParams<{ id: string, detail: string }>() - function onTrue(val: boolean) { - if (val) { - toast.success("Sukses! Data dihapus"); + async function fetchDeleteCalender(val: boolean) { + try { + if (val) { + const response = await funDeleteCalenderById( + param.detail + ) + if (response.success) { + toast.success(response.message) + setModal(false) + router.push(`/division/${param.id}/calender`) + } else { + toast.error(response.message) + } + } + setModal(false) + } catch (error) { + console.log(error); + setModal(false) + toast.error("Gagal hapus calender, coba lagi nanti"); } - setModal(false) } + return ( + {JSON.stringify(param)} - setModal(true)} justify={'center'} align={'center'} direction={'column'} > + setModal(true)} justify={'center'} align={'center'} direction={'column'} > @@ -33,7 +52,7 @@ export default function DrawerDetailEvent() { Hapus - router.push('/calender/update')} justify={'center'} align={'center'} direction={'column'} > + router.push('/calender/update')} justify={'center'} align={'center'} direction={'column'} > @@ -45,7 +64,7 @@ export default function DrawerDetailEvent() { setModal(false)} description="Apakah Anda yakin ingin menghapus data?" - onYes={(val) => { onTrue(val) }} /> + onYes={(val) => { fetchDeleteCalender(val) }} /> ); } diff --git a/src/module/calender/ui/navbar_create_division_calender.tsx b/src/module/calender/ui/navbar_create_division_calender.tsx index 82043db..9d1dbc6 100644 --- a/src/module/calender/ui/navbar_create_division_calender.tsx +++ b/src/module/calender/ui/navbar_create_division_calender.tsx @@ -1,15 +1,37 @@ "use client" import { LayoutNavbarNew, WARNA } from '@/module/_global'; -import { Box, Button, Group, Input, SimpleGrid, Stack, Text, Textarea, TextInput } from '@mantine/core'; +import { Avatar, Box, Button, Flex, Group, Input, SimpleGrid, Stack, Text, Textarea, TextInput } from '@mantine/core'; import { DateInput, TimeInput } from '@mantine/dates'; import React, { useState } from 'react'; import { IoIosArrowDropright } from 'react-icons/io'; -import { useRouter } from 'next/navigation'; +import { useParams, useRouter } from 'next/navigation'; import LayoutModal from '@/module/_global/layout/layout_modal'; import toast from 'react-hot-toast'; +import moment from 'moment'; +import { useHookstate } from '@hookstate/core'; +import { globalCalender } from '../lib/val_calender'; +import { IFormMemberCalender } from '../lib/type_calender'; +import { funCreateCalender } from '../lib/api_calender'; +import CreateUserCalender from './create_user_calender'; export default function NavbarCreateDivisionCalender() { + const [value, setValue] = useState(null); + const router = useRouter() const [isModal, setModal] = useState(false) + const memberUser = useHookstate(globalCalender) + const memberValue = memberUser.get() as IFormMemberCalender[] + const [openMember, setOpenMember] = useState(false) + const param = useParams<{ id: string, detail: string }>() + const [isData, setData] = useState({ + idDivision: "", + title: "", + dateStart: "", + timeStart: "", + timeEnd: "", + linkMeet: "", + repeatEventTyper: "1", + desc: "", + }) function onTrue(val: boolean) { if (val) { @@ -17,12 +39,66 @@ export default function NavbarCreateDivisionCalender() { } setModal(false) } - const [value, setValue] = useState(null); - const router = useRouter() + + async function onSubmit() { + try { + if (isData.timeStart > isData.timeEnd) { + return toast.error("Waktu Akhir Tidak tepat"); + } + const response = await funCreateCalender({ + idDivision: param.id, + title: isData.title, + dateStart: isData.dateStart, + timeStart: isData.timeStart, + timeEnd: isData.timeEnd, + linkMeet: isData.linkMeet, + repeatEventTyper: isData.repeatEventTyper, + desc: isData.desc, + member: memberValue + }) + + if (response.success) { + toast.success(response.message) + setModal(false) + setData({ + ...isData, + title: "", + dateStart: "", + timeStart: "", + timeEnd: "", + linkMeet: "", + repeatEventTyper: "1", + desc: "", + }) + memberUser.set([]) + } else { + toast.error(response.message) + } + } catch (error) { + console.log(error) + toast.error("Gagal menambahkan pengumuman, coba lagi nanti"); + } + console.log({ + idDivision: param.id, + title: isData.title, + dateStart: isData.dateStart, + timeStart: isData.timeStart, + timeEnd: isData.timeEnd, + linkMeet: isData.linkMeet, + repeatEventTyper: isData.repeatEventTyper, + desc: isData.desc, + member: memberValue + }) + } + + if(openMember) return setOpenMember(false)}/> + + return ( + {/*
{JSON.stringify(param.id, null, 1)}
*/} setData({ ...isData, title: event.target.value })} /> { + setValue(val); + setData({ ...isData, dateStart: moment(val).format("YYYY-MM-DD") }); + }} + placeholder="Input Tanggal" + label="Tanggal" + minDate={new Date()} /> setData({ ...isData, timeStart: event.target.value })} /> setData({ ...isData, timeEnd: event.target.value })} /> setData({ ...isData, linkMeet: event.target.value })} /> router.push('/calender/create?page=ulangi-event')}> - router.push('/calender/create?page=user-calender')}> + setOpenMember(true)}> + value={isData.desc} + size="md" placeholder='Deskripsi' label="Deskripsi" + onChange={(event) => setData({ ...isData, desc: event.target.value })} + /> + { + memberUser.length > 0 && + + + Anggota Terpilih + Total {memberUser.length} Anggota + + + + + {memberUser.get().map((v: any, i: any) => { + return ( + + + + + + {v.name} + + + + + Anggota + + + ); + })} + + + + + } +