-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
21d80e4
commit 88929cd
Showing
6 changed files
with
230 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import React, { useState } from "react"; | ||
import { notification } from "~~/utils/scaffold-eth/notification"; | ||
|
||
export function CheckInForm({ endpoint }: { endpoint: string }) { | ||
const [email, setEmail] = useState(""); | ||
const [loading, setLoading] = useState(false); | ||
|
||
const handleCheckIn = async () => { | ||
if (!email) { | ||
notification.error("Email is required"); | ||
return; | ||
} | ||
|
||
setLoading(true); | ||
|
||
try { | ||
const response = await fetch(endpoint, { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify({ email }), | ||
}); | ||
|
||
if (!response.ok) { | ||
throw new Error("Failed to check in"); | ||
} | ||
|
||
const result = await response.json(); | ||
notification.success(result.message); | ||
setEmail(""); // Clear the input field | ||
} catch (error) { | ||
notification.error(`${(error as Error).message}`); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
return ( | ||
<div> | ||
<div className="flex items-center join w-full max-w-2xl mt-8"> | ||
<input | ||
className="input input-bordered join-item w-full max-w-2xl" | ||
value={email} | ||
onChange={e => setEmail(e.target.value)} | ||
type="email" | ||
placeholder="Email" | ||
/> | ||
<button onClick={handleCheckIn} disabled={loading} className="btn btn-secondary join-item rounded-r-full"> | ||
{" "} | ||
{loading ? "Checking in..." : "Check In"} | ||
</button> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
"use client"; | ||
|
||
import { useEffect, useState } from "react"; | ||
import { CheckInForm } from "./CheckIn"; | ||
|
||
type CountdownTimerProps = { | ||
onComplete?: () => void; | ||
}; | ||
|
||
export default function CountdownTimer({ onComplete }: CountdownTimerProps) { | ||
const calculateInitialTime = (): number => { | ||
const now = new Date(); | ||
const target = new Date(); | ||
target.setHours(15, 0, 0, 0); // Set target time to 2 PM today | ||
|
||
const timeDifference = target.getTime() - now.getTime(); | ||
const initialTimeInSeconds = Math.max(0, Math.floor(timeDifference / 1000)); | ||
|
||
return initialTimeInSeconds; | ||
}; | ||
|
||
const [timeLeft, setTimeLeft] = useState(calculateInitialTime()); | ||
|
||
useEffect(() => { | ||
if (timeLeft <= 0) { | ||
onComplete?.(); | ||
return; | ||
} | ||
|
||
const timer = setInterval(() => { | ||
setTimeLeft(prevTime => prevTime - 1); | ||
}, 1000); | ||
|
||
return () => clearInterval(timer); | ||
}, [timeLeft, onComplete]); | ||
|
||
const formatTime = (time: number): { hours: string; minutes: string; seconds: string } => { | ||
if (isNaN(time) || time < 0) return { hours: "00", minutes: "00", seconds: "00" }; | ||
|
||
const hours = Math.floor(time / 3600); | ||
const minutes = Math.floor((time % 3600) / 60); | ||
const seconds = time % 60; | ||
return { | ||
hours: hours.toString().padStart(2, "0"), | ||
minutes: minutes.toString().padStart(2, "0"), | ||
seconds: seconds.toString().padStart(2, "0"), | ||
}; | ||
}; | ||
|
||
const { hours, minutes, seconds } = formatTime(timeLeft); | ||
|
||
return ( | ||
<div className="w-full max-w-2xl mx-auto overflow-hidden"> | ||
{timeLeft > 0 ? ( | ||
<div className="p-6 sm:p-10"> | ||
<h2 className="text-2xl font-bold text-gray-800 mb-4 text-center">Online Check-in closes in </h2> | ||
<div className="flex justify-center items-center space-x-4 sm:space-x-8"> | ||
<div className="flex flex-col items-center"> | ||
<span className="text-4xl sm:text-6xl font-bold text-primary tabular-nums" aria-live="polite"> | ||
{hours} | ||
</span> | ||
<span className="text-sm sm:text-base text-gray-600 mt-1">Hours</span> | ||
</div> | ||
<span className="text-4xl sm:text-6xl font-bold text-gray-400">:</span> | ||
<div className="flex flex-col items-center"> | ||
<span className="text-4xl sm:text-6xl font-bold text-primary tabular-nums" aria-live="polite"> | ||
{minutes} | ||
</span> | ||
<span className="text-sm sm:text-base text-gray-600 mt-1">Minutes</span> | ||
</div> | ||
<span className="text-4xl sm:text-6xl font-bold text-gray-400">:</span> | ||
<div className="flex flex-col items-center"> | ||
<span className="text-4xl sm:text-6xl font-bold text-primary tabular-nums" aria-live="polite"> | ||
{seconds} | ||
</span> | ||
<span className="text-sm sm:text-base text-gray-600 mt-1">Seconds</span> | ||
</div> | ||
</div> | ||
<CheckInForm endpoint="/api/checkin/online" /> | ||
</div> | ||
) : ( | ||
<p className="mt-6 text-xl font-semibold text-center text-gray-700">Online Check-in is now closed</p> | ||
)} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { NextApiRequest, NextApiResponse } from "next"; | ||
import clientPromise from "~~/utils/mongodb"; | ||
|
||
export default async function handler(req: NextApiRequest, res: NextApiResponse) { | ||
if (req.method !== "POST") { | ||
return res.status(405).json({ error: "Method not allowed" }); | ||
} | ||
|
||
const { email } = req.body; | ||
|
||
if (!email) { | ||
return res.status(400).json({ error: "Email is required" }); | ||
} | ||
|
||
try { | ||
const client = await clientPromise; | ||
const db = client.db("eth-rwanda-hackathon"); | ||
const collection = db.collection("hackers-checkin"); | ||
|
||
await collection.insertOne({ | ||
email, | ||
inperson: true, | ||
checkedInAt: new Date(), | ||
}); | ||
|
||
res.status(200).json({ message: "Checked in in-person successfully" }); | ||
} catch (error) { | ||
console.error("Error during in-person check-in:", error); | ||
res.status(500).json({ error: "Internal Server Error" }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { NextApiRequest, NextApiResponse } from "next"; | ||
import clientPromise from "~~/utils/mongodb"; | ||
|
||
export default async function handler(req: NextApiRequest, res: NextApiResponse) { | ||
if (req.method !== "POST") { | ||
return res.status(405).json({ error: "Method not allowed" }); | ||
} | ||
|
||
const { email } = req.body; | ||
|
||
if (!email) { | ||
return res.status(400).json({ error: "Email is required" }); | ||
} | ||
|
||
try { | ||
const client = await clientPromise; | ||
const db = client.db("eth-rwanda-hackathon"); | ||
const collection = db.collection("hackers-checkin"); | ||
|
||
await collection.insertOne({ | ||
email, | ||
inperson: false, | ||
checkedInAt: new Date(), | ||
}); | ||
console.log("Checked in online successfully"); | ||
res.status(200).json({ message: "Checked in online successfully" }); | ||
} catch (error) { | ||
console.error("Error during online check-in:", error); | ||
res.status(500).json({ error: "Internal Server Error" }); | ||
} | ||
} |