치지직 앱으로 연동하고, 연동 확인된 ID만 접속할 수 있도록 수정, 개발용으로는 채널ID를 수동으로 접속할 수 있도록 변경.

최초 추천 고정 배치 추가.
This commit is contained in:
kimyu
2026-09-18 04:09:31 +09:00
parent 6f72824598
commit 73520f9f06
26 changed files with 1272 additions and 162 deletions

View File

@@ -48,28 +48,38 @@ export function useRoom(roomId: string | null) {
? crypto.randomUUID()
: `c-${Date.now()}-${Math.random().toString(16).slice(2)}`;
let es: EventSource | null = null;
let cancelled = false;
void fetch(`/api/rooms/${roomId}`)
.then((r) => r.json())
.then((j) => {
.then(async (r) => {
const j = await r.json();
if (cancelled) return;
if (!r.ok) {
setError(j.error || '방을 불러오지 못했습니다.');
return;
}
if (j.room) setRoom(j.room as PublicRoomState);
else setError(j.error || '방을 불러오지 못했습니다.');
})
.catch(() => setError('방을 불러오지 못했습니다.'));
const es = new EventSource(
`/api/rooms/${roomId}/events?clientId=${encodeURIComponent(clientId)}`,
);
es.addEventListener('room', (ev) => {
try {
setRoom(JSON.parse((ev as MessageEvent).data) as PublicRoomState);
setError(null);
} catch {
// ignore
}
});
es.onerror = () => {
// keep last state; browser will retry SSE
};
es = new EventSource(
`/api/rooms/${roomId}/events?clientId=${encodeURIComponent(clientId)}`,
);
es.addEventListener('room', (ev) => {
try {
setRoom(JSON.parse((ev as MessageEvent).data) as PublicRoomState);
setError(null);
} catch {
// ignore
}
});
es.onerror = () => {
// keep last state; browser will retry SSE
};
})
.catch(() => {
if (!cancelled) setError('방을 불러오지 못했습니다.');
});
const leave = () => {
try {
@@ -94,8 +104,9 @@ export function useRoom(roomId: string | null) {
window.addEventListener('pagehide', leave);
return () => {
cancelled = true;
window.removeEventListener('pagehide', leave);
es.close();
es?.close();
leave();
};
}, [roomId]);
@@ -136,5 +147,26 @@ export function useRoom(roomId: string | null) {
[roomId],
);
return { room, error, consumeDice, simulateDonation };
const addDice = useCallback(
async (count = 1) => {
if (!roomId) return { ok: false as const, error: '방이 없습니다.' };
const res = await fetch(`/api/rooms/${roomId}/add-dice`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ count }),
});
const json = await res.json();
if (!res.ok) {
return {
ok: false as const,
error: (json.error as string) || '주사위를 추가할 수 없습니다.',
};
}
setRoom(json.room as PublicRoomState);
return { ok: true as const };
},
[roomId],
);
return { room, error, consumeDice, simulateDonation, addDice };
}