import { defineStore } from 'pinia' import { ref } from 'vue' import { Notify } from 'quasar' import { matchesApi, type MatchNotification, type ReceivedMatch } from '@/api/matches' import { createUserNotifications } from '@/lib/chatSocket' /** * 매칭 상태/알림 스토어. * - 로그인 시 connect(userId, myDogId): 실시간 알림 구독 + 받은/보낸 매칭 로드 * - received: 내 개가 받은 대기중 신청 (수락/거절 대상) * - sentPendingTargetIds: 내가 신청한 진행중 대상 dogId (버튼 "진행중" 표시) * - openChatMatchId: 수락된 매칭 → 1:1 채팅 열기 신호 */ export const useMatchingStore = defineStore('matching', () => { const received = ref([]) const sentPendingTargetIds = ref>(new Set()) const openChatMatchId = ref(null) let socket: ReturnType | null = null let myDogId: number | null = null async function refresh(dogId: number): Promise { myDogId = dogId try { const [rec, snt] = await Promise.all([matchesApi.received(dogId), matchesApi.sent(dogId)]) received.value = rec sentPendingTargetIds.value = new Set(snt.map((m) => m.targetDogId)) } catch { // 무시 (미로그인/네트워크) } } function connect(userId: number, dogId: number): void { disconnect() myDogId = dogId void refresh(dogId) socket = createUserNotifications(userId, onNotification) socket.activate() } function disconnect(): void { socket?.deactivate() socket = null received.value = [] sentPendingTargetIds.value = new Set() } function onNotification(n: MatchNotification): void { Notify.create({ message: n.message, caption: n.title, color: colorFor(n.type), icon: iconFor(n.type), position: 'top', timeout: 4000, }) if (n.type === 'ACCEPTED') { openChatMatchId.value = n.matchId // 신청자: 수락됨 → 채팅 열기 } if (myDogId != null) void refresh(myDogId) // 목록/진행중 동기화 } async function accept(id: number): Promise { await matchesApi.accept(id) received.value = received.value.filter((m) => m.id !== id) openChatMatchId.value = id // 수락자도 바로 채팅 열기 } async function reject(id: number): Promise { await matchesApi.reject(id) received.value = received.value.filter((m) => m.id !== id) } /** 매칭 신청 직후 낙관적으로 진행중 표시. */ function markSent(targetDogId: number): void { const next = new Set(sentPendingTargetIds.value) next.add(targetDogId) sentPendingTargetIds.value = next } function isPending(targetDogId: number): boolean { return sentPendingTargetIds.value.has(targetDogId) } return { received, sentPendingTargetIds, openChatMatchId, connect, disconnect, refresh, accept, reject, markSent, isPending, } }) function colorFor(type: MatchNotification['type']): string { switch (type) { case 'ACCEPTED': return 'positive' case 'REJECTED': case 'EXPIRED': return 'grey-8' default: return 'primary' } } function iconFor(type: MatchNotification['type']): string { switch (type) { case 'NEW_REQUEST': return 'favorite' case 'ACCEPTED': return 'celebration' case 'EXPIRED': return 'schedule' default: return 'heart_broken' } }