Skip to content

Commit 0bbc297

Browse files
fix(p0): clarify no-deal end state and harden setup validation
1 parent 90362dd commit 0bbc297

File tree

3 files changed

+31
-7
lines changed

3 files changed

+31
-7
lines changed

App.tsx

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,16 @@ const App: React.FC = () => {
140140
if (prev.status !== AuctionStatus.RUNNING) return prev;
141141
const newPrice = prev.currentPrice - config.decrementAmount;
142142

143-
if (newPrice < config.floorPrice) {
143+
if (newPrice <= config.floorPrice) {
144+
const terminalPrice = config.floorPrice;
144145
soundService.playEnd();
146+
showInfo('Floor reached — no deal.');
145147
return {
146148
...prev,
149+
currentPrice: terminalPrice,
147150
status: AuctionStatus.ENDED,
148151
winner: null,
149-
history: [...prev.history, { price: prev.currentPrice, timestamp: new Date(), event: 'PAUSE', details: 'Floor Reached' }],
152+
history: [...prev.history, { price: terminalPrice, timestamp: new Date(), event: 'NO_DEAL', details: 'Floor Reached' }],
150153
};
151154
}
152155

@@ -354,7 +357,11 @@ const App: React.FC = () => {
354357
if (!Number.isFinite(parsed)) {
355358
throw new Error(`${label} must be a valid number.`);
356359
}
357-
return Math.max(min, Math.floor(parsed));
360+
const normalized = Math.floor(parsed);
361+
if (normalized < min) {
362+
throw new Error(`${label} must be at least ${min}.`);
363+
}
364+
return normalized;
358365
};
359366

360367
let nextConfig: AuctionConfig;
@@ -382,7 +389,12 @@ const App: React.FC = () => {
382389
.filter(Boolean)
383390
.map((name, idx) => ({ id: String(idx + 1), name, color: founders[idx]?.color ?? 'bg-cyan-500' }));
384391

385-
const nextFounders = buildParticipants(nextConfig.participantCount, parsedNames.length > 0 ? parsedNames : founders);
392+
if (parsedNames.length !== nextConfig.participantCount) {
393+
showError(`Please provide exactly ${nextConfig.participantCount} participant initials.`);
394+
return;
395+
}
396+
397+
const nextFounders = buildParticipants(nextConfig.participantCount, parsedNames);
386398

387399
setConfig(nextConfig);
388400
setFounders(nextFounders);
@@ -618,13 +630,25 @@ const App: React.FC = () => {
618630
<div className="flex-none mb-2 border-b border-slate-800 pb-2">
619631
<h3 className="text-[10px] md:text-xs font-bold text-slate-500 uppercase tracking-widest mb-1 md:mb-3">History</h3>
620632
<div className="flex gap-1.5 md:gap-2 overflow-x-auto pb-1 mask-linear scrollbar-hide">
621-
{gameState.history.slice().reverse().map((log, idx) => <div key={idx} className="flex-shrink-0 px-2 py-1 rounded bg-slate-900 border border-slate-800 text-xs md:text-sm font-mono whitespace-nowrap"><span className={log.event === 'WIN' ? 'text-green-400' : 'text-slate-300'}>${log.price.toLocaleString()}</span><span className="mx-1 opacity-20">|</span><span className="opacity-75">{log.event === 'WIN' ? log.details : log.event}</span></div>)}
633+
{gameState.history.slice().reverse().map((log, idx) => <div key={idx} className="flex-shrink-0 px-2 py-1 rounded bg-slate-900 border border-slate-800 text-xs md:text-sm font-mono whitespace-nowrap"><span className={log.event === 'WIN' ? 'text-green-400' : log.event === 'NO_DEAL' ? 'text-amber-300' : 'text-slate-300'}>${log.price.toLocaleString()}</span><span className="mx-1 opacity-20">|</span><span className="opacity-75">{log.event === 'WIN' ? log.details : log.event === 'NO_DEAL' ? 'NO DEAL' : log.event}</span></div>)}
622634
</div>
623635
</div>
624636

625637
<div className="flex-1 flex flex-col justify-center items-center min-h-0">
626638
<div className="w-full max-w-4xl flex flex-col items-center">
627639
<Ticker price={gameState.currentPrice} status={gameState.status} nextDropTime={gameState.nextDropTime} dropIntervalMs={config.dropIntervalMs} />
640+
641+
{gameState.status === AuctionStatus.ENDED && gameState.winner && (
642+
<div className="mt-4 px-4 py-2 rounded-xl border border-emerald-400/40 bg-emerald-500/10 text-emerald-200 text-sm md:text-base font-semibold text-center">
643+
SOLD — ${gameState.currentPrice.toLocaleString()} to {gameState.winner.name}
644+
</div>
645+
)}
646+
647+
{gameState.status === AuctionStatus.ENDED && !gameState.winner && (
648+
<div className="mt-4 px-4 py-2 rounded-xl border border-amber-400/40 bg-amber-500/10 text-amber-200 text-sm md:text-base font-semibold text-center">
649+
FLOOR REACHED — NO DEAL
650+
</div>
651+
)}
628652
</div>
629653
</div>
630654
</div>

components/FounderButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export const FounderButton: React.FC<FounderButtonProps> = ({
8282
</div>
8383

8484
<div className={`font-bold display-font uppercase ${isWinner ? 'text-xs md:text-lg tracking-normal' : 'text-sm md:text-base tracking-tight'}`}>
85-
{isWinner ? 'ACCEPTED' : isRunning ? (disabled ? 'WAIT' : 'ACCEPT') : (isClaimed ? 'READY' : 'OPEN')}
85+
{isWinner ? 'ACCEPTED' : isEnded ? 'PASSED' : isRunning ? (disabled ? 'WAIT' : 'ACCEPT') : (isClaimed ? 'READY' : 'OPEN')}
8686
</div>
8787

8888
{isRunning && !disabled && (

types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export enum AuctionStatus {
2222
export interface BidLog {
2323
price: number;
2424
timestamp: Date;
25-
event: 'DROP' | 'START' | 'PAUSE' | 'WIN';
25+
event: 'DROP' | 'START' | 'NO_DEAL' | 'WIN';
2626
details?: string;
2727
}
2828

0 commit comments

Comments
 (0)