/** * @file Read-only panel displaying vampire quests grouped by zone. * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ /* eslint-disable max-lines-per-function -- Complex component with many render paths */ /* eslint-disable react/no-multi-comp -- QuestCard sub-component is tightly coupled */ import { useState, type JSX } from "react"; import { useGame } from "../../context/gameContext.js"; import type { VampireQuest, VampireQuestReward, VampireZone, } from "@elysium/types"; /** * Formats a duration in seconds to a human-readable string. * @param seconds - The total number of seconds to format. * @returns The formatted duration string. */ const formatDuration = (seconds: number): string => { const secondsPerHour = 3600; const secondsPerMinute = 60; if (seconds >= secondsPerHour) { const hours = Math.floor(seconds / secondsPerHour); const remainderSeconds = seconds % secondsPerHour; const minutes = Math.floor(remainderSeconds / secondsPerMinute); return `${String(hours)}h ${String(minutes)}m`; } if (seconds >= secondsPerMinute) { const minutes = Math.floor(seconds / secondsPerMinute); const secs = seconds % secondsPerMinute; return `${String(minutes)}m ${String(secs)}s`; } return `${String(seconds)}s`; }; /** * Returns a human-readable label string for a vampire quest reward. * @param reward - The reward to describe. * @param formatNumber - The number formatter function. * @returns The label string for the given reward type. */ const getRewardLabel = ( reward: VampireQuestReward, formatNumber: (value: number)=> string, ): string => { if (reward.type === "blood") { return `🩸 ${formatNumber(reward.amount ?? 0)} Blood`; } if (reward.type === "ichor") { return `💧 ${formatNumber(reward.amount ?? 0)} Ichor`; } if (reward.type === "soulShards") { return `💠 ${formatNumber(reward.amount ?? 0)} Soul Shards`; } if (reward.type === "upgrade") { return "🔓 Upgrade Unlocked"; } if (reward.type === "thrall") { return "🧟 New Thrall Tier"; } return "🦇 Equipment Unlocked"; }; interface VampireQuestCardProperties { readonly quest: VampireQuest; readonly unlockHint: string | undefined; readonly zoneIsOpen: boolean; } /** * Renders a single vampire quest card (read-only). * @param props - The component properties. * @param props.quest - The vampire quest to display. * @param props.unlockHint - The name of the prerequisite quest, if locked. * @param props.zoneIsOpen - Whether the quest's zone is currently unlocked. * @returns The JSX element. */ const VampireQuestCard = ({ quest, unlockHint, zoneIsOpen, }: VampireQuestCardProperties): JSX.Element => { const { formatNumber } = useGame(); return (
{quest.description}
{"⏱ "} {formatDuration(quest.durationSeconds)}
{"📜 Complete: "} {unlockHint}
} > : null } {quest.status === "available" && {"📋 Available"} } {quest.status === "active" && {"⏳ In Progress"} } {quest.status === "completed" && {"✅ Completed"} }{"Loading..."}
{"Vampire expansion not yet unlocked."}
{activeZone.description}
{String(completedCount)} {" / "} {String(zoneQuests.length)} {" quests completed"}
{activeZone.status === "locked" &&{"🔒 This zone is locked. Defeat the required vampire boss"} {" to unlock it."}
}{"No quests in this zone."}
: zoneQuests.map((quest: VampireQuest) => { return