f558073ef8
- DB: messenger_rooms/participants/messages/reactions/files 테이블 생성 - Backend: REST API 9개 엔드포인트 + Socket.IO 실시간 핸들러 - Frontend: Gmail 스타일 FAB + 모달, 채팅방 목록, 채팅 패널 - 기능: DM/그룹/채널, 파일 첨부, 이모지 리액션, 멘션, 스레드 - 알림: 토스트 on/off 토글, FAB 읽지 않은 배지 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> [RAPID-fix] 메신저 API snake_case→camelCase 변환 및 Socket.IO URL 수정 - useRooms/useMessages/useCompanyUsers 훅에서 DB 응답 camelCase 변환 - Socket.IO 기본 연결 URL 3001 → 8080 수정 - runMigration.ts 마이그레이션 파일 경로 수정 (../../ → ../../../) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> [RAPID-fix] 방 생성 API camelCase/snake_case 호환 처리 - createRoom 컨트롤러에서 participantIds/type/name (camelCase) fallback 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> [RAPID-fix] 메시지 전송 API 추가 (sendMessage 라우트/컨트롤러 누락) - POST /api/messenger/rooms/:roomId/messages 라우트 등록 - MessengerController.sendMessage 메서드 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
77 lines
2.0 KiB
TypeScript
77 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import React, { createContext, useContext, useState, useCallback, useEffect } from "react";
|
|
|
|
interface MessengerContextValue {
|
|
isOpen: boolean;
|
|
selectedRoomId: string | null;
|
|
unreadCount: number;
|
|
notificationEnabled: boolean;
|
|
openMessenger: (roomId?: string) => void;
|
|
closeMessenger: () => void;
|
|
selectRoom: (roomId: string) => void;
|
|
setUnreadCount: (count: number) => void;
|
|
toggleNotification: () => void;
|
|
}
|
|
|
|
const MessengerContext = createContext<MessengerContextValue | undefined>(undefined);
|
|
|
|
export function MessengerProvider({ children }: { children: React.ReactNode }) {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [selectedRoomId, setSelectedRoomId] = useState<string | null>(null);
|
|
const [unreadCount, setUnreadCount] = useState(0);
|
|
const [notificationEnabled, setNotificationEnabled] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const stored = localStorage.getItem("messenger_notification");
|
|
if (stored !== null) {
|
|
setNotificationEnabled(stored === "true");
|
|
}
|
|
}, []);
|
|
|
|
const openMessenger = useCallback((roomId?: string) => {
|
|
setIsOpen(true);
|
|
if (roomId) setSelectedRoomId(roomId);
|
|
}, []);
|
|
|
|
const closeMessenger = useCallback(() => {
|
|
setIsOpen(false);
|
|
}, []);
|
|
|
|
const selectRoom = useCallback((roomId: string) => {
|
|
setSelectedRoomId(roomId);
|
|
}, []);
|
|
|
|
const toggleNotification = useCallback(() => {
|
|
setNotificationEnabled((prev) => {
|
|
const next = !prev;
|
|
localStorage.setItem("messenger_notification", String(next));
|
|
return next;
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<MessengerContext.Provider
|
|
value={{
|
|
isOpen,
|
|
selectedRoomId,
|
|
unreadCount,
|
|
notificationEnabled,
|
|
openMessenger,
|
|
closeMessenger,
|
|
selectRoom,
|
|
setUnreadCount,
|
|
toggleNotification,
|
|
}}
|
|
>
|
|
{children}
|
|
</MessengerContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useMessengerContext() {
|
|
const ctx = useContext(MessengerContext);
|
|
if (!ctx) throw new Error("useMessengerContext must be used within MessengerProvider");
|
|
return ctx;
|
|
}
|