From a538d88ec136ceb21c69872879dfd39917fcab92 Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 9 Sep 2024 10:48:53 +0800 Subject: [PATCH 1/3] upd: kalender Deskripsi: - mengeluarkan anggota - edit api acara kalender - log user No Issues --- src/app/api/calender/[id]/member/route.ts | 53 +++++++++++++++++++ src/app/api/calender/[id]/route.ts | 35 +++++------- src/app/api/calender/history/route.ts | 6 +-- src/app/api/calender/route.ts | 7 ++- src/module/calender/lib/api_calender.ts | 13 ++++- src/module/calender/lib/type_calender.ts | 2 +- .../calender/ui/date_event_division.tsx | 4 +- .../calender/ui/dawer_division_calender.tsx | 2 +- .../calender/ui/detail_event_division.tsx | 35 +++++++++--- .../calender/ui/drawer_detail_event.tsx | 4 +- .../calender/ui/navbar_division_calender.tsx | 2 +- .../calender/ui/update_division_calender.tsx | 24 ++++----- 12 files changed, 132 insertions(+), 55 deletions(-) diff --git a/src/app/api/calender/[id]/member/route.ts b/src/app/api/calender/[id]/member/route.ts index 69ceb7f..1bb833b 100644 --- a/src/app/api/calender/[id]/member/route.ts +++ b/src/app/api/calender/[id]/member/route.ts @@ -54,4 +54,57 @@ export async function POST(request: Request, context: { params: { id: string } } } +} + +// MENGELUARKAN ANGGOTA +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 { idUser } = (await request.json()); + + const data = await prisma.divisionCalendar.count({ + where: { + id: id, + }, + }); + + + if (data == 0) { + return NextResponse.json( + { + success: false, + message: "Gagal mengeluarkan anggota, data tidak ditemukan", + }, + { status: 404 } + ); + } + + const del = await prisma.divisionCalendarMember.deleteMany({ + where: { + idUser: idUser, + idCalendar: id + } + }) + + + // create log user + const log = await createLogUser({ act: 'DELETE', desc: 'User mengeluarkan anggota acara kalender', table: 'divisionCalendar', data: String(id) }) + + + return NextResponse.json( + { + success: true, + message: "Berhasil mengeluarkan anggota", + }, + { status: 200 } + ); + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mengeluarkan anggota, coba lagi nanti", reason: (error as Error).message, }, { status: 500 }); + } } \ 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 34149d1..76f740a 100644 --- a/src/app/api/calender/[id]/route.ts +++ b/src/app/api/calender/[id]/route.ts @@ -1,7 +1,7 @@ - import { prisma } from "@/module/_global"; import { funGetUserByCookies } from "@/module/auth"; -import _, { result } from "lodash"; +import { createLogUser } from "@/module/user"; +import _ from "lodash"; import moment from "moment"; import { NextResponse } from "next/server"; @@ -52,7 +52,7 @@ export async function GET(request: Request, context: { params: { id: string } }) const timeStart = moment.utc(dataCalender?.timeStart).format("HH:mm") const timeEnd = moment.utc(dataCalender?.timeEnd).format("HH:mm") - const result = { ...dataCalender, timeStart, timeEnd } + const result = { ...dataCalender, timeStart, timeEnd } const member = await prisma.divisionCalendarMember.findMany({ @@ -135,6 +135,9 @@ export async function DELETE(request: Request, context: { params: { id: string } } }); + // create log user + const log = await createLogUser({ act: 'DELETE', desc: 'User menghapus data acara kalender', table: 'divisionCalendar', data: id }) + return NextResponse.json({ success: true, message: "Berhasil menghapus calender", data }, { status: 200 }); } catch (error) { @@ -159,7 +162,7 @@ export async function PUT(request: Request, context: { params: { id: string } }) const { id } = context.params const userId = user.id - const { title, desc, timeStart, dateStart, timeEnd, linkMeet, repeatEventTyper, member } = await request.json() + const { title, desc, timeStart, dateStart, timeEnd, linkMeet, repeatEventTyper } = await request.json() const cek = await prisma.divisionCalendar.count({ where: { @@ -171,7 +174,7 @@ export async function PUT(request: Request, context: { params: { id: string } }) return NextResponse.json( { success: false, - message: "Gagal mengedit calender, data tidak ditemukan", + message: "Gagal mengedit acara, data tidak ditemukan", }, { status: 404 } ); @@ -199,31 +202,17 @@ export async function PUT(request: Request, context: { params: { id: string } }) } }); - const del = await prisma.divisionCalendarMember.deleteMany({ - where: { - idCalendar: id - } - }) - - const omitMember = member.map((v: any) => ({ - ..._.omit(v, ["name", "idUser"]), - idCalendar: data.id, - idUser: v.idUser - })) - const insertMember = await prisma.divisionCalendarMember.createMany({ - data: omitMember - }); + // create log user + const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate data acara kalender', table: 'divisionCalendar', data: id }) - - - return NextResponse.json({ success: true, message: "Berhasil mengedit calender" }, { status: 200 }); + return NextResponse.json({ success: true, message: "Berhasil mengedit acara" }, { status: 200 }); } catch (error) { return NextResponse.json( { success: false, - message: "Gagal mengedit calender, coba lagi nanti", + message: "Gagal mengedit acara, coba lagi nanti", }, { status: 500 } ); diff --git a/src/app/api/calender/history/route.ts b/src/app/api/calender/history/route.ts index 024bbcf..c86f61f 100644 --- a/src/app/api/calender/history/route.ts +++ b/src/app/api/calender/history/route.ts @@ -80,15 +80,15 @@ export async function GET(request: Request) { } }) - return NextResponse.json({ success: true, message: "Berhasil mendapatkan calender", data: result }, { status: 200 }); + return NextResponse.json({ success: true, message: "Berhasil mendapatkan riwayat acara kalender", data: result }, { status: 200 }); } else { - return NextResponse.json({ success: false, message: "Gagal mendapatkan calender, data tidak ditemukan" }, { status: 404 }); + return NextResponse.json({ success: false, message: "Gagal mendapatkan riwayat acara kalender, coba lagi nanti" }, { status: 404 }); } } catch (error) { console.error(error) - return NextResponse.json({ success: false, message: "Gagal mendapatkan calender, data tidak ditemukan" }, { status: 404 }); + return NextResponse.json({ success: false, message: "Gagal mendapatkan riwayat acara kalender, coba lagi nanti" }, { status: 404 }); } } \ No newline at end of file diff --git a/src/app/api/calender/route.ts b/src/app/api/calender/route.ts index 2ffa030..18fe82c 100644 --- a/src/app/api/calender/route.ts +++ b/src/app/api/calender/route.ts @@ -5,6 +5,7 @@ import _ from "lodash"; import moment from "moment"; import { NextResponse } from "next/server"; import "moment/locale/id"; +import { createLogUser } from '@/module/user'; //GET ALL CALENDER export async function GET(request: Request) { @@ -139,11 +140,13 @@ export async function POST(request: Request) { }); + // create log user + const log = await createLogUser({ act: 'CREATE', desc: 'User membuat data acara kalender', table: 'divisionCalendar', data: data.id }) - return NextResponse.json({ success: true, message: "Berhasil mendapatkan calender" }, { status: 200 }); + return NextResponse.json({ success: true, message: "Berhasil membuat acara kalender" }, { status: 200 }); } catch (error) { console.error(error); - return NextResponse.json({ success: false, message: "Gagal mendapatkan calender, coba lagi nanti", reason: (error as Error).message, }, { status: 500 }); + return NextResponse.json({ success: false, message: "Gagal membuat acara kalender, coba lagi nanti", reason: (error as Error).message, }, { status: 500 }); } } \ No newline at end of file diff --git a/src/module/calender/lib/api_calender.ts b/src/module/calender/lib/api_calender.ts index 77b5e5f..607eaf9 100644 --- a/src/module/calender/lib/api_calender.ts +++ b/src/module/calender/lib/api_calender.ts @@ -58,4 +58,15 @@ export const funAddMemberCalender = async (path: string, data: IFormMemberCalend body: JSON.stringify(data), }); return await response.json().catch(() => null); -}; \ No newline at end of file +}; + +export const funDeleteMemberCalender = async (path: string, data: { idUser: string }) => { + const response = await fetch(`/api/calender/${path}/member`, { + method: "DELETE", + 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/calender/lib/type_calender.ts b/src/module/calender/lib/type_calender.ts index 902b44c..c40200a 100644 --- a/src/module/calender/lib/type_calender.ts +++ b/src/module/calender/lib/type_calender.ts @@ -73,7 +73,7 @@ export interface IEditCalender { linkMeet?: string repeatEventTyper?: string desc?: string, - member?: IFormMemberCalender[] + // member?: IFormMemberCalender[] } export interface IEditMemberCalender { diff --git a/src/module/calender/ui/date_event_division.tsx b/src/module/calender/ui/date_event_division.tsx index d8d688a..f4d5b29 100644 --- a/src/module/calender/ui/date_event_division.tsx +++ b/src/module/calender/ui/date_event_division.tsx @@ -109,7 +109,7 @@ export default function DateEventDivision() { - Event + Acara {loading ? Array(6) @@ -123,7 +123,7 @@ export default function DateEventDivision() { _.isEmpty(isData) ? - Tidak ada event + Tidak ada acara : isData.map((event, index) => { diff --git a/src/module/calender/ui/dawer_division_calender.tsx b/src/module/calender/ui/dawer_division_calender.tsx index 36b46c9..9340caf 100644 --- a/src/module/calender/ui/dawer_division_calender.tsx +++ b/src/module/calender/ui/dawer_division_calender.tsx @@ -18,7 +18,7 @@ export default function DawerDivisionCalender() { - Tambah Kalender + Tambah Acara window.location.href = `/division/${param.id}/calender/history`} justify={'center'} align={'center'} direction={'column'} > diff --git a/src/module/calender/ui/detail_event_division.tsx b/src/module/calender/ui/detail_event_division.tsx index 1db1da6..be4facd 100644 --- a/src/module/calender/ui/detail_event_division.tsx +++ b/src/module/calender/ui/detail_event_division.tsx @@ -10,7 +10,7 @@ import { TbCopy } from 'react-icons/tb'; import { HiMenu } from 'react-icons/hi'; import DrawerDetailEvent from './drawer_detail_event'; import { useParams, useRouter } from 'next/navigation'; -import { funGetOneCalender } from '../lib/api_calender'; +import { funDeleteMemberCalender, funGetOneCalender } from '../lib/api_calender'; import { useShallowEffect } from '@mantine/hooks'; import moment from "moment"; import "moment/locale/id"; @@ -18,6 +18,7 @@ import { IDataDetailByIdCalender, IDataDetailByIdMember } from '../lib/type_cale import SkeletonDetailEvent from './skeleton_detail_event'; import { IoIosCloseCircle } from 'react-icons/io'; import LayoutModal from '@/module/_global/layout/layout_modal'; +import toast from 'react-hot-toast'; export default function DetailEventDivision() { const param = useParams<{ id: string, detail: string }>() @@ -29,6 +30,7 @@ export default function DetailEventDivision() { const [openDrawerUser, setOpenDrawerUser] = useState(false) const [isOpenModal, setOpenModal] = useState(false) const router = useRouter() + const [dataChoose, setDataChoose] = useState({ id: '', name: '' }) const getData = async () => { @@ -50,9 +52,27 @@ export default function DetailEventDivision() { getData() }, []) + async function onSubmit() { + try { + const res = await funDeleteMemberCalender(param.detail, { idUser: dataChoose.id }); + if (res.success) { + toast.success(res.message) + setDataChoose({ id: '', name: '' }) + getData() + setOpenDrawer(false) + setOpenDrawerUser(false) + } else { + toast.error(res.message) + } + } catch (error) { + console.error(error); + toast.error("Gagal mengeluarkan anggota, coba lagi nanti"); + } + } + return ( - setOpenDrawer(true)} bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Settings"> } /> @@ -242,7 +262,10 @@ export default function DetailEventDivision() { { isDataAnggota.map((v, i) => { return ( - setOpenDrawerUser(true)} key={i}> + { + setDataChoose({ id: v.idUser, name: v.name }) + setOpenDrawerUser(true) + }} key={i}> Menu} onClose={() => setOpenDrawerUser(false)}> + {dataChoose.name}} onClose={() => setOpenDrawerUser(false)}> { router.push('/member/' + ) }} + onClick={() => { router.push('/member/' + dataChoose.id) }} justify={'center'} align={'center'} direction={'column'} > @@ -317,7 +340,7 @@ export default function DetailEventDivision() { description="Apakah Anda yakin ingin mengeluarkan anggota?" onYes={(val) => { if (val) { - // onSubmit() + onSubmit() } setOpenModal(false) }} /> diff --git a/src/module/calender/ui/drawer_detail_event.tsx b/src/module/calender/ui/drawer_detail_event.tsx index d5b4903..6779fd7 100644 --- a/src/module/calender/ui/drawer_detail_event.tsx +++ b/src/module/calender/ui/drawer_detail_event.tsx @@ -49,7 +49,7 @@ export default function DrawerDetailEvent() { - Hapus + Hapus Acara router.push(`/division/${param.id}/calender/update/${param.detail}`)} justify={'center'} align={'center'} direction={'column'} > @@ -57,7 +57,7 @@ export default function DrawerDetailEvent() { - Edit Kalender + Edit Acara router.push(`/division/${param.id}/calender/${param.detail}/add-member`)} justify={'center'} align={'center'} direction={'column'} > diff --git a/src/module/calender/ui/navbar_division_calender.tsx b/src/module/calender/ui/navbar_division_calender.tsx index fc9cd18..9cc6272 100644 --- a/src/module/calender/ui/navbar_division_calender.tsx +++ b/src/module/calender/ui/navbar_division_calender.tsx @@ -12,7 +12,7 @@ export default function NavbarDivisionCalender() { const param = useParams<{ id: string }>() return (
- setOpenDrawer(true)} bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Settings"> diff --git a/src/module/calender/ui/update_division_calender.tsx b/src/module/calender/ui/update_division_calender.tsx index f0015a9..450c575 100644 --- a/src/module/calender/ui/update_division_calender.tsx +++ b/src/module/calender/ui/update_division_calender.tsx @@ -19,8 +19,8 @@ import UpdateListUsers from './update_list_users'; export default function UpdateDivisionCalender() { const [isModal, setModal] = useState(false) const param = useParams<{ id: string, detail: string }>() - const memberUser = useHookstate(globalCalender) - const memberValue = memberUser.get() as IFormMemberCalender[] + // const memberUser = useHookstate(globalCalender) + // const memberValue = memberUser.get() as IFormMemberCalender[] const [isDataCalender, setDataCalender] = useState() const [openMember, setOpenMember] = useState(false) const [loading, setLoading] = useState(true) @@ -38,7 +38,7 @@ export default function UpdateDivisionCalender() { setLoading(true) const response = await funGetOneCalender(param.detail) setDataCalender(response.data.calender) - memberUser.set(response.data.member) + // memberUser.set(response.data.member) } catch (error) { console.error(error) } finally { @@ -63,7 +63,7 @@ export default function UpdateDivisionCalender() { linkMeet: isDataCalender?.linkMeet, repeatEventTyper: isDataCalender?.repeatEventTyper, desc: isDataCalender?.desc, - member: memberValue + // member: memberValue }) if (response.success) { @@ -88,12 +88,11 @@ export default function UpdateDivisionCalender() { return ( - + {loading ? <> - @@ -102,7 +101,6 @@ export default function UpdateDivisionCalender() { - : <> @@ -114,8 +112,8 @@ export default function UpdateDivisionCalender() { }, }} size="md" - placeholder="Event Nama" - label="Event Nama" + placeholder="Acara" + label="Acara" defaultValue={isDataCalender?.title} onChange={ (event) => { @@ -250,8 +248,8 @@ export default function UpdateDivisionCalender() { }, }} size="md" - placeholder="Ulangi Event" - label="Ulangi Event" + placeholder="Ulangi Acara" + label="Ulangi Acara" data={[ { value: '1', label: 'Acara 1 Kali' }, { value: '2', label: 'Hari Kerja (Sen - Jum)' }, @@ -273,7 +271,7 @@ export default function UpdateDivisionCalender() { onBlur={() => setTouched({ ...touched, repeatEventTyper: true })} error={ touched.repeatEventTyper && ( - isDataCalender?.repeatEventTyper == "" ? "Ulangi Event Tidak Boleh Kosong" : null + isDataCalender?.repeatEventTyper == "" ? "Ulangi Acara Tidak Boleh Kosong" : null ) } required @@ -379,7 +377,7 @@ export default function UpdateDivisionCalender() { } setModal(false)} - description="Apakah Anda yakin ingin menambahkan data?" + description="Apakah Anda yakin ingin mengubah data?" onYes={(val) => { onSubmit(val) }} /> ); From 789fda0b02b561a5086049702c0f4065cb92c3a6 Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 9 Sep 2024 11:03:22 +0800 Subject: [PATCH 2/3] upd: calender Deskripsi; - update judul No Issues --- src/module/calender/ui/history_division_calender.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/calender/ui/history_division_calender.tsx b/src/module/calender/ui/history_division_calender.tsx index 5ef1bfe..ac560a2 100644 --- a/src/module/calender/ui/history_division_calender.tsx +++ b/src/module/calender/ui/history_division_calender.tsx @@ -37,7 +37,7 @@ export default function HistoryDivisionCalender() { }, [searchQuery]) return ( - + Date: Mon, 9 Sep 2024 16:34:38 +0800 Subject: [PATCH 3/3] upd: calender Deskripsi: - repeat pengulangan - install new package - tambah field table - ubah semua api mengikuti struktur tb baru No Issues --- package.json | 1 + prisma/schema.prisma | 5 +- src/app/api/calender/[id]/member/route.ts | 66 +++++++++ src/app/api/calender/[id]/route.ts | 87 +++++++++--- src/app/api/calender/history/route.ts | 22 ++- src/app/api/calender/indicator/route.ts | 5 +- src/app/api/calender/route.ts | 68 +++++++--- src/module/calender/lib/api_calender.ts | 5 + src/module/calender/lib/type_calender.ts | 6 + .../ui/create_user_detail_calender.tsx | 6 +- .../calender/ui/detail_event_division.tsx | 15 ++- .../calender/ui/drawer_detail_event.tsx | 14 +- .../ui/navbar_create_division_calender.tsx | 53 ++++++-- .../calender/ui/update_division_calender.tsx | 125 +++++++----------- yarn.lock | 7 + 15 files changed, 330 insertions(+), 155 deletions(-) diff --git a/package.json b/package.json index 809fc22..8ce3ce0 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "react-simple-toasts": "^5.10.0", "readdirp": "^3.6.0", "recharts": "2", + "rrule": "^2.8.1", "yargs": "^17.7.2" }, "devDependencies": { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 127e0dc..84cc75f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -397,7 +397,8 @@ model DivisionCalendar { dateEnd DateTime? @db.Date timeStart DateTime @db.Time() timeEnd DateTime @db.Time() - repeatEventTyper String // 1 = Acara 1 Kali, 2 = hari Kerja (senin - jumat), 3 = Minggu, 4 = Bulanan, 5 = Tahunan + repeatEventTyper String // once = Acara 1 Kali, weekdays = hari Kerja (senin - jumat), daily=setiap hari , weekly = setiap minggu, monthly = setiap bulan, yearly = setiap tahun + repeatValue Int @default(1) reminderInterval String? status Int @default(0) isActive Boolean @default(true) @@ -415,7 +416,7 @@ model DivisionCalendarReminder { DivisionCalendar DivisionCalendar @relation(fields: [idCalendar], references: [id]) idCalendar String dateStart DateTime @db.Date - dateEnd DateTime @db.Date + dateEnd DateTime? @db.Date timeStart DateTime @db.Time() timeEnd DateTime @db.Time() status Int @default(0) diff --git a/src/app/api/calender/[id]/member/route.ts b/src/app/api/calender/[id]/member/route.ts index 1bb833b..2fe8cc8 100644 --- a/src/app/api/calender/[id]/member/route.ts +++ b/src/app/api/calender/[id]/member/route.ts @@ -2,8 +2,74 @@ import { prisma } from "@/module/_global"; import { funGetUserByCookies } from "@/module/auth"; import { createLogUser } from "@/module/user"; import _ from "lodash"; +import moment from "moment"; import { NextResponse } from "next/server"; + +// GET ONE DATA KALENDER BY ID KALENDER +export async function GET(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 mendapatkan calender, data tidak ditemukan", + }, + { status: 404 } + ); + } + + const data = await prisma.divisionCalendar.findUnique({ + where: { + id: id + }, + select: { + id: true, + title: true, + desc: true, + timeStart: true, + dateStart: true, + timeEnd: true, + createdAt: true, + linkMeet: true, + repeatValue: true, + repeatEventTyper: true, + } + }); + + const { ...dataCalender } = data + const timeStart = moment.utc(dataCalender?.timeStart).format("HH:mm") + const timeEnd = moment.utc(dataCalender?.timeEnd).format("HH:mm") + + const result = { ...dataCalender, timeStart, timeEnd } + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan calender", data: result }, { status: 200 }); + + } catch (error) { + return NextResponse.json( + { + success: false, + message: "Gagal mendapatkan calender, data tidak ditemukan", + }, + { status: 404 } + ); + } +} + + // TAMBAH MEMBER KALENDER export async function POST(request: Request, context: { params: { id: string } }) { try { diff --git a/src/app/api/calender/[id]/route.ts b/src/app/api/calender/[id]/route.ts index 76f740a..96c2d97 100644 --- a/src/app/api/calender/[id]/route.ts +++ b/src/app/api/calender/[id]/route.ts @@ -1,11 +1,12 @@ import { prisma } from "@/module/_global"; import { funGetUserByCookies } from "@/module/auth"; import { createLogUser } from "@/module/user"; -import _ from "lodash"; +import _, { remove } from "lodash"; import moment from "moment"; import { NextResponse } from "next/server"; +import { Frequency, RRule } from 'rrule'; -// GET ONE CALENDER +// GET ONE CALENDER BY ID KALENDER REMINDER export async function GET(request: Request, context: { params: { id: string } }) { try { const user = await funGetUserByCookies() @@ -15,7 +16,7 @@ export async function GET(request: Request, context: { params: { id: string } }) const { id } = context.params - const cek = await prisma.divisionCalendar.count({ + const cek = await prisma.divisionCalendarReminder.count({ where: { id: id } @@ -25,39 +26,51 @@ export async function GET(request: Request, context: { params: { id: string } }) return NextResponse.json( { success: false, - message: "Gagal mendapatkan calender, data tidak ditemukan", + message: "Gagal mendapatkan acara, data tidak ditemukan", }, { status: 404 } ); } - const data = await prisma.divisionCalendar.findUnique({ + const data: any = await prisma.divisionCalendarReminder.findUnique({ where: { id: id }, select: { id: true, - title: true, - desc: true, timeStart: true, dateStart: true, timeEnd: true, createdAt: true, - linkMeet: true, - repeatEventTyper: true, + DivisionCalendar: { + select: { + id: true, + title: true, + desc: true, + linkMeet: true, + repeatEventTyper: true, + repeatValue: true, + } + } } }); - - const { ...dataCalender } = data + const { DivisionCalendar, ...dataCalender } = data const timeStart = moment.utc(dataCalender?.timeStart).format("HH:mm") const timeEnd = moment.utc(dataCalender?.timeEnd).format("HH:mm") + const idCalendar = data?.DivisionCalendar.id + const title = data?.DivisionCalendar?.title + const desc = data?.DivisionCalendar?.desc + const linkMeet = data?.DivisionCalendar?.linkMeet + const repeatEventTyper = data?.DivisionCalendar?.repeatEventTyper + const repeatValue = data?.DivisionCalendar?.repeatValue - const result = { ...dataCalender, timeStart, timeEnd } + + const result = { ...dataCalender, timeStart, timeEnd, idCalendar, title, desc, linkMeet, repeatEventTyper, repeatValue } const member = await prisma.divisionCalendarMember.findMany({ where: { - idCalendar: id + idCalendar: data?.DivisionCalendar.id }, select: { id: true, @@ -120,7 +133,7 @@ export async function DELETE(request: Request, context: { params: { id: string } return NextResponse.json( { success: false, - message: "Gagal menghapus calender, data tidak ditemukan", + message: "Gagal menghapus acara kalender, data tidak ditemukan", }, { status: 404 } ); @@ -138,7 +151,7 @@ export async function DELETE(request: Request, context: { params: { id: string } // create log user const log = await createLogUser({ act: 'DELETE', desc: 'User menghapus data acara kalender', table: 'divisionCalendar', data: id }) - return NextResponse.json({ success: true, message: "Berhasil menghapus calender", data }, { status: 200 }); + return NextResponse.json({ success: true, message: "Berhasil menghapus acara kalender", data }, { status: 200 }); } catch (error) { return NextResponse.json( @@ -151,7 +164,7 @@ export async function DELETE(request: Request, context: { params: { id: string } } } -// EDIT CALENDER BY ID +// EDIT CALENDER BY IDKALENDER export async function PUT(request: Request, context: { params: { id: string } }) { try { @@ -162,7 +175,7 @@ export async function PUT(request: Request, context: { params: { id: string } }) const { id } = context.params const userId = user.id - const { title, desc, timeStart, dateStart, timeEnd, linkMeet, repeatEventTyper } = await request.json() + const { title, desc, timeStart, dateStart, timeEnd, linkMeet, repeatEventTyper, repeatValue } = await request.json() const cek = await prisma.divisionCalendar.count({ where: { @@ -198,10 +211,48 @@ export async function PUT(request: Request, context: { params: { id: string } }) timeEnd: timeEndFix, linkMeet: linkMeet, repeatEventTyper: repeatEventTyper, - status: statusCalender + status: statusCalender, + repeatValue: Number(repeatValue) + }, + select: { + idDivision: true } }); + const freq: Frequency = repeatEventTyper === "yearly" ? RRule.YEARLY : + repeatEventTyper === "monthly" ? RRule.MONTHLY : + repeatEventTyper === "weekly" ? RRule.WEEKLY : + repeatEventTyper === "daily" ? RRule.DAILY : + repeatEventTyper === "hourly" ? RRule.HOURLY : + repeatEventTyper === "minutely" ? RRule.MINUTELY : + RRule.SECONDLY; + + const rule = new RRule({ + freq, + interval: 1, + dtstart: new Date(dateStart), + count: repeatValue + }); + + const hasil = rule.all().map(recurrenceDate => ({ + idDivision: data.idDivision, + idCalendar: id, + dateStart: recurrenceDate, + timeStart: timeStartFix, + timeEnd: timeEndFix, + dateEnd: recurrenceDate + })); + + const deleteReminder = await prisma.divisionCalendarReminder.deleteMany({ + where: { + idCalendar: id + } + }) + + const insertReminder = await prisma.divisionCalendarReminder.createMany({ + data: hasil + }) + // create log user const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate data acara kalender', table: 'divisionCalendar', data: id }) diff --git a/src/app/api/calender/history/route.ts b/src/app/api/calender/history/route.ts index c86f61f..40ce2d1 100644 --- a/src/app/api/calender/history/route.ts +++ b/src/app/api/calender/history/route.ts @@ -29,21 +29,29 @@ export async function GET(request: Request) { return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 404 }); } - const data = await prisma.divisionCalendar.findMany({ + const data = await prisma.divisionCalendarReminder.findMany({ where: { isActive: true, idDivision: idDivision, - title: { - contains: (name == undefined || name == "null") ? "" : name, - mode: "insensitive" + DivisionCalendar: { + title: { + contains: (name == undefined || name == "null") ? "" : name, + mode: "insensitive" + }, + isActive: true } + }, select: { id: true, - title: true, timeStart: true, dateStart: true, timeEnd: true, + DivisionCalendar: { + select: { + title: true, + } + } }, orderBy: [ { @@ -59,8 +67,8 @@ export async function GET(request: Request) { }); const allOmit = data.map((v: any) => ({ - ..._.omit(v, [""]), - dateStart: v.dateStart, + ..._.omit(v, ["DivisionCalendar"]), + title: v.DivisionCalendar.title })) // groupBy untuk dateStart diff --git a/src/app/api/calender/indicator/route.ts b/src/app/api/calender/indicator/route.ts index 317ba45..bc85d13 100644 --- a/src/app/api/calender/indicator/route.ts +++ b/src/app/api/calender/indicator/route.ts @@ -31,13 +31,16 @@ export async function GET(request: Request) { return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 404 }); } - const data = await prisma.divisionCalendar.findMany({ + const data = await prisma.divisionCalendarReminder.findMany({ where: { isActive: true, idDivision: String(idDivision), dateStart: { gte: new Date(awalDate), lte: new Date(akhirDate), + }, + DivisionCalendar: { + isActive: true } } }) diff --git a/src/app/api/calender/route.ts b/src/app/api/calender/route.ts index 18fe82c..0f0210e 100644 --- a/src/app/api/calender/route.ts +++ b/src/app/api/calender/route.ts @@ -1,4 +1,3 @@ -import { User } from './../../../module/discussion/lib/type_discussion'; import { prisma } from "@/module/_global"; import { funGetUserByCookies } from "@/module/auth"; import _ from "lodash"; @@ -6,6 +5,7 @@ import moment from "moment"; import { NextResponse } from "next/server"; import "moment/locale/id"; import { createLogUser } from '@/module/user'; +import { Frequency, RRule } from 'rrule'; //GET ALL CALENDER export async function GET(request: Request) { @@ -32,25 +32,33 @@ export async function GET(request: Request) { return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 404 }); } - const data = await prisma.divisionCalendar.findMany({ + const data = await prisma.divisionCalendarReminder.findMany({ where: { isActive: true, idDivision: idDivision, - dateStart: new Date(String(isDate)) + dateStart: new Date(String(isDate)), + DivisionCalendar:{ + isActive: true + } }, select: { id: true, - title: true, - desc: true, - status: true, + idCalendar: true, timeStart: true, dateStart: true, timeEnd: true, dateEnd: true, createdAt: true, - User: { + status: true, + DivisionCalendar: { select: { - name: true + title: true, + desc: true, + User: { + select: { + name: true + } + } } } }, @@ -60,8 +68,10 @@ export async function GET(request: Request) { }); const allOmit = data.map((v: any) => ({ - ..._.omit(v, ["User"]), - user_name: v.User.name, + ..._.omit(v, ["DivisionCalendar", "User"]), + title: v.DivisionCalendar.title, + desc: v.DivisionCalendar.desc, + user_name: v.DivisionCalendar.User.name, timeStart: moment.utc(v.timeStart).format('HH:mm'), timeEnd: moment.utc(v.timeEnd).format('HH:mm') })) @@ -88,7 +98,7 @@ 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, repeatEventTyper, member, linkMeet } = (await request.json()); + const { idDivision, title, desc, timeStart, timeEnd, dateStart, dateEnd, repeatEventTyper, member, linkMeet, repeatValue } = (await request.json()); const userId = user.id @@ -103,8 +113,6 @@ export async function POST(request: Request) { return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { 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() @@ -121,16 +129,44 @@ export async function POST(request: Request) { linkMeet, repeatEventTyper, desc, - status: statusCalender + repeatValue: Number(repeatValue) }, select: { id: true, - } }); + + const freq: Frequency = repeatEventTyper === "yearly" ? RRule.YEARLY : + repeatEventTyper === "monthly" ? RRule.MONTHLY : + repeatEventTyper === "weekly" ? RRule.WEEKLY : + repeatEventTyper === "daily" ? RRule.DAILY : + repeatEventTyper === "hourly" ? RRule.HOURLY : + repeatEventTyper === "minutely" ? RRule.MINUTELY : + RRule.SECONDLY; + + const rule = new RRule({ + freq, + interval: 1, + dtstart: new Date(dateStart), + count: repeatValue + }); + + const hasil = rule.all().map(recurrenceDate => ({ + idDivision: idDivision, + idCalendar: data.id, + dateStart: recurrenceDate, + timeStart: timeStartFix, + timeEnd: timeEndFix, + dateEnd: recurrenceDate + })); + + const insertReminder = await prisma.divisionCalendarReminder.createMany({ + data: hasil + }) + const omitMember = member.map((v: any) => ({ - ..._.omit(v, ["name", "idUser"]), + ..._.omit(v, ["name", "idUser", "img"]), idCalendar: data.id, idUser: v.idUser })) diff --git a/src/module/calender/lib/api_calender.ts b/src/module/calender/lib/api_calender.ts index 607eaf9..92786d1 100644 --- a/src/module/calender/lib/api_calender.ts +++ b/src/module/calender/lib/api_calender.ts @@ -14,6 +14,11 @@ export const funGetOneCalender = async (path: string) => { return await response.json().catch(() => null); } +export const funGetOneCalenderByIdCalendar = async (path: string) => { + const response = await fetch(`/api/calender/${path}/member`); + return await response.json().catch(() => null); +} + export const funCreateCalender = async (data: IFormCreateCalender) => { const response = await fetch("/api/calender", { method: "POST", diff --git a/src/module/calender/lib/type_calender.ts b/src/module/calender/lib/type_calender.ts index c40200a..0495bc6 100644 --- a/src/module/calender/lib/type_calender.ts +++ b/src/module/calender/lib/type_calender.ts @@ -1,5 +1,6 @@ export interface IDataCalender { id: string + idCalendar: string title: string desc: string status: number @@ -23,6 +24,7 @@ export interface IHistoryCalender { export interface IDataDetailByIdCalender { id: string + idCalendar: string title: string desc: string timeStart: string @@ -31,6 +33,7 @@ export interface IDataDetailByIdCalender { createdAt: string linkMeet: string repeatEventTyper: string + repeatValue: string } export interface IDataDetailByIdMember { id: string @@ -49,6 +52,7 @@ export interface IFormCreateCalender { linkMeet: string repeatEventTyper: string desc: string, + repeatValue: string, member: IFormMemberCalender[] } @@ -73,6 +77,7 @@ export interface IEditCalender { linkMeet?: string repeatEventTyper?: string desc?: string, + repeatValue?: string // member?: IFormMemberCalender[] } @@ -93,6 +98,7 @@ export interface IDetailByIdCalender { createdAt?: string linkMeet?: string repeatEventTyper?: string + repeatValue?: string } export interface IFormMemberCalenderNew { diff --git a/src/module/calender/ui/create_user_detail_calender.tsx b/src/module/calender/ui/create_user_detail_calender.tsx index e577416..bee93d1 100644 --- a/src/module/calender/ui/create_user_detail_calender.tsx +++ b/src/module/calender/ui/create_user_detail_calender.tsx @@ -11,12 +11,13 @@ import { HiMagnifyingGlass } from 'react-icons/hi2'; import { IoArrowBackOutline, IoClose } from 'react-icons/io5'; import { Carousel } from '@mantine/carousel'; import { funAddMemberCalender, funGetOneCalender } from '../lib/api_calender'; -import { IDataDetailByIdMember } from '../lib/type_calender'; +import { IDataDetailByIdCalender, IDataDetailByIdMember } from '../lib/type_calender'; export default function CreateUserDetailCalender() { const router = useRouter() const param = useParams<{ id: string, detail: string }>() const [selectedFiles, setSelectedFiles] = useState([]) + const [isDataCalender, setDataCalender] = useState() const [isData, setData] = useState([]) const [isDataAnggota, setDataAnggota] = useState([]) const [selectAll, setSelectAll] = useState(false) @@ -30,6 +31,7 @@ export default function CreateUserDetailCalender() { const response = await funGetSearchMemberDivision("?search=", param.id) const res = await funGetOneCalender(param.detail) if (response.success) { + setDataCalender(res.data.calender) setDataAnggota(res.data.member) setData(response.data) setLoading(false) @@ -84,7 +86,7 @@ export default function CreateUserDetailCalender() { return toast.error("Error! silahkan pilih anggota") } - const res = await funAddMemberCalender(param.detail, selectedFiles) + const res = await funAddMemberCalender(String(isDataCalender?.idCalendar), selectedFiles) if (res.success) { toast.success(res.message) router.push('./') diff --git a/src/module/calender/ui/detail_event_division.tsx b/src/module/calender/ui/detail_event_division.tsx index be4facd..f270de3 100644 --- a/src/module/calender/ui/detail_event_division.tsx +++ b/src/module/calender/ui/detail_event_division.tsx @@ -54,7 +54,7 @@ export default function DetailEventDivision() { async function onSubmit() { try { - const res = await funDeleteMemberCalender(param.detail, { idUser: dataChoose.id }); + const res = await funDeleteMemberCalender(String(isDataCalender?.idCalendar), { idUser: dataChoose.id }); if (res.success) { toast.success(res.message) setDataChoose({ id: '', name: '' }) @@ -141,11 +141,12 @@ export default function DetailEventDivision() { xl: 11 }}> - {isDataCalender?.repeatEventTyper.toString() === '1' ? 'Acara 1 Kali' : - isDataCalender?.repeatEventTyper.toString() === '2' ? 'Hari Kerja (senin - jumat)' : - isDataCalender?.repeatEventTyper.toString() === '3' ? 'Minggu' : - isDataCalender?.repeatEventTyper.toString() === '4' ? 'Bulanan' : - isDataCalender?.repeatEventTyper.toString() === '5' ? 'Tahunan' : + {isDataCalender?.repeatEventTyper.toString() === 'once' ? 'Acara 1 Kali' : + isDataCalender?.repeatEventTyper.toString() === 'daily' ? 'Setiap Hari' : + // isDataCalender?.repeatEventTyper.toString() === 'weekdays' ? 'Hari Kerja (senin - jumat)' : + isDataCalender?.repeatEventTyper.toString() === 'weekly' ? 'Mingguan' : + isDataCalender?.repeatEventTyper.toString() === 'monthly' ? 'Bulanan' : + isDataCalender?.repeatEventTyper.toString() === 'yearly' ? 'Tahunan' : ''} @@ -345,7 +346,7 @@ export default function DetailEventDivision() { setOpenModal(false) }} /> setOpenDrawer(false)}> - + ); diff --git a/src/module/calender/ui/drawer_detail_event.tsx b/src/module/calender/ui/drawer_detail_event.tsx index 6779fd7..1797754 100644 --- a/src/module/calender/ui/drawer_detail_event.tsx +++ b/src/module/calender/ui/drawer_detail_event.tsx @@ -5,13 +5,11 @@ import { Box, Flex, SimpleGrid, Stack, Text } from '@mantine/core'; 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'; import { FaUsers } from 'react-icons/fa6'; -export default function DrawerDetailEvent() { +export default function DrawerDetailEvent({ idCalendar }: { idCalendar: string }) { const router = useRouter() const [isModal, setModal] = useState(false) const param = useParams<{ id: string, detail: string }>() @@ -19,9 +17,7 @@ export default function DrawerDetailEvent() { async function fetchDeleteCalender(val: boolean) { try { if (val) { - const response = await funDeleteCalenderById( - param.detail - ) + const response = await funDeleteCalenderById(idCalendar) if (response.success) { toast.success(response.message) setModal(false) @@ -34,7 +30,7 @@ export default function DrawerDetailEvent() { } catch (error) { console.error(error); setModal(false) - toast.error("Gagal hapus calender, coba lagi nanti"); + toast.error("Gagal hapus acara, coba lagi nanti"); } } @@ -52,7 +48,7 @@ export default function DrawerDetailEvent() { Hapus Acara - router.push(`/division/${param.id}/calender/update/${param.detail}`)} justify={'center'} align={'center'} direction={'column'} > + router.push(`/division/${param.id}/calender/update/${idCalendar}`)} justify={'center'} align={'center'} direction={'column'} > @@ -71,7 +67,7 @@ export default function DrawerDetailEvent() { setModal(false)} - description="Apakah Anda yakin ingin menghapus data?" + description="Apakah Anda yakin ingin menghapus data acara ini? Data ini akan mempengaruhi semua data yang terkait" 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 115549f..0ab122e 100644 --- a/src/module/calender/ui/navbar_create_division_calender.tsx +++ b/src/module/calender/ui/navbar_create_division_calender.tsx @@ -1,6 +1,6 @@ "use client" import { LayoutNavbarNew, WARNA } from '@/module/_global'; -import { Avatar, Box, Button, Divider, Flex, Grid, Group, Input, rem, Select, SimpleGrid, Stack, Text, Textarea, TextInput } from '@mantine/core'; +import { Avatar, Box, Button, Divider, Flex, Grid, Group, Input, NumberInput, rem, Select, 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'; @@ -28,7 +28,8 @@ export default function NavbarCreateDivisionCalender() { timeStart: false, timeEnd: false, repeatEventTyper: false, - desc: false + desc: false, + repeatValue: false }) const [isData, setData] = useState({ idDivision: "", @@ -39,6 +40,7 @@ export default function NavbarCreateDivisionCalender() { linkMeet: "", repeatEventTyper: "", desc: "", + repeatValue: "1" }) async function onSubmit(val: boolean) { @@ -56,6 +58,7 @@ export default function NavbarCreateDivisionCalender() { linkMeet: isData.linkMeet, repeatEventTyper: isData.repeatEventTyper, desc: isData.desc, + repeatValue: isData.repeatValue, member: memberValue }) @@ -80,10 +83,9 @@ export default function NavbarCreateDivisionCalender() { if (openMember) return setOpenMember(false)} /> - return ( - + { @@ -216,7 +219,31 @@ export default function NavbarCreateDivisionCalender() { onBlur={() => setTouched({ ...touched, repeatEventTyper: true })} error={ touched.repeatEventTyper && ( - isData.repeatEventTyper == "" ? "Ulangi Event Tidak Boleh Kosong" : null + isData.repeatEventTyper == "" ? "Ulangi Acara Tidak Boleh Kosong" : null + ) + } + /> + { + setData({ ...isData, repeatValue: String(event.currentTarget.value) }) + setTouched({ ...touched, repeatValue: false }) + }} + onBlur={() => setTouched({ ...touched, repeatValue: true })} + error={ + touched.repeatValue && ( + isData.repeatValue == "" ? "Jumlah pengulangan tidak boleh kosong" : null || + Number(isData.repeatValue) <= 0 ? "Jumlah pengulangan tidak boleh 0" : null ) } /> @@ -286,7 +313,7 @@ export default function NavbarCreateDivisionCalender() { - Anggota + Anggota diff --git a/src/module/calender/ui/update_division_calender.tsx b/src/module/calender/ui/update_division_calender.tsx index 450c575..11bb57c 100644 --- a/src/module/calender/ui/update_division_calender.tsx +++ b/src/module/calender/ui/update_division_calender.tsx @@ -1,26 +1,21 @@ "use client" import { LayoutNavbarNew, WARNA } from '@/module/_global'; -import { Avatar, Box, Button, Divider, Flex, Grid, Group, Input, rem, Select, SimpleGrid, Skeleton, Stack, Text, Textarea, TextInput } from '@mantine/core'; +import { Box, Button, Group, rem, Select, SimpleGrid, Skeleton, 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 { useParams, useRouter } from 'next/navigation'; import LayoutModal from '@/module/_global/layout/layout_modal'; import toast from 'react-hot-toast'; -import { funEditCalenderById, funGetOneCalender } from '../lib/api_calender'; +import { funEditCalenderById, funGetOneCalender, funGetOneCalenderByIdCalendar, } from '../lib/api_calender'; import { useShallowEffect } from '@mantine/hooks'; -import { IDataDetailByIdCalender, IDataDetailByIdMember, IDetailByIdCalender, IEditMemberCalender, IFormMemberCalender } from '../lib/type_calender'; +import { IDetailByIdCalender } from '../lib/type_calender'; import moment from 'moment'; import "moment/locale/id"; -import { useHookstate } from '@hookstate/core'; -import { globalCalender } from '../lib/val_calender'; import UpdateListUsers from './update_list_users'; export default function UpdateDivisionCalender() { const [isModal, setModal] = useState(false) const param = useParams<{ id: string, detail: string }>() - // const memberUser = useHookstate(globalCalender) - // const memberValue = memberUser.get() as IFormMemberCalender[] const [isDataCalender, setDataCalender] = useState() const [openMember, setOpenMember] = useState(false) const [loading, setLoading] = useState(true) @@ -30,17 +25,22 @@ export default function UpdateDivisionCalender() { timeStart: false, timeEnd: false, repeatEventTyper: false, - desc: false + desc: false, + repeatValue: false }) const fetchGetOne = async () => { try { setLoading(true) - const response = await funGetOneCalender(param.detail) - setDataCalender(response.data.calender) - // memberUser.set(response.data.member) + const response = await funGetOneCalenderByIdCalendar(param.detail) + if (response.success) { + setDataCalender(response.data) + } else { + toast.error(response.message) + } } catch (error) { console.error(error) + toast.error("Terjadi kesalahan! Silahkan coba kembali"); } finally { setLoading(false) } @@ -63,7 +63,7 @@ export default function UpdateDivisionCalender() { linkMeet: isDataCalender?.linkMeet, repeatEventTyper: isDataCalender?.repeatEventTyper, desc: isDataCalender?.desc, - // member: memberValue + repeatValue: isDataCalender?.repeatValue }) if (response.success) { @@ -88,7 +88,7 @@ export default function UpdateDivisionCalender() { return ( - + {loading ? @@ -229,7 +229,6 @@ export default function UpdateDivisionCalender() { size="md" placeholder="Link Meet" label="Link Meet" - // value={isDataCalender?.linkMeet} defaultValue={isDataCalender?.linkMeet} onChange={ (event) => { @@ -251,11 +250,12 @@ export default function UpdateDivisionCalender() { placeholder="Ulangi Acara" label="Ulangi Acara" data={[ - { value: '1', label: 'Acara 1 Kali' }, - { value: '2', label: 'Hari Kerja (Sen - Jum)' }, - { value: '3', label: 'Mingguan' }, - { value: '4', label: 'Bulanan' }, - { value: '5', label: 'Tahunan' }, + { value: 'once', label: 'Acara 1 Kali' }, + { value: 'daily', label: 'Setiap Hari' }, + // { value: 'weekdays', label: 'Hari Kerja (Sen - Jum)' }, + { value: 'weekly', label: 'Mingguan' }, + { value: 'monthly', label: 'Bulanan' }, + { value: 'yearly', label: 'Tahunan' }, ]} value={isDataCalender?.repeatEventTyper} defaultValue={isDataCalender?.repeatEventTyper} @@ -276,6 +276,30 @@ export default function UpdateDivisionCalender() { } required /> + { + setDataCalender({ ...isDataCalender, repeatValue: String(event.currentTarget.value) }) + setTouched({ ...touched, repeatValue: false }) + }} + onBlur={() => setTouched({ ...touched, repeatValue: true })} + error={ + touched.repeatValue && ( + isDataCalender?.repeatValue == "" ? "Jumlah pengulangan tidak boleh kosong" : null || + Number(isDataCalender?.repeatValue) <= 0 ? "Jumlah pengulangan tidak boleh dibawah 1" : null + ) + } + />