# fix - Notifikasi report posting _ Realtime notifikasi ## Issuee: Cooming soon saat report komentar langsung menuju tablenya
497 lines
14 KiB
TypeScript
497 lines
14 KiB
TypeScript
"use client";
|
|
|
|
import mqtt_client from "@/util/mqtt_client";
|
|
import {
|
|
ActionIcon,
|
|
AppShell,
|
|
Badge,
|
|
Box,
|
|
Burger,
|
|
Card,
|
|
Center,
|
|
Divider,
|
|
Drawer,
|
|
Group,
|
|
Header,
|
|
Indicator,
|
|
MediaQuery,
|
|
NavLink,
|
|
Navbar,
|
|
Paper,
|
|
ScrollArea,
|
|
Stack,
|
|
Text,
|
|
Title,
|
|
useMantineTheme,
|
|
} from "@mantine/core";
|
|
import {
|
|
IconBell,
|
|
IconCheck,
|
|
IconChecks,
|
|
IconCircleDot,
|
|
IconCircleDotFilled,
|
|
IconUserSquareRounded,
|
|
} from "@tabler/icons-react";
|
|
import { useAtom } from "jotai";
|
|
import _ from "lodash";
|
|
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
|
import { useRouter } from "next/navigation";
|
|
import React, { useEffect, useState } from "react";
|
|
import { MODEL_USER } from "../home/model/interface";
|
|
import { MODEL_NOTIFIKASI } from "../notifikasi/model/interface";
|
|
import Admin_Logout from "./component_global/logout";
|
|
import {
|
|
gs_admin_hotMenu,
|
|
gs_admin_subMenu,
|
|
gs_layout_admin_isNavbarOpen,
|
|
} from "./global_state";
|
|
import { listAdminPage } from "./list_page";
|
|
import adminNotifikasi_countNotifikasi from "./notifikasi/fun/count/count_is_read";
|
|
import adminNotifikasi_getByUserId from "./notifikasi/fun/get/get_notifikasi_by_user_id";
|
|
import adminNotifikasi_funUpdateIsReadById from "./notifikasi/fun/update/fun_update_is_read_by_id";
|
|
import adminNotifikasi_findRouterJob from "./notifikasi/route_setting/job";
|
|
import adminNotifikasi_findRouterForum from "./notifikasi/route_setting/forum";
|
|
|
|
export default function AdminLayout({
|
|
children,
|
|
listNotif,
|
|
dataUser,
|
|
countNotifikasi,
|
|
}: {
|
|
children: React.ReactNode;
|
|
listNotif: MODEL_NOTIFIKASI[];
|
|
dataUser: MODEL_USER;
|
|
countNotifikasi: number;
|
|
}) {
|
|
const theme = useMantineTheme();
|
|
const [opened, setOpened] = useState(false);
|
|
const router = useRouter();
|
|
const [activeId, setActiveId] = useAtom(gs_admin_hotMenu);
|
|
const [activeChild, setActiveChild] = useAtom(gs_admin_subMenu);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const [user, setUser] = useState(dataUser);
|
|
const userRoleId = user.masterUserRoleId;
|
|
|
|
const [isNotif, setIsNotif] = useState(false);
|
|
const [dataNotif, setDataNotif] = useState(listNotif);
|
|
|
|
const [countNotif, setCountNotif] = useState(countNotifikasi);
|
|
const [isNavbarOpen, setIsNavbarOpen] = useAtom(gs_layout_admin_isNavbarOpen);
|
|
|
|
const developerNavbar = listAdminPage.map((e, i) => (
|
|
<Box key={e.id}>
|
|
<NavLink
|
|
sx={{
|
|
":hover": {
|
|
backgroundColor: "transparent",
|
|
},
|
|
}}
|
|
fw={activeId === e.id ? "bold" : "normal"}
|
|
icon={
|
|
// active === e.id ? loading ? <Loader size={10} /> : e.icon : e.icon
|
|
e.icon
|
|
}
|
|
label={<Text size={"sm"}>{e.name}</Text>}
|
|
onClick={() => {
|
|
setLoading(true);
|
|
setActiveId(e.id);
|
|
setActiveChild(null);
|
|
e.path === "" ? router.push(e.child[0].path) : router.push(e.path);
|
|
e.path === "" ? setActiveChild(e.child[0].id) : "";
|
|
}}
|
|
>
|
|
{_.isEmpty(e.child) ? (
|
|
""
|
|
) : (
|
|
<Box>
|
|
{e.child.map((v, ii) => (
|
|
<Box key={v.id}>
|
|
<NavLink
|
|
sx={{
|
|
":hover": {
|
|
backgroundColor: "transparent",
|
|
},
|
|
}}
|
|
fw={activeChild === v.id ? "bold" : "normal"}
|
|
label={<Text>{v.name}</Text>}
|
|
icon={
|
|
activeChild === v.id ? (
|
|
<IconCircleDotFilled size={10} />
|
|
) : (
|
|
<IconCircleDot size={10} />
|
|
)
|
|
}
|
|
onClick={() => {
|
|
setActiveId(e.id);
|
|
setActiveChild(v.id);
|
|
router.push(v.path);
|
|
}}
|
|
/>
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
)}
|
|
</NavLink>
|
|
</Box>
|
|
));
|
|
|
|
const bukanDeveloper = listAdminPage.slice(0, -1);
|
|
const adminNavbar = bukanDeveloper.map((e) => (
|
|
<Box key={e.id}>
|
|
<NavLink
|
|
opened={e?.id === activeId && isNavbarOpen ? true : false}
|
|
sx={{
|
|
":hover": {
|
|
backgroundColor: "transparent",
|
|
},
|
|
}}
|
|
fw={activeId === e.id ? "bold" : "normal"}
|
|
icon={e.icon}
|
|
label={<Text size={"sm"}>{e.name}</Text>}
|
|
onClick={() => {
|
|
setLoading(true);
|
|
setActiveId(e.id);
|
|
setActiveChild(null);
|
|
e.path === "" ? router.push(e.child[0].path) : router.push(e.path);
|
|
e.path === "" ? setActiveChild(e.child[0].id) : "";
|
|
|
|
setIsNavbarOpen(true);
|
|
}}
|
|
>
|
|
{_.isEmpty(e.child) ? (
|
|
""
|
|
) : (
|
|
<Box>
|
|
{e.child.map((v, ii) => (
|
|
<Box key={v.id}>
|
|
<NavLink
|
|
sx={{
|
|
":hover": {
|
|
backgroundColor: "transparent",
|
|
},
|
|
}}
|
|
fw={activeChild === v.id ? "bold" : "normal"}
|
|
label={<Text>{v.name}</Text>}
|
|
icon={
|
|
activeChild === v.id ? (
|
|
<IconCircleDotFilled size={10} />
|
|
) : (
|
|
<IconCircleDot size={10} />
|
|
)
|
|
}
|
|
onClick={() => {
|
|
setActiveId(e.id);
|
|
setActiveChild(v.id);
|
|
router.push(v.path);
|
|
}}
|
|
/>
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
)}
|
|
</NavLink>
|
|
</Box>
|
|
));
|
|
|
|
async function onLoadNotifikasi() {
|
|
const loadNotif = await adminNotifikasi_getByUserId();
|
|
setDataNotif(loadNotif as any);
|
|
}
|
|
|
|
useEffect(() => {
|
|
mqtt_client.subscribe("ADMIN");
|
|
|
|
mqtt_client.on("message", (topic: any, message: any) => {
|
|
const data = JSON.parse(message.toString());
|
|
// console.log(data);
|
|
setCountNotif(countNotif + data.count);
|
|
});
|
|
}, [countNotif]);
|
|
|
|
return (
|
|
<>
|
|
<AppShell
|
|
padding="md"
|
|
navbarOffsetBreakpoint="md"
|
|
asideOffsetBreakpoint="sm"
|
|
header={
|
|
<Header height={"6vh"} bg={"gray.2"}>
|
|
{/* Web View */}
|
|
<MediaQuery smallerThan={"md"} styles={{ display: "none" }}>
|
|
<Group position="apart" align="center" h={"100%"} px={"md"}>
|
|
<Title order={3}>Dashboard Admin</Title>
|
|
|
|
<Group>
|
|
<ActionIcon
|
|
radius={"xl"}
|
|
onClick={() => {
|
|
setIsNotif(true);
|
|
onLoadNotifikasi();
|
|
}}
|
|
>
|
|
<Indicator
|
|
processing
|
|
label={<Text fz={10}>{countNotif}</Text>}
|
|
>
|
|
<IconBell />
|
|
</Indicator>
|
|
</ActionIcon>
|
|
<Divider orientation="vertical" color="dark" />
|
|
<Group>
|
|
<Text>{user?.username}</Text>
|
|
<IconUserSquareRounded />
|
|
</Group>
|
|
</Group>
|
|
</Group>
|
|
</MediaQuery>
|
|
|
|
{/* Mobile View */}
|
|
<MediaQuery largerThan="md" styles={{ display: "none" }}>
|
|
<Group h={50} align="center" px={"md"} position="apart">
|
|
<Burger
|
|
opened={opened}
|
|
onClick={() => setOpened((o) => !o)}
|
|
size="sm"
|
|
color={theme.colors.gray[6]}
|
|
mr="xl"
|
|
/>
|
|
<Title order={6}>Dashboard Admin</Title>
|
|
{/* <Admin_Logout /> */}
|
|
<ActionIcon>
|
|
<IconBell />
|
|
</ActionIcon>
|
|
</Group>
|
|
</MediaQuery>
|
|
</Header>
|
|
}
|
|
navbar={
|
|
<MediaQuery smallerThan={"md"} styles={{ display: "none" }}>
|
|
<Navbar
|
|
h={"94vh"}
|
|
width={{ lg: 250, md: 200, sm: 200, base: 250 }}
|
|
hiddenBreakpoint="md"
|
|
hidden={!opened}
|
|
p="xs"
|
|
bg={"gray.2"}
|
|
>
|
|
<Navbar.Section grow component={ScrollArea}>
|
|
<Stack>
|
|
{userRoleId === "3" ? developerNavbar : adminNavbar}
|
|
</Stack>
|
|
</Navbar.Section>
|
|
<Navbar.Section>
|
|
<Stack>
|
|
<Divider />
|
|
<Group position="apart">
|
|
<Text fs={"italic"} c={"gray"} fz={"xs"}>
|
|
V 1.0.0
|
|
</Text>
|
|
<Admin_Logout />
|
|
</Group>
|
|
</Stack>
|
|
</Navbar.Section>
|
|
</Navbar>
|
|
</MediaQuery>
|
|
}
|
|
>
|
|
{children}
|
|
</AppShell>
|
|
{/* Drawer Mobile View */}
|
|
<Drawer opened={opened} onClose={() => setOpened(false)} size={"50%"}>
|
|
<Stack spacing={"xl"}>
|
|
{listAdminPage.map((e) => (
|
|
<Text key={e.id} onClick={() => router.push(e.path)}>
|
|
{e.name}
|
|
</Text>
|
|
))}
|
|
</Stack>
|
|
</Drawer>
|
|
|
|
{/* Drawer Notifikasi */}
|
|
<Drawer
|
|
title={
|
|
<Group position="apart">
|
|
<Text fw={"bold"} fz={"lg"}>
|
|
Notifikasi
|
|
</Text>
|
|
</Group>
|
|
}
|
|
opened={isNotif}
|
|
onClose={() => setIsNotif(false)}
|
|
position="right"
|
|
size={"xs"}
|
|
>
|
|
<DrawerNotifikasi
|
|
data={dataNotif}
|
|
onLoadReadNotif={(val: any) => {
|
|
setDataNotif(val);
|
|
}}
|
|
onChangeNavbar={(val: any) => {
|
|
setActiveId(val.id);
|
|
setActiveChild(val.childId);
|
|
}}
|
|
onToggleNavbar={setIsNavbarOpen}
|
|
onLoadCountNotif={(val: any) => {
|
|
setCountNotif(val);
|
|
}}
|
|
/>
|
|
</Drawer>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function DrawerNotifikasi({
|
|
data,
|
|
onLoadReadNotif,
|
|
onChangeNavbar,
|
|
onToggleNavbar,
|
|
onLoadCountNotif,
|
|
}: {
|
|
data: MODEL_NOTIFIKASI[];
|
|
onLoadReadNotif: (val: any) => void;
|
|
onChangeNavbar: (val: any) => void;
|
|
onToggleNavbar: (val: any) => void;
|
|
onLoadCountNotif: (val: any) => void;
|
|
}) {
|
|
const router = useRouter();
|
|
|
|
if (_.isEmpty(data)) {
|
|
return (
|
|
<>
|
|
<Center>
|
|
<Text c={"gray"} fz={"xs"}>
|
|
Tidak ada notifikasi
|
|
</Text>
|
|
</Center>
|
|
</>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Paper h={"100%"}>
|
|
<Stack>
|
|
{data.map((e, i) => (
|
|
<Card
|
|
style={{
|
|
transition: "0.5s",
|
|
}}
|
|
key={e?.id}
|
|
// withBorder
|
|
bg={e?.isRead ? "gray.1" : "gray.4"}
|
|
sx={{
|
|
borderColor: "gray",
|
|
borderStyle: "solid",
|
|
borderWidth: "0.5px",
|
|
":hover": {
|
|
backgroundColor: "#C1C2C5",
|
|
},
|
|
}}
|
|
onClick={async () => {
|
|
e?.kategoriApp === "JOB" &&
|
|
adminNotifikasi_findRouterJob({
|
|
data: e,
|
|
router: router,
|
|
onChangeNavbar: (val: any) => {
|
|
onChangeNavbar(val);
|
|
},
|
|
onToggleNavbar: onToggleNavbar,
|
|
});
|
|
|
|
e?.kategoriApp === "FORUM" &&
|
|
adminNotifikasi_findRouterForum({
|
|
data: e,
|
|
router: router,
|
|
onChangeNavbar(val) {
|
|
onChangeNavbar(val);
|
|
},
|
|
onToggleNavbar(val) {
|
|
onToggleNavbar(val);
|
|
},
|
|
});
|
|
|
|
const updateIsRead = await adminNotifikasi_funUpdateIsReadById({
|
|
notifId: e?.id,
|
|
});
|
|
|
|
if (updateIsRead) {
|
|
const loadCountNotif =
|
|
await adminNotifikasi_countNotifikasi();
|
|
onLoadCountNotif(loadCountNotif);
|
|
|
|
const loadDataNotif = await adminNotifikasi_getByUserId();
|
|
onLoadReadNotif(loadDataNotif);
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
// callBackIsNotifikasi(false);
|
|
}}
|
|
>
|
|
<Card.Section p={"sm"}>
|
|
<Stack spacing={"xs"}>
|
|
<Group position="apart">
|
|
<Text fw={"bold"} fz={10}>
|
|
# {e?.kategoriApp}
|
|
</Text>
|
|
{e?.status ? (
|
|
<Badge fz={10} size="sm">
|
|
{e?.status}
|
|
</Badge>
|
|
) : (
|
|
""
|
|
)}
|
|
</Group>
|
|
<Divider color="gray.3" />
|
|
</Stack>
|
|
</Card.Section>
|
|
<Card.Section px={"sm"} pb={"sm"}>
|
|
<Stack spacing={0}>
|
|
<Text lineClamp={2} fw={"bold"} fz={"xs"}>
|
|
{e?.title}
|
|
</Text>
|
|
<Text lineClamp={2} fz={"xs"}>
|
|
{e?.pesan}
|
|
</Text>
|
|
</Stack>
|
|
</Card.Section>
|
|
<Card.Section p={"sm"}>
|
|
<Group position="apart">
|
|
<Text fz={10} color="gray">
|
|
{new Intl.DateTimeFormat("id-ID", {
|
|
dateStyle: "long",
|
|
}).format(e?.createdAt)}
|
|
|
|
<Text span inherit fz={10} color="gray">
|
|
{", "}
|
|
{new Intl.DateTimeFormat("id-ID", {
|
|
timeStyle: "short",
|
|
}).format(e?.createdAt)}
|
|
</Text>
|
|
</Text>
|
|
{e?.isRead ? (
|
|
<Group spacing={5}>
|
|
<IconChecks color="gray" size={10} />
|
|
<Text fz={10} color="gray">
|
|
Sudah dilihat
|
|
</Text>
|
|
</Group>
|
|
) : (
|
|
<Group spacing={5}>
|
|
<IconCheck color="gray" size={10} />
|
|
<Text fz={10} color="gray">
|
|
Belum dilihat
|
|
</Text>
|
|
</Group>
|
|
)}
|
|
</Group>
|
|
</Card.Section>
|
|
</Card>
|
|
))}
|
|
</Stack>
|
|
</Paper>
|
|
</>
|
|
);
|
|
}
|