Skip to content

Commit

Permalink
feat: time until hacking countdown timer
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderl19 committed Nov 3, 2023
1 parent 380fbb8 commit 7586998
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 160 deletions.
1 change: 1 addition & 0 deletions apps/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@types/react": "18.2.20",
"@types/react-dom": "^18.2.0",
"bootstrap": "^5.3.1",
"clsx": "^2.0.0",
"date-fns-tz": "^2.0.0",
"eslint": "8.46.0",
"eslint-config-next": "^13.4.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@use "bootstrap-utils" as bootstrap;

.countdown {
margin: 56px 0 80px 0;
opacity: 0;
transition: opacity 225ms cubic-bezier(0.32, 0, 0.67, 0);

span {
text-align: center;
font-weight: 600;

&.time {
display: block;
@include bootstrap.font-size(6rem);
line-height: 100%;

.number {
display: inline-block;
text-align: center;
width: 2ch;
}

.colon {
opacity: 0.75;
}
}

&.caption {
display: block;
@include bootstrap.font-size(1.5rem);
}
}
}

.loaded {
opacity: 1;
}
111 changes: 39 additions & 72 deletions apps/site/src/views/Schedule/components/Countdown/Countdown.tsx
Original file line number Diff line number Diff line change
@@ -1,86 +1,53 @@
"use client";

import { useEffect, useState, useRef, MutableRefObject } from "react";
import Col from "react-bootstrap/Col";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import { useEffect, useState } from "react";

import CountdownItem from "../CountdownItem/CountdownItem";
import Loader from "../Loader/Loader";
import clsx from "clsx";
import styles from "./Countdown.module.scss";

const SECOND = 1000;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;

interface Time {
days: number;
hours: number;
minutes: number;
seconds: number;
}

const computeTimeTil = () => {
const end = new Date(2023, 10, 4, 10, 0, 0);

const now = new Date();

const distance = +end - +now;

const days = Math.floor(distance / DAY);
const hours = Math.floor((distance % DAY) / HOUR);
const minutes = Math.floor((distance % HOUR) / MINUTE);
const seconds = Math.floor((distance % MINUTE) / SECOND);
return {
days,
hours,
minutes,
seconds,
};
};
// 10/4/23 10AM in UTC
const hackingStarts = new Date(Date.UTC(2023, 10, 4, 17, 0, 0));

export default function Countdown() {
const timer: MutableRefObject<NodeJS.Timer | undefined> = useRef();
const [remaining, setRemaining] = useState<Time | null>(null);
const [remainingSeconds, setRemainingSeconds] = useState<number>(NaN);

useEffect(() => {
timer.current = setInterval(handleCountdown, 1000);
return () => clearInterval(timer.current || undefined);
setRemainingSeconds(
(hackingStarts.valueOf() - new Date().valueOf()) / 1000,
);
const interval = setInterval(() => {
setRemainingSeconds((r) => r - 1);
}, 1000);

return () => clearInterval(interval);
}, []);

const handleCountdown = () => {
const time: Time = computeTimeTil();

setRemaining(time);
};

return (
<Container style={{ marginTop: "60px" }}>
{remaining !== null ? (
<>
<Row className="justify-content-center text-center mb-5">
{remaining.days !== 0 ? (
<Col>
<CountdownItem num={remaining.days} text="days" />
</Col>
) : null}
<Col>
<CountdownItem num={remaining.hours} text="hours" />
</Col>
<Col>
<CountdownItem num={remaining.minutes} text="minutes" />
</Col>
<Col>
<CountdownItem num={remaining.seconds} text="seconds" />
</Col>
</Row>
<h2>Until Hacking Begins</h2>
</>
) : (
<Row className="justify-content-center">
<Loader />
</Row>
<div
className={clsx(
styles.countdown,
!isNaN(remainingSeconds) && styles.loaded,
)}
</Container>
>
<span className={styles.time}>
<span className={styles.number}>
{Math.floor(remainingSeconds / (60 * 60))}
</span>
<span className={styles.colon}>:</span>
<span className={styles.number}>
{Math.floor((remainingSeconds / 60) % 60)
.toString()
.padStart(2, "0")}
</span>

<span className={styles.colon}>:</span>
<span className={styles.number}>
{Math.floor(remainingSeconds % 60)
.toString()
.padStart(2, "0")}
</span>
</span>
<span className={styles.caption}>Until Hacking Begins</span>
</div>
);
}

This file was deleted.

This file was deleted.

14 changes: 0 additions & 14 deletions apps/site/src/views/Schedule/components/Loader/Loader.module.scss

This file was deleted.

40 changes: 0 additions & 40 deletions apps/site/src/views/Schedule/components/Loader/Loader.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import Accordion from "react-bootstrap/Accordion";
import Col from "react-bootstrap/Col";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import { utcToZonedTime } from "date-fns-tz";

import clip from "@/assets/images/clip.svg";

import styles from "./ClipboardSchedule.module.scss";
import Countdown from "../../components/Countdown/Countdown";

interface ClipboardScheduleProps {
schedule: {
Expand Down Expand Up @@ -62,6 +62,7 @@ function ClipboardSchedule({ schedule }: ClipboardScheduleProps) {
initial="initial"
animate="animate"
>
<Countdown />
<Accordion defaultActiveKey="0" className={styles.accordion}>
{schedule.map((day, i) => (
<div key={i}>
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7586998

Please sign in to comment.