210 lines
6.4 KiB
TypeScript
Executable File
210 lines
6.4 KiB
TypeScript
Executable File
import { Pizza, PlayCircle, Moon, Compass, Sword, FeatherIcon } from 'lucide-react';
|
|
import CollectResourcesButton from './CollectResourcesButton';
|
|
import { Pet } from '../types/Pet';
|
|
import { useState, useEffect } from 'react';
|
|
import { updatePetAction, getPetGatheredResources } from '../services/api/api';
|
|
import { PetActionGathered, PetBasicAction, PetGatherAction } from '../types/PetAction';
|
|
import ActionButton from './button/ActionButton';
|
|
import ActionResourceButton from './ActionResourceButton';
|
|
import ResourceSelectionModal from './modal/ResourceSelectionModal';
|
|
|
|
interface InteractionMenuProps {
|
|
pet: Pet;
|
|
onPetUpdate: (updatedPet: Pet) => void;
|
|
onCustomize: () => void;
|
|
}
|
|
|
|
export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuProps) {
|
|
const [gatheredResources, setGatheredResources] = useState<PetActionGathered[]>([]);
|
|
const [remainingCooldown, setRemainingCooldown] = useState<number | null>(null);
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const updateCooldown = () => {
|
|
if (!pet.basicActionCooldown) {
|
|
setRemainingCooldown(null);
|
|
return;
|
|
}
|
|
|
|
const cooldownTime = new Date(pet.basicActionCooldown).getTime();
|
|
const now = new Date().getTime();
|
|
const remaining = Math.max(0, cooldownTime - now);
|
|
|
|
if (remaining === 0) {
|
|
setRemainingCooldown(null);
|
|
} else {
|
|
setRemainingCooldown(remaining);
|
|
}
|
|
};
|
|
|
|
updateCooldown();
|
|
const interval = setInterval(updateCooldown, 1000);
|
|
return () => clearInterval(interval);
|
|
}, [pet.basicActionCooldown]);
|
|
|
|
useEffect(() => {
|
|
const fetchGatheredResources = async () => {
|
|
if (pet.petGatherAction === 'IDLE') {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const resources = await getPetGatheredResources(pet.id);
|
|
setGatheredResources(resources);
|
|
} catch (error) {
|
|
console.error('Failed to fetch gathered resources:', error);
|
|
}
|
|
};
|
|
|
|
fetchGatheredResources();
|
|
const interval = setInterval(fetchGatheredResources, 10000); // Poll every 10 seconds
|
|
|
|
return () => clearInterval(interval);
|
|
}, [pet.id, pet.petGatherAction]);
|
|
|
|
const formatCooldownTime = (ms: number) => {
|
|
const minutes = Math.floor(ms / 60000);
|
|
const seconds = Math.floor((ms % 60000) / 1000);
|
|
|
|
if (minutes > 0) {
|
|
return `${minutes} minute${minutes > 1 ? 's' : ''} remaining`;
|
|
}
|
|
return `${seconds} second${seconds > 1 ? 's' : ''} remaining`;
|
|
};
|
|
|
|
const handleGatherComplete = (updatedPet: Pet) => {
|
|
onPetUpdate(updatedPet);
|
|
};
|
|
|
|
function performBasicAction(basicAction: PetBasicAction): () => void {
|
|
return async () => {
|
|
try {
|
|
const updatedPet = await updatePetAction(pet.id, { basicAction: basicAction });
|
|
onPetUpdate(updatedPet);
|
|
} catch (error) {
|
|
console.error('Failed to perform basic action:', error);
|
|
}
|
|
};
|
|
}
|
|
|
|
const handleActionStart = async (actionType: 'gather' | 'explore' | 'battle') => {
|
|
if (actionType === 'gather') {
|
|
setIsModalOpen(true);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const action: PetGatherAction = actionType === 'explore' ? 'EXPLORE' : 'BATTLE';
|
|
const updatedPet = await updatePetAction(pet.id, { gatherAction: action });
|
|
onPetUpdate(updatedPet);
|
|
} catch (error) {
|
|
console.error('Failed to start action:', error);
|
|
}
|
|
};
|
|
|
|
const handleResourceSelect = async (resourceType: string) => {
|
|
if (resourceType === 'stop') {
|
|
try {
|
|
const updatedPet = await updatePetAction(pet.id, { gatherAction: 'IDLE' });
|
|
onPetUpdate(updatedPet);
|
|
} catch (error) {
|
|
console.error('Failed to stop action:', error);
|
|
}
|
|
setIsModalOpen(false);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const action: PetGatherAction = `GATHERING_${resourceType.toUpperCase()}` as PetGatherAction;
|
|
const updatedPet = await updatePetAction(pet.id, { gatherAction: action });
|
|
onPetUpdate(updatedPet);
|
|
} catch (error) {
|
|
console.error('Failed to start gathering:', error);
|
|
} finally {
|
|
setIsModalOpen(false);
|
|
}
|
|
};
|
|
|
|
const handleCollect = () => {
|
|
setGatheredResources([]);
|
|
}
|
|
|
|
return (
|
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 bg-gray-900 p-6 rounded-xl shadow-xl">
|
|
{remainingCooldown !== null && (
|
|
<div className="col-span-2 md:col-span-3 text-center p-2 bg-yellow-900/30 border-2 border-yellow-500/50 rounded-lg">
|
|
<span className="text-yellow-200">Cooldown: {formatCooldownTime(remainingCooldown)}</span>
|
|
</div>
|
|
)}
|
|
|
|
<ActionButton
|
|
icon={Pizza}
|
|
label="Feed"
|
|
onClick={performBasicAction('FEED')}
|
|
color="green"
|
|
disabled={remainingCooldown !== null}
|
|
/>
|
|
<ActionButton
|
|
icon={PlayCircle}
|
|
label="Play"
|
|
onClick={performBasicAction('PLAY')}
|
|
color="blue"
|
|
disabled={remainingCooldown !== null}
|
|
/>
|
|
<ActionButton
|
|
icon={Moon}
|
|
label="Sleep"
|
|
onClick={performBasicAction('SLEEP')}
|
|
color="purple"
|
|
disabled={remainingCooldown !== null}
|
|
/>
|
|
|
|
<div className="col-span-2 md:col-span-3 grid grid-cols-3 gap-4">
|
|
<ActionResourceButton
|
|
pet={pet}
|
|
icon={FeatherIcon}
|
|
label="Gather"
|
|
actionType="gather"
|
|
color="amber"
|
|
onActionClick={() => handleActionStart('gather')}
|
|
onActionComplete={handleGatherComplete}
|
|
/>
|
|
<ActionResourceButton
|
|
pet={pet}
|
|
icon={Compass}
|
|
label="Explore"
|
|
actionType="explore"
|
|
color="emerald"
|
|
onActionClick={() => handleActionStart('explore')}
|
|
onActionComplete={handleGatherComplete}
|
|
/>
|
|
<ActionResourceButton
|
|
pet={pet}
|
|
icon={Sword}
|
|
label="Battle"
|
|
actionType="battle"
|
|
color="red"
|
|
onActionClick={() => handleActionStart('battle')}
|
|
onActionComplete={handleGatherComplete}
|
|
/>
|
|
</div>
|
|
|
|
<div className="col-span-2 md:col-span-3">
|
|
<CollectResourcesButton
|
|
petId={pet.id}
|
|
resources={gatheredResources}
|
|
onCollect={handleCollect}
|
|
onPetUpdate={onPetUpdate}
|
|
/>
|
|
</div>
|
|
|
|
<ResourceSelectionModal
|
|
isOpen={isModalOpen}
|
|
onClose={() => setIsModalOpen(false)}
|
|
onGather={handleResourceSelect}
|
|
pet={pet}
|
|
isGathering={pet.petGatherAction !== 'IDLE'}
|
|
/>
|
|
</div>
|
|
);
|
|
} |