Skip to content

Commit 8158ba6

Browse files
committed
Re-enable event start gate and implement waiting countdown UI for participants
1 parent 120f8ce commit 8158ba6

File tree

2 files changed

+90
-10
lines changed

2 files changed

+90
-10
lines changed

Treasure_Hunt_Backend/src/controllers/teamController.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,16 @@ export const getCurrentQuestion = async (req, res) => {
182182
const { id: userId, username } = req.user;
183183

184184
// ── EVENT START GATE — DISABLED FOR TESTING ──
185-
// const EVENT_START = new Date('2026-03-06T05:30:00.000Z');
186-
// const now = new Date();
187-
// if (now < EVENT_START) {
188-
// return res.json({
189-
// success: true,
190-
// not_started: true,
191-
// event_start: EVENT_START.toISOString(),
192-
// message: 'The treasure hunt has not started yet!'
193-
// });
194-
// }
185+
const EVENT_START = new Date('2026-03-06T05:30:00.000Z');
186+
const now = new Date();
187+
if (now < EVENT_START) {
188+
return res.json({
189+
success: true,
190+
not_started: true,
191+
event_start: EVENT_START.toISOString(),
192+
message: 'The treasure hunt has not started yet!'
193+
});
194+
}
195195

196196
// 1. AUTO-ASSIGNMENT: If user has no questions, assign ALL questions in random order
197197
const checkAssignments = await pool.query(

Treasure_Hunt_Frontend/src/pages/participant/Participant.jsx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ const Participant = () => {
8686
const [isBonusMode, setIsBonusMode] = useState(false);
8787
const [completedBonus, setCompletedBonus] = useState(0);
8888

89+
const [eventNotStarted, setEventNotStarted] = useState(false);
90+
const [eventStartTime, setEventStartTime] = useState(null);
91+
const [timeLeft, setTimeLeft] = useState({ obj: null, str: '' });
92+
8993
useEffect(() => { fetchCurrentQuestion(false); }, []);
9094

9195
const fetchCurrentQuestion = async (isBonus = false) => {
@@ -105,6 +109,11 @@ const Participant = () => {
105109
});
106110
if (response.question_number) setQuestionNumber(prev => Math.max(prev, response.question_number));
107111
setCompletedBonus(response.completed_bonus || 0);
112+
setEventNotStarted(false);
113+
} else if (response.not_started) {
114+
setEventNotStarted(true);
115+
setEventStartTime(response.event_start);
116+
setCurrentQuestion(null);
108117
} else if (response.completed) {
109118
if (isBonus) {
110119
setError('No more bonus questions available on this path!');
@@ -126,6 +135,41 @@ const Participant = () => {
126135
}
127136
};
128137

138+
useEffect(() => {
139+
let timer;
140+
if (eventNotStarted && eventStartTime) {
141+
const targetDate = new Date(eventStartTime);
142+
const updateTimer = () => {
143+
const now = new Date();
144+
const diff = targetDate - now;
145+
if (diff <= 0) {
146+
clearInterval(timer);
147+
setEventNotStarted(false);
148+
fetchCurrentQuestion(false); // Fetch questions now that event started
149+
} else {
150+
const d = Math.floor(diff / (1000 * 60 * 60 * 24));
151+
const h = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
152+
const m = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
153+
const s = Math.floor((diff % (1000 * 60)) / 1000);
154+
155+
let parts = [];
156+
if (d > 0) parts.push(`${d}d`);
157+
if (d > 0 || h > 0) parts.push(`${h}h`);
158+
parts.push(`${m}m`);
159+
parts.push(`${s}s`);
160+
161+
setTimeLeft({
162+
obj: { d, h, m, s },
163+
str: parts.join(' ')
164+
});
165+
}
166+
};
167+
updateTimer();
168+
timer = setInterval(updateTimer, 1000);
169+
}
170+
return () => clearInterval(timer);
171+
}, [eventNotStarted, eventStartTime]);
172+
129173
// Compress image using canvas — returns a File under targetSize
130174
const compressImage = (file, maxWidth = 1200, quality = 0.7, targetSizeMB = 2) => {
131175
return new Promise((resolve) => {
@@ -277,6 +321,42 @@ const Participant = () => {
277321
/* ─── Completion state ──── */
278322
if (currentQuestion?.completed) return <CompletionScreen />;
279323

324+
/* ─── Event Not Started state ──── */
325+
if (eventNotStarted) {
326+
return (
327+
<div className="flex-col-center" style={{ flex: 1, position: 'relative', padding: '2rem' }}>
328+
<DottedPath />
329+
<motion.div
330+
initial={{ scale: 0.9, opacity: 0 }}
331+
animate={{ scale: 1, opacity: 1 }}
332+
className="adventure-card"
333+
style={{ textAlign: 'center', maxWidth: 400, border: '3px solid var(--color-green)' }}
334+
>
335+
<span style={{ fontSize: '3rem', display: 'block', marginBottom: '0.8rem', animation: 'spin 10s linear infinite' }}></span>
336+
<h2 style={{ fontSize: '1.6rem', color: 'var(--color-green)', marginBottom: '0.5rem', fontFamily: 'var(--font-heading)' }}>
337+
THE VOYAGE BEGINS SOON
338+
</h2>
339+
<p style={{ color: 'var(--color-brown)', fontWeight: 600, fontSize: '1rem', marginBottom: '1.5rem', fontFamily: 'var(--font-body)' }}>
340+
Hold tight, explorer. Your treasure map is still being charted.
341+
</p>
342+
343+
<div style={{
344+
background: 'var(--color-bg-primary)',
345+
padding: '1.2rem',
346+
borderRadius: '12px',
347+
border: '2px dashed var(--color-green-light)',
348+
display: 'inline-block'
349+
}}>
350+
<div style={{ fontSize: '0.8rem', color: 'var(--color-green)', letterSpacing: 2, marginBottom: '0.5rem', fontWeight: 800 }}>STARTS IN</div>
351+
<div style={{ fontSize: '2rem', fontFamily: 'var(--font-heading)', color: 'var(--color-red)', letterSpacing: '1px' }}>
352+
{timeLeft.str || "Loading..."}
353+
</div>
354+
</div>
355+
</motion.div>
356+
</div>
357+
);
358+
}
359+
280360
/* ─── No question found ──── */
281361
if (!currentQuestion) {
282362
return (

0 commit comments

Comments
 (0)