From 506d8ab01b8b930611e89dc50c3ff38174cd8b3c Mon Sep 17 00:00:00 2001 From: amel Date: Sun, 5 Jan 2025 14:13:52 +0800 Subject: [PATCH 1/5] rev: diskusi umum Deskripsi: - detail diskusi - list anggota diskusi - blm selesai No Issues --- .../discussion/[id]/member/page.tsx | 9 + .../(application)/discussion/[id]/page.tsx | 4 +- .../discussion-general/[id]/member/route.ts | 92 +++++ src/app/api/discussion-general/[id]/route.ts | 112 ++++++ src/module/discussion_general/index.ts | 6 +- .../lib/api_discussion_general.ts | 7 +- .../lib/type_discussion_general.ts | 19 +- .../lib/val_discussion_general.ts | 3 +- .../ui/detail_discussion_general.tsx | 380 ++++++++++++++++++ .../ui/drawer_detail_discussion_general.tsx | 163 ++++++++ .../discussion_general/ui/list_discussion.tsx | 9 +- .../ui/member_discussion_general.tsx | 278 +++++++++++++ 12 files changed, 1072 insertions(+), 10 deletions(-) create mode 100644 src/app/(application)/discussion/[id]/member/page.tsx create mode 100644 src/app/api/discussion-general/[id]/member/route.ts create mode 100644 src/app/api/discussion-general/[id]/route.ts create mode 100644 src/module/discussion_general/ui/detail_discussion_general.tsx create mode 100644 src/module/discussion_general/ui/drawer_detail_discussion_general.tsx create mode 100644 src/module/discussion_general/ui/member_discussion_general.tsx diff --git a/src/app/(application)/discussion/[id]/member/page.tsx b/src/app/(application)/discussion/[id]/member/page.tsx new file mode 100644 index 0000000..bf272ef --- /dev/null +++ b/src/app/(application)/discussion/[id]/member/page.tsx @@ -0,0 +1,9 @@ +import { MemberDiscussionGeneral } from "@/module/discussion_general"; + +export default function Page() { + return ( + <> + + + ) +} \ No newline at end of file diff --git a/src/app/(application)/discussion/[id]/page.tsx b/src/app/(application)/discussion/[id]/page.tsx index c306dfe..d179343 100644 --- a/src/app/(application)/discussion/[id]/page.tsx +++ b/src/app/(application)/discussion/[id]/page.tsx @@ -1,7 +1,9 @@ +import { DetailDiscussionGeneral } from "@/module/discussion_general"; + export default function Page() { return ( <> - detail diskusi umum + ) } \ No newline at end of file diff --git a/src/app/api/discussion-general/[id]/member/route.ts b/src/app/api/discussion-general/[id]/member/route.ts new file mode 100644 index 0000000..806923d --- /dev/null +++ b/src/app/api/discussion-general/[id]/member/route.ts @@ -0,0 +1,92 @@ +import { prisma } from "@/module/_global"; +import { funGetUserByCookies } from "@/module/auth"; +import { createLogUser } from "@/module/user"; +import _ from "lodash"; +import { NextResponse } from "next/server"; + + +// ADD MEMBER DISCUSSION GENERAL +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 } = (await request.json()) + + const cek = await prisma.discussion.count({ + where: { + id, + isActive: true + } + }) + + if (cek == 0) { + return NextResponse.json({ success: false, message: "Gagal menambahkan anggota, data tidak ditemukan" }, { status: 404 }); + } + + if (member.length > 0) { + const dataMember = member.map((v: any) => ({ + ..._.omit(v, ["idUser", "name", "img"]), + idDiscussion: id, + idUser: v.idUser + })) + + const insertMember = await prisma.discussionMember.createMany({ + data: dataMember + }) + } + + // create log user + const log = await createLogUser({ act: 'CREATE', desc: 'User menambah anggota diskusi umum', table: 'discussion', data: String(id) }) + return NextResponse.json({ success: true, message: "Berhasil menambahkan anggota diskusi umum" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menambahkan anggota, coba lagi nanti (error : 500)" }, { status: 500 }); + } +} + + +// 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 cek = await prisma.discussion.count({ + where: { + id, + isActive: true + } + }) + + if (cek == 0) { + return NextResponse.json({ success: false, message: "Gagal, data tidak ditemukan" }, { status: 404 }); + } + + const deleteMember = await prisma.discussionMember.deleteMany({ + where: { + idDiscussion: id, + idUser + } + }) + + // create log user + const log = await createLogUser({ act: 'DELETE', desc: 'User mengeluarkan anggota diskusi umum', table: 'discussion', data: String(id) }) + + return NextResponse.json({ success: true, message: "Berhasil mengeluarkan anggota diskusi umum" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mengeluarkan anggota, coba lagi nanti (error : 500)" }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/discussion-general/[id]/route.ts b/src/app/api/discussion-general/[id]/route.ts new file mode 100644 index 0000000..9aacc5e --- /dev/null +++ b/src/app/api/discussion-general/[id]/route.ts @@ -0,0 +1,112 @@ +import { prisma } from "@/module/_global"; +import { funGetUserByCookies } from "@/module/auth"; +import _ from "lodash"; +import moment from "moment"; +import { NextResponse } from "next/server"; + +export async function GET(request: Request, context: { params: { id: string } }) { + try { + let dataFix + const { id } = context.params + const { searchParams } = new URL(request.url); + const kategori = searchParams.get("cat"); + + const user = await funGetUserByCookies() + if (user.id == undefined) { + return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 }); + } + + const cek = await prisma.discussion.count({ + where: { + id, + isActive: true + } + }) + + if (cek == 0) { + return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" }, { status: 404 }); + } + + if (kategori == "detail") { + const data = await prisma.discussion.findUnique({ + where: { + id, + isActive: true + }, + select: { + id: true, + title: true, + desc: true, + status: true, + createdAt: true, + } + }) + + dataFix = { + id: data?.id, + title: data?.title, + desc: data?.desc, + status: data?.status, + createdAt: moment(data?.createdAt).format("ll"), + } + + } else if (kategori == "komentar") { + const data = await prisma.discussionComment.findMany({ + where: { + idDiscussion: id, + isActive: true + }, + select: { + id: true, + comment: true, + createdAt: true, + idUser: true, + User: { + select: { + name: true, + img: true + } + } + } + }) + + dataFix = data.map((v: any) => ({ + ..._.omit(v, ["createdAt", "User",]), + createdAt: moment(v.createdAt).format("ll"), + username: v.User.name, + img: v.User.img + })) + + } else if (kategori == "anggota") { + const data = await prisma.discussionMember.findMany({ + where: { + idDiscussion: id, + isActive: true + }, + select: { + idUser: true, + User: { + select: { + name: true, + img: true + } + } + } + }) + + dataFix = data.map((v: any) => ({ + ..._.omit(v, ["User",]), + name: v.User.name, + img: v.User.img + })) + } + + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan diskusi", data: dataFix }, { status: 200 }); + + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/module/discussion_general/index.ts b/src/module/discussion_general/index.ts index e9e427b..e612e04 100644 --- a/src/module/discussion_general/index.ts +++ b/src/module/discussion_general/index.ts @@ -1,7 +1,11 @@ import FormCreateDiscussionGeneral from "./ui/create_discussion"; +import DetailDiscussionGeneral from "./ui/detail_discussion_general"; import ListDiscussionGeneral from "./ui/list_discussion"; +import MemberDiscussionGeneral from "./ui/member_discussion_general"; import NavbarDiscussionGeneral from "./ui/navbar_discussion"; export { ListDiscussionGeneral } export { NavbarDiscussionGeneral } -export { FormCreateDiscussionGeneral } \ No newline at end of file +export { FormCreateDiscussionGeneral } +export { DetailDiscussionGeneral } +export { MemberDiscussionGeneral } \ No newline at end of file diff --git a/src/module/discussion_general/lib/api_discussion_general.ts b/src/module/discussion_general/lib/api_discussion_general.ts index d1fb6f3..d9cf15b 100644 --- a/src/module/discussion_general/lib/api_discussion_general.ts +++ b/src/module/discussion_general/lib/api_discussion_general.ts @@ -14,4 +14,9 @@ export const funCreateDiscussionGeneral = async (data: { idGroup: string, title: body: JSON.stringify(data), }); return await response.json().catch(() => null); -} \ No newline at end of file +} + +export const funGetOneDiscussionGeneral = async (id: string, path: string) => { + const response = await fetch(`/api/discussion-general/${id}${(path) ? path : ''}`, { next: { tags: ['discussion-general'] } }); + return await response.json().catch(() => null); +} diff --git a/src/module/discussion_general/lib/type_discussion_general.ts b/src/module/discussion_general/lib/type_discussion_general.ts index a27cefe..94b130d 100644 --- a/src/module/discussion_general/lib/type_discussion_general.ts +++ b/src/module/discussion_general/lib/type_discussion_general.ts @@ -2,4 +2,21 @@ export interface IFormMemberDisscussionGeneral { idUser: string, name: string, img: string - } \ No newline at end of file + } + + export interface IDetailDiscussionGeneral{ + id: string + title: string + desc: string + status: number + createdAt: string + } + + export interface IComentsDisscussionGeneral{ + id: string + comment: string + createdAt: string + idUser: string + img: string + username: string +} \ No newline at end of file diff --git a/src/module/discussion_general/lib/val_discussion_general.ts b/src/module/discussion_general/lib/val_discussion_general.ts index 3c3fb26..321771d 100644 --- a/src/module/discussion_general/lib/val_discussion_general.ts +++ b/src/module/discussion_general/lib/val_discussion_general.ts @@ -1,4 +1,5 @@ import { hookstate } from "@hookstate/core"; import { IFormMemberDisscussionGeneral } from "./type_discussion_general"; -export const globalMemberDiscussionGeneral = hookstate([]); \ No newline at end of file +export const globalMemberDiscussionGeneral = hookstate([]); +export const globalRefreshDiscussionGeneral = hookstate(false); \ No newline at end of file diff --git a/src/module/discussion_general/ui/detail_discussion_general.tsx b/src/module/discussion_general/ui/detail_discussion_general.tsx new file mode 100644 index 0000000..651b540 --- /dev/null +++ b/src/module/discussion_general/ui/detail_discussion_general.tsx @@ -0,0 +1,380 @@ +"use client" +import { globalRole, keyWibu, LayoutDrawer, LayoutNavbarNew, TEMA } from "@/module/_global"; +import { globalIsAdminDivision, globalIsMemberDivision } from "@/module/division_new"; +import { useHookstate } from "@hookstate/core"; +import { ActionIcon, Avatar, Badge, Box, Center, Divider, Flex, Grid, Group, rem, Skeleton, Spoiler, Text, TextInput } from "@mantine/core"; +import { useMediaQuery, useShallowEffect } from "@mantine/hooks"; +import moment from "moment"; +import "moment/locale/id"; +import { useParams, useRouter } from "next/navigation"; +import { useState } from "react"; +import toast from "react-hot-toast"; +import { GrChatOption } from "react-icons/gr"; +import { HiMenu } from "react-icons/hi"; +import { VscSend } from "react-icons/vsc"; +import { useWibuRealtime } from "wibu-realtime"; +import { funGetOneDiscussionGeneral } from "../lib/api_discussion_general"; +import { IComentsDisscussionGeneral, IDetailDiscussionGeneral } from "../lib/type_discussion_general"; +import { globalRefreshDiscussionGeneral } from "../lib/val_discussion_general"; +import DrawerDetailDiscussionGeneral from "./drawer_detail_discussion_general"; +import { BiSolidCommentDetail } from "react-icons/bi"; + +export default function DetailDiscussionGeneral() { + const [isData, setData] = useState() + const [isDataKomentar, setDataKomentar] = useState([]) + const [isComent, setIsComent] = useState("") + const param = useParams<{ id: string }>() + const [isLoad, setIsLoad] = useState(true) + const [loadingKomentar, setLoadingKomentar] = useState(false) + const refresh = useHookstate(globalRefreshDiscussionGeneral) + const roleLogin = useHookstate(globalRole) + const [isCreator, setCreator] = useState(false) + const [isUser, setUser] = useState('') + const adminLogin = useHookstate(globalIsAdminDivision) + const memberDivision = useHookstate(globalIsMemberDivision) + const tema = useHookstate(TEMA) + const router = useRouter() + const [openDrawer, setOpenDrawer] = useState(false) + const isMobile = useMediaQuery('(max-width: 369px)') + const isMobile2 = useMediaQuery("(max-width: 438px)") + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) + + const getData = async (loading: boolean) => { + try { + setIsLoad(loading) + const response = await funGetOneDiscussionGeneral(param.id, "?cat=detail") + if (response.success) { + setData(response.data) + } else { + toast.error(response.message) + } + } catch (error) { + console.error(error) + toast.error("Gagal mendapatkan data, coba lagi nanti") + } finally { + setIsLoad(false) + } + } + + useShallowEffect(() => { + getData(true) + }, [refresh.get()]) + + // useShallowEffect(() => { + // if (dataRealTime && dataRealTime.some((i: any) => i.category == 'discussion-detail' && i.id == param.id)) { + // getData(false) + // } + + // if (dataRealTime && dataRealTime.some((i: any) => i.category == 'discussion-delete' && i.id == param.id && i.user != isUser)) { + // toast.error("Data telah di hapus, anda akan beralih ke halaman list diskusi") + // setTimeout(() => { + // router.push(`/division/${param.id}/discussion`) + // }, 1000) + // } + // }, [dataRealTime]) + + async function getKomentar(loading: boolean) { + try { + setLoadingKomentar(loading) + const response = await funGetOneDiscussionGeneral(param.id, "?cat=komentar") + if (response.success) { + setData(response.data) + } else { + toast.error(response.message) + } + } catch (error) { + console.error(error) + } finally { + setLoadingKomentar(false) + } + } + + // const sendComent = async () => { + // try { + // if (isComent.trim() == "") { + // return toast.error("Masukkan Komentar Anda") + // } + // const response = await funCreateComent(id, { comment: isComent, idDiscussion: param.detail }) + + // if (response.success) { + // setIsComent("") + // setDataRealtime([{ + // category: "discussion-detail", + // id: id, + // }]) + // reloadData() + // } else { + // toast.error(response.message) + // } + // } catch (error) { + // console.error(error) + // } + // } + + + + + + return ( + + setOpenDrawer(true)} bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings"> + + + : <> + } + /> + setOpenDrawer(false)}> + setOpenDrawer(false)} id={param.id} status={Number(isData?.status)} /> + + + + + {isLoad ? + Array(1) + .fill(null) + .map((_, i) => ( + + + + + + + + + + + + + + + + + + )) : + <> + {isDataKomentar?.length == 0 ? + + + + + + + + + + {isData?.title} + {isData?.status === 1 ? "BUKA" : "TUTUP"} + + + + + {isData?.createdAt} + + + + + + + {isData?.desc} + + + + + {isDataKomentar?.length ? + + {isDataKomentar?.length} Komentar + : ""} + + + + : + + + + + + + + + + {isData?.title} + {isData?.status === 1 ? "BUKA" : "TUTUP"} + + + + + {isData?.createdAt} + + + + + + + {isData?.desc} + + + + + {isDataKomentar?.length ? + + {isDataKomentar.length} Komentar + : ""} + + + + } + + } + + {isLoad ? + Array(2) + .fill(0) + .map((_, i) => ( + + + + + + + + + + + + + + + + + + + + + + + )) : + isDataKomentar.map((v, i) => { + return ( + + + + + + + + + {v.username} + + + + + {moment(v.createdAt).format("ll")} + + + + + + {v.comment} + + + + + + + + ); + }) + } + + + {isLoad ? + + : + + + + {300 - isComent.length} karakter tersisa + + + + + setIsComent(e.target.value)} + value={isComent} + maxLength={300} + /> + + + +
+ + + +
+
+
+
+
+
+ } +
+ ) +} + diff --git a/src/module/discussion_general/ui/drawer_detail_discussion_general.tsx b/src/module/discussion_general/ui/drawer_detail_discussion_general.tsx new file mode 100644 index 0000000..d6eada3 --- /dev/null +++ b/src/module/discussion_general/ui/drawer_detail_discussion_general.tsx @@ -0,0 +1,163 @@ +import { keyWibu, TEMA } from "@/module/_global"; +import LayoutModal from "@/module/_global/layout/layout_modal"; +import { useHookstate } from "@hookstate/core"; +import { Box, Flex, SimpleGrid, Stack, Text } from "@mantine/core"; +import { useParams, useRouter } from "next/navigation"; +import { useState } from "react"; +import { BsTrash3 } from "react-icons/bs"; +import { FaCheck, FaPencil, FaUsers } from "react-icons/fa6"; +import { MdClose } from "react-icons/md"; +import { useWibuRealtime } from "wibu-realtime"; +import { globalRefreshDiscussionGeneral } from "../lib/val_discussion_general"; + +export default function DrawerDetailDiscussionGeneral({ onSuccess, id, status }: { onSuccess: (val: boolean) => void, id: string, status: number }) { + const [isValModal, setValModal] = useState(false) + const [isValModalStatus, setValModalStatus] = useState(false) + const router = useRouter() + const param = useParams<{ id: string, detail: string }>() + const refresh = useHookstate(globalRefreshDiscussionGeneral) + const tema = useHookstate(TEMA) + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) + const [loadingUpdate, setLoadingUpdate] = useState(false) + const [loadingDelete, setLoadingDelete] = useState(false) + + + // async function fetchStatusDiscussion(val: boolean) { + // try { + // setLoadingUpdate(true) + // if (val) { + // const response = await funEditStatusDiscussion(id, { status: status }) + // if (response.success) { + // toast.success(response.message) + // refresh.set(!refresh.get()) + // setDataRealtime([{ + // category: "discussion-detail", + // id: id, + // }]) + // onSuccess(false) + // } else { + // toast.error(response.message) + // } + // } + // } catch (error) { + // console.error(error); + // toast.error("Gagal menambahkan diskusi, coba lagi nanti"); + // } finally { + // setLoadingUpdate(false) + // setValModalStatus(false) + // } + // } + + // async function fetchDeleteDiscussion(val: boolean) { + // try { + // if (val) { + // setLoadingDelete(true) + // const response = await funDeleteDiscussion(id) + // if (response.success) { + // setDataRealtime([ + // { + // category: "discussion-delete", + // id: id, + // user: response.user + // }, + // { + // category: "division/" + param.id + "/discussion", + // } + // ]) + // toast.success(response.message) + // onSuccess(false) + // router.push(`/division/${param.id}/discussion`) + // } else { + // toast.error(response.message) + // } + // } + // } catch (error) { + // console.error(error); + // toast.error("Gagal hapus diskusi, coba lagi nanti"); + // } finally { + // setLoadingDelete(false) + // setValModal(false) + // } + // } + + + return ( + + + + + window.location.href = `/discussion/${param.id}/member/`} justify={'center'} align={'center'} direction={'column'} > + + + + + Anggota + + + + window.location.href = `/discussion/${param.id}/update/`} justify={'center'} align={'center'} direction={'column'} > + + + + + Edit + + + + setValModalStatus(true)} > + {status === 1 ? ( + <> + + + + + Tutup Diskusi + + + ) : ( + <> + + + + + + Buka Diskusi + + + )} + + + setValModal(true)} justify={'center'} align={'center'} direction={'column'} > + + + + + Hapus + + + + + + + setValModal(false)} + description="Apakah Anda yakin ingin menghapus diskusi ini?" + onYes={(val) => { + // fetchDeleteDiscussion(val) + }} /> + + + setValModalStatus(false)} + description="Apakah Anda yakin ingin mengubah status diskusi ini?" + onYes={(val) => { + // fetchStatusDiscussion(val) + }} /> + + ) +} \ No newline at end of file diff --git a/src/module/discussion_general/ui/list_discussion.tsx b/src/module/discussion_general/ui/list_discussion.tsx index 99d96b9..a5d8b7a 100644 --- a/src/module/discussion_general/ui/list_discussion.tsx +++ b/src/module/discussion_general/ui/list_discussion.tsx @@ -1,23 +1,22 @@ 'use client' import { currentScroll, globalNotifPage, keyWibu, ReloadButtonTop, TEMA } from "@/module/_global"; import { useHookstate } from "@hookstate/core"; -import { ActionIcon, Avatar, Badge, Box, Divider, Flex, Grid, Group, Skeleton, Spoiler, Text, TextInput } from "@mantine/core"; +import { ActionIcon, Badge, Box, Divider, Flex, Grid, Group, Skeleton, Spoiler, Text, TextInput } from "@mantine/core"; import { useShallowEffect } from "@mantine/hooks"; import _ from "lodash"; -import { useParams, useRouter } from "next/navigation"; +import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import toast from "react-hot-toast"; +import { BiSolidCommentDetail } from "react-icons/bi"; import { GrChatOption } from "react-icons/gr"; import { HiMagnifyingGlass } from "react-icons/hi2"; import { useWibuRealtime } from "wibu-realtime"; import { funGetAllDiscussionGeneral } from "../lib/api_discussion_general"; -import { BiSolidCommentDetail } from "react-icons/bi"; export default function ListDiscussionGeneral() { const [isData, setData] = useState([]) const [searchQuery, setSearchQuery] = useState('') - const param = useParams<{ id: string }>() const [loading, setLoading] = useState(true) const tema = useHookstate(TEMA) const router = useRouter() @@ -229,7 +228,7 @@ export default function ListDiscussionGeneral() { overflowWrap: "break-word" }} onClick={() => { - router.push(`/division/${param.id}/discussion/${v.id}`) + router.push(`/discussion/${v.id}`) }} > {v.desc} diff --git a/src/module/discussion_general/ui/member_discussion_general.tsx b/src/module/discussion_general/ui/member_discussion_general.tsx new file mode 100644 index 0000000..ddda736 --- /dev/null +++ b/src/module/discussion_general/ui/member_discussion_general.tsx @@ -0,0 +1,278 @@ +"use client" +import { globalRole, LayoutDrawer, LayoutNavbarNew, SkeletonList, TEMA } from '@/module/_global'; +import LayoutModal from '@/module/_global/layout/layout_modal'; +import { useHookstate } from '@hookstate/core'; +import { ActionIcon, Avatar, Box, Divider, Flex, Grid, Group, SimpleGrid, Stack, Text } from '@mantine/core'; +import { useMediaQuery, useShallowEffect } from '@mantine/hooks'; +import { useParams, useRouter } from 'next/navigation'; +import { useState } from 'react'; +import toast from 'react-hot-toast'; +import { AiOutlineUserAdd } from 'react-icons/ai'; +import { FaPencil, FaToggleOff, FaUserTie } from 'react-icons/fa6'; +import { IoIosCloseCircle } from 'react-icons/io'; +import { funGetOneDiscussionGeneral } from '../lib/api_discussion_general'; +import { IFormMemberDisscussionGeneral } from '../lib/type_discussion_general'; + + +export default function MemberDiscussionGeneral() { + const router = useRouter() + const [openDrawer, setDrawer] = useState(false) + const [openDrawerInfo, setDrawerInfo] = useState(false) + const [valActive, setValActive] = useState(true) + const param = useParams<{ id: string }>() + const [member, setMember] = useState([]) + const [loading, setLoading] = useState(true) + const [valChooseMember, setChooseMember] = useState("") + const [valChooseMemberStatus, setChooseMemberStatus] = useState(false) + const [valChooseMemberName, setChooseMemberName] = useState("") + const [isOpenModal, setOpenModal] = useState(false) + const [isOpenModalStatus, setOpenModalStatus] = useState(false) + const roleLogin = useHookstate(globalRole) + const [isAdmin, setAdmin] = useState(false) + const isMobile = useMediaQuery('(max-width: 455px)') + const isMobile2 = useMediaQuery("(max-width: 438px)") + const tema = useHookstate(TEMA) + const [loadingStatus, setLoadingStatus] = useState(false) + const [loadingDelete, setLoadingDelete] = useState(false) + + async function getOneData(loading: boolean) { + try { + setLoading(loading) + const res = await funGetOneDiscussionGeneral(param.id, "?cat=anggota"); + if (res.success) { + setMember(res.data) + } else { + toast.error(res.message); + } + } catch (error) { + console.error(error); + toast.error("Gagal mendapatkan data, coba lagi nanti"); + } finally { + setLoading(false) + } + } + + useShallowEffect(() => { + getOneData(true); + }, [param.id]) + + + async function onClickMember(id: string, status: boolean) { + setChooseMember(id) + setChooseMemberStatus(status) + setDrawer(true) + } + + + // async function deleteMember() { + // try { + // setLoadingDelete(true) + // const res = await funDeleteMemberDivision(param.id, { id: valChooseMember }) + // if (res.success) { + // toast.success(res.message) + // setDrawer(false) + // getOneData(false) + // } else { + // toast.error(res.message) + // } + // } catch (error) { + // console.error(error); + // toast.error("Gagal mendapatkan divisi, coba lagi nanti"); + // } finally { + // setLoadingDelete(false) + // setOpenModal(false) + // } + // } + + + // async function editStatusAdmin() { + // try { + // const res = await funEditStatusAdminDivision(param.id, { id: valChooseMember, isAdmin: valChooseMemberStatus }) + // if (res.success) { + // toast.success(res.message) + // getOneData(false) + // } else { + // toast.error(res.message) + // } + // setDrawer(false) + // } catch (error) { + // console.error(error); + // toast.error("Gagal mendapatkan divisi, coba lagi nanti"); + // } + // } + + // async function editStatusDivisi() { + // try { + // setLoadingStatus(true) + // const res = await funUpdateStatusDivision(param.id, { isActive: valActive }) + // if (res.success) { + // toast.success(res.message) + // getOneData(false) + // } else { + // toast.error(res.message) + // } + // } catch (error) { + // console.error(error); + // toast.error("Gagal mendapatkan divisi, coba lagi nanti"); + // } finally { + // setDrawerInfo(false) + // setLoadingStatus(false) + // setOpenModalStatus(false) + // } + // } + + return ( + + } /> + + {/* + Deskripsi Divisi + + { + loading ? + Array(3) + .fill(null) + .map((_, i) => ( + + + + )) + : + (deskripsi != null && deskripsi != undefined && deskripsi != "") ? + {deskripsi} + : Tidak ada deskripsi + } + + */} + + + {member.length} Anggota + + + + {loading ? + <> + : + router.push('/division/add-member/' + param.id)}> + + + + Tambah Anggota + + } + + + + {loading + ? Array(6) + .fill(null) + .map((_, i) => ( + + + + )) + : member.map((v, i) => { + return ( + + { + if ((roleLogin.get() != 'user' && roleLogin.get() != 'coadmin') || isAdmin) { + // onClickMember(v.id, (v.isAdmin) ? true : false) + setChooseMemberName(v.name) + } + }} + > + + + + + + {v.name} + + + + + + + + ); + }) + } + + + + + + + setDrawer(false)} title={valChooseMemberName}> + + valActive ? editStatusAdmin() : undefined} + > + + + + {(valChooseMemberStatus == false) ? "Jadikan admin" : "Memberhentikan sebagai admin"} + + valActive ? setOpenModal(true) : undefined}> + + + + Keluarkan dari divisi + + + + + setOpenModal(false)} + description="Apakah Anda yakin ingin mengeluarkan anggota?" + onYes={(val) => { + // if (!val) { + // setOpenModal(false) + // } else { + // deleteMember() + // } + }} /> + + setDrawerInfo(false)} title={"Menu"}> + + + + router.push('/division/edit/' + param.id)} justify={'center'} align={'center'} direction={'column'} > + + + + + Edit Divisi + + + { setOpenModalStatus(true) }} justify={'center'} align={'center'} direction={'column'} > + + + + + {valActive ? "Non Aktifkan Divisi" : "Aktifkan Divisi"} + + + + + + + + setOpenModalStatus(false)} + description="Apakah Anda yakin ingin mangubah status aktifasi divisi?" + onYes={(val) => { + // if (!val) { + // setOpenModalStatus(false) + // } else { + // editStatusDivisi() + // } + }} /> + + ); +} From 8bfd85c49a454c9ba2629f62577d585424de621b Mon Sep 17 00:00:00 2001 From: amel Date: Sun, 5 Jan 2025 14:25:05 +0800 Subject: [PATCH 2/5] rev: banner pada cosupadmin --- src/module/home/ui/view_detail_feature.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/module/home/ui/view_detail_feature.tsx b/src/module/home/ui/view_detail_feature.tsx index 3176130..d5cca9d 100644 --- a/src/module/home/ui/view_detail_feature.tsx +++ b/src/module/home/ui/view_detail_feature.tsx @@ -120,6 +120,25 @@ export default function ViewDetailFeature() { Jabatan + { + roleLogin.get() == "cosupadmin" && + router.push('/banner')}> +
+ + + +
+
+ Banner +
+
+ } { roleLogin.get() == "supadmin" && <> From b2801480aac74800b9310ca9b4361aa1fe1cf96b Mon Sep 17 00:00:00 2001 From: amel Date: Sun, 5 Jan 2025 17:15:53 +0800 Subject: [PATCH 3/5] rev: file upload ekstensi Deskripsi: - tambah type ekstensi file upload pada project, task divisi dan dokumen divisi No Issues --- .../ui/drawer_menu_document_division.tsx | 2 +- .../document/ui/navbar_document_division.tsx | 76 +++++++++++-------- .../project/ui/add_file_detail_project.tsx | 3 +- src/module/project/ui/create_project.tsx | 2 +- .../project/ui/list_file_detail_project.tsx | 60 +++++++++++---- src/module/project/ui/results_file.tsx | 47 ++++++++++-- src/module/task/ui/add_file_detail_task.tsx | 2 +- src/module/task/ui/create_task.tsx | 2 +- src/module/task/ui/detail_list_file_task.tsx | 59 ++++++++++---- src/module/task/ui/results_file.tsx | 50 +++++++++--- 10 files changed, 219 insertions(+), 84 deletions(-) diff --git a/src/module/document/ui/drawer_menu_document_division.tsx b/src/module/document/ui/drawer_menu_document_division.tsx index 7fefc09..cc99b97 100644 --- a/src/module/document/ui/drawer_menu_document_division.tsx +++ b/src/module/document/ui/drawer_menu_document_division.tsx @@ -149,7 +149,7 @@ export default function DrawerMenuDocumentDivision() { }} activateOnClick={false} maxSize={3 * 1024 ** 2} - accept={['text/csv', 'image/png', 'image/jpeg', 'image/heic', 'application/pdf']} + accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { refresh.set(true) setOpenModal(false) diff --git a/src/module/document/ui/navbar_document_division.tsx b/src/module/document/ui/navbar_document_division.tsx index 80af889..a513250 100644 --- a/src/module/document/ui/navbar_document_division.tsx +++ b/src/module/document/ui/navbar_document_division.tsx @@ -34,6 +34,7 @@ export default function NavbarDocumentDivision() { const [isOpenModalView, setOpenModalView] = useState(false); const [isExtension, setExtension] = useState(""); const [idStorage, setIdStorage] = useState(""); + const [nameFileFull, setNameFileFull] = useState(""); const [name, setName] = useState(""); const [isOpen, setOpen] = useState(false); const [isDelete, setIsDelete] = useState(false); @@ -253,9 +254,18 @@ export default function NavbarDocumentDivision() { setRename(true); } - const onDownload = async () => { + const onDownload = async (kategori: string, file?: { idFile: string, nameFile: string }) => { try { - const fileUrl = `https://wibu-storage.wibudev.com/api/files/${selectedFiles[0].idStorage}`; + let idStorageDownload, nameFileDownload = "" + if (kategori == "selected") { + idStorageDownload = selectedFiles[0].idStorage + nameFileDownload = `${selectedFiles[0].name}.${selectedFiles[0].extension}` + } else if (kategori == "klik") { + idStorageDownload = file?.idFile + nameFileDownload = String(file?.nameFile) + } + + const fileUrl = `https://wibu-storage.wibudev.com/api/files/${idStorageDownload}`; const response = await fetch(fileUrl); const blob = await response.blob(); @@ -263,7 +273,7 @@ export default function NavbarDocumentDivision() { const link = document.createElement("a"); const url = window.URL.createObjectURL(blob); link.href = url; - link.download = `${selectedFiles[0].name}.${selectedFiles[0].extension}`; // Nama file yang akan diunduh + link.download = nameFileDownload; // Nama file yang akan diunduh document.body.appendChild(link); link.click(); @@ -341,7 +351,7 @@ export default function NavbarDocumentDivision() { direction={"column"} onClick={() => { if (selectedFiles.length > 0 && copyAllowed) { - onDownload(); + onDownload("selected"); } }} > @@ -663,9 +673,7 @@ export default function NavbarDocumentDivision() { ) : ( dataDocument.map((v, i) => { - const isSelected = selectedFiles.some( - (i: any) => i?.id == v.id - ); + const isSelected = selectedFiles.some((i: any) => i?.id == v.id); return ( @@ -680,20 +688,17 @@ export default function NavbarDocumentDivision() { xl: 1, }} onClick={() => { - if ( - v.category == "FOLDER" && - selectedFiles.length == 0 && - !dariSelectAll - ) { + if (v.category == "FOLDER" && selectedFiles.length == 0 && !dariSelectAll) { router.push("?path=" + v.id); - } else if ( - v.category == "FILE" && - selectedFiles.length == 0 && - !dariSelectAll - ) { + } else if (v.category == "FILE" && selectedFiles.length == 0 && !dariSelectAll) { setExtension(v.extension); setIdStorage(v.idStorage); - setOpenModalView(true); + setNameFileFull(v.name + "." + v.extension) + if (v.extension != "doc" && v.extension != "docx" && v.extension != "xls" && v.extension != "xlsx" && v.extension != "ppt" && v.extension != "pptx") { + setOpenModalView(true); + } else { + onDownload("klik", { idFile: v.idStorage, nameFile: v.name + "." + v.extension }) + } } }} > @@ -712,7 +717,13 @@ export default function NavbarDocumentDivision() { {v.category == "FOLDER" ? ( ) : v.extension == "pdf" || - v.extension == "csv" ? ( + v.extension == "csv" || + v.extension == "doc" || + v.extension == "docx" || + v.extension == "xls" || + v.extension == "xlsx" || + v.extension == "ppt" || + v.extension == "pptx" ? ( ) : ( @@ -723,7 +734,13 @@ export default function NavbarDocumentDivision() { {v.category == "FOLDER" ? ( ) : v.extension == "pdf" || - v.extension == "csv" ? ( + v.extension == "csv" || + v.extension == "doc" || + v.extension == "docx" || + v.extension == "xls" || + v.extension == "xlsx" || + v.extension == "ppt" || + v.extension == "pptx" ? ( ) : ( @@ -747,20 +764,17 @@ export default function NavbarDocumentDivision() { { - if ( - v.category == "FOLDER" && - selectedFiles.length == 0 && - !dariSelectAll - ) { + if (v.category == "FOLDER" && selectedFiles.length == 0 && !dariSelectAll) { router.push("?path=" + v.id); - } else if ( - v.category == "FILE" && - selectedFiles.length == 0 && - !dariSelectAll - ) { + } else if (v.category == "FILE" && selectedFiles.length == 0 && !dariSelectAll) { setExtension(v.extension); setIdStorage(v.idStorage); - setOpenModalView(true); + setNameFileFull(v.name + "." + v.extension) + if (v.extension != "doc" && v.extension != "docx" && v.extension != "xls" && v.extension != "xlsx" && v.extension != "ppt" && v.extension != "pptx") { + setOpenModalView(true); + } else { + onDownload("klik", { idFile: v.idStorage, nameFile: v.name + "." + v.extension }) + } } }} > diff --git a/src/module/project/ui/add_file_detail_project.tsx b/src/module/project/ui/add_file_detail_project.tsx index c6ca3dd..d1efa2c 100644 --- a/src/module/project/ui/add_file_detail_project.tsx +++ b/src/module/project/ui/add_file_detail_project.tsx @@ -69,7 +69,6 @@ export default function AddFileDetailProject() { } const response = await funAddFileProject(param.id, fd) - console.group(response) if (response.success) { setDataRealtime([{ category: "project-detail-file", @@ -107,7 +106,7 @@ export default function AddFileDetailProject() { }} activateOnClick={false} maxSize={3 * 1024 ** 2} - accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf']} + accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') }} diff --git a/src/module/project/ui/create_project.tsx b/src/module/project/ui/create_project.tsx index 57793c6..31232ff 100644 --- a/src/module/project/ui/create_project.tsx +++ b/src/module/project/ui/create_project.tsx @@ -413,7 +413,7 @@ export default function CreateProject() { }} activateOnClick={false} maxSize={3 * 1024 ** 2} - accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf']} + accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') }} diff --git a/src/module/project/ui/list_file_detail_project.tsx b/src/module/project/ui/list_file_detail_project.tsx index 9a65f43..c9fe0ad 100644 --- a/src/module/project/ui/list_file_detail_project.tsx +++ b/src/module/project/ui/list_file_detail_project.tsx @@ -7,8 +7,9 @@ import { useMediaQuery, useShallowEffect } from '@mantine/hooks'; import { useParams } from 'next/navigation'; import { useState } from 'react'; import toast from 'react-hot-toast'; -import { BsFileTextFill, BsFiletypeCsv, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng } from 'react-icons/bs'; +import { BsFileTextFill, BsFiletypeCsv, BsFiletypeDocx, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng, BsFiletypePptx, BsFiletypeXlsx } from 'react-icons/bs'; import { FaTrash } from 'react-icons/fa6'; +import { ImDownload3 } from "react-icons/im"; import { useWibuRealtime } from 'wibu-realtime'; import { funDeleteFileProject, funGetOneProjectById } from '../lib/api_project'; import { IDataFileProject } from '../lib/type_project'; @@ -113,6 +114,28 @@ export default function ListFileDetailProject() { } }, [dataRealTime]) + const onDownload = async () => { + try { + const fileUrl = `https://wibu-storage.wibudev.com/api/files/${idStorage}`; + const response = await fetch(fileUrl); + const blob = await response.blob(); + + // Create a link element, use Blob URL + const link = document.createElement("a"); + const url = window.URL.createObjectURL(blob); + link.href = url; + link.download = `${nameData}`; // Nama file yang akan diunduh + document.body.appendChild(link); + link.click(); + + // Cleanup + window.URL.revokeObjectURL(url); + document.body.removeChild(link); + } catch (error) { + alert(error); + } + }; + return ( <> @@ -167,13 +190,12 @@ export default function ListFileDetailProject() { }}> {item.extension == "pdf" && } {item.extension == "csv" && } - {item.extension == "png" && } - {item.extension == "jpg" && } - {item.extension == "jpeg" && } - {item.extension == "PNG" && } - {item.extension == "JPG" && } - {item.extension == "JPEG" && } + {(item.extension == "png" || item.extension == "PNG") && } + {(item.extension == "jpg" || item.extension == "jpeg" || item.extension == "JPG" || item.extension == "JPEG") && } {item.extension == "heic" && } + {(item.extension == "doc" || item.extension == "docx") && } + {(item.extension == "xls" || item.extension == "xlsx") && } + {(item.extension == "ppt" || item.extension == "pptx") && } {nameData}} onClose={() => setOpenDrawer(false)}> - - { setOpenModalView(true) }} justify={'center'} align={'center'} direction={'column'} > + + { + (isExtension != "doc" && isExtension != "docx" && isExtension != "xls" && isExtension != "xlsx" && isExtension != "ppt" && isExtension != "pptx") && + { setOpenModalView(true) }} justify={'center'} align={'center'} direction={'column'} > + + + + + Lihat file + + + } + + { onDownload() }} justify={'center'} align={'center'} direction={'column'} > - + - Lihat file + Download @@ -227,7 +259,7 @@ export default function ListFileDetailProject() { - Hapus file + Hapus } diff --git a/src/module/project/ui/results_file.tsx b/src/module/project/ui/results_file.tsx index 86c1f4d..4709110 100644 --- a/src/module/project/ui/results_file.tsx +++ b/src/module/project/ui/results_file.tsx @@ -1,10 +1,38 @@ - import { Box, Center, Grid, Group, Text } from '@mantine/core'; -import React from 'react'; -import { BsFiletypeCsv, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng } from 'react-icons/bs'; +import { useShallowEffect } from '@mantine/hooks'; +import { useState } from 'react'; +import { BsFiletypeCsv, BsFiletypeDocx, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng, BsFiletypePptx, BsFiletypeXlsx } from 'react-icons/bs'; import { IListFileTaskProject } from '../lib/type_project'; export default function ResultsFile({ name, extension }: IListFileTaskProject) { + const [fixed, setFixed] = useState(extension) + + function cekExtension() { + let jadi = extension + if (extension == "msword") { + jadi = "doc" + } else if (extension == "vnd.openxmlformats-officedocument.wordprocessingml.document") { + jadi = "docx" + } else if (extension == "vnd.ms-excel") { + jadi = "xls" + } else if (extension == "vnd.openxmlformats-officedocument.spreadsheetml.sheet") { + jadi = "xlsx" + } else if (extension == "vnd.ms-powerpoint") { + jadi = "ppt" + } else if (extension == "vnd.openxmlformats-officedocument.presentationml.presentation") { + jadi = "pptx" + } else { + jadi = extension + } + + setFixed(jadi) + } + + + useShallowEffect(() => { + cekExtension() + }, []); + return (
- {extension == "pdf" && } - {extension == "csv" && } - {extension == "png" && } - {extension == "jpg" || extension == "jpeg" && } - {extension == "heic" && } + {fixed == "pdf" && } + {fixed == "csv" && } + {fixed == "png" && } + {fixed == "jpg" || fixed == "jpeg" && } + {fixed == "heic" && } + {fixed == "doc" || fixed == "docx" && } + {fixed == "xls" || fixed == "xlsx" && } + {fixed == "ppt" || fixed == "pptx" && }
diff --git a/src/module/task/ui/add_file_detail_task.tsx b/src/module/task/ui/add_file_detail_task.tsx index 7bc6884..a9d2150 100644 --- a/src/module/task/ui/add_file_detail_task.tsx +++ b/src/module/task/ui/add_file_detail_task.tsx @@ -107,7 +107,7 @@ export default function AddFileDetailTask() { }} activateOnClick={false} maxSize={3 * 1024 ** 2} - accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf']} + accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') }} diff --git a/src/module/task/ui/create_task.tsx b/src/module/task/ui/create_task.tsx index dc4a033..bda6323 100644 --- a/src/module/task/ui/create_task.tsx +++ b/src/module/task/ui/create_task.tsx @@ -336,7 +336,7 @@ export default function CreateTask() { }} activateOnClick={false} maxSize={3 * 1024 ** 2} - accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf']} + accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') }} diff --git a/src/module/task/ui/detail_list_file_task.tsx b/src/module/task/ui/detail_list_file_task.tsx index 50364d4..198bddc 100644 --- a/src/module/task/ui/detail_list_file_task.tsx +++ b/src/module/task/ui/detail_list_file_task.tsx @@ -1,18 +1,19 @@ 'use client' import { globalRole, keyWibu, LayoutDrawer, LayoutModalViewFile, TEMA } from "@/module/_global"; import LayoutModal from "@/module/_global/layout/layout_modal"; +import { globalIsMemberDivision } from "@/module/division_new"; import { useHookstate } from "@hookstate/core"; import { Box, Center, Flex, Grid, Group, SimpleGrid, Skeleton, Stack, Text } from "@mantine/core"; import { useShallowEffect } from "@mantine/hooks"; import { useParams } from "next/navigation"; import { useState } from "react"; import toast from "react-hot-toast"; -import { BsFileTextFill, BsFiletypeCsv, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng } from "react-icons/bs"; +import { BsFileTextFill, BsFiletypeCsv, BsFiletypeDocx, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng, BsFiletypePptx, BsFiletypeXlsx } from "react-icons/bs"; import { FaTrash } from "react-icons/fa6"; +import { ImDownload3 } from "react-icons/im"; import { useWibuRealtime } from "wibu-realtime"; import { funDeleteFileTask, funGetTaskDivisionById } from "../lib/api_task"; import { IDataFileTaskDivision } from "../lib/type_task"; -import { globalIsMemberDivision } from "@/module/division_new"; export default function ListFileDetailTask() { const roleLogin = useHookstate(globalRole) @@ -111,6 +112,28 @@ export default function ListFileDetailTask() { } }, [dataRealTime]) + const onDownload = async () => { + try { + const fileUrl = `https://wibu-storage.wibudev.com/api/files/${idDataStorage}`; + const response = await fetch(fileUrl); + const blob = await response.blob(); + + // Create a link element, use Blob URL + const link = document.createElement("a"); + const url = window.URL.createObjectURL(blob); + link.href = url; + link.download = `${nameData}`; // Nama file yang akan diunduh + document.body.appendChild(link); + link.click(); + + // Cleanup + window.URL.revokeObjectURL(url); + document.body.removeChild(link); + } catch (error) { + alert(error); + } + }; + return ( File @@ -159,13 +182,12 @@ export default function ListFileDetailTask() {
{item.extension == "pdf" && } {item.extension == "csv" && } - {item.extension == "png" && } - {item.extension == "jpg" && } - {item.extension == "jpeg" && } - {item.extension == "PNG" && } - {item.extension == "JPG" && } - {item.extension == "JPEG" && } + {(item.extension == "png" || item.extension == "PNG") && } + {(item.extension == "jpg" || item.extension == "jpeg" || item.extension == "JPG" || item.extension == "JPEG") && } {item.extension == "heic" && } + {(item.extension == "doc" || item.extension == "docx") && } + {(item.extension == "xls" || item.extension == "xlsx") && } + {(item.extension == "ppt" || item.extension == "pptx") && }
@@ -185,15 +207,24 @@ export default function ListFileDetailTask() { {nameData}} onClose={() => setOpenDrawer(false)}> - - { setOpenModalView(true) }} justify={'center'} align={'center'} direction={'column'} > + + { + (isExtension != "doc" && isExtension != "docx" && isExtension != "xls" && isExtension != "xlsx" && isExtension != "ppt" && isExtension != "pptx") && + { setOpenModalView(true) }} justify={'center'} align={'center'} direction={'column'} > + + + + + Lihat file + + + } + { onDownload() }} justify={'center'} align={'center'} direction={'column'} > - + - Lihat file + Download { diff --git a/src/module/task/ui/results_file.tsx b/src/module/task/ui/results_file.tsx index 4bc6f5c..ebfbc62 100644 --- a/src/module/task/ui/results_file.tsx +++ b/src/module/task/ui/results_file.tsx @@ -1,9 +1,38 @@ import { Box, Center, Grid, Group, Text } from '@mantine/core'; -import React from 'react'; -import { BsFiletypeCsv, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng } from 'react-icons/bs'; +import React, { useState } from 'react'; +import { BsFiletypeCsv, BsFiletypeDocx, BsFiletypeHeic, BsFiletypeJpg, BsFiletypePdf, BsFiletypePng, BsFiletypePptx, BsFiletypeXlsx } from 'react-icons/bs'; import { IListFileTask } from '../lib/type_task'; +import { useShallowEffect } from '@mantine/hooks'; export default function ResultsFile({ name, extension }: IListFileTask) { + const [fixed, setFixed] = useState(extension) + + function cekExtension() { + let jadi = extension + if (extension == "msword") { + jadi = "doc" + } else if (extension == "vnd.openxmlformats-officedocument.wordprocessingml.document") { + jadi = "docx" + } else if (extension == "vnd.ms-excel") { + jadi = "xls" + } else if (extension == "vnd.openxmlformats-officedocument.spreadsheetml.sheet") { + jadi = "xlsx" + } else if (extension == "vnd.ms-powerpoint") { + jadi = "ppt" + } else if (extension == "vnd.openxmlformats-officedocument.presentationml.presentation") { + jadi = "pptx" + } else { + jadi = extension + } + + setFixed(jadi) + } + + + useShallowEffect(() => { + cekExtension() + }, []); + return (
- {extension == "pdf" && } - {extension == "csv" && } - {extension == "png" && } - {extension == "jpg" && } - {extension == "jpeg" && } - {extension == "PNG" && } - {extension == "JPG" && } - {extension == "JPEG" && } - {extension == "heic" && } + {fixed == "pdf" && } + {fixed == "csv" && } + {fixed == "png" && } + {fixed == "jpg" || fixed == "jpeg" && } + {fixed == "heic" && } + {fixed == "doc" || fixed == "docx" && } + {fixed == "xls" || fixed == "xlsx" && } + {fixed == "ppt" || fixed == "pptx" && }
From 9b8ca0c99c6be01df2eb29d43ae4f164b3118985 Mon Sep 17 00:00:00 2001 From: amel Date: Sun, 5 Jan 2025 17:34:27 +0800 Subject: [PATCH 4/5] rev: alert file upload Deskripsi; - perbaiki alert file upload No Issues --- src/module/document/ui/drawer_menu_document_division.tsx | 2 +- src/module/project/ui/add_file_detail_project.tsx | 2 +- src/module/project/ui/create_project.tsx | 2 +- src/module/task/ui/add_file_detail_task.tsx | 2 +- src/module/task/ui/create_task.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/module/document/ui/drawer_menu_document_division.tsx b/src/module/document/ui/drawer_menu_document_division.tsx index cc99b97..f6de9db 100644 --- a/src/module/document/ui/drawer_menu_document_division.tsx +++ b/src/module/document/ui/drawer_menu_document_division.tsx @@ -154,7 +154,7 @@ export default function DrawerMenuDocumentDivision() { refresh.set(true) setOpenModal(false) setOpenDrawerDocument(false) - toast.error('File yang diizinkan: .csv, .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') + toast.error('File yang diizinkan: .csv, .png, .jpg, .heic, .pdf, .doc, .docx, .xls, .xlsx dengan ukuran maksimal 3 MB') }} > openRef.current?.()}> diff --git a/src/module/project/ui/add_file_detail_project.tsx b/src/module/project/ui/add_file_detail_project.tsx index d1efa2c..b1ceb76 100644 --- a/src/module/project/ui/add_file_detail_project.tsx +++ b/src/module/project/ui/add_file_detail_project.tsx @@ -108,7 +108,7 @@ export default function AddFileDetailProject() { maxSize={3 * 1024 ** 2} accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { - return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') + return toast.error('File yang diizinkan: .csv, .png, .jpg, .heic, .pdf, .doc, .docx, .xls, .xlsx dengan ukuran maksimal 3 MB') }} > diff --git a/src/module/project/ui/create_project.tsx b/src/module/project/ui/create_project.tsx index 31232ff..1a09ae0 100644 --- a/src/module/project/ui/create_project.tsx +++ b/src/module/project/ui/create_project.tsx @@ -415,7 +415,7 @@ export default function CreateProject() { maxSize={3 * 1024 ** 2} accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { - return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') + return toast.error('File yang diizinkan: .csv, .png, .jpg, .heic, .pdf, .doc, .docx, .xls, .xlsx dengan ukuran maksimal 3 MB') }} > diff --git a/src/module/task/ui/add_file_detail_task.tsx b/src/module/task/ui/add_file_detail_task.tsx index a9d2150..a992454 100644 --- a/src/module/task/ui/add_file_detail_task.tsx +++ b/src/module/task/ui/add_file_detail_task.tsx @@ -109,7 +109,7 @@ export default function AddFileDetailTask() { maxSize={3 * 1024 ** 2} accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { - return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') + return toast.error('File yang diizinkan: .csv, .png, .jpg, .heic, .pdf, .doc, .docx, .xls, .xlsx dengan ukuran maksimal 3 MB') }} > diff --git a/src/module/task/ui/create_task.tsx b/src/module/task/ui/create_task.tsx index bda6323..fc24332 100644 --- a/src/module/task/ui/create_task.tsx +++ b/src/module/task/ui/create_task.tsx @@ -338,7 +338,7 @@ export default function CreateTask() { maxSize={3 * 1024 ** 2} accept={['image/png', 'image/jpeg', 'image/heic', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']} onReject={(files) => { - return toast.error('File yang diizinkan: .png, .jpg, .heic, .pdf dengan ukuran maksimal 3 MB') + return toast.error('File yang diizinkan: .csv, .png, .jpg, .heic, .pdf, .doc, .docx, .xls, .xlsx dengan ukuran maksimal 3 MB') }} > From e697b2d650a511d926138e67249eac70afe69ede Mon Sep 17 00:00:00 2001 From: amel Date: Sun, 5 Jan 2025 18:06:55 +0800 Subject: [PATCH 5/5] rev: create divisi Deskripsi: - anggota divisi boleh 1 anggota saja No Issues --- src/module/division_new/ui/create_division.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/module/division_new/ui/create_division.tsx b/src/module/division_new/ui/create_division.tsx index 22c9373..3996563 100644 --- a/src/module/division_new/ui/create_division.tsx +++ b/src/module/division_new/ui/create_division.tsx @@ -49,8 +49,11 @@ export default function CreateDivision() { const cek = checkAll() if (!cek) return false - if (member.length <= 1) - return toast.error("Error! Silahkan pilih anggota lebih dari 1") + + if (member.length == 0) + return toast.error("Error! Silahkan pilih anggota") + // if (member.length <= 1) + // return toast.error("Error! Silahkan pilih anggota lebih dari 1") setChooseAdmin(true) }