From b30a51e84afe71cb07e3c352db22c4fee9bf7eec Mon Sep 17 00:00:00 2001 From: kent Date: Tue, 13 Jan 2026 20:42:43 +0900 Subject: [PATCH] =?UTF-8?q?feat(SAM/WEB):=20=EA=B1=B0=EB=9E=98=EC=B2=98?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20?= =?UTF-8?q?=EC=8B=A0=EA=B7=9C=EC=97=85=EC=B2=B4=20FCM=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fcm.ts에 sendNewClientNotification 프리셋 함수 추가 - channel_id: push_urgent (신규업체 알림용) - type: new_client - 거래처관리 페이지에 "신규업체" 알림 버튼 추가 - Bell 아이콘과 함께 헤더 액션에 배치 - useTransition으로 로딩 상태 관리 --- .../client-management-sales-admin/page.tsx | 37 ++++++++++++++++--- src/lib/actions/fcm.ts | 15 ++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx b/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx index 37f04272..ece2b188 100644 --- a/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx +++ b/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx @@ -15,7 +15,7 @@ * - 페이지 기반 CRUD (등록/수정/상세 → 별도 페이지로 이동) */ -import { useState, useRef, useEffect, useCallback } from "react"; +import { useState, useRef, useEffect, useCallback, useTransition } from "react"; import { useRouter } from "next/navigation"; import { useClientList, Client } from "@/hooks/useClientList"; import { @@ -28,6 +28,7 @@ import { XCircle, Eye, Loader2, + Bell, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; @@ -53,9 +54,12 @@ import { AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; +import { sendNewClientNotification } from "@/lib/actions/fcm"; +import { isNextRedirectError } from "@/lib/utils/redirect-error"; export default function CustomerAccountManagementPage() { const router = useRouter(); + const [isPending, startTransition] = useTransition(); // API 훅 사용 const { @@ -336,6 +340,23 @@ export default function CustomerAccountManagementPage() { } }; + // FCM 알림 발송 핸들러 + const handleSendNotification = useCallback(async () => { + startTransition(async () => { + try { + const result = await sendNewClientNotification(); + if (result.success) { + toast.success(`신규업체 알림을 발송했습니다. (${result.sentCount || 0}건)`); + } else { + toast.error(result.error || "알림 발송에 실패했습니다."); + } + } catch (error) { + if (isNextRedirectError(error)) throw error; + toast.error("알림 발송 중 오류가 발생했습니다."); + } + }); + }, []); + // 상태 뱃지 const getStatusBadge = (status: "활성" | "비활성") => { if (status === "활성") { @@ -578,10 +599,16 @@ export default function CustomerAccountManagementPage() { description="거래처 정보 및 계정을 관리합니다" icon={Building2} headerActions={ - +
+ + +
} stats={stats} searchValue={searchTerm} diff --git a/src/lib/actions/fcm.ts b/src/lib/actions/fcm.ts index b81ec33c..3f41ceea 100644 --- a/src/lib/actions/fcm.ts +++ b/src/lib/actions/fcm.ts @@ -145,4 +145,19 @@ export async function sendNoticeNotification( channel_id: 'notice', ...customParams, }); +} + +/** + * 신규업체 알림 발송 (프리셋) + */ +export async function sendNewClientNotification( + customParams?: Partial +): Promise { + return sendFcmNotification({ + title: '신규업체 알림', + body: '새로운 업체가 등록되었습니다.', + type: 'new_client', + channel_id: 'push_urgent', + ...customParams, + }); } \ No newline at end of file