refactor : divisi

Deskripsi:
- folder management divisi

No Issues
This commit is contained in:
amel
2024-08-13 10:25:27 +08:00
parent 334f94cb39
commit a628e1c053
28 changed files with 21 additions and 39 deletions

View File

@@ -0,0 +1,37 @@
'use client'
import React, { useRef } from 'react';
import { Carousel } from '@mantine/carousel';
import { WARNA } from '@/module/_global';
import Autoplay from 'embla-carousel-autoplay';
import { Flex, Text } from '@mantine/core';
export default function CarouselDivision() {
const autoplay = useRef(Autoplay({ delay: 5000 }));
return (
<>
<Carousel
withIndicators
height={150}
plugins={[autoplay.current]}
onMouseEnter={autoplay.current.stop}
onMouseLeave={autoplay.current.reset}
>
<Carousel.Slide bg={WARNA.biruTua} style={{ borderRadius: 10 }}>
<Flex justify={'center'} h={"100%"} align={'center'}>
<Text c={"white"}>INFORMASI DARMASABA</Text>
</Flex>
</Carousel.Slide>
<Carousel.Slide bg={WARNA.biruTua} style={{ borderRadius: 10 }}>
<Flex justify={'center'} h={"100%"} align={'center'}>
<Text c={"white"}>INFORMASI DARMASABA</Text>
</Flex>
</Carousel.Slide>
<Carousel.Slide bg={WARNA.biruTua} style={{ borderRadius: 10 }}>
<Flex justify={'center'} h={"100%"} align={'center'}>
<Text c={"white"}>INFORMASI DARMASABA</Text>
</Flex>
</Carousel.Slide>
</Carousel>
</>
);
}

View File

@@ -0,0 +1,9 @@
import React from 'react';
import NavbarAdminDivision from './navbar_admin_division';
export default function CreateAdminDivision({ data }: { data: any }) {
return (
<NavbarAdminDivision data={data} onSuccess={() => { }} />
);
}

View File

@@ -0,0 +1,184 @@
"use client"
import { API_ADDRESS, LayoutNavbarNew, WARNA } from '@/module/_global';
import LayoutModal from '@/module/_global/layout/layout_modal';
import { funGetUserByCookies } from '@/module/auth';
import { TypeUser } from '@/module/user';
import { useHookstate } from '@hookstate/core';
import { Avatar, Box, Button, Divider, Group, Stack, Text, TextInput } from '@mantine/core';
import { useParams, useRouter } from 'next/navigation';
import React, { useState } from 'react';
import toast from 'react-hot-toast';
import { FaCheck } from 'react-icons/fa6';
import { HiMagnifyingGlass } from 'react-icons/hi2';
import { globalMemberDivision } from '../lib/val_division';
import { useShallowEffect } from '@mantine/hooks';
import { funGetAllmember } from '@/module/user/member/lib/api_member';
import { IDataMemberDivision } from '../lib/type_division';
import { funAddDivisionMember, funGetDivisionById } from '../lib/api_division';
const dataUser = [
{
id: 1,
img: "https://i.pravatar.cc/1000?img=3",
name: "Doni Setiawan",
},
{
id: 2,
img: "https://i.pravatar.cc/1000?img=10",
name: "Ilham Udin",
},
{
id: 3,
img: "https://i.pravatar.cc/1000?img=11",
name: "Didin Anang",
},
{
id: 4,
img: "https://i.pravatar.cc/1000?img=21",
name: "Angga Saputra",
},
{
id: 5,
img: "https://i.pravatar.cc/1000?img=32",
name: "Marcel Widianto",
},
{
id: 6,
img: "https://i.pravatar.cc/1000?img=37",
name: "Bagas Nusantara",
},
];
export default function CreateAnggotaDivision() {
const router = useRouter()
const [selectedFiles, setSelectedFiles] = useState<any>([]);
const [dataMember, setDataMember] = useState<TypeUser>([])
const [memberDb, setMemberDb] = useState<IDataMemberDivision[]>([])
const [group, setGroup] = useState("")
const [isOpen, setOpen] = useState(false)
const param = useParams<{ id: string }>()
const handleFileClick = (index: number) => {
if (selectedFiles.some((i: any) => i.idUser == dataMember[index].id)) {
setSelectedFiles(selectedFiles.filter((i: any) => i.idUser != dataMember[index].id))
} else {
setSelectedFiles([...selectedFiles, { idUser: dataMember[index].id, name: dataMember[index].name }])
}
};
async function loadMember(group: string, search: string) {
const res = await funGetAllmember('?active=true&group=' + group + '&search=' + search);
const user = await funGetUserByCookies();
if (res.success) {
setDataMember(res.data.filter((i: any) => i.id != user.id))
} else {
toast.error(res.message)
}
}
async function loadFirst() {
const respon = await funGetDivisionById(param.id);
if (respon.success) {
setMemberDb(respon.data.member)
setGroup(respon.data.division.idGroup)
loadMember(respon.data.division.idGroup, "")
} else {
toast.error(respon.message);
}
}
async function addMember() {
try {
const res = await funAddDivisionMember(param.id, selectedFiles)
if (res.success) {
toast.success(res.message)
router.push("/division/info/" + param.id)
} else {
toast.error(res.message)
}
setOpen(false)
} catch (error) {
setOpen(false)
console.log(error);
toast.error("Gagal menambahkan anggota divisi, coba lagi nanti");
}
}
useShallowEffect(() => {
loadFirst()
}, []);
return (
<Box>
<LayoutNavbarNew back="" title="tambah anggota"
menu
/>
<Box p={20}>
<Stack>
<TextInput
styles={{
input: {
color: WARNA.biruTua,
borderRadius: '#A3A3A3',
borderColor: '#A3A3A3',
},
}}
size="md"
radius={30}
leftSection={<HiMagnifyingGlass size={20} />}
placeholder="Pencarian"
onChange={(e: any) => loadMember(group, e.target.value)}
/>
</Stack>
<Box mt={20}>
{dataMember.map((v: any, index: any) => {
const isSelected = selectedFiles.some((i: any) => i.idUser == dataMember[index].id)
const found = memberDb.some((i: any) => i.idUser == v.id)
return (
<Box my={10} key={index} onClick={() => (!found) ? handleFileClick(index) : null}>
<Group justify='space-between' align='center'>
<Group>
<Avatar src={"v.img"} alt="it's me" size="lg" />
<Stack align="flex-start" justify="flex-start">
<Text>{v.name}</Text>
<Text c={"dimmed"}>{(found) ? "sudah menjadi anggota divisi" : ""}</Text>
</Stack>
</Group>
{isSelected ? <FaCheck /> : null}
</Group>
<Box mt={10}>
<Divider size={"xs"} />
</Box>
</Box>
)
})}
</Box>
<Box mt="xl">
<Button
color="white"
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { setOpen(true) }}
>
Simpan
</Button>
</Box>
</Box>
<LayoutModal opened={isOpen} onClose={() => setOpen(false)}
description="Apakah Anda yakin ingin menambahkan anggota divisi?"
onYes={(val) => {
if (val) {
addMember()
} else {
setOpen(false)
}
}} />
</Box>
);
}

View File

@@ -0,0 +1,216 @@
"use client";
import { API_ADDRESS, LayoutNavbarNew, WARNA } from "@/module/_global";
import { useHookstate } from "@hookstate/core";
import {
Avatar,
Box,
Button,
Flex,
Group,
Select,
Stack,
Text,
Textarea,
TextInput,
} from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import React, { useState } from "react";
import { IoIosArrowDropright } from "react-icons/io";
import { globalMemberDivision } from "../lib/val_division";
import toast from "react-hot-toast";
import { funGetUserByCookies } from "@/module/auth";
import { funGetAllGroup, IDataGroup } from "@/module/group";
import NavbarAdminDivision from "./navbar_admin_division";
import NavbarCreateUsers from "./navbar_create_users";
export default function CreateDivision() {
const router = useRouter();
const [dataGroup, setDataGroup] = useState<IDataGroup[]>([]);
const [roleUser, setRoleUser] = useState<any>("")
const [isChooseAnggota, setChooseAnggota] = useState(false)
const [isChooseAdmin, setChooseAdmin] = useState(false)
const member = useHookstate(globalMemberDivision)
const [body, setBody] = useState<any>({
idGroup: "",
name: "",
desc: "",
});
async function loadData() {
const loadGroup = await funGetAllGroup('?active=true')
if (loadGroup.success) {
setDataGroup(loadGroup.data);
} else {
toast.error(loadGroup.message);
}
const loadUser = await funGetUserByCookies();
setRoleUser(loadUser.idUserRole)
}
function onSubmit() {
if (roleUser == "supadmin" && (body.idGroup == "" || body.idGroup == null)) {
return toast.error("Error! grup harus diisi")
}
if (body.name == "") {
return toast.error("Error! nama divisi harus diisi")
}
if (member.length == 0) {
return toast.error("Error! belum ada anggota yang terdaftar")
}
setChooseAdmin(true)
}
function onToChooseAnggota() {
if (roleUser == "supadmin" && body.idGroup == "")
return toast.error("Error! grup harus diisi")
setChooseAnggota(true)
}
function onChooseGroup(val: any) {
member.set([])
setBody({ ...body, idGroup: val })
}
useShallowEffect(() => {
loadData();
}, []);
if (isChooseAdmin) return <NavbarAdminDivision data={body} onSuccess={(val) => {
if (val) {
member.set([])
setBody({
...body,
idGroup: "",
name: "",
desc: "",
})
}
setChooseAdmin(false)
}} />
if (isChooseAnggota) return <NavbarCreateUsers grup={body.idGroup} onClose={() => { setChooseAnggota(false) }} />
return (
<Box>
<LayoutNavbarNew back="/division" title="Tambah Divisi" menu />
<Box p={20}>
<Stack>
{
(roleUser == "supadmin") && (
<Select
placeholder="Grup"
label="Grup"
size="md"
required
radius={40}
data={dataGroup?.map((pro: any) => ({
value: String(pro.id),
label: pro.name
}))}
onChange={(val) => {
onChooseGroup(val)
}}
value={body.idGroup}
/>
)
}
<TextInput
placeholder="Nama Divisi"
label="Nama Divisi"
size="md"
required
radius={40}
value={body.name}
onChange={(val) => { setBody({ ...body, name: val.target.value }) }}
/>
<Textarea size="md" placeholder="Deskripsi" label="Deskripsi" value={body.desc} radius={10} onChange={(val) => { setBody({ ...body, desc: val.currentTarget.value }) }} />
<Box onClick={() => { onToChooseAnggota() }}>
<Group
justify="space-between"
p={10}
style={{
border: `1px solid ${"#D6D8F6"}`,
borderRadius: 10,
}}
>
<Text>Pilih Anggota</Text>
<IoIosArrowDropright size={25} />
</Group>
</Box>
<Box pt={20}>
<Group justify="space-between">
<Text c={WARNA.biruTua}>Anggota Terpilih</Text>
<Text c={WARNA.biruTua}>Total {member.length} Anggota</Text>
</Group>
<Box pt={10}>
<Box mb={20}>
<Box
style={{
border: `1px solid ${"#C7D6E8"}`,
borderRadius: 10,
}}
px={20}
py={10}
>
{(member.length === 0) ? (
<Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada anggota</Text>
) : member.get().map((v: any, i: any) => {
return (
<Flex
justify={"space-between"}
align={"center"}
mt={20}
key={i}
>
<Group>
<Avatar src={v.img} alt="it's me" size="lg" />
<Box>
<Text c={WARNA.biruTua} fw={"bold"}>
{v.name}
</Text>
</Box>
</Group>
<Text c={WARNA.biruTua} fw={"bold"}>
Anggota
</Text>
</Flex>
);
})}
</Box>
</Box>
</Box>
</Box>
<Box mt="xl">
<Button
color="white"
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => {
onSubmit()
}}
>
Simpan
</Button>
</Box>
</Stack>
</Box>
</Box>
);
}

View File

@@ -0,0 +1,86 @@
"use client";
import { LayoutNavbarNew, WARNA } from "@/module/_global";
import { Box, Select, Stack, Text } from "@mantine/core";
import { DateInput } from "@mantine/dates";
import React, { useState } from "react";
import EchartPaiReport from "./echart_pai_report";
import EchartBarReport from "./echart_bar_report";
import EventReport from "./event_report";
import DiscussionReport from "./discussion_report";
export default function CreateReport() {
const [value, setValue] = useState<Date | null>(null);
return (
<Box>
<LayoutNavbarNew back="/division" title="Report Divisi" menu />
<Box p={20}>
<Stack>
<Select
placeholder="Grup"
label="Grup"
size="md"
required
radius={10}
/>
<DateInput
value={value}
onChange={setValue}
radius={10}
size="md"
required
label="Date input"
placeholder="Date input"
/>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<EchartPaiReport />
</Box>
</Box>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<EchartBarReport />
</Box>
</Box>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<EventReport />
</Box>
</Box>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<DiscussionReport />
</Box>
</Box>
</Stack>
</Box>
</Box>
);
}

View File

@@ -0,0 +1,9 @@
import React from 'react';
import NavbarCreateUsers from './navbar_create_users';
export default function CreateUsers({ grup }: { grup: string }) {
return (
<NavbarCreateUsers grup={grup} onClose={() => {}}/>
);
}

View File

@@ -0,0 +1,67 @@
import { WARNA } from "@/module/_global";
import { Box, Group, Text } from "@mantine/core";
import { GoDiscussionClosed } from "react-icons/go";
import { CiClock2, CiUser } from "react-icons/ci";
const dataDiskusi = [
{
id: 1,
judul: 'Mengatasi Limbah Makanan ',
user: 'Fibra Marcell',
date: '21 Juni 2024'
},
{
id: 2,
judul: 'Pentingnya Menjaga Kelestarian Hutan ',
user: 'Bayu Tegar',
date: '15 Juni 2024'
},
{
id: 3,
judul: 'Mengatasi Limbah Industri ',
user: 'Nian Putri',
date: '11 Mei 2024'
},
{
id: 4,
judul: 'Manfaat Sampah Plastik',
user: 'Budi Prasetyo',
date: '10 Mei 2024'
},
]
export default function DiscussionReport() {
return (
<Box pt={10}>
<Text ta={"center"} mb={20} fw={'bold'}>DISKUSI</Text>
{dataDiskusi.map((v, i) => {
return (
<Box key={i} m={10}>
<Box style={{
borderRadius: 10,
border: `1px solid ${"#D6D8F6"}`,
padding: 15
}} mb={10}>
<Group align="center">
<GoDiscussionClosed size={25} />
<Box w={{ base: 230, md: 300 }}>
<Text truncate="end" fw={'bold'}>{v.judul}</Text>
</Box>
</Group>
<Group justify="space-between" align="center" mt={20} c={'#8C8C8C'}>
<Group gap={5} align="center">
<CiUser size={18} />
<Text fz={13}>{v.user}</Text>
</Group>
<Group gap={5} align="center">
<CiClock2 size={18} />
<Text fz={13}>{v.date}</Text>
</Group>
</Group>
</Box>
</Box>
)
})
}
</Box>
)
}

View File

@@ -0,0 +1,41 @@
"use client"
import { WARNA } from "@/module/_global";
import { Box, Stack, SimpleGrid, Flex, Text } from "@mantine/core";
import { useParams, useRouter } from "next/navigation";
import { BsInfoCircle } from "react-icons/bs";
import { FaPencil } from "react-icons/fa6";
import { TbReportAnalytics } from "react-icons/tb";
export default function DrawerDetailDivision() {
const param = useParams<{ id: string }>()
const router = useRouter()
return (
<Box>
<Stack pt={10}>
<SimpleGrid
cols={{ base: 2, sm: 2, lg: 3 }}
>
<Flex onClick={() => router.push('/division/info/' + param.id)} justify={'center'} align={'center'} direction={'column'} >
<Box>
<BsInfoCircle size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua}>Informasi Divisi</Text>
</Box>
</Flex>
<Flex onClick={() => {
router.push('/division/report/' + param.id)
}} justify={'center'} align={'center'} direction={'column'} >
<Box>
<TbReportAnalytics size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua}>Report Divisi</Text>
</Box>
</Flex>
</SimpleGrid>
</Stack>
</Box>
);
}

View File

@@ -0,0 +1,50 @@
"use client"
import { WARNA } from '@/module/_global';
import { Box, Flex, SimpleGrid, Stack, Text } from '@mantine/core';
import { useRouter } from 'next/navigation';
import React, { useState } from 'react';
import { HiOutlineFilter } from 'react-icons/hi';
import { IoAddCircle } from 'react-icons/io5';
import { TbReportAnalytics } from "react-icons/tb";
export default function DrawerDivision() {
const router = useRouter()
return (
<Box>
<Stack pt={10}>
<SimpleGrid
cols={{ base: 3, sm: 3, lg: 3 }}
>
<Flex onClick={() => router.push('/division/create')} justify={'center'} align={'center'} direction={'column'} >
<Box>
<IoAddCircle size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua}>Tambah Divisi</Text>
</Box>
</Flex>
<Flex onClick={() => {
router.push('/division?page=filter')
}} justify={'center'} align={'center'} direction={'column'} >
<Box>
<HiOutlineFilter size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua}>Filter</Text>
</Box>
</Flex>
<Flex onClick={() => {
router.push('/division?page=report')
}} justify={'center'} align={'center'} direction={'column'} >
<Box>
<TbReportAnalytics size={30} color={WARNA.biruTua} />
</Box>
<Box>
<Text c={WARNA.biruTua}>Report</Text>
</Box>
</Flex>
</SimpleGrid>
</Stack>
</Box>
);
}

View File

@@ -0,0 +1,105 @@
import React, { useState } from 'react';
import { EChartsOption, color } from "echarts";
import EChartsReact from "echarts-for-react";
import { useShallowEffect } from '@mantine/hooks';
import * as echarts from 'echarts';
import { Box } from '@mantine/core';
import { WARNA } from '@/module/_global';
export default function EchartBarReport() {
const [options, setOptions] = useState<EChartsOption>({});
useShallowEffect(() => {
loadData()
}, [])
const loadData = () => {
const option: EChartsOption = {
title: {
text: "DOKUMEN",
top: '2%',
left: 'center',
textStyle: {
color: WARNA.biruTua
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['File', 'Folder', 'Documen'],
axisLabel: {
fontSize: 14
},
axisTick: {
alignWithLabel: true
},
axisLine: {
show: true,
},
}
],
yAxis: [
{
type: 'value',
show: true,
splitLine: {
lineStyle: {
color: "gray",
opacity: 0.1
}
},
}
],
series: [
{
name: 'Direct',
type: 'bar',
barWidth: '70%',
data: [
{
value: 78,
name: 'Confidence',
itemStyle: {
color: "#F3C96B"
}
},
{
value: 35,
name: 'Supportive',
itemStyle: {
color: "#9EC97F"
}
},
{
value: 58,
name: 'Positive',
itemStyle: {
color: "#5971C0"
}
},
],
}
]
};
setOptions(option);
}
return (
<Box>
<EChartsReact style={{ height: 400, width: "auto" }} option={options} />
</Box>
);
}

View File

@@ -0,0 +1,69 @@
import React, { useState } from 'react';
import { EChartsOption, color } from "echarts";
import EChartsReact from "echarts-for-react";
import { useShallowEffect } from '@mantine/hooks';
import * as echarts from 'echarts';
import { Box } from '@mantine/core';
import { WARNA } from '@/module/_global';
export default function EchartPaiReport() {
const [options, setOptions] = useState<EChartsOption>({});
useShallowEffect(() => {
loadData()
}, [])
const loadData = () => {
const option: EChartsOption = {
title: {
text: "PROGRES TUGAS",
top: '2%',
left: 'center',
textStyle: {
color: WARNA.biruTua
}
},
legend: {
top: 'bottom',
},
series: [
{
name: 'Progres Tugas',
type: 'pie',
radius: '70%',
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 2,
borderWidth: 2
},
label: {
position: "inner",
formatter: (a) => {
return `${a.value + "%"}`;
},
},
data: [
{ value: 25, name: 'Dikerjakan' },
{ value: 35, name: 'Selesai dikerjakan' },
{ value: 10, name: 'Segera dikerjakan' },
{ value: 30, name: 'Batal dikerjakan' },
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
setOptions(option);
}
return (
<Box>
<EChartsReact style={{ height: 400, width: "auto" }} option={options} />
</Box>
);
}

View File

@@ -0,0 +1,130 @@
"use client"
import { LayoutNavbarNew, WARNA } from '@/module/_global';
import LayoutModal from '@/module/_global/layout/layout_modal';
import { Box, Button, Select, Stack, Textarea, 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 { funEditDivision, funGetDivisionById } from '../lib/api_division';
import { funGetAllGroup, IDataGroup } from '@/module/group';
import { funGetUserByCookies } from '@/module/auth';
export default function EditDivision() {
const [openModal, setOpenModal] = useState(false)
const router = useRouter()
const param = useParams<{ id: string }>()
const [loading, setLoading] = useState(false)
const [body, setBody] = useState<any>({
idGroup: "",
name: "",
desc: "",
});
function onTrue(val: boolean) {
if (val) {
toast.success("Sukses! Data tersimpan");
}
setOpenModal(false)
}
async function getOneData() {
try {
setLoading(true);
const res = await funGetDivisionById(param.id);
if (res.success) {
setBody({
...body,
idGroup: res.data.division.idGroup,
name: res.data.division.name,
desc: res.data.division.desc
})
} else {
toast.error(res.message);
}
setLoading(false);
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
} finally {
setLoading(false);
}
}
async function onUpdate() {
try {
const res = await funEditDivision(param.id, body)
if (res.success) {
toast.success(res.message)
} else {
toast.error(res.message)
}
setOpenModal(false)
} catch (error) {
console.log(error)
setOpenModal(false)
toast.error("Gagal mengedit divisi, coba lagi nanti");
}
}
useShallowEffect(() => {
getOneData();
}, [param.id])
return (
<Box>
<LayoutNavbarNew back="" title="Edit Divisi" menu />
<Box p={20}>
<Stack>
{/* <Select
placeholder="Grup"
label="Grup"
size="md"
required
radius={40}
/> */}
<TextInput
placeholder="Judul"
label="Judul"
size="md"
required
radius={40}
value={body.name}
onChange={(e) => { setBody({ ...body, name: e.target.value }) }}
/>
<Textarea placeholder="Deskripsi" label="Deskripsi" size="md" radius={10}
value={body.desc}
onChange={(e) => { setBody({ ...body, desc: e.currentTarget.value }) }}
/>
<Box mt="xl">
<Button
color="white"
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { setOpenModal(true) }}
>
Simpan
</Button>
</Box>
</Stack>
</Box>
<LayoutModal opened={openModal} onClose={() => setOpenModal(false)} description='Apakah Anda yakin ingin edit data'
onYes={(val) => {
if (val) {
onUpdate()
} else {
setOpenModal(false)
}
}} />
</Box>
)
}

View File

@@ -0,0 +1,62 @@
import { Box, Divider, Group, ScrollArea, Stack, Text } from '@mantine/core';
import React from 'react';
const dataEvent = [
{
id: 1,
title: 'Pembahasan Mengenai Darmasaba',
jamAwal: "10.00",
jamAkhir: "11.00",
dibuat: "Jhon"
},
{
id: 2,
title: 'Pembahasan Mengenai Darmasaba',
jamAwal: "11.00",
jamAkhir: "12.00",
dibuat: "Jhon"
},
{
id: 3,
title: 'Pembahasan Mengenai Darmasaba',
jamAwal: "13.00",
jamAkhir: "14.00",
dibuat: "Jhon"
},
{
id: 4,
title: 'Pembahasan Mengenai Darmasaba',
jamAwal: "15.00",
jamAkhir: "16.00",
dibuat: "Jhon"
},
]
export default function EventReport() {
return (
<Box>
<Text mb={20} mt={10} ta={'center'} fw={"bold"}>EVENT SELESAI DILAKSANAKAN</Text>
{dataEvent.map((event, index) => {
const bgColor = ['#D8D8F1', '#FED6C5'][index % 2]
const colorDivider = ['#535FCA', '#A7A7A7'][index % 2]
return (
<Box key={event.id} m={10}>
<Box bg={bgColor} pl={15} p={10} style={{
borderRadius: 10
}} h={113}>
<Group>
<Divider h={92} size="lg" orientation="vertical" color={colorDivider} />
<Box>
<Text>{event.jamAwal} - {event.jamAkhir}</Text>
<Text fw={"bold"}>{event.title}</Text>
<Text>Dibuat oleh : {event.dibuat}</Text>
</Box>
</Group>
</Box>
</Box>
)
})}
</Box>
);
}

View File

@@ -0,0 +1,157 @@
"use client"
import { WARNA } from '@/module/_global';
import { ActionIcon, Box, Center, Grid, Group, SimpleGrid, Text } from '@mantine/core';
import React, { useState } from 'react';
import { HiMiniUserGroup } from 'react-icons/hi2';
import { IoIosArrowRoundForward } from 'react-icons/io';
import { LuClipboardEdit } from "react-icons/lu";
import { GoCommentDiscussion } from "react-icons/go";
import { BsFileEarmarkText } from "react-icons/bs";
import { IoCalendarOutline } from "react-icons/io5";
import { LuFileSignature } from "react-icons/lu";
import { useParams, useRouter } from 'next/navigation';
import { funGetDetailDivisionById } from '../lib/api_division';
import toast from 'react-hot-toast';
import { useShallowEffect } from '@mantine/hooks';
import { IDataJumlahDetailDivision } from '../lib/type_division';
export default function FeatureDetailDivision() {
const param = useParams<{ id: string }>()
const router = useRouter()
const [feature, setFeature] = useState<IDataJumlahDetailDivision>()
async function fetchData() {
try {
const res = await funGetDetailDivisionById(param.id, 'jumlah');
if (res.success) {
setFeature(res.data)
} else {
toast.error(res.message);
}
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
}
}
useShallowEffect(() => {
fetchData()
}, [param.id])
return (
<Box pt={10}>
<Text c={WARNA.biruTua} mb={10} fw={'bold'} fz={16}>Features</Text>
<SimpleGrid
cols={{ base: 2, sm: 2, lg: 2 }}
style={{
alignItems: "center",
alignContent: "center"
}}
>
<Box bg={'white'} style={{
border: `1px solid ${WARNA.bgHijauMuda}`,
borderRadius: 10,
padding: 10
}} onClick={() => router.push(param.id + '/task')}>
<Grid justify='center' align='center'>
<Grid.Col span={"auto"}>
<ActionIcon variant="filled"
size={"xl"}
aria-label="Gradient action icon"
radius={100}
color={WARNA.bgHijauMuda}
>
<LuClipboardEdit size={25} color={WARNA.biruTua} />
</ActionIcon>
</Grid.Col>
<Grid.Col span={{ base: 7, md: 9 }}>
<Text fz={15} c={WARNA.biruTua} fw={"bold"}>Tugas</Text>
<Group justify='space-between' align='center'>
<Text fz={10} c={"gray"}>{feature?.tugas} Tugas</Text>
<IoIosArrowRoundForward size={20} color='gray' />
</Group>
</Grid.Col>
</Grid>
</Box>
<Box bg={'white'} style={{
border: `1px solid ${WARNA.bgHijauMuda}`,
borderRadius: 10,
padding: 10
}} onClick={() => router.push(param.id + '/document')}>
<Grid justify='center' align='center'>
<Grid.Col span={"auto"}>
<ActionIcon variant="filled"
size={"xl"}
aria-label="Gradient action icon"
radius={100}
color={WARNA.bgHijauMuda}
>
<BsFileEarmarkText size={25} color={WARNA.biruTua} />
</ActionIcon>
</Grid.Col>
<Grid.Col span={{ base: 7, md: 9 }}>
<Text fz={15} c={WARNA.biruTua} fw={"bold"}>Dokumen</Text>
<Group justify='space-between' align='center'>
<Text fz={10} c={"gray"}>{feature?.dokumen} File</Text>
<IoIosArrowRoundForward size={20} color='gray' />
</Group>
</Grid.Col>
</Grid>
</Box>
<Box bg={'white'} style={{
border: `1px solid ${WARNA.bgHijauMuda}`,
borderRadius: 10,
padding: 10
}} onClick={() => router.push(param.id + '/discussion')}>
<Grid justify='center' align='center'>
<Grid.Col span={"auto"}>
<ActionIcon variant="filled"
size={"xl"}
aria-label="Gradient action icon"
radius={100}
color={WARNA.bgHijauMuda}
>
<GoCommentDiscussion size={25} color={WARNA.biruTua} />
</ActionIcon>
</Grid.Col>
<Grid.Col span={{ base: 7, md: 9 }}>
<Text fz={15} c={WARNA.biruTua} fw={"bold"}>Diskusi</Text>
<Group justify='space-between' align='center'>
<Text fz={10} c={"gray"}>{feature?.diskusi} Diskusi</Text>
<IoIosArrowRoundForward size={20} color='gray' />
</Group>
</Grid.Col>
</Grid>
</Box>
<Box bg={'white'} style={{
border: `1px solid ${WARNA.bgHijauMuda}`,
borderRadius: 10,
padding: 10
}} onClick={() => router.push(param.id + '/calender')}>
<Grid justify='center' align='center'>
<Grid.Col span={"auto"}>
<ActionIcon variant="filled"
size={"xl"}
aria-label="Gradient action icon"
radius={100}
color={WARNA.bgHijauMuda}
>
<IoCalendarOutline size={25} color={WARNA.biruTua} />
</ActionIcon>
</Grid.Col>
<Grid.Col span={{ base: 7, md: 9 }}>
<Text fz={15} c={WARNA.biruTua} fw={"bold"}>Kalender</Text>
<Group justify='space-between' align='center'>
<Text fz={10} c={"gray"}>{feature?.kalender} Acara</Text>
<IoIosArrowRoundForward size={20} color='gray' />
</Group>
</Grid.Col>
</Grid>
</Box>
</SimpleGrid>
</Box>
);
}

View File

@@ -0,0 +1,219 @@
"use client"
import { LayoutDrawer, LayoutNavbarNew, SkeletonSingle, WARNA } from '@/module/_global';
import { ActionIcon, Avatar, Box, Button, Divider, Flex, Group, Skeleton, Stack, Text } 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 { AiOutlineUserAdd } from 'react-icons/ai';
import { FaUserTie } from 'react-icons/fa6';
import { IoIosCloseCircle } from 'react-icons/io';
import { LuClipboardEdit } from 'react-icons/lu';
import { funDeleteMemberDivision, funEditStatusAdminDivision, funGetDivisionById } from '../lib/api_division';
import { IDataMemberDivision } from '../lib/type_division';
import LayoutModal from '@/module/_global/layout/layout_modal';
export default function InformationDivision() {
const router = useRouter()
const [openDrawer, setDrawer] = useState(false)
const param = useParams<{ id: string }>()
const [name, setName] = useState('')
const [deskripsi, setDeskripsi] = useState('')
const [member, setMember] = useState<IDataMemberDivision[]>([])
const [loading, setLoading] = useState(false)
const [valChooseMember, setChooseMember] = useState("")
const [valChooseMemberStatus, setChooseMemberStatus] = useState<boolean>(false)
const [valChooseMemberName, setChooseMemberName] = useState("")
const [isOpenModal, setOpenModal] = useState(false)
async function getOneData() {
try {
setLoading(true);
const res = await funGetDivisionById(param.id);
if (res.success) {
setName(res.data.division.name);
setDeskripsi(res.data.division.desc);
setMember(res.data.member)
} else {
toast.error(res.message);
}
setLoading(false);
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
} finally {
setLoading(false);
}
}
useShallowEffect(() => {
getOneData();
}, [param.id])
async function onClickMember(id: string, status: boolean) {
setChooseMember(id)
setChooseMemberStatus(status)
setDrawer(true)
}
async function deleteMember() {
try {
const res = await funDeleteMemberDivision(param.id, { id: valChooseMember })
if (res.success) {
toast.success(res.message)
setDrawer(false)
getOneData()
} else {
toast.error(res.message)
}
setOpenModal(false)
} catch (error) {
console.error(error);
setOpenModal(false)
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
}
}
async function editStatusAdmin() {
try {
const res = await funEditStatusAdminDivision(param.id, { id: valChooseMember, isAdmin: valChooseMemberStatus })
if (res.success) {
toast.success(res.message)
getOneData()
} else {
toast.error(res.message)
}
setDrawer(false)
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
}
}
return (
<Box>
<LayoutNavbarNew back={""} title={name}
menu={
<ActionIcon variant="light" onClick={() => {
router.push('/division/edit/' + param.id)
}} bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Settings">
<LuClipboardEdit size={20} color='white' />
</ActionIcon>}
/>
<Box p={20}>
<Box>
<Text fw={"bold"}>Deskripsi Divisi</Text>
<Box p={20} bg={"white"} style={{
borderRadius: 10,
border: `1px solid ${WARNA.borderBiruMuda}`,
}}>
{
loading ?
Array(3)
.fill(null)
.map((_, i) => (
<Stack align="stretch" justify="center" key={i} mb={10}>
<Skeleton height={10} radius="md" m={0} />
</Stack>
))
:
(deskripsi != null && deskripsi != undefined) ?
<Text ta={"justify"}>{deskripsi}</Text>
: <></>
}
</Box>
</Box>
<Box mt={20}>
<Box p={20} bg={"white"} style={{
borderRadius: 10,
border: `1px solid ${WARNA.borderBiruMuda}`,
}}>
<Box>
<Text>{member.length} Anggota</Text>
</Box>
<Box mt={15}>
<Group align='center' onClick={() => router.push('/division/add-member/' + param.id)}>
<Avatar size="lg">
<AiOutlineUserAdd size={30} color={WARNA.biruTua} />
</Avatar>
<Text>Tambah Anggota</Text>
</Group>
</Box>
<Box pt={10}>
<Box mb={10}>
{loading
? Array(3)
.fill(null)
.map((_, i) => (
<Box key={i}>
<SkeletonSingle />
</Box>
))
: member.map((v, i) => {
return (
<Box key={i}>
<Flex
justify={"space-between"}
align={"center"}
mt={10}
onClick={() => { onClickMember(v.id, (v.isAdmin) ? true : false), setChooseMemberName(v.name) }}
>
<Group>
<Avatar src={"v.img"} alt="it's me" size="lg" />
<Box>
<Text c={WARNA.biruTua} fw={"bold"}>
{v.name}
</Text>
</Box>
</Group>
<Text c={WARNA.biruTua} fw={"bold"}>
{(v.isAdmin) ? 'Admin' : 'Anggota'}
</Text>
</Flex>
<Box mt={10}>
<Divider size={"xs"} />
</Box>
</Box>
);
})
}
</Box>
</Box>
</Box>
</Box>
</Box>
<LayoutDrawer opened={openDrawer} onClose={() => setDrawer(false)} title={valChooseMemberName}>
<Box>
<Group align='center' mb={20} onClick={() => editStatusAdmin()}>
<ActionIcon variant="light" size={60} aria-label="admin" radius="xl">
<FaUserTie size={30} color={WARNA.biruTua} />
</ActionIcon>
<Text c={WARNA.biruTua}>{(valChooseMemberStatus == false) ? "Jadikan admin" : "Memberhentikan sebagai admin"}</Text>
</Group>
<Group align='center' onClick={() => setOpenModal(true)}>
<ActionIcon variant="light" size={60} aria-label="admin" radius="xl">
<IoIosCloseCircle size={40} color={WARNA.biruTua} />
</ActionIcon>
<Text c={WARNA.biruTua}>Keluarkan dari divisi</Text>
</Group>
</Box>
</LayoutDrawer>
<LayoutModal opened={isOpenModal} onClose={() => setOpenModal(false)}
description="Apakah Anda yakin ingin mengeluarkan anggota?"
onYes={(val) => {
if (!val) {
setOpenModal(false)
} else {
deleteMember()
}
}} />
</Box>
);
}

View File

@@ -0,0 +1,140 @@
"use client"
import { WARNA } from "@/module/_global";
import { Box, Group, Skeleton, Stack, Text } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";
import { CiUser, CiClock2 } from "react-icons/ci";
import { GoDiscussionClosed } from "react-icons/go";
import { funGetDetailDivisionById } from "../lib/api_division";
import { IDataDiscussionOnDetailDivision } from "../lib/type_division";
const dataDiskusi = [
{
id: 1,
judul: "Mengatasi Limbah Makanan ",
user: "Fibra Marcell",
date: "21 Juni 2024",
},
{
id: 2,
judul: "Pentingnya Menjaga Kelestarian Hutan ",
user: "Bayu Tegar",
date: "15 Juni 2024",
},
{
id: 3,
judul: "Mengatasi Limbah Industri ",
user: "Nian Putri",
date: "11 Mei 2024",
},
{
id: 4,
judul: "Manfaat Sampah Plastik",
user: "Budi Prasetyo",
date: "10 Mei 2024",
},
];
export default function ListDiscussionOnDetailDivision() {
const router = useRouter();
const param = useParams<{ id: string }>()
const [data, setData] = useState<IDataDiscussionOnDetailDivision[]>([])
const [loading, setLoading] = useState(true);
async function fetchData() {
try {
setLoading(true);
const res = await funGetDetailDivisionById(param.id, 'new-discussion');
if (res.success) {
setData(res.data)
} else {
toast.error(res.message);
}
setLoading(false);
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
} finally {
setLoading(false);
}
}
useShallowEffect(() => {
fetchData()
}, [param.id])
return (
<>
<Box pt={10}>
<Text c={WARNA.biruTua} mb={10} fw={"bold"} fz={16}>
Diskusi Terbaru
</Text>
<Box
bg={"white"}
style={{
borderRadius: 10,
border: `1px solid ${"#D6D8F6"}`,
padding: 20,
}}
>
{
loading ?
Array(2)
.fill(null)
.map((_, i) => (
<Stack align="stretch" justify="center" key={i} pb={10}>
<Skeleton height={80} radius="md" m={0} />
<Group justify="space-between">
<Skeleton height={10} radius="md" m={0} w={100} />
<Skeleton height={10} radius="md" m={0} w={100} />
</Group>
</Stack>
))
:
(data.length === 0) ?
<Stack align="stretch" justify="center" w={"100%"}>
<Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada diskusi</Text>
</Stack>
: <></>
}
{data.map((v, i) => {
return (
<Box
key={i}
style={{
borderRadius: 10,
border: `1px solid ${"#D6D8F6"}`,
padding: 10,
}}
mb={10}
onClick={() => router.push(`/discussion/${v.id}`)}
>
<Group>
<GoDiscussionClosed size={25} />
<Box w={{ base: 230, md: 400 }}>
<Text fw={"bold"} truncate="end">
{v.title}
</Text>
</Box>
</Group>
<Group justify="space-between" mt={20} c={"#8C8C8C"}>
<Group gap={5} align="center">
<CiUser size={18} />
<Text fz={13}>{v.user}</Text>
</Group>
<Group gap={5} align="center">
<CiClock2 size={18} />
<Text fz={13}>{v.date}</Text>
</Group>
</Group>
</Box>
);
})}
</Box>
</Box>
</>
);
}

View File

@@ -0,0 +1,165 @@
'use client'
import { API_ADDRESS, LayoutDrawer, LayoutNavbarNew, WARNA } from '@/module/_global';
import { ActionIcon, Avatar, Box, Card, Center, Divider, Flex, Grid, Group, Text, TextInput, Title } from '@mantine/core';
import { useRouter } from 'next/navigation';
import React, { useState } from 'react';
import { HiMenu } from 'react-icons/hi';
import { HiMagnifyingGlass, HiMiniPresentationChartBar, HiMiniUserGroup, HiOutlineListBullet, HiSquares2X2 } from 'react-icons/hi2';
import { MdAccountCircle } from 'react-icons/md';
import DrawerDivision from './drawer_division';
import { useShallowEffect } from '@mantine/hooks';
import { IDataDivison } from '../lib/type_division';
import { funGetAllDivision } from '../lib/api_division';
import toast from 'react-hot-toast';
export default function ListDivision() {
const [isList, setIsList] = useState(false)
const router = useRouter()
const [openDrawer, setOpenDrawer] = useState(false)
const [data, setData] = useState<IDataDivison[]>([])
const [jumlah, setJumlah] = useState(0)
const [searchQuery, setSearchQuery] = useState('')
const handleList = () => {
setIsList(!isList)
}
const fetchData = async (search: string) => {
try {
setData([]);
const response = await funGetAllDivision('?search=' + search)
if (response.success) {
setData(response.data)
setJumlah(response.data.length)
} else {
toast.error(response.message);
}
} catch (error) {
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
console.error(error);
}
};
function searchDivision(search: string) {
setSearchQuery(search)
fetchData(search)
}
useShallowEffect(() => {
fetchData(searchQuery)
}, [searchQuery])
return (
<Box>
<LayoutNavbarNew back='/home' title='Divisi'
menu={<ActionIcon variant="light" onClick={() => (setOpenDrawer(true))} bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Settings">
<HiMenu size={20} color='white' />
</ActionIcon>} />
<Box p={20}>
<Grid justify='center' align='center'>
<Grid.Col span={10}>
<TextInput
styles={{
input: {
color: WARNA.biruTua,
borderRadius: '#A3A3A3',
borderColor: '#A3A3A3',
},
}}
size="md"
radius={30}
leftSection={<HiMagnifyingGlass size={20} />}
placeholder="Pencarian"
value={searchQuery}
onChange={(val) => { searchDivision(val.target.value) }}
/>
</Grid.Col>
<Grid.Col span={'auto'}>
<Flex justify={'center'}>
{isList ? (
<HiOutlineListBullet size={35} color={WARNA.biruTua} onClick={handleList} />
) : (
<HiSquares2X2 size={35} color={WARNA.biruTua} onClick={handleList} />
)}
</Flex>
</Grid.Col>
</Grid>
<Box pt={20}>
<Box bg={WARNA.biruTua} p={10} style={{ borderRadius: 10 }}>
<Text fw={'bold'} c={'white'}>Total Divisi</Text>
<Flex justify={'center'} align={'center'} h={'100%'}>
<Text fz={40} fw={'bold'} c={'white'}>{jumlah}</Text>
</Flex>
</Box>
</Box>
{isList ? (
<Box pt={20}>
{data?.map((v: any, i: any) => {
return (
<Box key={i}>
<Group justify="space-between" mb={10} onClick={() => router.push(`/division/${v.id}`)}>
<Group>
<Center>
<ActionIcon
variant="gradient"
size={50}
aria-label="Gradient action icon"
radius={100}
gradient={{
from: '#DFDA7C',
to: '#F2AF46',
deg: 174
}}
>
<HiMiniUserGroup size={25} color={WARNA.biruTua} />
</ActionIcon>
</Center>
<Text>{v.name}</Text>
</Group>
</Group>
<Divider my="sm" />
</Box>
);
})}
</Box>
) : (
<Box pt={20}>
{data?.map((v: any, i: any) => {
return (
<Box key={i} mb={20}>
<Card shadow="sm" padding="md" component="a" radius={10} onClick={() => router.push(`/division/${v.id}`)}>
<Card.Section>
<Box h={120} bg={WARNA.biruTua}>
<Flex justify={'center'} align={'center'} h={"100%"}>
<Title order={3} c={"white"}>{v.name}</Title>
</Flex>
</Box>
</Card.Section>
<Box pt={10}>
<Text>{v.desc}</Text>
<Group align='center' pt={10} justify='flex-end'>
<Avatar.Group>
<Avatar>
<MdAccountCircle size={32} color={WARNA.biruTua} />
</Avatar>
<Avatar>+{v.jumlah_member - 1}</Avatar>
</Avatar.Group>
</Group>
</Box>
</Card>
</Box>
);
})}
</Box>
)}
</Box>
<LayoutDrawer opened={openDrawer} title={'Menu'} onClose={() => setOpenDrawer(false)}>
<DrawerDivision />
</LayoutDrawer>
</Box>
);
}

View File

@@ -0,0 +1,86 @@
'use client'
import { WARNA } from "@/module/_global";
import { Carousel } from "@mantine/carousel";
import { Box, Image, Text, Center, Paper, Stack, UnstyledButton, Skeleton, Group } from "@mantine/core";
import * as ICON from '../../division/lib/file_icon'
import { useParams, useRouter } from "next/navigation";
import { useShallowEffect } from "@mantine/hooks";
import toast from "react-hot-toast";
import { funGetDetailDivisionById } from "../lib/api_division";
import { IDataKalenderOnDetailDivision } from "../lib/type_division";
import { useState } from "react";
const iconContainer = (icon: string) => 'data:image/svg+xml;base64,' + btoa(icon)
export default function ListDocumentOnDetailDivision() {
const router = useRouter()
const param = useParams<{ id: string }>()
const [data, setData] = useState<IDataKalenderOnDetailDivision[]>([])
const [loading, setLoading] = useState(true);
async function fetchData() {
try {
setLoading(true);
const res = await funGetDetailDivisionById(param.id, 'new-file');
if (res.success) {
setData(res.data)
} else {
toast.error(res.message);
}
setLoading(false);
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
} finally {
setLoading(false);
}
}
useShallowEffect(() => {
fetchData()
}, [param.id])
return (
<Box pt={10}>
<Text c={WARNA.biruTua} mb={10} fw={'bold'} fz={16}>Dokumen Terbaru</Text>
<Group justify="center" grow>
{
loading
?
Array(4)
.fill(null)
.map((_, i) => (
<Stack align="stretch" justify="center" key={i}>
<Skeleton height={80} radius="md" m={0} />
<Skeleton height={10} radius="md" m={0} />
</Stack>
))
: (data.length === 0) ?
<Stack align="stretch" justify="center" w={"100%"}>
<Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada file</Text>
</Stack>
: <></>
}
</Group>
<Carousel dragFree slideGap={"xs"} align="start" slideSize={"xs"} withIndicators withControls={false}>
{
data.map((v) =>
<Carousel.Slide key={v.id}>
<UnstyledButton onClick={() => router.push(`/document`)}>
<Stack gap={0}>
<Paper withBorder shadow="sm" radius={12} >
<Center p={"md"}>
<Image w={"75"} src={(v.extension == "pdf") ? iconContainer(ICON.PDF) : iconContainer(ICON.IMAGE)} alt="image" />
</Center>
</Paper>
<Box p={"sm"}>
<Text c={"dimmed"} truncate="end" ta={"center"}>{v.name + '.' + v.extension}</Text>
</Box>
</Stack>
</UnstyledButton>
</Carousel.Slide>
)}
</Carousel>
</Box>
)
}

View File

@@ -0,0 +1,89 @@
'use client'
import { WARNA } from "@/module/_global";
import { Carousel } from "@mantine/carousel";
import { Avatar, Box, Group, Skeleton, Stack, Text } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import toast from "react-hot-toast";
import { CiClock2 } from "react-icons/ci";
import { funGetDetailDivisionById } from "../lib/api_division";
import { useState } from "react";
import { IDataTaskOnDetailDivision } from "../lib/type_division";
export default function ListTaskOnDetailDivision() {
const router = useRouter()
const param = useParams<{ id: string }>()
const [data, setData] = useState<IDataTaskOnDetailDivision[]>([])
const [loading, setLoading] = useState(true);
async function fetchData() {
try {
setLoading(true);
const res = await funGetDetailDivisionById(param.id, 'today-task');
if (res.success) {
setData(res.data)
} else {
toast.error(res.message);
}
setLoading(false);
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan divisi, coba lagi nanti");
} finally {
setLoading(false);
}
}
useShallowEffect(() => {
fetchData()
}, [param.id])
return (
<Box pt={10}>
<Text c={WARNA.biruTua} mb={10} fw={'bold'} fz={16}>Tugas Hari Ini</Text>
<Group justify="center" grow>
{
loading ?
Array(2)
.fill(null)
.map((_, i) => (
<Stack align="stretch" justify="center" key={i}>
<Skeleton height={80} radius="md" m={0} />
<Skeleton height={10} radius="md" m={0} />
</Stack>
))
:
(data.length === 0) ?
<Stack align="stretch" justify="center" w={"100%"}>
<Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada tugas hari ini</Text>
</Stack>
: <></>
}
</Group>
<Carousel dragFree slideGap={"xs"} align="start" slideSize={"xs"} withIndicators withControls={false}>
{data.map((v, i) =>
<Carousel.Slide key={v.id}>
<Box p={20} w={{ base: 300, md: 400 }} onClick={() => router.push(`/task/${v.id}`)} bg={WARNA.biruTua} style={{ borderRadius: 10, border: `1px solid ${"#D6D8F6"}` }}>
<Text fw={'bold'} c={WARNA.bgWhite} truncate="end">{v.title}</Text>
<Group justify="space-between" mt={20} c={'#aeaeae'}>
<Group gap={5} align="center">
<CiClock2 size={18} />
<Text fz={13}>{v.dateStart}</Text>
</Group >
<Group gap={5} align="center">
{/* <Avatar.Group>
<Avatar>
<MdAccountCircle size={32} color={WARNA.biruTua} />
</Avatar>
<Avatar>+{v.jumlah}</Avatar>
</Avatar.Group> */}
</Group>
</Group>
</Box>
</Carousel.Slide>
)}
</Carousel>
</Box>
)
}

View File

@@ -0,0 +1,132 @@
"use client"
import { API_ADDRESS, LayoutNavbarNew, WARNA } from '@/module/_global';
import { useHookstate } from '@hookstate/core';
import { Avatar, Box, Button, Checkbox, Divider, Flex, Group, Stack, Text, TextInput } from '@mantine/core';
import { useRouter } from 'next/navigation';
import React, { useState } from 'react';
import { HiMagnifyingGlass } from 'react-icons/hi2';
import toast from 'react-hot-toast';
import { globalMemberDivision } from '../lib/val_division';
import { funCreateDivision } from '../lib/api_division';
import { IFormMemberDivision } from '../lib/type_division';
export default function NavbarAdminDivision({ data, onSuccess }: { data: any, onSuccess: (val: any) => void }) {
const router = useRouter()
const member = useHookstate(globalMemberDivision)
const memberValue = member.get() as IFormMemberDivision[]
const [value, setValue] = useState<string[]>([]);
async function onSubmit() {
if (value.length === 0) {
return toast.error("Error! Silahkan pilih admin divisi")
}
try {
const response = await funCreateDivision({ data: data, member: memberValue, admin: value })
if (response.success) {
toast.success(response.message);
onSuccess(true)
} else {
toast.error(response.message)
onSuccess(false)
}
} catch (error) {
console.log(error);
onSuccess(false)
toast.error("Gagal menambahkan grup, coba lagi nanti");
}
// try {
// const res = await fetch(API_ADDRESS.apiCreateDivision, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify({
// data: data,
// member: member.get(),
// admin: value
// })
// })
// const errorData = await res.json();
// if (res.status == 201) {
// toast.success('Sukses! data tersimpan')
// onSuccess(true)
// } else {
// toast.error(errorData.message);
// onSuccess(false)
// }
// } catch (error) {
// toast.error('Error')
// onSuccess(false)
// }
}
return (
<Box>
<LayoutNavbarNew title="Pilih Admin Divisi" menu />
<Box p={20}>
<TextInput
styles={{
input: {
color: WARNA.biruTua,
borderRadius: '#A3A3A3',
borderColor: '#A3A3A3',
},
}}
size="md"
radius={30}
leftSection={<HiMagnifyingGlass size={20} />}
placeholder="Pencarian"
/>
<Box pt={20}>
<Checkbox.Group value={value} onChange={setValue}>
{
(member.length === 0) ? (
<Text c="dimmed" ta={"center"} fs={"italic"}>Belum ada anggota</Text>
) : member.get().map((v: any, i: any) => {
return (
<Box key={i}>
<Flex
justify={"space-between"}
align={"center"}
>
<Group>
<Avatar src={v.img} alt="it's me" size="lg" />
<Box>
<Text c={WARNA.biruTua} fw={"bold"}>
{v.name}
</Text>
</Box>
</Group>
<Checkbox value={v.idUser} />
</Flex>
<Divider my={20} />
</Box>
);
})
}
</Checkbox.Group>
</Box>
<Box mt="xl">
<Button
color="white"
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { onSubmit() }}
>
Simpan
</Button>
</Box>
</Box>
</Box>
);
}

View File

@@ -0,0 +1,121 @@
"use client"
import { API_ADDRESS, LayoutNavbarNew, WARNA } from '@/module/_global';
import { useHookstate } from '@hookstate/core';
import { Avatar, Box, Button, Center, Input, SimpleGrid, Stack, Text, TextInput } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { useRouter } from 'next/navigation';
import React, { useState } from 'react';
import { HiMagnifyingGlass } from 'react-icons/hi2';
import { TypeUser } from '@/module/user';
import { funGetUserByCookies } from '@/module/auth';
import toast from 'react-hot-toast';
import { globalMemberDivision } from '../lib/val_division';
export default function NavbarCreateUsers({ grup, onClose }: { grup?: string, onClose: (val: any) => void }) {
const router = useRouter()
const member = useHookstate(globalMemberDivision)
const [selectedFiles, setSelectedFiles] = useState<any>([]);
const [dataMember, setDataMember] = useState<TypeUser>([])
const handleFileClick = (index: number) => {
if (selectedFiles.some((i: any) => i.id == dataMember[index].id)) {
setSelectedFiles(selectedFiles.filter((i: any) => i.id != dataMember[index].id))
} else {
setSelectedFiles([...selectedFiles, {idUser: dataMember[index].id, name: dataMember[index].name}])
}
};
async function loadData() {
const loadMember = await fetch(API_ADDRESS.apiGetAllUser + '&active=true&groupID=' + grup);
const user = await funGetUserByCookies();
const hasil = await loadMember.json()
setDataMember(hasil.filter((i: any) => i.id != user.id))
// cek data member sebelumnya
if (member.length > 0) {
setSelectedFiles(JSON.parse(JSON.stringify(member.get())))
}
}
function onSubmit() {
if (selectedFiles.length == 0) {
return toast.error("Error! silahkan pilih anggota")
}
member.set(selectedFiles)
onClose(true)
}
useShallowEffect(() => {
loadData()
}, []);
return (
<Box>
<LayoutNavbarNew title="Pilih Anggota" menu />
<Box p={20}>
<Stack>
<TextInput
styles={{
input: {
color: WARNA.biruTua,
borderRadius: '#A3A3A3',
borderColor: '#A3A3A3',
},
}}
size="md"
radius={30}
leftSection={<HiMagnifyingGlass size={20} />}
placeholder="Pencarian"
/>
<Box pt={10}>
<SimpleGrid
cols={{ base: 2, sm: 2, lg: 2 }}
spacing={{ base: 20, sm: "xl" }}
verticalSpacing={{ base: "md", sm: "xl" }}
>
{dataMember.map((v, index) => {
const isSelected = selectedFiles.some((i: any) => i.idUser == dataMember[index].id);
return (
<Box key={index} mb={10}>
<Box
bg={isSelected ? WARNA.bgHijauMuda : "white"}
style={{
border: `1px solid ${WARNA.biruTua}`,
borderRadius: 20,
}}
py={10}
onClick={() => handleFileClick(index)}
>
<Center>
<Avatar src={"https://i.pravatar.cc/1000?img=37"} alt="it's me" size="xl" />
</Center>
<Text mt={20} ta="center">
{v.name}
</Text>
</Box>
</Box>
);
})}
</SimpleGrid>
</Box>
</Stack>
<Box mt="xl">
<Button
color="white"
bg={WARNA.biruTua}
size="lg"
radius={30}
fullWidth
onClick={() => { onSubmit() }}
>
Simpan
</Button>
</Box>
</Box>
</Box>
);
}

View File

@@ -0,0 +1,50 @@
'use client'
import { LayoutDrawer, LayoutNavbarNew, WARNA } from "@/module/_global";
import { ActionIcon, Box } from "@mantine/core";
import { useState } from "react";
import { HiMenu } from "react-icons/hi";
import DrawerDetailDivision from "./drawer_detail_division";
import { funGetDivisionById } from "../lib/api_division";
import { useParams } from "next/navigation";
import toast from "react-hot-toast";
import { useShallowEffect } from "@mantine/hooks";
export default function NavbarDetailDivision() {
const [openDrawer, setOpenDrawer] = useState(false)
const param = useParams<{ id: string }>()
const [name, setName] = useState('')
async function getOneData() {
try {
const res = await funGetDivisionById(param.id);
if (res.success) {
setName(res.data.division.name);
} else {
toast.error(res.message);
}
} catch (error) {
console.error(error);
toast.error("Gagal mendapatkan grup, coba lagi nanti");
}
}
useShallowEffect(() => {
getOneData();
}, [param.id])
return (
<>
<LayoutNavbarNew back="" title={name} menu={
<ActionIcon variant="light" onClick={() => (setOpenDrawer(true))} bg={WARNA.bgIcon} size="lg" radius="lg" aria-label="Settings">
<HiMenu size={20} color='white' />
</ActionIcon>
} />
<LayoutDrawer opened={openDrawer} title={'Menu'} onClose={() => setOpenDrawer(false)}>
<DrawerDetailDivision />
</LayoutDrawer>
</>
);
}

View File

@@ -0,0 +1,80 @@
"use client"
import { LayoutNavbarNew, WARNA } from '@/module/_global';
import { Box, Stack } from '@mantine/core';
import { DateInput } from '@mantine/dates';
import React, { useState } from 'react';
import EchartPaiReport from './echart_pai_report';
import EchartBarReport from './echart_bar_report';
import EventReport from './event_report';
import DiscussionReport from './discussion_report';
export default function ReportDivisionId() {
const [value, setValue] = useState<Date | null>(null);
return (
<Box>
<LayoutNavbarNew back="/division/1" title="Report Divisi" menu />
<Box p={20}>
<Stack>
<DateInput
value={value}
onChange={setValue}
radius={10}
size="md"
required
label="Date input"
placeholder="Date input"
/>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<EchartPaiReport />
</Box>
</Box>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<EchartBarReport />
</Box>
</Box>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<EventReport />
</Box>
</Box>
<Box pt={10}>
<Box
bg={"white"}
style={{
border: `1px solid ${WARNA.borderBiruMuda}`,
borderRadius: 10,
padding: 10,
}}
>
<DiscussionReport />
</Box>
</Box>
</Stack>
</Box>
</Box>
);
}