generated from nhcarrigan/template
a3daed1683
Sets up the full monorepo with pnpm workspaces. Includes shared types package, Hono API with Discord OAuth/JWT auth, Prisma v6 + MongoDB Atlas, and React + Vite frontend with game loop, five tabs, and Discord-linked save/load.
74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
import type { Upgrade } from "@elysium/types";
|
||
import { useGame } from "../../context/GameContext.js";
|
||
|
||
interface UpgradeCardProps {
|
||
upgrade: Upgrade;
|
||
currentGold: number;
|
||
currentEssence: number;
|
||
}
|
||
|
||
const UpgradeCard = ({ upgrade, currentGold, currentEssence }: UpgradeCardProps): React.JSX.Element => {
|
||
const { buyUpgrade } = useGame();
|
||
const canAfford =
|
||
currentGold >= upgrade.costGold && currentEssence >= upgrade.costEssence;
|
||
|
||
if (upgrade.purchased) {
|
||
return (
|
||
<div className="upgrade-card purchased">
|
||
<span className="upgrade-name">✅ {upgrade.name}</span>
|
||
<span className="upgrade-desc">{upgrade.description}</span>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="upgrade-card">
|
||
<div className="upgrade-info">
|
||
<h3>{upgrade.name}</h3>
|
||
<p>{upgrade.description}</p>
|
||
<p className="upgrade-multiplier">×{upgrade.multiplier} multiplier</p>
|
||
</div>
|
||
<div className="upgrade-cost">
|
||
{upgrade.costGold > 0 && <span>🪙 {upgrade.costGold.toLocaleString()}</span>}
|
||
{upgrade.costEssence > 0 && <span>✨ {upgrade.costEssence.toLocaleString()}</span>}
|
||
</div>
|
||
<button
|
||
className="buy-button"
|
||
disabled={!canAfford}
|
||
onClick={() => { buyUpgrade(upgrade.id); }}
|
||
type="button"
|
||
>
|
||
Buy
|
||
</button>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export const UpgradePanel = (): React.JSX.Element => {
|
||
const { state } = useGame();
|
||
|
||
if (!state) return <section className="panel"><p>Loading...</p></section>;
|
||
|
||
const availableUpgrades = state.upgrades.filter((u) => u.unlocked);
|
||
|
||
return (
|
||
<section className="panel upgrade-panel">
|
||
<h2>Upgrades</h2>
|
||
{availableUpgrades.length === 0 ? (
|
||
<p className="empty-state">No upgrades available yet — keep adventuring!</p>
|
||
) : (
|
||
<div className="upgrade-list">
|
||
{availableUpgrades.map((upgrade) => (
|
||
<UpgradeCard
|
||
key={upgrade.id}
|
||
upgrade={upgrade}
|
||
currentGold={state.resources.gold}
|
||
currentEssence={state.resources.essence}
|
||
/>
|
||
))}
|
||
</div>
|
||
)}
|
||
</section>
|
||
);
|
||
};
|