Merge pull request #128 from bipproduction/amalia/19-agustus-24

Amalia/19 agustus 24
This commit is contained in:
Amalia
2024-08-19 17:41:32 +08:00
committed by GitHub
17 changed files with 910 additions and 12 deletions

View File

@@ -257,7 +257,8 @@ model DivisionProject {
Division Division @relation(fields: [idDivision], references: [id])
idDivision String
title String
desc String @db.Text
desc String? @db.Text
reason String? @db.Text
status Int @default(0) // 0 = pending, 1 = ongoing, 2 = done, 3 = cancelled
isActive Boolean @default(true)
createdAt DateTime @default(now())

View File

@@ -0,0 +1,9 @@
import { AddMemberDetailTask } from "@/module/task"
function Page() {
return (
<AddMemberDetailTask />
)
}
export default Page

View File

@@ -0,0 +1,9 @@
import { AddDetailTask } from "@/module/task"
function Page() {
return (
<AddDetailTask />
)
}
export default Page

View File

@@ -0,0 +1,9 @@
import { CancelTask } from "@/module/task"
function Page() {
return (
<CancelTask />
)
}
export default Page

View File

@@ -0,0 +1,9 @@
import { EditTask } from "@/module/task"
function Page() {
return (
<EditTask />
)
}
export default Page

View File

@@ -0,0 +1,61 @@
import { prisma } from "@/module/_global";
import { funGetUserByCookies } from "@/module/auth";
import _ from "lodash";
import moment from "moment";
import { NextResponse } from "next/server";
// ADD MEMBER TASK DIVISI
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 { member, idDivision } = (await request.json());
const data = await prisma.divisionProject.count({
where: {
id: id,
},
});
console.log(member, idDivision)
if (data == 0) {
return NextResponse.json(
{
success: false,
message: "Tambah anggota tugas gagal, data tugas tidak ditemukan",
},
{ status: 404 }
);
}
if (member.length > 0) {
const dataMember = member.map((v: any) => ({
..._.omit(v, ["idUser", "name"]),
idDivision: idDivision,
idProject: id,
idUser: v.idUser,
}))
const insertMember = await prisma.divisionProjectMember.createMany({
data: dataMember
})
}
return NextResponse.json(
{
success: true,
message: "Berhasil menambahkan anggota tugas",
},
{ status: 200 }
);
} catch (error) {
console.log(error);
return NextResponse.json({ success: false, message: "Gagal menambah anggota tugas, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -108,6 +108,7 @@ export async function GET(request: Request, context: { params: { id: string } })
},
select: {
id: true,
idUser: true,
User: {
select: {
name: true,
@@ -134,4 +135,156 @@ export async function GET(request: Request, context: { params: { id: string } })
console.log(error);
return NextResponse.json({ success: false, message: "Gagal mendapatkan tugas divisi, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}
}
// CREATE NEW DETAIL TASK DIVISI
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, idDivision } = (await request.json());
const data = await prisma.divisionProject.count({
where: {
id: id,
},
});
if (data == 0) {
return NextResponse.json(
{
success: false,
message: "Tambah detail tugas gagal, data tugas tidak ditemukan",
},
{ status: 404 }
);
}
const create = await prisma.divisionProjectTask.create({
data: {
idProject: id,
idDivision,
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 ditambahkan",
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 });
}
}
// PEMBATALAN TASK DIVISI
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 { reason } = (await request.json());
const data = await prisma.divisionProject.count({
where: {
id: id,
},
});
if (data == 0) {
return NextResponse.json(
{
success: false,
message: "Pembatalan tugas gagal, data tugas tidak ditemukan",
},
{ status: 404 }
);
}
const update = await prisma.divisionProject.update({
where: {
id
},
data: {
reason: reason,
status: 3
}
});
return NextResponse.json(
{
success: true,
message: "Tugas berhasil dibatalkan",
},
{ status: 200 }
);
} catch (error) {
console.log(error);
return NextResponse.json({ success: false, message: "Gagal membatalkan tugas, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}
// EDIT TASK DIVISI
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 { title } = (await request.json());
const data = await prisma.divisionProject.count({
where: {
id: id,
},
});
if (data == 0) {
return NextResponse.json(
{
success: false,
message: "Tugas gagal diedit, data tugas tidak ditemukan",
},
{ status: 404 }
);
}
const update = await prisma.divisionProject.update({
where: {
id
},
data: {
title
}
});
return NextResponse.json(
{
success: true,
message: "Tugas berhasil diedit",
},
{ status: 200 }
);
} catch (error) {
console.log(error);
return NextResponse.json({ success: false, message: "Gagal mengedit tugas, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -78,6 +78,7 @@ export async function GET(request: Request) {
}
// CREATE PROJECT TASK DIVISION
export async function POST(request: Request) {
try {
const user = await funGetUserByCookies()

View File

@@ -1,3 +1,6 @@
import AddDetailTask from "./ui/add_detail_task";
import AddMemberDetailTask from "./ui/add_member_detail_task";
import CancelTask from "./ui/cancel_task";
import ViewDateEndTask from "./ui/create_date_end_task";
import CreateTask from "./ui/create_task";
import CreateUsersProject from "./ui/create_users_project";
@@ -6,6 +9,7 @@ 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 EditTask from "./ui/edit_task";
import FileSave from "./ui/file_save";
import NavbarDetailDivisionTask from "./ui/navbar_detail_division_task";
import NavbarDivisionTask from "./ui/navbar_division_task";
@@ -22,4 +26,8 @@ export { ListTugasDetailTask }
export { ProgressDetailTask }
export { ListFileDetailTask }
export { ListAnggotaDetailTask }
export { EditDetailTask }
export { EditDetailTask }
export { AddDetailTask }
export { AddMemberDetailTask }
export { CancelTask }
export { EditTask }

View File

@@ -1,4 +1,4 @@
import { IFormDateTask, IFormTaskDivision } from "./type_task";
import { IFormAddDetailTask, IFormAddMemberTask, IFormDateTask, IFormTaskDivision } from "./type_task";
export const funGetAllTask = async (path?: string) => {
const response = await fetch(`/api/task${(path) ? path : ''}`, { next: { tags: ['task'] } });
@@ -64,4 +64,52 @@ export const funEditDetailTask = async (path: string, data: IFormDateTask) => {
body: JSON.stringify(data),
});
return await response.json().catch(() => null);
};
export const funCreateDetailTask = async (path: string, data: IFormAddDetailTask) => {
const response = await fetch(`/api/task/${path}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
return await response.json().catch(() => null);
};
export const funAddMemberTask = async (path: string, data: IFormAddMemberTask) => {
const response = await fetch(`/api/task/${path}/member`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
return await response.json().catch(() => null);
};
export const funCancelTask = async (path: string, data: { reason: string }) => {
const response = await fetch(`/api/task/${path}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
return await response.json().catch(() => null);
};
export const funEditTask = async (path: string, data: { title: string }) => {
const response = await fetch(`/api/task/${path}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
return await response.json().catch(() => null);
};

View File

@@ -19,6 +19,19 @@ export interface IFormDateTask {
title: string
}
export interface IFormAddDetailTask {
dateStart: Date,
dateEnd: Date,
title: string
idDivision: string
}
export interface IFormAddMemberTask {
idDivision: string
member: IFormMemberTask[] | []
}
export interface IFormTaskDivision {
idDivision: string
@@ -44,6 +57,7 @@ export interface IDataListTaskDivision {
export interface IDataMemberTaskDivision {
id: string
idUser: string
name: string
email: string
}

View File

@@ -0,0 +1,147 @@
"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 { IFormDateTask } from "../lib/type_task";
import moment from "moment";
import { funCreateDetailTask } from "../lib/api_task";
import LayoutModal from "@/module/_global/layout/layout_modal";
export default function AddDetailTask() {
const [value, setValue] = useState<[Date | null, Date | null]>([null, null]);
const router = useRouter()
const [title, setTitle] = useState("")
const [openModal, setOpenModal] = useState(false)
const param = useParams<{ id: string, detail: string }>()
function onVerification() {
if (value[0] == null || value[1] == null)
return toast.error("Error! harus memilih tanggal")
if (title == "")
return toast.error("Error! harus memasukkan judul tugas")
setOpenModal(true)
}
async function onSubmit() {
try {
const res = await funCreateDetailTask(param.detail, {
title,
dateStart: (value[0] != null) ? value[0] : new Date,
dateEnd: (value[1] != null) ? value[1] : new Date,
idDivision: param.id
})
if (res.success) {
toast.success(res.message)
setOpenModal(false)
router.push(`/division/${param.id}/task/${param.detail}`)
} else {
toast.error(res.message)
}
} catch (error) {
console.log(error)
toast.error("Gagal menambahkan tugas, coba lagi nanti")
}
}
return (
<Box>
<LayoutNavbarNew back="" title={"Tambah Tugas"} menu />
<Box p={20}>
<Group
justify="center"
bg={"white"}
py={20}
style={{ borderRadius: 10, border: `1px solid ${"#D6D8F6"}` }}
>
<DatePicker
styles={{}}
type="range"
value={value}
onChange={setValue}
size="md"
c={WARNA.biruTua}
/>
</Group>
<SimpleGrid cols={{ base: 2, sm: 2, lg: 2 }} mt={20}>
<Box>
<Text>Tanggal Mulai</Text>
<Group
justify="center"
bg={"white"}
h={45}
style={{ borderRadius: 10, border: `1px solid ${"#D6D8F6"}` }}
>
<Text>{value[0] ? `${moment(value[0]).format('DD-MM-YYYY')}` : ""}</Text>
</Group>
</Box>
<Box>
<Text c={WARNA.biruTua}>Tanggal Berakhir</Text>
<Group
justify="center"
bg={"white"}
h={45}
style={{ borderRadius: 10, border: `1px solid ${"#D6D8F6"}` }}
>
<Text>{value[1] ? `${moment(value[1]).format('DD-MM-YYYY')}` : ""}</Text>
</Group>
</Box>
</SimpleGrid>
<Stack pt={15}>
<Input
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
placeholder="Input Nama Tahapan"
size="md"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</Stack>
<Box mt={"xl"}>
<Button
c={"white"}
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { onVerification() }}
>
Simpan
</Button>
</Box>
</Box>
<LayoutModal opened={openModal} onClose={() => setOpenModal(false)}
description="Apakah Anda yakin ingin menambahkan tugas?"
onYes={(val) => {
if (val) {
onSubmit()
}
setOpenModal(false)
}} />
</Box>
);
}

View File

@@ -0,0 +1,203 @@
"use client"
import { LayoutNavbarNew, WARNA } from "@/module/_global";
import { funGetDivisionById, IDataMemberDivision } from "@/module/division_new";
import {
Anchor,
Avatar,
Box,
Button,
Checkbox,
Divider,
Flex,
Group,
Stack,
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 { FaCheck } from "react-icons/fa6";
import { funAddMemberTask, funGetTaskDivisionById } from "../lib/api_task";
import { IDataMemberTaskDivision } from "../lib/type_task";
import LayoutModal from "@/module/_global/layout/layout_modal";
export default function AddMemberDetailTask() {
const router = useRouter()
const param = useParams<{ id: string, detail: string }>()
const [selectedFiles, setSelectedFiles] = useState<any>([])
const [isData, setData] = useState<IDataMemberDivision[]>([])
const [isDataMember, setDataMember] = useState<IDataMemberTaskDivision[]>([])
const [selectAll, setSelectAll] = useState(false)
const [openModal, setOpenModal] = useState(false)
async function getData() {
try {
const response = await funGetDivisionById(param.id)
if (response.success) {
setData(response.data.member)
} else {
toast.error(response.message)
}
const res = await funGetTaskDivisionById(param.detail, 'member');
if (res.success) {
setDataMember(res.data)
} else {
toast.error(res.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 (!isDataMember.some((i: any) => i.idUser == isData[index].idUser)) {
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 onVerifikasi() {
if (selectedFiles.length == 0) {
return toast.error("Error! silahkan pilih anggota")
}
setOpenModal(true)
}
async function onSubmit() {
try {
const res = await funAddMemberTask(param.detail, { idDivision: param.id, member: selectedFiles });
if (res.success) {
toast.success(res.message)
router.back()
} else {
toast.error(res.message)
}
} catch (error) {
console.log(error)
toast.error("Gagal menambahkan anggota, coba lagi nanti");
}
}
return (
<Box>
<LayoutNavbarNew
back=""
title="Pilih Anggota"
menu
/>
<Box p={20}>
{/* <TextInput
styles={{
input: {
color: WARNA.biruTua,
borderRadius: WARNA.biruTua,
borderColor: WARNA.biruTua,
},
}}
size="md"
radius={30}
leftSection={<HiMagnifyingGlass size={20} />}
placeholder="Pencarian"
/> */}
<Group justify="space-between" mt={20} onClick={handleSelectAll}>
<Text c={WARNA.biruTua} fw={"bold"}>
Pilih Semua Anggota
</Text>
{selectAll ? <FaCheck style={{ marginRight: 10 }} /> : ""}
</Group>
<Box mt={15}>
{isData.map((v, i) => {
const isSelected = selectedFiles.some((i: any) => i?.idUser == v.idUser);
const found = isDataMember.some((i: any) => i.idUser == v.idUser)
return (
<Box mb={15} key={i} onClick={() => (!found) ? handleFileClick(i) : null}>
<Flex justify={"space-between"} align={"center"}>
<Group>
<Avatar src={"v.image"} alt="it's me" size="lg" />
<Stack align="flex-start" justify="flex-start">
<Text style={{
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
}}>
{v.name}
</Text>
<Text c={"dimmed"}>{(found) ? "sudah menjadi anggota" : ""}</Text>
</Stack>
</Group>
<Text
style={{
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
paddingLeft: 20,
}}
>
{isSelected ? <FaCheck style={{ marginRight: 10 }} /> : ""}
</Text>
</Flex>
<Divider my={"md"} />
</Box>
);
})}
</Box>
<Box mt={"xl"}>
<Button
c={"white"}
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { onVerifikasi() }}
>
Simpan
</Button>
</Box>
</Box>
<LayoutModal opened={openModal} onClose={() => setOpenModal(false)}
description="Apakah Anda yakin ingin menambahkan anggota?"
onYes={(val) => {
if (val) {
onSubmit()
}
setOpenModal(false)
}} />
</Box>
);
}

View File

@@ -0,0 +1,87 @@
"use client";
import { LayoutNavbarNew, WARNA } from "@/module/_global";
import {
Box,
Button,
Stack,
Textarea,
} from "@mantine/core";
import React, { useState } from "react";
import { useParams, useRouter } from "next/navigation";
import toast from "react-hot-toast";
import { funCancelTask } from "../lib/api_task";
import LayoutModal from "@/module/_global/layout/layout_modal";
export default function CancelTask() {
const router = useRouter()
const [alasan, setAlasan] = useState("")
const [openModal, setOpenModal] = useState(false)
const param = useParams<{ id: string, detail: string }>()
function onVerification() {
if (alasan == "")
return toast.error("Error! harus memasukkan alasan pembatalan tugas")
setOpenModal(true)
}
async function onSubmit() {
try {
const res = await funCancelTask(param.detail, { reason: alasan })
if (res.success) {
toast.success(res.message)
router.push("./")
} else {
toast.error(res.message)
}
} catch (error) {
console.log(error)
toast.error("Gagal membatalkan tugas, coba lagi nanti")
}
}
return (
<Box>
<LayoutNavbarNew back="" title={"Pembatalan Tugas"} menu />
<Box p={20}>
<Stack pt={15}>
<Textarea styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
value={alasan}
size="md" placeholder='Contoh : Tugas tidak sesuai' label="Alasan Pembatalan"
onChange={(event) => setAlasan(event.target.value)}
/>
</Stack>
<Box mt={"xl"}>
<Button
c={"white"}
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { onVerification() }}
>
Simpan
</Button>
</Box>
</Box>
<LayoutModal opened={openModal} onClose={() => setOpenModal(false)}
description="Apakah Anda yakin ingin membatalkan tugas ini? Pembatalan tugas bersifat permanen"
onYes={(val) => {
if (val) {
onSubmit()
}
setOpenModal(false)
}} />
</Box>
);
}

View File

@@ -52,7 +52,6 @@ export default function CreateTask() {
async function onSubmit() {
try {
console.log("kirim",fileForm)
const response = await funCreateTask({ idDivision: param.id, title, task: dataTask, file: fileForm, member: memberValue })
if (response.success) {

View File

@@ -0,0 +1,110 @@
"use client";
import { LayoutNavbarNew, WARNA } from "@/module/_global";
import {
Box,
Button,
Input,
Stack,
Textarea,
} from "@mantine/core";
import React, { useState } from "react";
import { useParams, useRouter } from "next/navigation";
import toast from "react-hot-toast";
import LayoutModal from "@/module/_global/layout/layout_modal";
import { funEditTask, funGetTaskDivisionById } from "../lib/api_task";
import { useShallowEffect } from "@mantine/hooks";
export default function EditTask() {
const router = useRouter()
const [title, setTitle] = useState("")
const [openModal, setOpenModal] = useState(false)
const param = useParams<{ id: string, detail: string }>()
function onVerification() {
if (title == "")
return toast.error("Error! harus memasukkan judul tugas")
setOpenModal(true)
}
async function onSubmit() {
try {
const res = await funEditTask(param.detail, { title })
if (res.success) {
toast.success(res.message)
router.push("./")
} else {
toast.error(res.message)
}
} catch (error) {
console.log(error)
toast.error("Gagal mengedit tugas, coba lagi nanti")
}
}
async function getOneData() {
try {
const res = await funGetTaskDivisionById(param.detail, 'data');
if (res.success) {
setTitle(res.data.title);
} else {
toast.error(res.message);
}
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan data tugas divisi, coba lagi nanti");
}
}
useShallowEffect(() => {
getOneData();
}, [param.detail])
return (
<Box>
<LayoutNavbarNew back="" title={"Edit Judul Tugas"} menu />
<Box p={20}>
<Stack pt={15}>
<Input
styles={{
input: {
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
},
}}
placeholder="Tugas"
size="md"
value={title}
onChange={(e) => { setTitle(e.target.value) }}
/>
</Stack>
<Box mt={"xl"}>
<Button
c={"white"}
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { onVerification() }}
>
Simpan
</Button>
</Box>
</Box>
<LayoutModal opened={openModal} onClose={() => setOpenModal(false)}
description="Apakah Anda yakin ingin mengedit tugas ini?"
onYes={(val) => {
if (val) {
onSubmit()
}
setOpenModal(false)
}} />
</Box>
);
}

View File

@@ -8,7 +8,8 @@ import { funGetTaskDivisionById } from "../lib/api_task";
import { useShallowEffect } from "@mantine/hooks";
import { HiMenu } from "react-icons/hi";
import { IoAddCircle } from "react-icons/io5";
import { RiFilter2Line } from "react-icons/ri";
import { FaPencil, FaUsers } from "react-icons/fa6";
import { MdCancel } from "react-icons/md";
export default function NavbarDetailDivisionTask() {
const router = useRouter()
@@ -45,7 +46,7 @@ export default function NavbarDetailDivisionTask() {
size="lg"
radius="lg"
aria-label="Settings"
onClick={() => { }}
onClick={() => { setOpen(true) }}
>
<HiMenu size={20} color="white" />
</ActionIcon>
@@ -63,14 +64,14 @@ export default function NavbarDetailDivisionTask() {
cursor: 'pointer'
}}
onClick={() => {
router.push('/announcement/create')
router.push(param.detail + '/add-task')
}}
>
<Box>
<IoAddCircle size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua} ta='center'>Tambah Pengumuman</Text>
<Text c={WARNA.biruTua} ta='center'>Tambah Tugas</Text>
</Box>
</Flex>
@@ -79,20 +80,49 @@ export default function NavbarDetailDivisionTask() {
cursor: 'pointer'
}}
onClick={() => {
router.push('/announcement?page=filter')
router.push(param.detail + '/add-member')
}}
>
<Box>
<RiFilter2Line size={30} color={WARNA.biruTua} />
<FaUsers size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua} ta='center'>Filter</Text>
<Text c={WARNA.biruTua} ta='center'>Tambah anggota</Text>
</Box>
</Flex>
<Flex justify={'center'} align={'center'} direction={'column'}
style={{
cursor: 'pointer'
}}
onClick={() => { router.push(param.detail + '/cancel') }}
>
<Box>
<MdCancel size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua} ta='center'>Batal</Text>
</Box>
</Flex>
<Flex justify={'center'} align={'center'} direction={'column'}
style={{
cursor: 'pointer'
}}
onClick={() => { router.push(param.detail + '/edit') }}
>
<Box>
<FaPencil size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua} ta='center'>Edit</Text>
</Box>
</Flex>
</SimpleGrid>
</Stack>
</Box>
</LayoutDrawer>
</>
)
}