2025-11-10 00:04:17 +09:00
|
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
|
|
import React, { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
|
|
|
|
import { SendMessageForm } from "@/app/components/SendMessageForm";
|
|
|
|
|
|
|
|
|
|
|
|
type MessageTarget = { receiverId: string; receiverNickname?: string | null } | null;
|
|
|
|
|
|
type Ctx = { openMessageModal: (target: { receiverId: string; receiverNickname?: string | null }) => void };
|
|
|
|
|
|
|
|
|
|
|
|
const MessageModalCtx = createContext<Ctx>({ openMessageModal: () => {} });
|
|
|
|
|
|
|
|
|
|
|
|
export function useMessageModal() {
|
|
|
|
|
|
return useContext(MessageModalCtx);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function MessageModalProvider({ children }: { children: React.ReactNode }) {
|
|
|
|
|
|
const [target, setTarget] = useState<MessageTarget>(null);
|
|
|
|
|
|
const dialogRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
|
|
const openMessageModal = (t: { receiverId: string; receiverNickname?: string | null }) => {
|
|
|
|
|
|
setTarget({ receiverId: t.receiverId, receiverNickname: t.receiverNickname ?? null });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const close = () => setTarget(null);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
function onKey(e: KeyboardEvent) {
|
|
|
|
|
|
if (e.key === "Escape") close();
|
|
|
|
|
|
}
|
|
|
|
|
|
document.addEventListener("keydown", onKey);
|
|
|
|
|
|
return () => document.removeEventListener("keydown", onKey);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<MessageModalCtx.Provider value={{ openMessageModal }}>
|
|
|
|
|
|
{children}
|
|
|
|
|
|
{target && (
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="fixed inset-0 z-[1000] flex items-center justify-center"
|
|
|
|
|
|
role="dialog"
|
|
|
|
|
|
aria-modal="true"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="absolute inset-0 bg-black/40"
|
|
|
|
|
|
onClick={close}
|
|
|
|
|
|
aria-hidden
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div
|
|
|
|
|
|
ref={dialogRef}
|
|
|
|
|
|
className="relative z-[1001] w-[92%] max-w-[520px] rounded-lg bg-white shadow-xl border border-neutral-200"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="px-5 py-3 border-b border-neutral-200 flex items-center justify-between">
|
|
|
|
|
|
<h3 className="text-base font-semibold text-neutral-900">쪽지 보내기</h3>
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={close}
|
|
|
|
|
|
className="h-8 w-8 inline-flex items-center justify-center rounded-md hover:bg-neutral-100 cursor-pointer"
|
|
|
|
|
|
aria-label="닫기"
|
|
|
|
|
|
>
|
|
|
|
|
|
×
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="p-5">
|
2025-11-10 01:39:44 +09:00
|
|
|
|
<SendMessageForm receiverId={target.receiverId} receiverNickname={target.receiverNickname} onSent={close} />
|
2025-11-10 00:04:17 +09:00
|
|
|
|
</div>
|
|
|
|
|
|
<div className="px-5 pb-4 flex items-center justify-end">
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={close}
|
|
|
|
|
|
className="h-9 px-4 rounded-md border border-neutral-300 bg-white text-sm hover:bg-neutral-100 cursor-pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
닫기
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</MessageModalCtx.Provider>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|