1- import React , { useEffect , useRef , useState } from "react" ;
1+ import React , { useEffect , useRef , useState } from "react" ;
22import $ from "jquery" ;
33import "./CountDown.css" ;
44import SparkleLayer from "../overlays/SparkleLayer.jsx" ;
@@ -11,9 +11,9 @@ if (typeof window !== "undefined") {
1111 window . $ = $ ;
1212}
1313
14- // Import FlipClock CSS and JS with correct paths (use the exported path from package.json)
14+ // Import FlipClock CSS and JS
1515import "flipclock/themes/flipclock" ;
16- import { flipClock , elapsedTime , theme , stopWhen } from "flipclock" ;
16+ import { flipClock , countdown , theme } from "flipclock" ;
1717
1818const CountDown = ( ) => {
1919 const messageRef = useRef ( null ) ;
@@ -26,7 +26,6 @@ const CountDown = () => {
2626
2727 // Check if FlipClock is available
2828 useEffect ( ( ) => {
29- // FlipClock is ready after import
3029 setIsFlipClockReady ( true ) ;
3130 } , [ ] ) ;
3231
@@ -42,7 +41,6 @@ const CountDown = () => {
4241 } ;
4342
4443 const setCounterData = async ( flag , startTime , endTime ) => {
45- // Try to get CSRF token from cookie (Django sets csrftoken cookie)
4644 const getCsrfTokenFromCookie = ( ) => {
4745 const name = "csrftoken" ;
4846 const cookies = document . cookie . split ( ";" ) ;
@@ -60,19 +58,13 @@ const CountDown = () => {
6058 document . querySelector ( "[name=csrfmiddlewaretoken]" ) ?. value ;
6159
6260 try {
63- const headers = {
64- "Content-Type" : "application/json" ,
65- } ;
66-
67- // Only add CSRF token if it exists
68- if ( csrftoken ) {
69- headers [ "X-CSRFToken" ] = csrftoken ;
70- }
61+ const headers = { "Content-Type" : "application/json" } ;
62+ if ( csrftoken ) headers [ "X-CSRFToken" ] = csrftoken ;
7163
7264 const response = await fetch ( `${ baseUrl } setcounter/` , {
7365 method : "POST" ,
7466 headers : headers ,
75- credentials : "include" , // Include cookies for CSRF
67+ credentials : "include" ,
7668 body : JSON . stringify ( { flag, startTime, endTime } ) ,
7769 } ) ;
7870
@@ -83,56 +75,43 @@ const CountDown = () => {
8375 return await response . json ( ) ;
8476 } catch ( error ) {
8577 console . error ( "Error setting countdown data:" , error ) ;
86- throw error ; // Re-throw to handle in handleStart
78+ throw error ;
8779 }
8880 } ;
8981
82+ // ✅ Fixed: Countdown version (28:00:00 → 00:00:00)
9083 const initializeFlipClock = ( startTime , endTime , shouldCount = true ) => {
91- if ( ! isFlipClockReady ) {
92- console . warn ( "FlipClock is not ready yet" ) ;
93- return ;
94- }
95-
96- if ( ! flipClockRef . current ) {
97- console . warn ( "FlipClock ref is not available" ) ;
98- return ;
99- }
84+ if ( ! isFlipClockReady ) return ;
85+ if ( ! flipClockRef . current ) return ;
10086
10187 try {
102- // Clean up existing clock if any
10388 if ( clock ) {
10489 clock . unmount ( ) ;
10590 setClock ( null ) ;
10691 }
10792
108- // Clear the container
10993 flipClockRef . current . innerHTML = "" ;
11094
111- let elapsedTimeFace ;
95+ const now = Date . now ( ) ;
96+ const remaining = Math . max ( 0 , endTime - now ) ;
11297
113- if ( shouldCount ) {
114- // Still counting - count from start to end time
115- elapsedTimeFace = elapsedTime ( {
116- from : new Date ( startTime ) ,
117- to : new Date ( endTime ) , // Count until end time
118- format : "hh:mm:ss" ,
119- } ) ;
120- } else {
121- // Static clock - show the exact duration between start and end
122- // This ensures it shows exactly 28:00:00 (or whatever the duration was) when stopped
123- elapsedTimeFace = elapsedTime ( {
124- from : new Date ( startTime ) ,
125- to : new Date ( endTime ) , // Use actual end time to show exact duration
126- format : "hh:mm:ss" ,
127- } ) ;
128- }
98+ const countdownFace = countdown ( {
99+ duration : remaining / 1000 , // in seconds
100+ format : "hh:mm:ss" ,
101+ whenEnded : ( ) => {
102+ if ( messageRef . current ) {
103+ messageRef . current . textContent =
104+ "GAME OVER: Hackathon Complete! You've Leveled Up!" ;
105+ messageRef . current . style . fontSize = "1.5rem" ;
106+ }
107+ } ,
108+ } ) ;
129109
130- // Create the FlipClock with the elapsed time face and theme
131110 const fc = flipClock ( {
132- face : elapsedTimeFace ,
111+ face : countdownFace ,
133112 theme : theme ( ) ,
134113 parent : flipClockRef . current ,
135- autoStart : shouldCount , // Only auto-start if we want counting
114+ autoStart : shouldCount ,
136115 } ) ;
137116
138117 setClock ( fc ) ;
@@ -148,7 +127,7 @@ const CountDown = () => {
148127 const currentTime = Date . now ( ) ;
149128 const endTime = currentTime + countdownDuration ;
150129 await setCounterData ( true , currentTime , endTime ) ;
151- initializeFlipClock ( currentTime , endTime , true ) ; // true = start counting
130+ initializeFlipClock ( currentTime , endTime , true ) ;
152131 if ( startButtonRef . current )
153132 startButtonRef . current . style . display = "none" ;
154133 } else {
@@ -169,53 +148,42 @@ const CountDown = () => {
169148
170149 useEffect ( ( ) => {
171150 if ( ! isFlipClockReady ) return ;
172-
173151 let intervalId ;
174152
175153 ( async ( ) => {
176154 const counterData = await fetchCounterData ( ) ;
177155 const currentTime = Date . now ( ) ;
178156
179157 if ( counterData && counterData . flag ) {
180- // Countdown has been started
181158 const remainingTime = counterData . endTime - currentTime ;
182159
183160 if ( remainingTime > 0 ) {
184- // Timer is still running - hide button and show elapsed time
185161 if ( startButtonRef . current )
186162 startButtonRef . current . style . display = "none" ;
187163
188- // Initialize clock with the actual start time and end time from server
189164 initializeFlipClock (
190165 counterData . startTime ,
191166 counterData . endTime ,
192167 true
193168 ) ;
194169
195- // Set up interval to check if time has ended
196- intervalId = setInterval ( async ( ) => {
170+ intervalId = setInterval ( ( ) => {
197171 const now = Date . now ( ) ;
198172 if ( now >= counterData . endTime ) {
199- // Time's up - show game over message
200173 if ( messageRef . current ) {
201174 messageRef . current . textContent =
202175 "GAME OVER: Hackathon Complete! You've Leveled Up!" ;
203176 messageRef . current . style . fontSize = "1.5rem" ;
204177 }
205-
206- // Reinitialize clock to show final time (static)
207178 initializeFlipClock (
208179 counterData . startTime ,
209180 counterData . endTime ,
210181 false
211182 ) ;
212-
213- // Clear the interval
214183 clearInterval ( intervalId ) ;
215184 }
216- } , 1000 ) ; // Check every second
185+ } , 1000 ) ;
217186 } else {
218- // Timer has ended
219187 if ( messageRef . current ) {
220188 messageRef . current . textContent =
221189 "GAME OVER: Hackathon Complete! You've Leveled Up!" ;
@@ -224,32 +192,23 @@ const CountDown = () => {
224192 if ( startButtonRef . current )
225193 startButtonRef . current . style . display = "none" ;
226194
227- // Show the final elapsed time (static, not counting)
228195 initializeFlipClock (
229196 counterData . startTime ,
230197 counterData . endTime ,
231198 false
232199 ) ;
233200 }
234201 } else {
235- // No countdown has been started yet - show button and clock at 00:00:00
236202 if ( startButtonRef . current )
237203 startButtonRef . current . style . display = "block" ;
238-
239- // Show static clock at 00:00:00 when no countdown is active
240204 const now = Date . now ( ) ;
241- initializeFlipClock ( now , now , false ) ; // false = don't count
205+ initializeFlipClock ( now , now + countdownDuration , false ) ;
242206 }
243207 } ) ( ) ;
244208
245- // Cleanup on unmount
246209 return ( ) => {
247- if ( clock ) {
248- clock . unmount ( ) ;
249- }
250- if ( intervalId ) {
251- clearInterval ( intervalId ) ;
252- }
210+ if ( clock ) clock . unmount ( ) ;
211+ if ( intervalId ) clearInterval ( intervalId ) ;
253212 } ;
254213 } , [ isFlipClockReady ] ) ;
255214
@@ -259,7 +218,6 @@ const CountDown = () => {
259218 < SparkleLayer className = "fixed inset-0 z-10 pointer-events-none" />
260219 < Fireworks className = "fixed inset-0 z-20 pointer-events-none" />
261220 < div className = "dark-cover" >
262- { /* Back to Home Link */ }
263221 < a
264222 href = "/"
265223 className = "absolute top-6 left-6 text-lg md:text-xl font-rye text-white hover:text-[#F3A83A] transition-all duration-300 hover:scale-105 z-50"
@@ -276,14 +234,12 @@ const CountDown = () => {
276234 value = "{{ csrf_token }}"
277235 />
278236
279- { /* Header */ }
280237 < div className = "cu-countDown-header" >
281238 < h1 className = "cu-countDown-header-heading font-rye text-4xl md:text-6xl lg:text-7xl text-[#F3A83A] mb-8" >
282239 Hackathon CountDown
283240 </ h1 >
284241 </ div >
285242
286- { /* Countdown Timer Container */ }
287243 < div className = "countdown-timer-wrapper" >
288244 < div className = "countdown-timer" >
289245 < div id = "flipclock" ref = { flipClockRef } > </ div >
0 commit comments