Fix: admin

Deskripsi:
- Fix tampilan navbar
This commit is contained in:
2024-10-31 13:51:06 +08:00
parent a798f9a3bc
commit 604077cc8d
10 changed files with 786 additions and 47 deletions

View File

@@ -13,15 +13,13 @@ import {
Stack,
Title,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { IconLogout } from "@tabler/icons-react";
import { useAtom } from "jotai";
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function Admin_Logout() {
const router = useRouter();
const [opened, { toggle }] = useDisclosure(false);
const [opened, setOpened] = useState(false);
const [loading, setLoading] = useState(false);
const [kodeId, setKodeId] = useAtom(gs_kodeId);
@@ -43,7 +41,7 @@ export default function Admin_Logout() {
<>
<Modal
opened={opened}
onClose={toggle}
onClose={() => setOpened(false)}
centered
withCloseButton={false}
closeOnClickOutside={false}
@@ -53,7 +51,7 @@ export default function Admin_Logout() {
<Group align="center" position="center">
<Button
onClick={() => {
toggle();
setOpened(false);
setLoading(false);
}}
radius={50}
@@ -77,13 +75,9 @@ export default function Admin_Logout() {
{loading ? (
<Loader color="gray" />
) : (
<IconLogout
color={Warna.merah}
onClick={() => {
toggle();
setLoading(true);
}}
/>
<Button radius={"xl"} color={"red"} onClick={() => setOpened(true)}>
Keluar
</Button>
)}
</ActionIcon>
{/* <Button radius={"xl"} color={"red"} onClick={toggle}>

View File

@@ -0,0 +1,16 @@
import { atomWithStorage } from "jotai/utils";
export const gs_admin_navbar_menu = atomWithStorage<string>(
"gs_admin_navbar_menu",
"Main"
);
export const gs_admin_navbar_subMenu = atomWithStorage<string | null>(
"gs_admin_navbar_submenu",
null
);
export const gs_admin_navbar_isActive_dropdown = atomWithStorage<boolean>(
"gs_admin_navbar_isActive_dropdown",
false
);

View File

@@ -0,0 +1,3 @@
import { Admin_NewLayout } from "./new_layout";
export { Admin_NewLayout };

View File

@@ -4,10 +4,8 @@ import mqtt_client from "@/util/mqtt_client";
import {
ActionIcon,
AppShell,
Badge,
Box,
Burger,
Card,
Center,
Divider,
Drawer,
@@ -17,7 +15,6 @@ import {
MediaQuery,
NavLink,
Navbar,
Paper,
ScrollArea,
Stack,
Text,
@@ -26,15 +23,12 @@ import {
} 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";
@@ -46,15 +40,9 @@ import {
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";
import { adminNotifikasi_findRouterVoting } from "./notifikasi/route_setting/voting";
import { adminNotifikasi_findRouterEvent } from "./notifikasi/route_setting/event";
import adminNotifikasi_findRouterDonasi from "./notifikasi/route_setting/donasi";
import { ComponentAdmin_UIDrawerNotifikasi } from "./notifikasi/ui_drawer_notifikasi";
import { AccentColor, MainColor } from "../_global/color";
export default function AdminLayout({
children,
@@ -86,6 +74,7 @@ export default function AdminLayout({
const developerNavbar = listAdminPage.map((e, i) => (
<Box key={e.id}>
<NavLink
style={{ color: "white" }}
sx={{
":hover": {
backgroundColor: "transparent",
@@ -112,6 +101,7 @@ export default function AdminLayout({
{e.child.map((v, ii) => (
<Box key={v.id}>
<NavLink
style={{ color: "white" }}
sx={{
":hover": {
backgroundColor: "transparent",
@@ -144,6 +134,7 @@ export default function AdminLayout({
const adminNavbar = bukanDeveloper.map((e) => (
<Box key={e.id}>
<NavLink
style={{ color: "white" }}
opened={e?.id === activeId && isNavbarOpen ? true : false}
sx={{
":hover": {
@@ -220,9 +211,13 @@ export default function AdminLayout({
navbarOffsetBreakpoint="md"
asideOffsetBreakpoint="sm"
header={
<Header height={"6vh"} bg={"gray.2"}>
<Header
height={"6vh"}
bg={AccentColor.darkblue}
style={{ color: "white", borderStyle: "none" }}
>
{/* Web View */}
<MediaQuery smallerThan={"md"} styles={{ display: "none" }}>
<MediaQuery smallerThan={"sm"} styles={{ display: "none" }}>
<Group position="apart" align="center" h={"100%"} px={"md"}>
<Title order={3}>Dashboard Admin</Title>
@@ -238,7 +233,7 @@ export default function AdminLayout({
processing
label={<Text fz={10}>{countNotif}</Text>}
>
<IconBell />
<IconBell color="white" />
</Indicator>
</ActionIcon>
<Divider orientation="vertical" color="dark" />
@@ -251,7 +246,7 @@ export default function AdminLayout({
</MediaQuery>
{/* Mobile View */}
<MediaQuery largerThan="md" styles={{ display: "none" }}>
<MediaQuery largerThan="sm" styles={{ display: "none" }}>
<Group h={50} align="center" px={"md"} position="apart">
<Burger
opened={opened}
@@ -270,17 +265,21 @@ export default function AdminLayout({
</Header>
}
navbar={
<MediaQuery smallerThan={"md"} styles={{ display: "none" }}>
<MediaQuery smallerThan={"sm"} styles={{ display: "none" }}>
<Navbar
h={"94vh"}
width={{ lg: 250, md: 200, sm: 200, base: 250 }}
hiddenBreakpoint="md"
hidden={!opened}
p="xs"
bg={"gray.2"}
bg={AccentColor.darkblue}
>
<Navbar.Section grow component={ScrollArea}>
<Stack>
<Navbar.Section
grow
component={ScrollArea}
style={{ color: "white", transition: "0.5s" }}
>
<Stack style={{ color: "white" }}>
{userRoleId === "3" ? developerNavbar : adminNavbar}
</Stack>
</Navbar.Section>
@@ -288,7 +287,7 @@ export default function AdminLayout({
<Stack>
<Divider />
<Group position="apart">
<Text fs={"italic"} c={"gray"} fz={"xs"}>
<Text fs={"italic"} c={"white"} fz={"xs"}>
V 1.0.0
</Text>
<Admin_Logout />
@@ -345,5 +344,3 @@ export default function AdminLayout({
</>
);
}

View File

@@ -0,0 +1,423 @@
"use client";
import {
ActionIcon,
AppShell,
Box,
Center,
Divider,
Drawer,
Grid,
Group,
Menu,
Navbar,
NavLink,
ScrollArea,
Stack,
Text,
Title
} from "@mantine/core";
import { useMediaQuery } from "@mantine/hooks";
import {
IconBell,
IconCircleDot,
IconCircleDotFilled,
IconPhone,
IconUser,
IconUserCircle
} from "@tabler/icons-react";
import { useAtom } from "jotai";
import _ from "lodash";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { AccentColor, MainColor } from "../_global/color";
import { MODEL_USER } from "../home/model/interface";
import Admin_Logout from "./_admin_global/logout";
import {
gs_admin_navbar_isActive_dropdown,
gs_admin_navbar_menu,
gs_admin_navbar_subMenu,
} from "./_admin_global/new_global_state";
import { newListAdminPage } from "./new_list_page";
import { ComponentAdmin_UIDrawerNotifikasi } from "./notifikasi/ui_drawer_notifikasi";
export function Admin_NewLayout({
children,
user,
}: {
children: React.ReactNode;
user: MODEL_USER;
}) {
const matches = useMediaQuery("(min-width: 1024px)");
const [dataUser, setDataUser] = useState(user);
const userRoleId = dataUser.masterUserRoleId;
const [opened, setOpened] = useState(false);
// Notifikasi
const [isDrawerNotifikasi, setDrawerNotifikasi] = useState(false);
const [isNavbarOpen, setIsNavbarOpen] = useState(false);
return (
<>
<AppShell
padding="md"
navbarOffsetBreakpoint={1024}
asideOffsetBreakpoint="sm"
navbar={
<Navbar
width={{ lg: 250, md: 200, base: 250 }}
hiddenBreakpoint={1024}
hidden={!opened}
p="xs"
bg={AccentColor.darkblue}
>
{/* Header */}
<Navbar.Section style={{ color: "white" }}>
<Stack spacing={"lg"}>
<Grid>
<Grid.Col span={7}>
<Title order={3} lineClamp={1}>
{userRoleId == "2" ? "Admin" : "Developer"}
</Title>
</Grid.Col>
<Grid.Col span={5}>
<Stack h={"100%"} justify="center">
<Group position="right" spacing={5}>
<ButtonUserCircle dataUser={dataUser} />
<ActionIcon
variant="transparent"
onClick={() => setDrawerNotifikasi(true)}
>
<IconBell color="white" />
</ActionIcon>
</Group>
</Stack>
</Grid.Col>
</Grid>
<Divider color="white" />
</Stack>
</Navbar.Section>
{/* Main */}
<Navbar.Section
grow
component={ScrollArea}
style={{ color: "white", transition: "0.5s" }}
>
<Stack style={{ color: "white" }}>
<NavbarAdmin userRoleId={userRoleId} />
</Stack>
</Navbar.Section>
{/* Footer */}
<Navbar.Section>
<Stack>
<Divider />
<Group position="center">
<Text fs={"italic"} c={"white"} fz={"xs"}>
V 1.0.0
</Text>
</Group>
</Stack>
</Navbar.Section>
</Navbar>
}
>
{matches ? (
children
) : (
<Stack align="center" justify="center" h={"100%"}>
<Title>Sorry !</Title>
<Title order={4} align="center">
View Only Available For Desktop
</Title>
</Stack>
)}
</AppShell>
{/* Notifikasi */}
<Drawer
title={
<Group position="apart">
<Text fw={"bold"} fz={"lg"}>
Notifikasi
</Text>
</Group>
}
opened={isDrawerNotifikasi}
onClose={() => setDrawerNotifikasi(false)}
position="right"
size={"xs"}
>
<ComponentAdmin_UIDrawerNotifikasi
data={[]}
onLoadReadNotif={(val: any) => {
// setDataNotif(val);
}}
onChangeNavbar={(val: any) => {
// setActiveId(val.id);
// setActiveChild(val.childId);
}}
onToggleNavbar={setIsNavbarOpen}
onLoadCountNotif={(val: any) => {
// setCountNotif(val);
}}
/>
</Drawer>
</>
);
}
function NavbarAdmin({ userRoleId }: { userRoleId: string }) {
const router = useRouter();
// global state
const [openDropdown, setOpenDropdown] = useAtom(
gs_admin_navbar_isActive_dropdown
);
const [activeId, setActiveId] = useAtom(gs_admin_navbar_menu);
const [activeChildId, setActiveChildId] = useAtom(gs_admin_navbar_subMenu);
// Kalau fix developer navbar, fix juga navbar admin, dan berlaku sebaliknya
const developerNavbar = newListAdminPage.map((parent) => (
<Box key={parent.id}>
<NavLink
opened={openDropdown && activeId === parent.id}
styles={{
icon: {
color: activeId === parent.id ? MainColor.yellow : "white",
},
label: {
color: activeId === parent.id ? MainColor.yellow : "white",
},
}}
style={{
color: "white",
transition: "0.5s",
}}
sx={{
":hover": {
backgroundColor: "transparent",
},
}}
fw={activeId === parent.id ? "bold" : "normal"}
label={<Text>{parent.name}</Text>}
icon={parent.icon}
onClick={() => {
setActiveId(parent.id);
setActiveChildId("");
parent.path == "" ? setActiveChildId(parent.child[0].id) : "";
parent.path == ""
? router.push(parent.child[0].path)
: router.push(parent.path);
openDropdown && activeId === parent.id
? setOpenDropdown(false)
: setOpenDropdown(true);
}}
// active={activeId === parent.id}
>
{/* Navlink Children */}
{!_.isEmpty(parent.child) &&
parent.child.map((child) => (
<Box key={child.id}>
<NavLink
styles={{
icon: {
color:
activeChildId === child.id ? MainColor.yellow : "white",
},
label: {
color:
activeChildId === child.id ? MainColor.yellow : "white",
},
}}
style={{
color: "white",
transition: "0.5s",
}}
sx={{
":hover": {
backgroundColor: "transparent",
},
}}
fw={activeChildId === child.id ? "bold" : "normal"}
label={<Text>{child.name}</Text>}
icon={
activeChildId === child.id ? (
<IconCircleDotFilled size={10} />
) : (
<IconCircleDot size={10} />
)
}
onClick={() => {
setActiveChildId(child.id);
router.push(child.path);
}}
active={activeId === child.id}
/>
</Box>
))}
</NavLink>
</Box>
));
const bukanDeveloper = newListAdminPage.slice(0, -1);
const adminNavbar = bukanDeveloper.map((parent) => (
<Box key={parent.id}>
<NavLink
opened={openDropdown && activeId === parent.id}
styles={{
icon: {
color: activeId === parent.id ? MainColor.yellow : "white",
},
label: {
color: activeId === parent.id ? MainColor.yellow : "white",
},
}}
style={{
color: "white",
transition: "0.5s",
}}
sx={{
":hover": {
backgroundColor: "transparent",
},
}}
fw={activeId === parent.id ? "bold" : "normal"}
label={<Text>{parent.name}</Text>}
icon={parent.icon}
onClick={() => {
setActiveId(parent.id);
setActiveChildId("");
parent.path == "" ? setActiveChildId(parent.child[0].id) : "";
parent.path == ""
? router.push(parent.child[0].path)
: router.push(parent.path);
openDropdown && activeId === parent.id
? setOpenDropdown(false)
: setOpenDropdown(true);
}}
// active={activeId === parent.id}
>
{/* Navlink Children */}
{!_.isEmpty(parent.child) &&
parent.child.map((child) => (
<Box key={child.id}>
<NavLink
styles={{
icon: {
color:
activeChildId === child.id ? MainColor.yellow : "white",
},
label: {
color:
activeChildId === child.id ? MainColor.yellow : "white",
},
}}
style={{
color: "white",
transition: "0.5s",
}}
sx={{
":hover": {
backgroundColor: "transparent",
},
}}
fw={activeChildId === child.id ? "bold" : "normal"}
label={<Text>{child.name}</Text>}
icon={
activeChildId === child.id ? (
<IconCircleDotFilled size={10} />
) : (
<IconCircleDot size={10} />
)
}
onClick={() => {
setActiveChildId(child.id);
router.push(child.path);
}}
active={activeId === child.id}
/>
</Box>
))}
</NavLink>
</Box>
));
return userRoleId == "2" ? adminNavbar : developerNavbar;
}
function ButtonUserCircle({ dataUser }: { dataUser: MODEL_USER }) {
const [isOpenMenuUser, setOpenMenuUser] = useState(false);
return (
<>
<Menu
withArrow
arrowPosition="center"
opened={isOpenMenuUser}
onChange={setOpenMenuUser}
shadow="md"
width={250}
position="bottom-start"
styles={{
dropdown: {
backgroundColor: AccentColor.blue,
border: `1px solid ${AccentColor.skyblue}`,
},
item: {
color: "white",
":hover": {
backgroundColor: "gray",
},
},
arrow: {
borderTopColor: AccentColor.skyblue,
borderLeftColor: AccentColor.skyblue,
},
}}
>
<Menu.Target>
<ActionIcon variant="transparent" onClick={() => console.log("test")}>
<IconUserCircle color="white" />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Stack spacing={5} px={"xs"}>
<Menu.Item>
<Grid>
<Grid.Col span={2}>
<IconUser />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text lineClamp={1}>{dataUser.username}</Text>
</Grid.Col>
</Grid>
</Menu.Item>
<Menu.Item>
<Grid>
<Grid.Col span={2}>
<IconPhone />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text lineClamp={1}>+{dataUser.nomor}</Text>
</Grid.Col>
</Grid>
</Menu.Item>
<Menu.Divider />
<Center py={"xs"}>
<Admin_Logout />
</Center>
</Stack>
</Menu.Dropdown>
</Menu>
</>
);
}

View File

@@ -0,0 +1,308 @@
import { RouterAdminColab } from "@/app/lib/router_admin/router_admin_colab";
import { RouterAdminDeveloper } from "@/app/lib/router_admin/router_admin_developer";
import { RouterAdminDonasi } from "@/app/lib/router_admin/router_admin_donasi";
import { RouterAdminEvent } from "@/app/lib/router_admin/router_admin_event";
import { RouterAdminForum } from "@/app/lib/router_admin/router_admin_forum";
import { RouterAdminInvestasi } from "@/app/lib/router_admin/router_admin_investasi";
import { RouterAdminJob } from "@/app/lib/router_admin/router_admin_job";
import { RouterAdminMap } from "@/app/lib/router_admin/router_admin_map";
import { RouterAdminVote } from "@/app/lib/router_admin/router_admin_vote";
import { RouterAdminUserAccess } from "@/app/lib/router_admin/router_admn_user_acces";
import { RouterAdminAppInformation } from "@/app/lib/router_admin/router_app_information";
import { RouterAdminDashboard } from "@/app/lib/router_hipmi/router_admin";
import {
IconAffiliate,
IconBriefcase,
IconDashboard,
IconDeviceMobile,
IconHeartHandshake,
IconHome,
IconMap2,
IconMessages,
IconMoneybag,
IconPackageImport,
IconPresentation,
IconUserCog,
} from "@tabler/icons-react";
export const newListAdminPage = [
// Main Dashboard
{
id: "Main",
name: "Main Dashboard",
path: RouterAdminDashboard.main_admin,
icon: <IconHome />,
child: [],
},
// Investasi
{
id: "Investasi",
name: "Investasi",
path: "",
icon: <IconMoneybag />,
child: [
{
id: "Investasi_1",
name: "Dashboard",
path: RouterAdminInvestasi.main,
},
{
id: "Investasi_2",
name: "Table Publish",
path: RouterAdminInvestasi.table_publish,
},
{
id: "Investasi_3",
name: "Table Review",
path: RouterAdminInvestasi.table_review,
},
{
id: "Investasi_4",
name: "Table Reject",
path: RouterAdminInvestasi.table_reject,
},
],
},
//Donasi
{
id: "Donaasi",
name: "Donasi",
path: "",
icon: <IconHeartHandshake />,
child: [
{
id: "Donaasi_1",
name: "Dashboard",
path: RouterAdminDonasi.main,
},
{
id: "Donaasi_2",
name: "Table Publish",
path: RouterAdminDonasi.table_publish,
},
{
id: "Donaasi_3",
name: "Table Review",
path: RouterAdminDonasi.table_review,
},
{
id: "Donaasi_4",
name: "Table Reject",
path: RouterAdminDonasi.table_reject,
},
{
id: "Donaasi_5",
name: "Table Kategori",
path: RouterAdminDonasi.table_kategori,
},
],
},
// Event
{
id: "Event",
name: "Event",
path: "",
icon: <IconPresentation />,
child: [
{
id: "Event_1",
name: "Dashboard",
path: RouterAdminEvent.main_event,
},
{
id: "Event_2",
name: "Table Publish",
path: RouterAdminEvent.table_publish,
},
{
id: "Event_3",
name: "Table Review",
path: RouterAdminEvent.table_review,
},
{
id: "Event_4",
name: "Table Reject",
path: RouterAdminEvent.table_reject,
},
{
id: "Event_5",
name: "Tipe Acara",
path: RouterAdminEvent.detail_tipe_acara,
},
{
id: "Event_6",
name: "Riwayat",
path: RouterAdminEvent.detail_riwayat,
},
],
},
// Voting
{
id: "Voting",
name: "Voting",
path: "",
icon: <IconPackageImport />,
child: [
{
id: "Voting_1",
name: "Dashboard",
path: RouterAdminVote.main,
},
{
id: "Voting_2",
name: "Table Publish",
path: RouterAdminVote.table_publish,
},
{
id: "Voting_3",
name: "Table Review",
path: RouterAdminVote.table_review,
},
{
id: "Voting_4",
name: "Table Reject",
path: RouterAdminVote.table_reject,
},
{
id: "Voting_5",
name: "Riwayat",
path: RouterAdminVote.riwayat,
},
],
},
// Job Vacancy
{
id: "Job",
name: "Job Vacancy",
path: "",
icon: <IconBriefcase />,
child: [
{
id: "Job_1",
name: "Dashboard",
path: RouterAdminJob.main,
},
{
id: "Job_2",
name: "Table Publish",
path: RouterAdminJob.publish,
},
{
id: "Job_3",
name: "Table Review",
path: RouterAdminJob.review,
},
{
id: "Job_4",
name: "Table Reject",
path: RouterAdminJob.reject,
},
// {
// id: 65,
// name: "Arsip",
// path: RouterAdminJob.arsip,
// },
],
},
// Forum
{
id: "Forum",
name: "Forum",
path: "",
icon: <IconMessages />,
child: [
{
id: "Forum_1",
name: "Dashboard",
path: RouterAdminForum.main,
},
{
id: "Forum_2",
name: "Table Posting",
path: RouterAdminForum.table_posting,
},
{
id: "Forum_3",
name: "Report Posting",
path: RouterAdminForum.table_report_posting,
},
{
id: "Forum_4",
name: "Report Komentar",
path: RouterAdminForum.table_report_komentar,
},
],
},
// Project Collaboration
{
id: "Collaboration",
name: "Collaboration",
path: "",
icon: <IconAffiliate />,
child: [
{
id: "Collaboration_1",
name: "Dashboard",
path: RouterAdminColab.dashboard,
},
{
id: "Collaboration_2",
name: "Table Publish",
path: RouterAdminColab.table_publish,
},
{
id: "Collaboration_3",
name: "Table Group",
path: RouterAdminColab.table_group,
},
{
id: "Collaboration_4",
name: "Table Reject",
path: RouterAdminColab.table_reject,
},
],
},
// Maps
{
id: "Maps",
name: "Maps",
path: RouterAdminMap.main,
icon: <IconMap2 />,
child: [],
},
// App Information
{
id: "App Information",
name: "App Information",
path: RouterAdminAppInformation.main,
icon: <IconDeviceMobile />,
child: [],
},
// User Access
{
id: "User Access",
name: "User Access",
path: RouterAdminUserAccess.main,
icon: <IconUserCog />,
child: [],
},
// Developer
{
id: "Developer",
name: "Developer",
path: RouterAdminDeveloper.main,
icon: <IconDashboard />,
child: [],
},
];