/** * @file Daily challenge panel component showing today's challenges. * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ /* eslint-disable max-lines-per-function -- Complex component with many render paths */ import { useGame } from "../../context/gameContext.js"; import type { JSX } from "react"; /** * Formats the time remaining until the daily reset. * @returns The formatted time string. */ const formatTimeUntilReset = (): string => { const now = new Date(); const nowAsPst = new Date( now.toLocaleString("en-US", { timeZone: "America/Los_Angeles" }), ); const tomorrowMidnightPst = new Date(nowAsPst); tomorrowMidnightPst.setDate(tomorrowMidnightPst.getDate() + 1); tomorrowMidnightPst.setHours(0, 0, 0, 0); const pstOffset = nowAsPst.getTime() - now.getTime(); const resetAt = new Date(tomorrowMidnightPst.getTime() - pstOffset); const msRemaining = resetAt.getTime() - now.getTime(); const msPerHour = 1000 * 60 * 60; const msPerMinute = 1000 * 60; const hoursRemaining = Math.floor(msRemaining / msPerHour); const msAfterHours = msRemaining % msPerHour; const minutesRemaining = Math.floor(msAfterHours / msPerMinute); return `${String(hoursRemaining)}h ${String(minutesRemaining)}m`; }; /** * Renders the daily challenge panel with progress tracking. * @returns The JSX element. */ const DailyChallengePanel = (): JSX.Element => { const { state, formatNumber } = useGame(); if (state === null) { return (

{"Loading..."}

); } const { dailyChallenges } = state; if (dailyChallenges === undefined) { return (

{"📅 Daily Challenges"}

{"Load the game to generate today's challenges!"}

); } const completedCount = dailyChallenges.challenges.filter((challenge) => { return challenge.completed; }).length; return (

{"📅 Daily Challenges"}

{"Complete challenges for bonus 💎 crystals! Resets in "} {formatTimeUntilReset()} {" (PST midnight)."}

{completedCount} {" / "} {dailyChallenges.challenges.length} {" completed"}

{dailyChallenges.challenges.map((challenge) => { const progressScaled = challenge.progress * 100; const progressPercent = Math.min( 100, Math.floor(progressScaled / challenge.target), ); return (

{challenge.label}

{"Reward: "} {"💎 "} {formatNumber(challenge.rewardCrystals)} {" crystals"}

{challenge.completed ? {"✅ Complete!"} : <>

{formatNumber(challenge.progress)} {" / "} {formatNumber(challenge.target)}

}
); })}
); }; export { DailyChallengePanel };