Merge pull request #325 from bipproduction/amalia/04-nov-24

Amalia/04 nov 24
This commit is contained in:
Amalia
2024-11-04 16:04:40 +08:00
committed by GitHub
11 changed files with 181 additions and 160 deletions

View File

@@ -6,7 +6,7 @@ import { ActionIcon, Avatar, Badge, Box, Center, Divider, Flex, Grid, Group, rem
import { useMediaQuery, useShallowEffect } from "@mantine/hooks";
import moment from "moment";
import "moment/locale/id";
import { useParams, useRouter } from "next/navigation";
import { useParams } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";
import { GrChatOption } from "react-icons/gr";
@@ -23,7 +23,6 @@ export default function DetailDiscussion({ id, idDivision }: { id: string, idDiv
const [isComent, setIsComent] = useState("")
const param = useParams<{ id: string, detail: string }>()
const [isLoad, setIsLoad] = useState(true)
const router = useRouter()
const refresh = useHookstate(globalRefreshDiscussion)
const roleLogin = useHookstate(globalRole)
const [isCreator, setCreator] = useState(false)

View File

@@ -23,13 +23,15 @@ export default function DrawerDetailDiscussion({ onSuccess, id, status, idDivisi
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())
@@ -38,40 +40,37 @@ export default function DrawerDetailDiscussion({ onSuccess, id, status, idDivisi
id: id,
}])
onSuccess(false)
setValModalStatus(false)
} else {
toast.error(response.message)
}
}
setValModalStatus(false)
} catch (error) {
console.error(error);
setValModalStatus(false)
toast.error("Gagal menambahkan diskusi, coba lagi nanti");
} finally {
setLoadingUpdate(false)
setValModalStatus(false)
}
}
async function fetchDeleteDiscussion(val: boolean) {
try {
setLoadingDelete(true)
if (val) {
const response = await funDeleteDiscussion(id)
if (response.success) {
toast.success(response.message)
setValModal(false)
onSuccess(false)
router.push(`/division/${param.id}/discussion`)
} else {
toast.error(response.message)
}
}
setValModal(false)
} catch (error) {
console.error(error);
setValModal(false)
toast.error("Gagal hapus diskusi, coba lagi nanti");
} finally {
setLoadingDelete(false)
setValModal(false)
}
}
@@ -130,12 +129,12 @@ export default function DrawerDetailDiscussion({ onSuccess, id, status, idDivisi
</SimpleGrid>
</Stack>
<LayoutModal opened={isValModal} onClose={() => setValModal(false)}
<LayoutModal loading={loadingDelete} opened={isValModal} onClose={() => setValModal(false)}
description="Apakah Anda yakin ingin menghapus diskusi ini?"
onYes={(val) => { fetchDeleteDiscussion(val) }} />
<LayoutModal opened={isValModalStatus} onClose={() => setValModalStatus(false)}
<LayoutModal loading={loadingUpdate} opened={isValModalStatus} onClose={() => setValModalStatus(false)}
description="Apakah Anda yakin ingin mengubah status diskusi ini?"
onYes={(val) => { fetchStatusDiscussion(val) }} />
</Box>

View File

@@ -15,7 +15,6 @@ export default function FormCreateDiscussion({ id }: { id: string }) {
const [isValModal, setValModal] = useState(false)
const [loadingModal, setLoadingModal] = useState(false)
const router = useRouter()
const [isImg, setImg] = useState("")
const param = useParams<{ id: string, detail: string }>()
const [loading, setLoading] = useState(true)
const [img, setIMG] = useState<any | null>()
@@ -51,25 +50,27 @@ export default function FormCreateDiscussion({ id }: { id: string }) {
async function createDiscussion(val: boolean) {
try {
setLoadingModal(true)
const response = await funCreateDiscussion({
desc: isData.desc,
idDivision: id
})
if (val) {
setLoadingModal(true)
const response = await funCreateDiscussion({
desc: isData.desc,
idDivision: id
})
if (response.success) {
setDataRealtime(response.notif)
toast.success(response.message)
router.push(`/division/${param.id}/discussion/`)
} else {
toast.error(response.message)
if (response.success) {
setDataRealtime(response.notif)
toast.success(response.message)
router.push(`/division/${param.id}/discussion/`)
} else {
toast.error(response.message)
}
}
} catch (error) {
console.error(error);
toast.error("Gagal menambahkan diskusi, coba lagi nanti");
} finally {
setValModal(false)
setLoadingModal(false)
setValModal(false)
}
}

View File

@@ -1,16 +1,17 @@
'use client'
import { currentScroll, TEMA } from "@/module/_global";
import { currentScroll, globalNotifPage, ReloadButtonTop, TEMA } from "@/module/_global";
import { useHookstate } from "@hookstate/core";
import { Avatar, Badge, Box, Divider, Flex, Grid, Group, Skeleton, Spoiler, Text, TextInput } from "@mantine/core";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { GrChatOption } from "react-icons/gr";
import { HiMagnifyingGlass } from "react-icons/hi2";
import { funGetAllDiscussion } from "../lib/api_discussion";
import { useShallowEffect } from "@mantine/hooks";
import { IDataDiscussion } from "../lib/type_discussion";
import toast from "react-hot-toast";
import _ from "lodash";
import { useHookstate } from "@hookstate/core";
export default function ListDiscussion({ id }: { id: string }) {
const [isData, setData] = useState<IDataDiscussion[]>([])
@@ -21,11 +22,12 @@ export default function ListDiscussion({ id }: { id: string }) {
const router = useRouter()
const { value: containerRef } = useHookstate(currentScroll);
const [isPage, setPage] = useState(1)
const notifLoadPage = useHookstate(globalNotifPage)
const [isRefresh, setRefresh] = useState(false)
const getData = async (loading: boolean) => {
try {
if (loading)
setLoading(true)
setLoading(loading)
const response = await funGetAllDiscussion('?division=' + id + '&search=' + searchQuery + '&page=' + isPage)
if (response.success) {
if (isPage == 1) {
@@ -36,7 +38,6 @@ export default function ListDiscussion({ id }: { id: string }) {
} else {
toast.error(response.message)
}
setLoading(false)
} catch (error) {
console.error(error)
} finally {
@@ -75,8 +76,37 @@ export default function ListDiscussion({ id }: { id: string }) {
}, [containerRef, isPage]);
useShallowEffect(() => {
console.log(notifLoadPage.get())
if (notifLoadPage.get().category == 'division/' + param.id + '/discussion' && notifLoadPage.get().load == true) {
setRefresh(true)
}
}, [notifLoadPage.get().load])
function onRefresh() {
notifLoadPage.set({
category: '',
load: false
})
setRefresh(false)
setPage(1)
setTimeout(() => {
getData(false)
}, 500)
}
return (
<Box p={20}>
{
isRefresh &&
<ReloadButtonTop
onReload={() => { onRefresh() }}
title='UPDATE'
/>
}
<TextInput
styles={{
input: {

View File

@@ -2,7 +2,7 @@
import { keyWibu, LayoutDrawer, LayoutNavbarNew, TEMA } from "@/module/_global";
import LayoutModal from "@/module/_global/layout/layout_modal";
import { useHookstate } from "@hookstate/core";
import { Box, Button, Flex, Group, rem, SimpleGrid, Stack, Text, } from "@mantine/core";
import { Box, Button, Flex, Group, Loader, rem, SimpleGrid, Stack, Text, } from "@mantine/core";
import { Dropzone } from "@mantine/dropzone";
import _ from "lodash";
import { useParams, useRouter } from "next/navigation";
@@ -27,6 +27,7 @@ export default function AddFileDetailTask() {
const [openDrawerFile, setOpenDrawerFile] = useState(false)
const tema = useHookstate(TEMA)
const openRef = useRef<() => void>(null)
const [loadingUpload, setLoadingUpload] = useState(false)
const [dataRealTime, setDataRealtime] = useWibuRealtime({
WIBU_REALTIME_TOKEN: keyWibu,
project: "sdm"
@@ -41,6 +42,7 @@ export default function AddFileDetailTask() {
async function cekFileName(data: any) {
try {
setLoadingUpload(true)
const fd = new FormData();
fd.append(`file`, data);
const res = await funCekNamFileUploadTask(param.detail, fd)
@@ -53,6 +55,8 @@ export default function AddFileDetailTask() {
} catch (error) {
console.error(error)
toast.error("Gagal menambahkan file, coba lagi nanti")
} finally {
setLoadingUpload(false)
}
}
@@ -146,6 +150,12 @@ export default function AddFileDetailTask() {
</Box>
</Box>
}
{
loadingUpload &&
<Group justify="center" py={20}>
<Loader color="gray" type="dots" />
</Group>
}
</Box>
<Box pos={'fixed'} bottom={0} p={rem(20)} w={"100%"} style={{
maxWidth: rem(550),

View File

@@ -4,7 +4,7 @@ import LayoutModal from "@/module/_global/layout/layout_modal";
import { funGetSearchMemberDivision, IDataMemberDivision } from "@/module/division_new";
import { useHookstate } from "@hookstate/core";
import { Carousel } from "@mantine/carousel";
import { ActionIcon, Avatar, Box, Button, Center, Divider, Flex, Grid, Group, Indicator, rem, Stack, Text, TextInput } from "@mantine/core";
import { ActionIcon, Avatar, Box, Button, Center, Divider, Flex, Grid, Indicator, rem, Stack, Text, TextInput } from "@mantine/core";
import { useMediaQuery, useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
@@ -53,7 +53,6 @@ export default function AddMemberDetailTask() {
toast.error(res.message);
}
setLoading(false)
} catch (error) {
console.error(error)
toast.error("Gagal mendapatkan anggota, coba lagi nanti");
@@ -143,6 +142,7 @@ export default function AddMemberDetailTask() {
async function fetchGetMember(val: string) {
setSearchQuery(val)
try {
setLoading(true)
const res = await funGetSearchMemberDivision('?search=' + val, param.id);
if (res.success) {
setData(res.data)
@@ -151,6 +151,8 @@ export default function AddMemberDetailTask() {
}
} catch (error) {
console.error(error);
} finally {
setLoading(false)
}
}
@@ -243,12 +245,12 @@ export default function AddMemberDetailTask() {
<Box p={20}>
<Group justify="space-between" mt={100} onClick={handleSelectAll}>
{/* <Group justify="space-between" mt={100} onClick={handleSelectAll}>
<Text c={tema.get().utama} fw={"bold"}>
Pilih Semua Anggota
</Text>
{selectAll ? <FaCheck style={{ marginRight: 10 }} /> : ""}
</Group>
</Group> */}
{loading ? Array(8)
.fill(null)
.map((_, i) => (
@@ -267,7 +269,7 @@ export default function AddMemberDetailTask() {
const isSelected = selectedFiles.some((i: any) => i?.idUser == v.idUser);
const found = isDataMember.some((i: any) => i.idUser == v.idUser)
return (
<Box mb={15} key={i} onClick={() => (!found) ? handleFileClick(i) : null}>
<Box mb={15} mt={i === 0 ? 100 : 0} key={i} onClick={() => (!found) ? handleFileClick(i) : null}>
<Grid align='center'>
<Grid.Col span={{
base: 1,

View File

@@ -34,7 +34,6 @@ export default function CreateTask() {
const [dataTask, setDataTask] = useState<IFormDateTask[]>([])
const openRef = useRef<() => void>(null)
const [fileForm, setFileForm] = useState<any[]>([])
const [imgForm, setImgForm] = useState<any>()
const [listFile, setListFile] = useState<IListFileTask[]>([])
const [indexDelFile, setIndexDelFile] = useState<number>(0)
const [indexDelTask, setIndexDelTask] = useState<number>(0)

View File

@@ -1,38 +1,20 @@
"use client"
import { LayoutNavbarNew, SkeletonList, SkeletonSingle, TEMA } from "@/module/_global";
import { funGetDivisionById, funGetSearchMemberDivision, IDataMemberDivision } from "@/module/division_new";
import { LayoutNavbarNew, SkeletonList, TEMA } from "@/module/_global";
import { funGetSearchMemberDivision, IDataMemberDivision } from "@/module/division_new";
import { useHookstate } from "@hookstate/core";
import {
ActionIcon,
Avatar,
Box,
Button,
Center,
Divider,
Flex,
Grid,
Group,
Indicator,
rem,
Skeleton,
Stack,
Text,
TextInput,
} from "@mantine/core";
import { Carousel } from "@mantine/carousel";
import { ActionIcon, Avatar, Box, Button, Center, Divider, Flex, Grid, Group, Indicator, rem, Skeleton, Stack, Text, TextInput } from "@mantine/core";
import { useMediaQuery, useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import React, { useState } from "react";
import { useState } from "react";
import toast from "react-hot-toast";
import { globalMemberTask } from "../lib/val_task";
import { FaCheck } from "react-icons/fa6";
import { RiListCheck } from "react-icons/ri";
import { BsListCheck } from "react-icons/bs";
import { FaCheck } from "react-icons/fa6";
import { HiChevronLeft, HiMagnifyingGlass } from "react-icons/hi2";
import { IoArrowBackOutline, IoClose } from "react-icons/io5";
import { Carousel } from "@mantine/carousel";
import { globalMemberTask } from "../lib/val_task";
export default function CreateUsersProject({ onClose }: { onClose: (val: any) => void }) {
const router = useRouter()
const param = useParams<{ id: string }>()
const [selectedFiles, setSelectedFiles] = useState<any>([])
const [isData, setData] = useState<IDataMemberDivision[]>([])
@@ -57,7 +39,6 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) =>
} else {
toast.error(response.message)
}
setLoading(false)
} catch (error) {
console.error(error)
toast.error("Gagal mendapatkan anggota, coba lagi nanti");
@@ -122,6 +103,7 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) =>
async function fetchGetMember(val: string) {
setSearchQuery(val)
try {
setLoading(true)
const res = await funGetSearchMemberDivision('?search=' + val, param.id);
if (res.success) {
setData(res.data)
@@ -130,6 +112,8 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) =>
}
} catch (error) {
console.error(error);
} finally {
setLoading(false)
}
}
@@ -228,7 +212,7 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) =>
<Box p={20}>
{loading ?
{/* {loading ?
<Skeleton height={20} width={"100%"} mt={20} />
:
<Group justify="space-between" mt={100} onClick={handleSelectAll}>
@@ -237,7 +221,7 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) =>
</Text>
<BsListCheck size={25} style={{ marginRight: 5 }} color={tema.get().utama} />
</Group>
}
} */}
<Box mt={15} mb={100}>
{loading ?
Array(8)
@@ -249,47 +233,47 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) =>
))
:
(isData.length === 0) ?
<Stack align="stretch" justify="center" w={"100%"} h={"60vh"}>
<Text c="dimmed" ta={"center"} fs={"italic"}>Tidak ada anggota</Text>
</Stack>
:
isData.map((v, i) => {
const isSelected = selectedFiles.some((i: any) => i?.idUser == v.idUser);
return (
<Box mb={15} key={i} onClick={() => handleFileClick(i)}>
<Grid align='center'>
<Grid.Col span={{
base: 1,
xs: 1,
sm: 1,
md: 1,
lg: 1,
xl: 1
}}>
<Avatar src={`https://wibu-storage.wibudev.com/api/files/${v.img}`} alt="it's me" size="lg" />
</Grid.Col>
<Grid.Col span={{
base: 11,
xs: 11,
sm: 11,
md: 11,
lg: 11,
xl: 11,
}}>
<Flex justify='space-between' align={"center"}>
<Flex direction={'column'} align="flex-start" justify="flex-start">
<Text lineClamp={1} pl={isMobile2 ? 40 : 30}>{v.name}</Text>
<Stack align="stretch" justify="center" w={"100%"} h={"60vh"}>
<Text c="dimmed" ta={"center"} fs={"italic"}>Tidak ada anggota</Text>
</Stack>
:
isData.map((v, i) => {
const isSelected = selectedFiles.some((i: any) => i?.idUser == v.idUser);
return (
<Box mb={15} key={i} onClick={() => handleFileClick(i)} mt={i===0 ? 100 : 0}>
<Grid align='center'>
<Grid.Col span={{
base: 1,
xs: 1,
sm: 1,
md: 1,
lg: 1,
xl: 1
}}>
<Avatar src={`https://wibu-storage.wibudev.com/api/files/${v.img}`} alt="it's me" size="lg" />
</Grid.Col>
<Grid.Col span={{
base: 11,
xs: 11,
sm: 11,
md: 11,
lg: 11,
xl: 11,
}}>
<Flex justify='space-between' align={"center"}>
<Flex direction={'column'} align="flex-start" justify="flex-start">
<Text lineClamp={1} pl={isMobile2 ? 40 : 30}>{v.name}</Text>
</Flex>
{isSelected ? <FaCheck /> : null}
</Flex>
{isSelected ? <FaCheck /> : null}
</Flex>
</Grid.Col>
</Grid>
<Box mt={10}>
<Divider size={"xs"} />
</Grid.Col>
</Grid>
<Box mt={10}>
<Divider size={"xs"} />
</Box>
</Box>
</Box>
);
})
);
})
}
</Box>
</Box>

View File

@@ -114,7 +114,7 @@ export default function EditTask() {
onChange={(e) => { onValidation('title', e.target.value) }}
error={
touched.title && (
title == "" ? "Error! harus memasukkan judul tugas" : null
title == "" ? "Judul Tugas Tidak Boleh Kosong" : null
)
}
/>

View File

@@ -1,15 +1,15 @@
import { currentScroll, globalNotifPage, ReloadButtonTop, SkeletonList, TEMA } from "@/module/_global";
import { useHookstate } from "@hookstate/core";
import { ActionIcon, Avatar, Box, Card, Center, Divider, Flex, Grid, Group, Progress, Skeleton, Text, TextInput, Title } from "@mantine/core";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import { HiMagnifyingGlass, HiMiniPresentationChartBar, HiOutlineListBullet, HiSquares2X2 } from "react-icons/hi2";
import { MdAccountCircle } from "react-icons/md";
import { IDataTask } from "../lib/type_task";
import { funGetAllTask } from "../lib/api_task";
import toast from "react-hot-toast";
import { useMediaQuery, useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { useHookstate } from "@hookstate/core";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { HiMagnifyingGlass, HiMiniPresentationChartBar, HiOutlineListBullet, HiSquares2X2 } from "react-icons/hi2";
import { MdAccountCircle } from "react-icons/md";
import { funGetAllTask } from "../lib/api_task";
import { IDataTask } from "../lib/type_task";
export default function ListDivisionTask() {
const [isList, setIsList] = useState(false)
@@ -46,8 +46,6 @@ export default function ListDivisionTask() {
} else {
toast.error(response.message);
}
setLoading(false);
} catch (error) {
toast.error("Gagal mendapatkan tugas divisi, coba lagi nanti");
console.error(error);
@@ -149,7 +147,7 @@ export default function ListDivisionTask() {
<Box bg={tema.get().bgTotalKegiatan} p={10} style={{ borderRadius: 10 }}>
<Text fw={'bold'} c={tema.get().utama}>Total Tugas</Text>
<Flex justify={'center'} align={'center'} h={'100%'}>
<Text fz={40} fw={'bold'} c={tema.get().utama}>{totalData}</Text>
<Text fz={40} fw={'bold'} c={tema.get().utama}>{loading ? 0 : totalData}</Text>
</Flex>
</Box>
{isList ? (
@@ -173,7 +171,7 @@ export default function ListDivisionTask() {
isData.map((v, i) => {
return (
<Box key={i}>
<Grid align='center'>
<Grid align='center' onClick={() => router.push(`task/${v.id}`)}>
<Grid.Col span={{
base: 1,
xs: 1,
@@ -182,7 +180,7 @@ export default function ListDivisionTask() {
lg: 1,
xl: 1
}}>
<Group onClick={() => router.push(`task/${v.id}`)}>
<Group>
<Center>
<ActionIcon
variant="gradient"

View File

@@ -1,14 +1,13 @@
'use client'
import { Box, Button, Flex, rem, Tabs } from "@mantine/core";
import { TEMA } from "@/module/_global";
import { useHookstate } from "@hookstate/core";
import { Box, Button, Flex, rem } from "@mantine/core";
import { useRouter, useSearchParams } from "next/navigation";
import { IoIosCheckmarkCircleOutline } from "react-icons/io";
import { IoCloseCircleOutline } from "react-icons/io5";
import { RiProgress3Line } from "react-icons/ri";
import { TbClockPause } from "react-icons/tb";
import ListDivisionTask from "./list_division_task";
import { useRouter, useSearchParams } from "next/navigation";
import { Carousel } from "@mantine/carousel";
import { TEMA } from "@/module/_global";
import { useHookstate } from "@hookstate/core";
export default function TabsDivisionTask() {
const iconStyle = { width: rem(20), height: rem(20) };
@@ -43,40 +42,40 @@ export default function TabsDivisionTask() {
return (
<Box p={20}>
<Box
style={{
display: "flex",
gap: "20px",
position: "relative",
overflowX: "scroll",
scrollbarWidth: "none",
maxWidth: "550px"
}}
>
<Flex gap={"md"} justify={"space-between"}>
{dataStatus.map((item, index) => (
<Button
variant="subtle"
color={
status == item.id
? "white"
: (status == null && item.id == "0") ? "white" : tema.get().utama
}
onClick={() => { router.push("?status=" + item.id) }}
defaultValue={(status == "1" || status == "2" || status == "3") ? status : "0"}
radius={"xl"}
key={index}
bg={
status == item.id
? tema.get().bgFiturDivision
: (status == null && item.id == "0") ? tema.get().bgFiturDivision : "transparent"
}
leftSection={item.icon}
>
{item.title}
</Button>
))}
</Flex>
</Box>
style={{
display: "flex",
gap: "20px",
position: "relative",
overflowX: "scroll",
scrollbarWidth: "none",
maxWidth: "550px"
}}
>
<Flex gap={"md"} justify={"space-between"}>
{dataStatus.map((item, index) => (
<Button
variant="subtle"
color={
status == item.id
? "white"
: (status == null && item.id == "0") ? "white" : tema.get().utama
}
onClick={() => { router.push("?status=" + item.id) }}
defaultValue={(status == "1" || status == "2" || status == "3") ? status : "0"}
radius={"xl"}
key={index}
bg={
status == item.id
? tema.get().bgFiturDivision
: (status == null && item.id == "0") ? tema.get().bgFiturDivision : "transparent"
}
leftSection={item.icon}
>
{item.title}
</Button>
))}
</Flex>
</Box>
<ListDivisionTask />
</Box>
)