Skip to content

Commit 52a08f1

Browse files
committed
483: created waiting duel page UI (mockup)
1 parent 02810a8 commit 52a08f1

1 file changed

Lines changed: 178 additions & 0 deletions

File tree

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import { Api } from "@/lib/api/types";
2+
import {
3+
Button,
4+
Card,
5+
Group,
6+
Stack,
7+
Text,
8+
Badge,
9+
CopyButton,
10+
Avatar,
11+
Box,
12+
Center,
13+
} from "@mantine/core";
14+
15+
interface DuelPlayer {
16+
id: string;
17+
leetcodeUsername: string;
18+
ready: boolean;
19+
}
20+
21+
interface DuelWaitingScreenProps {
22+
lobby: Api<"LobbyDto">;
23+
players?: DuelPlayer[];
24+
currentUserId: string;
25+
isHost: boolean;
26+
onLeave: () => void;
27+
onStart: () => void;
28+
}
29+
30+
export function WaitingDuelPage({
31+
lobby,
32+
players = [],
33+
currentUserId,
34+
isHost,
35+
onLeave,
36+
onStart,
37+
}: DuelWaitingScreenProps) {
38+
const player1 = players[0] ?? null;
39+
const player2 = players[1] ?? null;
40+
const bothPlayersPresent = !!player1 && !!player2;
41+
42+
return (
43+
<Box
44+
style={{
45+
minHeight: "85vh",
46+
display: "flex",
47+
justifyContent: "center",
48+
alignItems: "center",
49+
}}
50+
>
51+
<Stack maw={480} w="100%" gap="xl">
52+
<Card
53+
padding="1.5rem"
54+
radius="lg"
55+
style={{
56+
backgroundColor: "#1a1c23",
57+
borderColor: "#3f3f46",
58+
borderWidth: "2px",
59+
}}
60+
>
61+
<Center mb="lg">
62+
<CopyButton value={lobby.joinCode}>
63+
{({ copied, copy }) => (
64+
<Button
65+
size="md"
66+
variant="filled"
67+
onClick={copy}
68+
styles={{
69+
root: {
70+
backgroundColor: "#1a3a52",
71+
border: "1px solid #2a4a62",
72+
borderRadius: "12px",
73+
},
74+
}}
75+
>
76+
<Group>
77+
<Text fw={700} ff="monospace" c="white" size="lg">
78+
{lobby.joinCode}
79+
</Text>
80+
<Badge
81+
color={copied ? "teal" : "green"}
82+
variant="filled"
83+
size="md"
84+
>
85+
{copied ? "✓ Copied" : "Copy"}
86+
</Badge>
87+
</Group>
88+
</Button>
89+
)}
90+
</CopyButton>
91+
</Center>
92+
<Stack gap="lg">
93+
<PlayerCard player={player1} currentUserId={currentUserId} />
94+
<Center>
95+
<Text
96+
c="dimmed"
97+
fw={700}
98+
size="3.5rem"
99+
style={{ fontStyle: "italic" }}
100+
>
101+
VS
102+
</Text>
103+
</Center>
104+
<PlayerCard player={player2} currentUserId={currentUserId} />
105+
<Stack mt="md">
106+
<Group justify="center">
107+
<Button variant="light" color="red" size="md" onClick={onLeave}>
108+
Leave Party
109+
</Button>
110+
{isHost && (
111+
<Button
112+
size="md"
113+
color="green"
114+
onClick={onStart}
115+
disabled={!bothPlayersPresent}
116+
>
117+
Start Duel
118+
</Button>
119+
)}
120+
</Group>
121+
</Stack>
122+
</Stack>
123+
</Card>
124+
</Stack>
125+
</Box>
126+
);
127+
}
128+
129+
function PlayerCard({
130+
player,
131+
currentUserId,
132+
}: {
133+
player: DuelPlayer | null;
134+
currentUserId: string;
135+
}) {
136+
const isCurrentUser = player?.id === currentUserId;
137+
const displayName =
138+
player ?
139+
isCurrentUser ? `${player.leetcodeUsername} (You)`
140+
: player.leetcodeUsername
141+
: "Waiting for opponent...";
142+
143+
return (
144+
<Card
145+
radius="md"
146+
style={{
147+
backgroundColor: "#24262e",
148+
borderColor: "#3f3f46",
149+
borderWidth: "2px",
150+
}}
151+
>
152+
<Stack align="center" gap={6}>
153+
<Avatar
154+
radius="xl"
155+
size={48}
156+
color={player ? "gray" : "dark"}
157+
styles={{
158+
root: {
159+
border: "2px solid #3f3f46",
160+
backgroundColor: player ? "#374151" : "#1f2937",
161+
},
162+
}}
163+
>
164+
<Text size="lg" fw={700} c={player ? "white" : "dimmed"}>
165+
{player ? player.leetcodeUsername.charAt(0).toUpperCase() : "?"}
166+
</Text>
167+
</Avatar>
168+
<Text
169+
fw={600}
170+
c={player ? "white" : "dimmed"}
171+
style={!player ? { fontStyle: "italic" } : undefined}
172+
>
173+
{displayName}
174+
</Text>
175+
</Stack>
176+
</Card>
177+
);
178+
}

0 commit comments

Comments
 (0)