diff --git a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx index b217531dd..65fd0030a 100644 --- a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx +++ b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx @@ -134,7 +134,7 @@ function DashboardPage() { {/* 전체 게시물 카드 */}
-
+

전체 게시물

{data?.pstTotCnt ? data.pstTotCnt.toLocaleString() : "-"} @@ -157,7 +157,7 @@ function DashboardPage() { {/* 오늘 접속자 수 카드 */}
-
+

오늘 접속자 수

{data?.accessTodayCnt @@ -184,7 +184,7 @@ function DashboardPage() { {/* API 호출 건수 카드 */}
-
+

API 호출 건수

{data?.apiTodayCnt ? data.apiTodayCnt.toLocaleString() : "-"} @@ -206,13 +206,13 @@ function DashboardPage() {
{/* 승인 대기 알림 */}
-
+

승인 대기 알림

{/* 사용자 승인 */} -
+
-
+
신규 가입 승인 대기
{/* 매뉴 승인 */} -
+
{(3).toLocaleString()}건
-
+
매뉴 수정 승인 대기
{/* 컨텐츠 승인 */} -
+
-
+
컨텐츠 수정 승인 대기
@@ -318,11 +318,11 @@ function DashboardPage() {
{/* 실시간 알림 */}
-
+

실시간 알림

-
+
신규 사용자 가입 {(1).toLocaleString()}분 전 @@ -344,11 +344,11 @@ function DashboardPage() {
{/* 일정 알림 */}
-
+

일정 알림

-
+
{(3).toLocaleString()}월 정기 시스템 점검 @@ -377,7 +377,7 @@ function DashboardPage() {
{/* 접속자 통계 */}
-
+

접속자 통계

@@ -392,7 +392,7 @@ function DashboardPage() {
{/* 메뉴별 접속 통계 */}
-
+

메뉴별 접속 통계

@@ -412,14 +412,14 @@ function DashboardPage() {
{/* 공지사항 */}
-
+

공지사항

{noticePostTableComponent}
{/* 신규 게시글 */}
-
+

신규 게시글

{recentPostTableComponent} diff --git a/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx b/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx index 46f3d45f0..1f8de050d 100644 --- a/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx +++ b/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx @@ -10,12 +10,18 @@ import { Button, Switch, Input, + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, } from "@common/components"; import { RoleAuthorizationsApi, type RoleAuthorizationsData, type RoleAuthorizationsByRoleId, } from "@/entities/role-authorization"; +import { SiteSelect } from "@/entities/site"; import { ENDPOINT } from "@/shared/config"; import { useAlertStore, useMutationWrapper, useDataTable } from "@/shared/lib"; @@ -107,17 +113,27 @@ function MappingRoleDialog({ - + 모듈 목록
+ + - - - 프로필 설정 -
-

최종접속일

-

{userInfo?.lastLoginDate}

-
-
-

접속 IP

-

-
- 로그아웃 -
- + + +
    +
  • + +
  • +
  • + 로그아웃 +
  • +
+
+ ) ) : ( diff --git a/packages/common/components/src/ui/header/notice-popover.tsx b/packages/common/components/src/ui/header/notice-popover.tsx new file mode 100644 index 000000000..6ee35371b --- /dev/null +++ b/packages/common/components/src/ui/header/notice-popover.tsx @@ -0,0 +1,141 @@ +import { useEffect, useState } from "react"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { getConfig } from "@common/config"; +import { ENDPOINT } from "../../config"; +import { cn, getCookie } from "../../lib"; +import { + getNoticeUserList, + getUnreadNoticeCount, + readNotice, +} from "../../api/notice-user"; +import { Label } from "../label"; +import { Badge } from "../badge"; +import { Button } from "../button"; +import { Checkbox } from "../checkbox"; +import { Popover, PopoverContent, PopoverTrigger } from "../popover"; + +import dayjs from "dayjs"; +import relativeTime from "dayjs/plugin/relativeTime"; +import "dayjs/locale/ko"; + +dayjs.extend(relativeTime); +dayjs.locale("ko"); + +const appConfig = getConfig(); +const userId = getCookie(appConfig.AUTH_USER_ID ?? ""); + +export function NoticePopover() { + const queryClient = useQueryClient(); + + const [open, setOpen] = useState(false); + const [selectedNoticeIds, setSelectedNoticeIds] = useState([]); + + const { data: noticeUserList } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.NOTICE_USER], + queryFn: () => getNoticeUserList(userId!), + enabled: !!userId, + }); + + const { data: unreadNoticeCount } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.NOTICE], + queryFn: () => getUnreadNoticeCount(userId!), + enabled: !!userId, + }); + + const handleSelectNotice = (notiId: number) => { + setSelectedNoticeIds((prevIds) => { + if (prevIds.includes(notiId)) { + return prevIds.filter((id) => id !== notiId); + } else { + return [...prevIds, notiId]; + } + }); + }; + + const handleSelectAll = () => { + if (noticeUserList?.content) { + if (selectedNoticeIds.length === noticeUserList.content.length) { + setSelectedNoticeIds([]); + } else { + const allIds = noticeUserList.content.map((item) => item.notiId); + setSelectedNoticeIds(allIds); + } + } + }; + + const handleReadNotice = async () => { + if (selectedNoticeIds.length === 0) return; + try { + await Promise.all(selectedNoticeIds.map((notiId) => readNotice(notiId))); + await queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.NOTICE_USER], + }); + await queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.NOTICE], + }); + setSelectedNoticeIds([]); + } catch (error) { + console.error("알림 읽음 처리 중 오류 발생:", error); + } + }; + + const isAllSelected = noticeUserList?.content + ? selectedNoticeIds.length === noticeUserList.content.length && + noticeUserList.content.length > 0 + : false; + + useEffect(() => { + if (open) setSelectedNoticeIds([]); + }, [open]); + + return ( + + +
+ 알림 {unreadNoticeCount ?? 0} +
+
+ +
+ + +
+
    + {noticeUserList?.content?.map((item) => ( +
  • + handleSelectNotice(item.notiId)} + /> +
    + {item.notiType} +

    {item.notiTtl}

    + + {dayjs(item.regDt).fromNow()} + +
    +
  • + ))} +
+
setOpen(false)} + > + +
+
+
+ ); +}