diff --git a/src/app/api/announcement/route.ts b/src/app/api/announcement/route.ts
index 3bf8a44..9c12699 100644
--- a/src/app/api/announcement/route.ts
+++ b/src/app/api/announcement/route.ts
@@ -117,6 +117,7 @@ export async function POST(request: Request) {
const { title, desc, groups } = (await request.json());
const villaId = user.idVillage
const userId = user.id
+ const userRoleLogin = user.idUserRole
const data = await prisma.announcement.create({
data: {
@@ -177,27 +178,43 @@ export async function POST(request: Request) {
desc: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.'
}))
+ if (userRoleLogin != "supadmin") {
+ const perbekel = await prisma.user.findFirst({
+ where: {
+ isActive: true,
+ idUserRole: "supadmin",
+ idVillage: user.idVillage
+ }
+ })
-
+ dataNotif.push({
+ idUserTo: perbekel?.id,
+ idUserFrom: userId,
+ category: 'announcement',
+ idContent: data.id,
+ title: 'Pengumuman Baru',
+ desc: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.'
+ })
+ }
const insertNotif = await prisma.notifications.createMany({
data: dataNotif
})
- for (let index = 0; index < dataNotif.length; index++) {
+ // for (let index = 0; index < dataNotif.length; index++) {
- const user = dataNotif[index].idUserTo
- const title = dataNotif[index].title
- const desc = dataNotif[index].desc
+ // const user = dataNotif[index].idUserTo
+ // const title = dataNotif[index].title
+ // const desc = dataNotif[index].desc
- mtqq_client.publish("app_SDM", JSON.stringify({
- "user": "clzm6swhg000tfgbhm3bau9ti",
- "title": title,
- "category": "announcement",
- "description": desc
- }))
- }
+ // mtqq_client.publish("app_SDM", JSON.stringify({
+ // "user": "clzm6swhg000tfgbhm3bau9ti",
+ // "title": title,
+ // "category": "announcement",
+ // "description": desc
+ // }))
+ // }
// create log user
diff --git a/src/app/api/home/notification/route.ts b/src/app/api/home/notification/route.ts
new file mode 100644
index 0000000..10e47bf
--- /dev/null
+++ b/src/app/api/home/notification/route.ts
@@ -0,0 +1,94 @@
+import { prisma } from "@/module/_global";
+import { funGetUserByCookies } from "@/module/auth";
+import { createLogUser } from "@/module/user";
+import _ from "lodash";
+import moment from "moment";
+import { NextResponse } from "next/server";
+
+// GET ALL NOTIFIKASI
+export async function GET(request: Request) {
+ try {
+ const user = await funGetUserByCookies();
+ if (user.id == undefined) {
+ return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
+ }
+
+ const { searchParams } = new URL(request.url);
+ const page = searchParams.get('page');
+ const dataSkip = Number(page) * 10 - 10;
+
+ const announcements = await prisma.notifications.findMany({
+ skip: dataSkip,
+ take: 10,
+ where: {
+ isActive: true,
+ idUserTo: user.id
+ },
+ orderBy: [
+ {
+ isRead: 'asc'
+ },
+ {
+ createdAt: 'desc'
+ }
+ ]
+
+ });
+
+ const allData = announcements.map((v: any) => ({
+ ..._.omit(v, ["createdAt"]),
+ createdAt: moment(v.createdAt).format("ll")
+ }))
+
+ return NextResponse.json({ success: true, message: "Berhasil mendapatkan notifikasi", data: allData, }, { status: 200 });
+ } catch (error) {
+ console.error(error);
+ return NextResponse.json({ success: false, message: "Gagal mendapatkan notifikasi, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
+ }
+}
+
+
+
+// UPDATE READ NOTIFIKASI
+export async function PUT(request: Request, context: { params: { id: string } }) {
+ try {
+ const user = await funGetUserByCookies()
+ if (user.id == undefined) {
+ return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
+ }
+ const { id } = await request.json();
+ const data = await prisma.notifications.count({
+ where: {
+ id: id,
+ },
+ });
+
+ if (data == 0) {
+ return NextResponse.json(
+ {
+ success: false,
+ message: "Gagal mendapatkan data, data tidak ditemukan",
+ },
+ { status: 404 }
+ );
+ }
+
+ const result = await prisma.notifications.update({
+ where: {
+ id: id,
+ },
+ data: {
+ isActive: false,
+ },
+ });
+
+ // create log user
+ const log = await createLogUser({ act: 'UPDATE', desc: 'User membaca notifikasi', table: 'notifications', data: id })
+
+ return NextResponse.json( { success: true, message: "Berhasil mendapatkan notifikasi", }, { status: 200 } );
+
+ } catch (error) {
+ console.error(error);
+ return NextResponse.json({ success: false, message: "Gagal mendapatkan notifikasi, coba lagi nanti", reason: (error as Error).message, }, { status: 500 });
+ }
+}
\ No newline at end of file
diff --git a/src/app/api/home/route.ts b/src/app/api/home/route.ts
index 918c174..2bdc630 100644
--- a/src/app/api/home/route.ts
+++ b/src/app/api/home/route.ts
@@ -358,6 +358,25 @@ export async function GET(request: Request) {
date: moment(v.dateStart).format("ll"),
user: v.User.name
}))
+ } else if (kategori == "header") {
+ const total = await prisma.notifications.count({
+ where: {
+ isActive: true,
+ isRead: false,
+ idUserTo: user.id
+ }
+ })
+
+ const desa = await prisma.village.findUnique({
+ where: {
+ id: idVillage
+ }
+ })
+
+ allData = {
+ totalNotif: total,
+ village: desa?.name
+ }
}
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: allData }, { status: 200 });
diff --git a/src/app/api/project/route.ts b/src/app/api/project/route.ts
index 0e81b2a..8cc83f9 100644
--- a/src/app/api/project/route.ts
+++ b/src/app/api/project/route.ts
@@ -137,7 +137,7 @@ export async function POST(request: Request) {
const { idGroup, title, task, member } = JSON.parse(dataBody as string)
const userId = user.id
-
+ const userRoleLogin = user.idUserRole
const data = await prisma.project.create({
data: {
@@ -198,6 +198,77 @@ export async function POST(request: Request) {
}
}
+ const memberNotif = await prisma.projectMember.findMany({
+ where: {
+ idProject: data.id
+ },
+ select: {
+ idUser: true
+ }
+ })
+
+ const dataNotif = memberNotif.map((v: any) => ({
+ ..._.omit(v, ["idUser"]),
+ idUserTo: v.idUser,
+ idUserFrom: userId,
+ category: 'project',
+ idContent: data.id,
+ title: 'Kegiatan Baru',
+ desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
+ }))
+
+ if (userRoleLogin != "supadmin") {
+ const perbekel = await prisma.user.findFirst({
+ where: {
+ isActive: true,
+ idUserRole: "supadmin",
+ idVillage: user.idVillage
+ }
+ })
+
+ dataNotif.push({
+ idUserTo: perbekel?.id,
+ idUserFrom: userId,
+ category: 'project',
+ idContent: data.id,
+ title: 'Kegiatan Baru',
+ desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
+ })
+ } else {
+ const atasanGroup = await prisma.user.findMany({
+ where: {
+ isActive: true,
+ idGroup: idGroup,
+ AND: {
+ OR: [
+ { idUserRole: 'cosupadmin' },
+ { idUserRole: 'admin' },
+ ]
+ }
+ },
+ select:{
+ id: true
+ }
+ })
+
+ const omitData = atasanGroup.map((v: any) => ({
+ ..._.omit(v, ["id"]),
+ idUserTo: v.id,
+ idUserFrom: userId,
+ category: 'project',
+ idContent: data.id,
+ title: 'Kegiatan Baru',
+ desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
+ }))
+
+ dataNotif.push(...omitData)
+
+ }
+
+ const insertNotif = await prisma.notifications.createMany({
+ data: dataNotif
+ })
+
// create log user
const log = await createLogUser({ act: 'CREATE', desc: 'User membuat data kegiatan', table: 'project', data: data.id })
diff --git a/src/module/home/lib/api_notification.ts b/src/module/home/lib/api_notification.ts
new file mode 100644
index 0000000..60e8000
--- /dev/null
+++ b/src/module/home/lib/api_notification.ts
@@ -0,0 +1,13 @@
+export const funGetAllNotification = async (path?: string) => {
+ const response = await fetch(`/api/home/notification${(path) ? path : ''}`, { next: { tags: ['notification'] } });
+ return await response.json().catch(() => null);
+}
+
+
+export const funReadNotification = async (data: { id: string }) => {
+ const response = await fetch(`/api/home/notification`, {
+ method: "PUT",
+ body: JSON.stringify(data),
+ });
+ return await response.json().catch(() => null);
+}
\ No newline at end of file
diff --git a/src/module/home/lib/api_search.ts b/src/module/home/lib/api_search.ts
index 406c010..5fbad0e 100644
--- a/src/module/home/lib/api_search.ts
+++ b/src/module/home/lib/api_search.ts
@@ -1,5 +1,3 @@
-
-
export const funGetSearchAll = async (path?: string) => {
const response = await fetch(`/api/home/search${(path) ? path : ''}`, { next: { tags: ['search'] } });
return await response.json().catch(() => null);
diff --git a/src/module/home/lib/type_notification.ts b/src/module/home/lib/type_notification.ts
new file mode 100644
index 0000000..73fefa7
--- /dev/null
+++ b/src/module/home/lib/type_notification.ts
@@ -0,0 +1,9 @@
+export interface IListNotification {
+ id: string
+ title: string
+ desc: string
+ category: string
+ idContent: string
+ isRead: boolean
+ createdAt: string
+}
\ No newline at end of file
diff --git a/src/module/home/ui/header_home.tsx b/src/module/home/ui/header_home.tsx
new file mode 100644
index 0000000..d0fadaa
--- /dev/null
+++ b/src/module/home/ui/header_home.tsx
@@ -0,0 +1,70 @@
+'use client'
+import { LayoutNavbarHome, TEMA } from "@/module/_global";
+import { useHookstate } from "@hookstate/core";
+import { ActionIcon, Box, Group, Indicator, Text } from "@mantine/core";
+import { useRouter } from "next/navigation";
+import { useState } from "react";
+import toast from "react-hot-toast";
+import { HiMagnifyingGlass, HiOutlineBell, HiOutlineUser } from "react-icons/hi2";
+import { funGetHome } from "../lib/api_home";
+import { useShallowEffect } from "@mantine/hooks";
+
+export default function HeaderHome() {
+ const router = useRouter()
+ const tema = useHookstate(TEMA)
+ const [isDesa, setDesa] = useState("")
+ const [isNotif, setNotif] = useState(0)
+
+
+ const fetchData = async () => {
+ try {
+ const response = await funGetHome('?cat=header')
+ if (response.success) {
+ setDesa(response.data.village)
+ setNotif(response.data.totalNotif)
+ } else {
+ toast.error(response.message);
+ }
+ } catch (error) {
+ toast.error("Gagal mendapatkan data, coba lagi nanti");
+ console.error(error);
+ }
+ };
+
+
+ useShallowEffect(() => {
+ fetchData();
+ }, []);
+
+
+ return (
+
+
+ {isDesa}
+
+
+ router.push('/home?cat=search')} variant="light" bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
+
+
+ {
+ isNotif > 0 ?
+
+ router.push('/home?cat=notification')} variant="light" bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
+
+
+
+ :
+ router.push('/home?cat=notification')} variant="light" bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
+
+
+ }
+
+ router.push('/profile')} variant="light" bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/module/home/ui/icon_navbar.tsx b/src/module/home/ui/icon_navbar.tsx
deleted file mode 100644
index c7399eb..0000000
--- a/src/module/home/ui/icon_navbar.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-"use client"
-import { TEMA, WARNA } from '@/module/_global';
-import { useHookstate } from '@hookstate/core';
-import { ActionIcon, Box, Group, Indicator, Text } from '@mantine/core';
-import { useRouter } from 'next/navigation';
-import React from 'react';
-import { HiMagnifyingGlass, HiOutlineBell, HiOutlineUser } from 'react-icons/hi2';
-
-export default function IconNavbar() {
- const router = useRouter()
- const tema = useHookstate(TEMA)
- return (
-
-
- router.push('/home?cat=search')} variant="light" bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
-
-
-
- router.push('/home?cat=notification')} variant="light" bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
-
-
-
- router.push('/profile')} variant="light" bg={tema.get().bgIcon} size="lg" radius="lg" aria-label="Settings">
-
-
-
-
- );
-}
-
diff --git a/src/module/home/ui/list_notification.tsx b/src/module/home/ui/list_notification.tsx
index da3b346..be7bfe5 100644
--- a/src/module/home/ui/list_notification.tsx
+++ b/src/module/home/ui/list_notification.tsx
@@ -1,11 +1,14 @@
"use client"
-import { TEMA, WARNA } from '@/module/_global';
+import { currentScroll, TEMA, WARNA } from '@/module/_global';
import { useHookstate } from '@hookstate/core';
-import { ActionIcon, Box, Center, Grid, Group, Spoiler, Text } from '@mantine/core';
-import { useMediaQuery } from '@mantine/hooks';
+import { ActionIcon, Box, Center, Flex, Grid, Group, Spoiler, Text } from '@mantine/core';
+import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
import { useRouter } from 'next/navigation';
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { FaBell } from 'react-icons/fa6';
+import { IListNotification } from '../lib/type_notification';
+import { funGetAllNotification, funReadNotification } from '../lib/api_notification';
+import toast from 'react-hot-toast';
const dataNotification = [
{
@@ -67,38 +70,125 @@ const dataNotification = [
export default function ListNotification() {
const router = useRouter()
- const isMobile = useMediaQuery('(max-width: 369px)');
+ const isMobile = useMediaQuery('(max-width: 369px)')
+ const [isData, setData] = useState([])
const tema = useHookstate(TEMA)
+ const { value: containerRef } = useHookstate(currentScroll)
+ const [isPage, setPage] = useState(1)
+ const [loading, setLoading] = useState(true)
+
+ async function fetchData(loading: boolean) {
+ try {
+ if (loading)
+ setLoading(true)
+ const res = await funGetAllNotification('?page=' + isPage)
+ if (res.success) {
+ if (isPage == 1) {
+ setData(res.data)
+ } else {
+ setData([...isData, ...res.data])
+ }
+
+ } else {
+ toast.error(res.message)
+ }
+ } catch (error) {
+ console.error(error)
+ toast.error("Gagal memuat data, coba lagi nanti")
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ useShallowEffect(() => {
+ fetchData(true)
+ }, [])
+
+ useShallowEffect(() => {
+ fetchData(false)
+ }, [isPage])
+
+ useEffect(() => {
+ const handleScroll = async () => {
+ if (containerRef && containerRef.current) {
+ const scrollTop = containerRef.current.scrollTop;
+ const containerHeight = containerRef.current.clientHeight;
+ const scrollHeight = containerRef.current.scrollHeight;
+
+ if (scrollTop + containerHeight >= scrollHeight) {
+ setPage(isPage + 1)
+ }
+
+ }
+ };
+
+ const container = containerRef?.current;
+ container?.addEventListener("scroll", handleScroll);
+ return () => {
+ container?.removeEventListener("scroll", handleScroll);
+ };
+ }, [containerRef, isPage]);
+
+
+
+ async function onReadNotif(category: string, idContent: string, idData: string) {
+ try {
+ const response = await funReadNotification({ id: idData })
+ if (response.success) {
+ router.push(`/${category}/${idContent}`)
+ } else {
+ toast.error(response.message)
+ }
+ } catch (error) {
+ console.error(error)
+ toast.error("Gagal memuat data, coba lagi nanti")
+ }
+ }
+
+
+
return (
- {dataNotification.map((v, i) => {
- return (
-
-
-
-
-
-
-
+ Tidak ada notifikasi
+
+ :
+ isData.map((v, i) => {
+ return (
+
+ {
+ onReadNotif(v.category, v.idContent, v.id)
+ }}
>
- {v.title}
+
+
+
+
+
+ {v.title}
+
+
+
+ {v.desc}
+
-
-
- {v.description}
-
-
-
- )
- })}
+
+ )
+ })
+ }
+ { }
);
}
diff --git a/src/module/home/ui/view_home.tsx b/src/module/home/ui/view_home.tsx
index a9f2f65..4ee8bd5 100644
--- a/src/module/home/ui/view_home.tsx
+++ b/src/module/home/ui/view_home.tsx
@@ -1,30 +1,23 @@
"use client"
-import { LayoutNavbarHome, NotificationCustome, ReloadButtonTop, TEMA, WARNA } from '@/module/_global';
-import { Box, Group, Notification, Stack, Text } from '@mantine/core';
-import React, { useState } from 'react';
+import { ReloadButtonTop } from '@/module/_global';
+import { Box, Stack } from '@mantine/core';
+import React from 'react';
import Carosole from './carosole';
import Features from './features';
-import IconNavbar from './icon_navbar';
import ListProjects from './list_project';
import ListDivisi from './list_divisi';
import ListDiscussion from './list_discussion';
import ListEventHome from './list_event';
import ChartProgressHome from './chart_progress_tugas';
import ChartDocumentHome from './chart_document';
-import { useHookstate } from '@hookstate/core';
+import HeaderHome from './header_home';
export default function ViewHome() {
- const tema = useHookstate(TEMA)
return (
<>
-
-
- Perbekel Darmasaba
-
-
-
+
{