Refactor card options

Replace checkboxes with "Present" and "Absent" options. Disable "Reveal Number" until an option is selected.
This commit is contained in:
gpt-engineer-app[bot] 2025-07-19 15:13:08 +00:00
parent 5861189703
commit eb15a2d5ac

View file

@ -1,7 +1,6 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
@ -13,7 +12,7 @@ interface BinarySearchTrickProps {
} }
const BinarySearchTrick = ({ showSocialShare = true }: BinarySearchTrickProps) => { const BinarySearchTrick = ({ showSocialShare = true }: BinarySearchTrickProps) => {
const [selectedCards, setSelectedCards] = useState<number[]>([]); const [cardStates, setCardStates] = useState<Record<number, 'unselected' | 'present' | 'absent'>>({});
const [result, setResult] = useState<number | null>(null); const [result, setResult] = useState<number | null>(null);
const [showResult, setShowResult] = useState(false); const [showResult, setShowResult] = useState(false);
const [isOneByOne, setIsOneByOne] = useState(false); const [isOneByOne, setIsOneByOne] = useState(false);
@ -76,7 +75,7 @@ const BinarySearchTrick = ({ showSocialShare = true }: BinarySearchTrickProps) =
const handleModeToggle = (checked: boolean) => { const handleModeToggle = (checked: boolean) => {
setIsOneByOne(checked); setIsOneByOne(checked);
setCurrentCardIndex(0); setCurrentCardIndex(0);
setSelectedCards([]); setCardStates({});
setShowResult(false); setShowResult(false);
}; };
@ -89,29 +88,33 @@ const BinarySearchTrick = ({ showSocialShare = true }: BinarySearchTrickProps) =
setCurrentCardIndex(prev => Math.min(cards.length - 1, prev + 1)); setCurrentCardIndex(prev => Math.min(cards.length - 1, prev + 1));
}; };
const handleCardToggle = (cardId: number) => { const handleCardSelection = (cardId: number, state: 'present' | 'absent') => {
setSelectedCards(prev => setCardStates(prev => ({
prev.includes(cardId) ...prev,
? prev.filter(id => id !== cardId) [cardId]: state
: [...prev, cardId] }));
);
setShowResult(false); setShowResult(false);
}; };
const calculateResult = () => { const calculateResult = () => {
const sum = selectedCards.reduce((acc, cardId) => acc + cardId, 0); const sum = Object.entries(cardStates)
.filter(([_, state]) => state === 'present')
.reduce((acc, [cardId, _]) => acc + parseInt(cardId), 0);
setResult(sum); setResult(sum);
setShowResult(true); setShowResult(true);
}; };
const reset = () => { const reset = () => {
setSelectedCards([]); setCardStates({});
setResult(null); setResult(null);
setShowResult(false); setShowResult(false);
setCurrentCardIndex(0); setCurrentCardIndex(0);
setCards(generateCards()); // Regenerate with new randomized order setCards(generateCards()); // Regenerate with new randomized order
}; };
// Check if at least one card has been selected (present or absent)
const hasAnySelection = Object.values(cardStates).some(state => state !== 'unselected');
// Get cards to display based on mode // Get cards to display based on mode
const getDisplayCards = () => { const getDisplayCards = () => {
if (isOneByOne) { if (isOneByOne) {
@ -232,48 +235,64 @@ const BinarySearchTrick = ({ showSocialShare = true }: BinarySearchTrickProps) =
)} )}
<div className={`grid gap-4 ${isOneByOne ? 'grid-cols-1 justify-items-center' : 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5'}`}> <div className={`grid gap-4 ${isOneByOne ? 'grid-cols-1 justify-items-center' : 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5'}`}>
{getDisplayCards().map((card) => ( {getDisplayCards().map((card) => {
<Card const cardState = cardStates[card.id] || 'unselected';
key={card.id} return (
className={`cursor-pointer transition-all duration-500 hover:shadow-lg animate-fade-in ${ <Card
selectedCards.includes(card.id) key={card.id}
? 'ring-2 ring-primary bg-primary/5' className={`transition-all duration-500 hover:shadow-lg animate-fade-in ${
: 'hover:bg-muted/50' cardState === 'present'
} ${isOneByOne ? 'max-w-md w-full' : ''}`} ? 'ring-2 ring-green-500 bg-green-50'
onClick={() => handleCardToggle(card.id)} : cardState === 'absent'
> ? 'ring-2 ring-red-500 bg-red-50'
<CardHeader className={`${isOneByOne ? 'pb-4' : 'pb-2'}`}> : 'hover:bg-muted/50'
<div className="flex items-center justify-between"> } ${isOneByOne ? 'max-w-md w-full' : ''}`}
<CardTitle className={`font-bold text-primary ${isOneByOne ? 'text-3xl' : 'text-xl'}`}> >
{card.id} <CardHeader className={`${isOneByOne ? 'pb-4' : 'pb-2'}`}>
</CardTitle> <div className="flex items-center justify-between">
<Checkbox <CardTitle className={`font-bold text-primary ${isOneByOne ? 'text-3xl' : 'text-xl'}`}>
checked={selectedCards.includes(card.id)} {card.id}
onChange={() => {}} // Controlled by card click </CardTitle>
/> <div className="flex gap-2">
</div> <Button
</CardHeader> size="sm"
<CardContent> variant={cardState === 'present' ? 'default' : 'outline'}
<div className={`grid grid-cols-4 gap-1 ${isOneByOne ? 'text-lg gap-2' : 'text-sm'}`}> onClick={() => handleCardSelection(card.id, 'present')}
{card.numbers.map((num) => ( >
<div Present
key={num} </Button>
className={`text-center bg-muted/30 rounded border ${isOneByOne ? 'p-3' : 'p-1'}`} <Button
> size="sm"
{num} variant={cardState === 'absent' ? 'destructive' : 'outline'}
onClick={() => handleCardSelection(card.id, 'absent')}
>
Absent
</Button>
</div> </div>
))} </div>
</div> </CardHeader>
</CardContent> <CardContent>
</Card> <div className={`grid grid-cols-4 gap-1 ${isOneByOne ? 'text-lg gap-2' : 'text-sm'}`}>
))} {card.numbers.map((num) => (
<div
key={num}
className={`text-center bg-muted/30 rounded border ${isOneByOne ? 'p-3' : 'p-1'}`}
>
{num}
</div>
))}
</div>
</CardContent>
</Card>
);
})}
</div> </div>
<div className="flex flex-col items-center space-y-4"> <div className="flex flex-col items-center space-y-4">
<div className="flex gap-4"> <div className="flex gap-4">
<Button <Button
onClick={calculateResult} onClick={calculateResult}
disabled={selectedCards.length === 0} disabled={!hasAnySelection}
size="lg" size="lg"
className="min-w-32" className="min-w-32"
> >