feat: 拦截浏览器返回键,退出房间前弹窗确认
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { useEffect, useState, useCallback, useRef } from "react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import TopNav from "@/components/TopNav";
|
||||
import SwipeDeck from "@/components/SwipeDeck";
|
||||
import LeaveConfirmModal from "@/components/LeaveConfirmModal";
|
||||
import { useRoomPolling } from "@/hooks/useRoomPolling";
|
||||
import { getUserId } from "@/lib/userId";
|
||||
|
||||
@@ -15,6 +16,8 @@ export default function RoomPage() {
|
||||
const [userId, setUserId] = useState("");
|
||||
const [joined, setJoined] = useState(false);
|
||||
const [joinFailed, setJoinFailed] = useState(false);
|
||||
const [showLeaveConfirm, setShowLeaveConfirm] = useState(false);
|
||||
const leavingRef = useRef(false);
|
||||
|
||||
const {
|
||||
userCount, match, matchType, matchLikes, runnerUps, likeCounts, swipeCounts, restaurants, notFound, mutate,
|
||||
@@ -34,6 +37,42 @@ export default function RoomPage() {
|
||||
}).catch(() => setJoinFailed(true));
|
||||
}, [roomId]);
|
||||
|
||||
useEffect(() => {
|
||||
window.history.pushState({ roomGuard: true }, "");
|
||||
|
||||
const handlePopState = () => {
|
||||
if (leavingRef.current) return;
|
||||
window.history.pushState({ roomGuard: true }, "");
|
||||
setShowLeaveConfirm(true);
|
||||
};
|
||||
|
||||
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
||||
if (leavingRef.current) return;
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
window.addEventListener("popstate", handlePopState);
|
||||
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||
return () => {
|
||||
window.removeEventListener("popstate", handlePopState);
|
||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const confirmLeave = useCallback(() => {
|
||||
leavingRef.current = true;
|
||||
setShowLeaveConfirm(false);
|
||||
router.push("/");
|
||||
}, [router]);
|
||||
|
||||
const cancelLeave = useCallback(() => {
|
||||
setShowLeaveConfirm(false);
|
||||
}, []);
|
||||
|
||||
const handleExitRequest = useCallback(() => {
|
||||
setShowLeaveConfirm(true);
|
||||
}, []);
|
||||
|
||||
const handleReset = useCallback(async () => {
|
||||
await fetch(`/api/room/${roomId}/reset`, { method: "POST" });
|
||||
await mutate();
|
||||
@@ -78,7 +117,7 @@ export default function RoomPage() {
|
||||
|
||||
return (
|
||||
<div className="flex h-dvh flex-col bg-background">
|
||||
<TopNav roomId={roomId} userCount={userCount} />
|
||||
<TopNav roomId={roomId} userCount={userCount} onExit={handleExitRequest} />
|
||||
<SwipeDeck
|
||||
restaurants={restaurants}
|
||||
roomId={roomId}
|
||||
@@ -94,6 +133,11 @@ export default function RoomPage() {
|
||||
onReset={handleReset}
|
||||
onNarrow={handleNarrow}
|
||||
/>
|
||||
<LeaveConfirmModal
|
||||
open={showLeaveConfirm}
|
||||
onConfirm={confirmLeave}
|
||||
onCancel={cancelLeave}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user