Notifikasi

# feat:
- Notifikasi di bagian admin

## No issue
This commit is contained in:
2024-06-10 16:22:05 +08:00
parent 0e16d6501f
commit 76f0396005
35 changed files with 618 additions and 200 deletions

View File

@@ -43,15 +43,18 @@ model User {
ProjectCollaboration_Message ProjectCollaboration_Message[]
AdminProjectCollaboration_Notifikasi ProjectCollaboration_Notifikasi[] @relation("AdminNotifProjectToUser")
UserProjectCollaboration_Notifikasi ProjectCollaboration_Notifikasi[] @relation("UserNotifProjectToUser")
Admin_Notifikasi Notifikasi[] @relation("AdminNotifikasi")
User_Notifikasi Notifikasi[] @relation("UserNotifikasi")
}
model MasterUserRole {
id String @id
name String
active Boolean @default(true)
createdAt DateTime? @default(now())
updatedAt DateTime? @updatedAt
User User[]
id String @id
name String
active Boolean @default(true)
createdAt DateTime? @default(now())
updatedAt DateTime? @updatedAt
User User[]
Notifikasi Notifikasi[]
}
model UserSession {
@@ -847,3 +850,23 @@ model NomorAdmin {
nomor String
}
model Notifikasi {
id String @id @default(cuid())
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
isRead Boolean @default(false)
appId String
kategoriApp String
pesan String
title String?
status String?
Role MasterUserRole? @relation(fields: [userRoleId], references: [id])
userRoleId String
User User @relation("UserNotifikasi", fields: [userId], references: [id], map: "NotifikasiUser")
userId String
Admin User @relation("AdminNotifikasi", fields: [adminId], references: [id], map: "NotifikasiAdmin")
adminId String
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -1,4 +1,6 @@
import { AdminLayout } from "@/app_modules/admin/main_dashboard";
import adminNotifikasi_countNotifikasi from "@/app_modules/admin/notifikasi/fun/count/count_is_read";
import adminNotifikasi_getByUserId from "@/app_modules/admin/notifikasi/fun/get/get_notifikasi_by_user_id";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import React from "react";
@@ -8,13 +10,20 @@ export default async function Layout({
}: {
children: React.ReactNode;
}) {
const userId = await user_getOneUserId()
const dataUser = await user_getOneByUserId(userId)
const userRole = dataUser?.masterUserRoleId
const userId = await user_getOneUserId();
const dataUser = await user_getOneByUserId(userId);
const listNotif = await adminNotifikasi_getByUserId();
const countNotifikasi = await adminNotifikasi_countNotifikasi();
return (
<>
<AdminLayout userRole={userRole as any}>{children}</AdminLayout>
<AdminLayout
listNotif={listNotif as any}
dataUser={dataUser as any}
countNotifikasi={countNotifikasi}
>
{children}
</AdminLayout>
</>
);
}

View File

@@ -0,0 +1,9 @@
import { Notifikasi_MainView } from "@/app_modules/admin/notifikasi";
export default async function Page() {
return (
<>
<Notifikasi_MainView />
</>
);
}

View File

@@ -1,7 +1,7 @@
export const RouterAdminJob = {
main: "/dev/admin/job/main",
table_publish: "/dev/admin/job/child/table_publish",
table_review: "/dev/admin/job/child/table_review",
table_reject: "/dev/admin/job/child/table_reject",
publish: "/dev/admin/job/child/publish",
review: "/dev/admin/job/child/review",
reject: "/dev/admin/job/child/reject",
arsip: "/dev/admin/job/child/arsip",
};

View File

@@ -0,0 +1,3 @@
export const RouterNotifikasi = {
main: "/dev/notifikasi",
};

View File

@@ -5,6 +5,14 @@ import { atomWithStorage } from "jotai/utils";
* @type number
* @
*/
export const gs_admin_hotMenu = atomWithStorage("gs_admin_hotMenu", 1)
export const gs_admin_hotMenu = atomWithStorage("gs_admin_hotMenu", 1);
export const gs_admin_subMenu = atomWithStorage<number | null>("gs_admin_subMenu",null)
export const gs_admin_subMenu = atomWithStorage<number | null>(
"gs_admin_subMenu",
null
);
export const gs_layout_admin_isNavbarOpen = atomWithStorage(
"gs_layout_admin_isNavbarOpen",
false
);

View File

@@ -1,6 +1,6 @@
import AdminJob_Main from "./main";
import AdminJob_TablePublish from "./child/table_publish";
import AdminJob_TableReview from "./child/table_review";
import AdminJob_TableReject from "./child/table_reject";
import AdminJob_TablePublish from "./child/publish";
import AdminJob_TableReview from "./child/review";
import AdminJob_TableReject from "./child/reject";
export { AdminJob_Main, AdminJob_TablePublish, AdminJob_TableReview, AdminJob_TableReject };

View File

@@ -3,69 +3,90 @@
import {
ActionIcon,
AppShell,
Badge,
Box,
Burger,
Button,
Card,
Center,
Divider,
Drawer,
Group,
Header,
Indicator,
MediaQuery,
NavLink,
Navbar,
Paper,
ScrollArea,
Stack,
Text,
Title,
useMantineTheme
useMantineTheme,
} from "@mantine/core";
import {
IconBell,
IconCheck,
IconChecks,
IconCircleDot,
IconCircleDotFilled,
IconDashboard
IconDashboard,
IconUserSquareRounded,
} from "@tabler/icons-react";
import { useAtom } from "jotai";
import _ from "lodash";
import { useRouter } from "next/navigation";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { auth_Logout } from "../auth/fun/fun_logout";
import { gs_kodeId } from "../auth/state/state";
import { ComponentGlobal_NotifikasiBerhasil } from "../component_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiPeringatan } from "../component_global/notif_global/notifikasi_peringatan";
import Admin_Logout from "./component_global/logout";
import { gs_admin_hotMenu, gs_admin_subMenu } from "./global_state";
import {
gs_admin_hotMenu,
gs_admin_subMenu,
gs_layout_admin_isNavbarOpen,
} from "./global_state";
import { listAdminPage } from "./list_page";
import { MODEL_NOTIFIKASI } from "../notifikasi/model/interface";
import { MODEL_USER } from "../home/model/interface";
import { useHover, useShallowEffect, useToggle } from "@mantine/hooks";
import moment from "moment";
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
import { RouterAdminJob } from "@/app/lib/router_admin/router_admin_job";
import adminNotifikasi_funUpdateIsReadById from "./notifikasi/fun/update/fun_update_is_read_by_id";
import adminNotifikasi_getByUserId from "./notifikasi/fun/get/get_notifikasi_by_user_id";
import adminNotifikasi_countNotifikasi from "./notifikasi/fun/count/count_is_read";
import mqtt_client from "@/util/mqtt_client";
export default function AdminLayout({
userRole,
children,
listNotif,
dataUser,
countNotifikasi,
}: {
userRole: string;
children: React.ReactNode;
listNotif: MODEL_NOTIFIKASI[];
dataUser: MODEL_USER;
countNotifikasi: number;
}) {
const theme = useMantineTheme();
const [opened, setOpened] = useState(false);
const router = useRouter();
const [active, setActive] = useAtom(gs_admin_hotMenu);
const [activeId, setActiveId] = useAtom(gs_admin_hotMenu);
const [activeChild, setActiveChild] = useAtom(gs_admin_subMenu);
const [loading, setLoading] = useState(false);
const [kodeId, setKodeId] = useAtom(gs_kodeId);
async function onClickLogout() {
// await auth_Logout(kodeId).then((res) => {
// ComponentGlobal_NotifikasiBerhasil("Berhasil Logout");
// });
await auth_Logout(kodeId).then((res) => {
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message);
setKodeId("");
} else {
ComponentGlobal_NotifikasiPeringatan(res.message);
}
});
}
const [user, setUser] = useState(dataUser);
const userRoleId = user.masterUserRoleId;
const navbarItems = listAdminPage.map((e, i) => (
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={{
@@ -73,7 +94,7 @@ export default function AdminLayout({
backgroundColor: "transparent",
},
}}
fw={active === e.id ? "bold" : "normal"}
fw={activeId === e.id ? "bold" : "normal"}
icon={
// active === e.id ? loading ? <Loader size={10} /> : e.icon : e.icon
e.icon
@@ -81,7 +102,7 @@ export default function AdminLayout({
label={<Text size={"sm"}>{e.name}</Text>}
onClick={() => {
setLoading(true);
setActive(e.id);
setActiveId(e.id);
setActiveChild(null);
e.path === "" ? router.push(e.child[0].path) : router.push(e.path);
e.path === "" ? setActiveChild(e.child[0].id) : "";
@@ -109,7 +130,7 @@ export default function AdminLayout({
)
}
onClick={() => {
setActive(e.id);
setActiveId(e.id);
setActiveChild(v.id);
router.push(v.path);
}}
@@ -123,26 +144,26 @@ export default function AdminLayout({
));
const bukanDeveloper = listAdminPage.slice(0, -1);
const notAdminDev = bukanDeveloper.map((e) => (
const adminNavbar = bukanDeveloper.map((e) => (
<Box key={e.id}>
<NavLink
opened={e?.id === activeId && isNavbarOpen ? true : false}
sx={{
":hover": {
backgroundColor: "transparent",
},
}}
fw={active === e.id ? "bold" : "normal"}
icon={
// active === e.id ? loading ? <Loader size={10} /> : e.icon : e.icon
e.icon
}
fw={activeId === e.id ? "bold" : "normal"}
icon={e.icon}
label={<Text size={"sm"}>{e.name}</Text>}
onClick={() => {
setLoading(true);
setActive(e.id);
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) ? (
@@ -167,7 +188,7 @@ export default function AdminLayout({
)
}
onClick={() => {
setActive(e.id);
setActiveId(e.id);
setActiveChild(v.id);
router.push(v.path);
}}
@@ -180,20 +201,20 @@ export default function AdminLayout({
</Box>
));
const navbarAdmin = (
<Box>
<NavLink
c="orange"
icon={<IconDashboard />}
label="Developer"
sx={{
":hover": {
backgroundColor: "transparent",
},
}}
/>
</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 (
<>
@@ -201,59 +222,34 @@ export default function AdminLayout({
padding="md"
navbarOffsetBreakpoint="md"
asideOffsetBreakpoint="sm"
navbar={
<MediaQuery smallerThan={"md"} styles={{ display: "none" }}>
<Navbar
h={"95%"}
width={{ lg: 250, md: 200, sm: 200, base: 250 }}
hiddenBreakpoint="md"
hidden={!opened}
p="xs"
bg={"gray.2"}
>
{/* <Navbar.Section>
<Center h={50}>
<Title order={4} ff={"sans-serif"}>
Dashboard Admin
</Title>
</Center>
<Divider />
</Navbar.Section> */}
<Navbar.Section grow component={ScrollArea}>
<Stack>{userRole === "3" ? navbarItems : notAdminDev}</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>
}
header={
<Header height={"5vh"} bg={"gray.2"}>
<Header height={"6vh"} bg={"gray.2"}>
{/* Web View */}
<MediaQuery smallerThan={"md"} styles={{ display: "none" }}>
<Group position="apart" align="center" h={"100%"} px={"md"}>
<Text fw={"lighter"}>Dashboard Admin</Text>
<Title order={4}> HIPMI</Title>
{/* <Group>
{listAdminPage.map((e) => (
<Text key={e.id} onClick={() => router.push(e.route)}>
{e.name}
</Text>
))}
</Group> */}
{/* <Admin_Logout /> */}
<ActionIcon radius={"xl"}>
<IconBell />
</ActionIcon>
<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>
@@ -276,10 +272,39 @@ export default function AdminLayout({
</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>
}
>
{/* {JSON.stringify(active)} */}
{children}
</AppShell>
{/* Drawer Mobile View */}
<Drawer opened={opened} onClose={() => setOpened(false)} size={"50%"}>
<Stack spacing={"xl"}>
{listAdminPage.map((e) => (
@@ -289,6 +314,183 @@ export default function AdminLayout({
))}
</Stack>
</Drawer>
{/* Drawer Notifikasi */}
<Drawer
title={
<Group position="apart">
<Text fw={"bold"} fz={"lg"}>
Notifikasi
</Text>
{/* <Button compact radius={"xl"} fz={10}>Tandai terliha</Button> */}
</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
key={e?.id}
// withBorder
bg={e?.isRead ? "gray.1" : "gray.4"}
sx={{
borderColor: "gray",
borderStyle: "solid",
borderWidth: "0.5px",
":hover": {
borderColor: "gray",
borderStyle: "solid",
borderWidth: "1.5px",
},
}}
onClick={async () => {
e?.kategoriApp === "JOB" &&
findRouterJob({
data: e,
router: router,
onChangeNavbar2: (val: any) => {
onChangeNavbar(val);
},
onToggleNavbar2: onToggleNavbar,
});
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"}>
<Group position="apart">
<Text fw={"bold"} fz={"xs"}>
# {e?.kategoriApp}
</Text>
{e?.status ? <Badge w={70}>{e?.status}</Badge> : ""}
</Group>
</Card.Section>
<Card.Section p={"sm"}>
<Text lineClamp={2}>{e?.pesan}</Text>
</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>
</>
);
}
async function findRouterJob({
data,
router,
onChangeNavbar2,
onToggleNavbar2,
}: {
data: MODEL_NOTIFIKASI;
router: AppRouterInstance;
onChangeNavbar2: (val: any) => void;
onToggleNavbar2: (val: any) => void;
}) {
const routeName = "/dev/admin/job/child/";
router.push(routeName + _.lowerCase(data.status));
onChangeNavbar2({
id: 6,
childId: 63,
});
onToggleNavbar2(true);
}

View File

@@ -194,17 +194,17 @@ export const listAdminPage = [
{
id: 62,
name: "Table Publish",
path: RouterAdminJob.table_publish,
path: RouterAdminJob.publish,
},
{
id: 63,
name: "Table Review",
path: RouterAdminJob.table_review,
path: RouterAdminJob.review,
},
{
id: 64,
name: "Table Reject",
path: RouterAdminJob.table_reject,
path: RouterAdminJob.reject,
},
{
id: 65,

View File

@@ -0,0 +1,17 @@
"use server";
import prisma from "@/app/lib/prisma";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
export default async function adminNotifikasi_countNotifikasi() {
const userId = await user_getOneUserId();
const data = await prisma.notifikasi.findMany({
where: {
adminId: userId,
isRead: false,
},
});
return data.length;
}

View File

@@ -0,0 +1,19 @@
"use server";
import prisma from "@/app/lib/prisma";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
export default async function adminNotifikasi_getByUserId() {
const adminId = await user_getOneUserId();
const data = await prisma.notifikasi.findMany({
orderBy:{
createdAt: "desc"
},
where: {
adminId: adminId,
userRoleId: "2",
},
});
return data;
}

View File

@@ -0,0 +1,21 @@
"use server";
import prisma from "@/app/lib/prisma";
export default async function adminNotifikasi_funUpdateIsReadById({
notifId,
}: {
notifId: string;
}) {
const updt = await prisma.notifikasi.update({
where: {
id: notifId,
},
data: {
isRead: true,
},
});
if (!updt) return { status: 400 };
return { status: 200 };
}

View File

@@ -0,0 +1,5 @@
// test notif
import Notifikasi_MainView from "./main";
export { Notifikasi_MainView };

View File

@@ -0,0 +1,25 @@
"use client";
import AppComponentGlobal_LayoutTamplate from "@/app_modules/component_global/component_layout_tamplate";
import ComponentGlobal_HeaderTamplate from "@/app_modules/component_global/header_tamplate";
import { Text } from "@mantine/core";
export default function Notifikasi_MainView() {
return (
<>
<AppComponentGlobal_LayoutTamplate
header={<ComponentGlobal_HeaderTamplate title="Notifikasi" />}
>
<MainView />
</AppComponentGlobal_LayoutTamplate>
</>
);
}
function MainView() {
return (
<>
<Text>notif</Text>
</>
);
}

View File

@@ -12,7 +12,6 @@ export async function user_getOneUserId() {
const c = cookies().get("ssn");
if (!c?.value || c.value === "") return redirect(RouterAuth.login);
const token = JSON.parse(
await unsealData(c?.value as string, {
password: config.server.password,

View File

@@ -0,0 +1 @@
// index

View File

@@ -23,6 +23,7 @@ import {
IconAward,
IconQrcode,
IconUserCircle,
IconBell,
} from "@tabler/icons-react";
import { Logout } from "../auth";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
@@ -32,6 +33,7 @@ import { useRouter } from "next/navigation";
import { ComponentGlobal_NotifikasiPeringatan } from "../component_global/notif_global/notifikasi_peringatan";
import { ComponentGlobal_NotifikasiBerhasil } from "../component_global/notif_global/notifikasi_berhasil";
import { RouterUserSearch } from "@/app/lib/router_hipmi/router_user_search";
import { RouterNotifikasi } from "@/app/lib/router_hipmi/router_notifikasi";
export default function HomeLayout({
dataUser,
@@ -157,11 +159,22 @@ export default function HomeLayout({
top={0}
h={50}
>
<Center h={"100%"}>
<Title order={4} c={"white"}>
HIPMI
</Title>
</Center>
<Group position="apart" h={"100%"} px={"md"}>
<ActionIcon variant="transparent" disabled></ActionIcon>
<Center>
<Title order={4} c={"white"}>
HIPMI
</Title>
</Center>
<ActionIcon
variant="transparent"
onClick={() => {
router.push(RouterNotifikasi.main);
}}
>
<IconBell />
</ActionIcon>
</Group>
</Box>
{/* Children */}

View File

@@ -1,13 +1,9 @@
"use client";
import { RouterJob } from "@/app/lib/router_hipmi/router_job";
import {
AspectRatio,
Box,
Button,
Center,
FileButton,
Flex,
Group,
Image,
Loader,
@@ -15,18 +11,15 @@ import {
Stack,
Text,
TextInput,
Textarea,
} from "@mantine/core";
import { IconCamera, IconUpload } from "@tabler/icons-react";
import { useAtom } from "jotai";
import _ from "lodash";
import { useRouter } from "next/navigation";
import React, { useState } from "react";
import { useState } from "react";
import { gs_job_hot_menu, gs_job_status } from "../global_state";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/component_global/notif_global/notifikasi_berhasil";
import "react-quill/dist/quill.snow.css";
import dynamic from "next/dynamic";
import "react-quill/dist/quill.snow.css";
const ReactQuill = dynamic(
() => {
return import("react-quill");
@@ -34,16 +27,20 @@ const ReactQuill = dynamic(
{ ssr: false }
);
import { useShallowEffect, useToggle } from "@mantine/hooks";
import { Job_funCreate } from "../fun/create/fun_create";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/component_global/notif_global/notifikasi_peringatan";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
import { MODEL_JOB } from "../model/interface";
import toast from "react-simple-toasts";
import ComponentJob_NotedBox from "../component/detail/noted_box";
import ComponentGlobal_V2_LoadingPage from "@/app_modules/component_global/loading_page_v2";
import { defaultDeskripsi, defaultSyarat } from "../component/default_value";
import ComponentGlobal_InputCountDown from "@/app_modules/component_global/input_countdown";
import ComponentGlobal_V2_LoadingPage from "@/app_modules/component_global/loading_page_v2";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/component_global/notif_global/notifikasi_peringatan";
import mqtt_client from "@/util/mqtt_client";
import { useShallowEffect } from "@mantine/hooks";
import { defaultDeskripsi, defaultSyarat } from "../component/default_value";
import ComponentJob_NotedBox from "../component/detail/noted_box";
import { MODEL_JOB } from "../model/interface";
import { Job_funCreate } from "../fun/create/fun_create";
import notifikasi_funCreate from "@/app_modules/notifikasi/fun/create/create_notif";
import { RouterJob } from "@/app/lib/router_hipmi/router_job";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/component_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
import { MODEL_NOTIFIKASI } from "@/app_modules/notifikasi/model/interface";
export default function Job_Create() {
const [value, setValue] = useState({
@@ -225,25 +222,40 @@ function ButtonAction({ value, file }: { value: MODEL_JOB; file: FormData }) {
const [hotMenu, setHotMenu] = useAtom(gs_job_hot_menu);
const [status, setStatus] = useAtom(gs_job_status);
const [preview, setPreview] = useToggle();
async function onAction() {
async function onCreate() {
const gambar = new FormData();
gambar.append("file", file as any);
// console.log(value);
const create = await Job_funCreate(value as any, gambar);
if (create.status === 201) {
const dataNotif = {
appId: create.data?.id as any,
kategoriApp: "JOB",
status: create.data?.MasterStatus?.name as any,
userId: create.data?.authorId as any,
pesan: create.data?.title as any,
title: "Job baru",
};
const notif = await notifikasi_funCreate({ data: dataNotif as any });
if (notif.status === 201) {
mqtt_client.publish(
"ADMIN",
JSON.stringify({
count: 1,
})
);
await Job_funCreate(value as any, gambar).then((res) => {
if (res.status === 201) {
setHotMenu(2);
setStatus("Review");
router.replace(RouterJob.status);
setIsLoading(true);
ComponentGlobal_NotifikasiBerhasil("Tambah Lowongan Berhasil");
} else {
ComponentGlobal_NotifikasiGagal(res.message);
ComponentGlobal_NotifikasiBerhasil(create.message);
}
});
} else {
ComponentGlobal_NotifikasiGagal(create.message);
}
}
return (
@@ -251,11 +263,6 @@ function ButtonAction({ value, file }: { value: MODEL_JOB; file: FormData }) {
<Stack>
<Group grow mt={"lg"} mb={70}>
<Button
style={{
transition: "0.5s",
}}
loaderPosition="center"
loading={isLoading ? true : false}
disabled={
value.title === "" ||
value.content === "" ||
@@ -267,10 +274,15 @@ function ButtonAction({ value, file }: { value: MODEL_JOB; file: FormData }) {
? true
: false
}
style={{
transition: "0.5s",
}}
loaderPosition="center"
loading={isLoading ? true : false}
w={"100%"}
radius={"xl"}
onClick={() => {
onAction();
onCreate();
}}
>
Simpan

View File

@@ -55,11 +55,22 @@ export async function Job_funCreate(req: MODEL_JOB, file: FormData) {
deskripsi: req.deskripsi,
authorId: authorId,
},
select: {
id: true,
authorId: true,
MasterStatus: {
select: {
name: true,
},
},
title: true,
},
});
if (!create) return { status: 400, message: "Gagal Disimpan" };
revalidatePath("/dev/job/main/status");
return {
data: create,
status: 201,
message: "Berhasil Disimpan",
};

View File

@@ -0,0 +1,35 @@
"use server";
import prisma from "@/app/lib/prisma";
import { MODEL_NOTIFIKASI } from "../../model/interface";
export default async function notifikasi_funCreate({
data,
}: {
data: MODEL_NOTIFIKASI;
}) {
const getAdmin = await prisma.user.findMany({
where: {
active: true,
masterUserRoleId: "2",
},
});
for (let a of getAdmin) {
const create = await prisma.notifikasi.create({
data: {
adminId: a.id,
userId: data.userId,
appId: data.appId,
status: data.status,
title: data.title,
pesan: data.pesan,
kategoriApp: data.kategoriApp,
userRoleId: "2",
},
});
if (!create) return { status: 400, message: "Gagal mengirim notifikasi" };
}
return { status: 201, message: "Berhasil mengirim notifikasi" };
}

View File

@@ -0,0 +1,9 @@
"use server"
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token"
export default async function notifikasi_getByUserId() {
const userId = await user_getOneUserId()
}

View File

@@ -0,0 +1 @@
// test notif

View File

@@ -0,0 +1,20 @@
import { MODEL_USER } from "@/app_modules/home/model/interface";
import { MODEL_NEW_DEFAULT_MASTER } from "@/app_modules/model_global/interface";
export interface MODEL_NOTIFIKASI {
id: string;
isActive: boolean;
createdAt: Date;
updatedAt: Date;
appId: string;
kategoriApp: string;
isRead: boolean;
title: string,
pesan: string;
User: MODEL_USER;
userId: string;
Admin: MODEL_USER;
adminId: string;
status?: string;
Role: MODEL_NEW_DEFAULT_MASTER;
userRoleId: String;
}

View File

@@ -2,11 +2,21 @@
{
"name": "banuna",
"nomor": "6282340374412",
"masterUserRoleId": "3"
"masterUserRoleId": "2"
},
{
"name": "firman",
"nomor": "6281339158911",
"masterUserRoleId": "2"
},
{
"name": "amalia",
"nomor": "628980185458",
"masterUserRoleId": "1"
},
{
"name": "lukman",
"nomor": "6287701790942",
"masterUserRoleId": "1"
}
]

View File

@@ -10,51 +10,17 @@ import { Button, Stack } from "@mantine/core";
export default function MqttLoader() {
useEffect(() => {
mqtt_client.on("connect", () => {
try {
console.log("connected");
} catch (error) {
console.log(error)
};
mqtt_client.subscribe("pesan");
mqtt_client.subscribe("pesan2");
// fetch("").then((res) => {
// mqtt_client.subscribe("pesan");
// });
});
mqtt_client.on("message", (topic: any, message: any) => {
// console.log(itu)
// evnPesan.emit("pesan", itu);
const data = JSON.parse(message.toString());
if (data) {
if (data.id === "1") {
console.log("ini untuk id satu", data.data);
}
}
console.log("connected");
});
}, []);
const onClick = async () => {
mqtt_client.publish("pesan2", "apa pesannya 2");
};
return null;
const onClick2 = () => {
mqtt_client.publish(
"pesan",
JSON.stringify({
id: "2",
title: "donasi",
data: "databta",
})
);
};
return null
// (
// <Stack>
// <Button onClick={onClick}>Tekan</Button>
// <Button onClick={onClick2}>Tekan 2</Button>
// </Stack>
// <>
// <Stack>
// <Button onClick={onClick}>Tekan</Button>
// <Button onClick={onClick2}>Tekan 2</Button>
// </Stack>
// </>
// );
}