refactor: reorganize pet action types and update related components for improved resource management
This commit is contained in:
parent
c2e5bf92a3
commit
88a9c6507c
@ -1,5 +1,5 @@
|
|||||||
import { LucideIcon } from 'lucide-react';
|
import { LucideIcon } from 'lucide-react';
|
||||||
import { Pet, Resources } from '../types/Pet';
|
import { Pet } from '../types/Pet';
|
||||||
import { isActionActive, formatResourceName, getResourceFromAction } from '../utils/petUtils';
|
import { isActionActive, formatResourceName, getResourceFromAction } from '../utils/petUtils';
|
||||||
|
|
||||||
const colorClassMap = {
|
const colorClassMap = {
|
||||||
@ -11,6 +11,15 @@ const colorClassMap = {
|
|||||||
purple: 'bg-purple-900/30 hover:bg-purple-800/50 border-purple-500/50',
|
purple: 'bg-purple-900/30 hover:bg-purple-800/50 border-purple-500/50',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
const activeColorClassMap = {
|
||||||
|
amber: 'bg-amber-700/50 border-amber-400',
|
||||||
|
emerald: 'bg-emerald-700/50 border-emerald-400',
|
||||||
|
red: 'bg-red-700/50 border-red-400',
|
||||||
|
green: 'bg-green-700/50 border-green-400',
|
||||||
|
blue: 'bg-blue-700/50 border-blue-400',
|
||||||
|
purple: 'bg-purple-700/50 border-purple-400',
|
||||||
|
} as const;
|
||||||
|
|
||||||
const getActionVerb = (actionType: 'gather' | 'explore' | 'battle'): string => {
|
const getActionVerb = (actionType: 'gather' | 'explore' | 'battle'): string => {
|
||||||
const verbs = {
|
const verbs = {
|
||||||
gather: 'Gathering',
|
gather: 'Gathering',
|
||||||
@ -30,7 +39,6 @@ interface ActionResourceButtonProps {
|
|||||||
color: ButtonColor;
|
color: ButtonColor;
|
||||||
onActionClick: () => void;
|
onActionClick: () => void;
|
||||||
onActionComplete: (updatedPet: Pet) => void;
|
onActionComplete: (updatedPet: Pet) => void;
|
||||||
onResourcesUpdate: (resources: Resources) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ActionResourceButton({
|
export default function ActionResourceButton({
|
||||||
@ -44,20 +52,31 @@ export default function ActionResourceButton({
|
|||||||
const isActive = isActionActive(pet.petGatherAction, actionType);
|
const isActive = isActionActive(pet.petGatherAction, actionType);
|
||||||
const currentResource = getResourceFromAction(pet.petGatherAction);
|
const currentResource = getResourceFromAction(pet.petGatherAction);
|
||||||
|
|
||||||
|
const getButtonText = () => {
|
||||||
|
if (!isActive) return label;
|
||||||
|
|
||||||
|
if (actionType === 'explore' && pet.petGatherAction === 'EXPLORE') {
|
||||||
|
return 'Exploring';
|
||||||
|
}
|
||||||
|
if (actionType === 'battle' && pet.petGatherAction === 'BATTLE') {
|
||||||
|
return 'Battling';
|
||||||
|
}
|
||||||
|
if (currentResource) {
|
||||||
|
return `${getActionVerb(actionType)} ${formatResourceName(currentResource)}`;
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={onActionClick}
|
onClick={onActionClick}
|
||||||
className={`flex items-center justify-center space-x-2
|
className={`flex items-center justify-center space-x-2
|
||||||
${colorClassMap[color]}
|
${isActive ? activeColorClassMap[color] : colorClassMap[color]}
|
||||||
border-2 rounded-lg p-4
|
border-2 rounded-lg p-4
|
||||||
transition-all duration-300 transform hover:scale-105 w-full`}
|
transition-all duration-300 transform hover:scale-105 w-full`}
|
||||||
>
|
>
|
||||||
<Icon className="w-6 h-6" />
|
<Icon className="w-6 h-6" />
|
||||||
<span>
|
<span>{getButtonText()}</span>
|
||||||
{isActive && currentResource
|
|
||||||
? `${getActionVerb(actionType)} ${formatResourceName(currentResource)}`
|
|
||||||
: label}
|
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
import { Resources } from '../types/Pet';
|
|
||||||
import { putPetCollectResources } from '../services/api/api';
|
import { putPetCollectResources } from '../services/api/api';
|
||||||
|
import { PetActionGathered } from '../types/PetAction';
|
||||||
|
import { Pet } from '../types/Pet';
|
||||||
|
|
||||||
interface CollectResourcesButtonProps {
|
interface CollectResourcesButtonProps {
|
||||||
petId: string;
|
petId: string;
|
||||||
resources: Resources;
|
resources: PetActionGathered[];
|
||||||
onCollect: () => void;
|
onCollect: () => void;
|
||||||
|
onPetUpdate: (pet: Pet) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CollectResourcesButton({ petId, resources, onCollect }: CollectResourcesButtonProps) {
|
export default function CollectResourcesButton({ petId, resources, onCollect, onPetUpdate }: CollectResourcesButtonProps) {
|
||||||
const hasResources = Object.values(resources).some(value => value > 0);
|
const hasResources = Object.values(resources).length > 0;
|
||||||
|
|
||||||
if (!hasResources) return null;
|
if (!hasResources) return null;
|
||||||
|
|
||||||
const handleCollect = async () => {
|
const handleCollect = async () => {
|
||||||
try {
|
try {
|
||||||
await putPetCollectResources(petId);
|
const updatedPet = await putPetCollectResources(petId);
|
||||||
|
onPetUpdate(updatedPet);
|
||||||
onCollect();
|
onCollect();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to collect resources:', error);
|
console.error('Failed to collect resources:', error);
|
||||||
@ -24,17 +27,20 @@ export default function CollectResourcesButton({ petId, resources, onCollect }:
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={handleCollect}
|
onClick={handleCollect}
|
||||||
className="flex items-center justify-center space-x-2
|
className="flex flex-col items-center justify-center
|
||||||
bg-green-900/30 hover:bg-green-800/50
|
bg-green-900/30 hover:bg-green-800/50
|
||||||
border-2 border-green-500/50 rounded-lg p-4
|
border-2 border-green-500/50 rounded-lg p-4
|
||||||
transition-all duration-300 transform hover:scale-105 w-full mt-2"
|
transition-all duration-300 transform hover:scale-105 w-full mt-2"
|
||||||
>
|
>
|
||||||
<span>
|
<span className="font-bold mb-1">Collect:</span>
|
||||||
Collect: {Object.entries(resources)
|
{resources.map((item, index) => (
|
||||||
.filter(([_, value]) => value > 0)
|
<span key={index}>
|
||||||
.map(([key, value]) => `${value} ${key}`)
|
{item.gameItem
|
||||||
.join(', ')}
|
? item.gameItem.name
|
||||||
</span>
|
: `${item.resource} x${item.amount}`
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import { Pizza, PlayCircle, Moon, Compass, Sword, FeatherIcon } from 'lucide-react';
|
import { Pizza, PlayCircle, Moon, Compass, Sword, FeatherIcon } from 'lucide-react';
|
||||||
import CollectResourcesButton from './CollectResourcesButton';
|
import CollectResourcesButton from './CollectResourcesButton';
|
||||||
import { Pet, Resources } from '../types/Pet';
|
import { Pet } from '../types/Pet';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { updatePetAction, getPetGatheredResources } from '../services/api/api';
|
import { updatePetAction, getPetGatheredResources } from '../services/api/api';
|
||||||
import { PetBasicAction } from '../types/PetUpdateActionRequest';
|
import { PetActionGathered, PetBasicAction, PetGatherAction } from '../types/PetAction';
|
||||||
import ActionButton from './button/ActionButton';
|
import ActionButton from './button/ActionButton';
|
||||||
import ActionResourceButton from './ActionResourceButton';
|
import ActionResourceButton from './ActionResourceButton';
|
||||||
import ResourceSelectionModal from './modal/ResourceSelectionModal';
|
import ResourceSelectionModal from './modal/ResourceSelectionModal';
|
||||||
import { PetAction } from '../types/PetUpdateActionRequest';
|
|
||||||
|
|
||||||
interface InteractionMenuProps {
|
interface InteractionMenuProps {
|
||||||
pet: Pet;
|
pet: Pet;
|
||||||
@ -16,10 +15,9 @@ interface InteractionMenuProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuProps) {
|
export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuProps) {
|
||||||
const [gatheredResources, setGatheredResources] = useState<Resources>({ wisdom: 0, gold: 0, food: 0, junk: 0 });
|
const [gatheredResources, setGatheredResources] = useState<PetActionGathered[]>([]);
|
||||||
const [remainingCooldown, setRemainingCooldown] = useState<number | null>(null);
|
const [remainingCooldown, setRemainingCooldown] = useState<number | null>(null);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [selectedActionType, setSelectedActionType] = useState<'gather' | 'explore' | 'battle' | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateCooldown = () => {
|
const updateCooldown = () => {
|
||||||
@ -78,14 +76,6 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
onPetUpdate(updatedPet);
|
onPetUpdate(updatedPet);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResourcesUpdate = (resources: Resources) => {
|
|
||||||
setGatheredResources(resources);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCollect = () => {
|
|
||||||
setGatheredResources({ wisdom: 0, gold: 0, food: 0, junk: 0 });
|
|
||||||
};
|
|
||||||
|
|
||||||
function performBasicAction(basicAction: PetBasicAction): () => void {
|
function performBasicAction(basicAction: PetBasicAction): () => void {
|
||||||
return async () => {
|
return async () => {
|
||||||
try {
|
try {
|
||||||
@ -99,13 +89,12 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
|
|
||||||
const handleActionStart = async (actionType: 'gather' | 'explore' | 'battle') => {
|
const handleActionStart = async (actionType: 'gather' | 'explore' | 'battle') => {
|
||||||
if (actionType === 'gather') {
|
if (actionType === 'gather') {
|
||||||
setSelectedActionType(actionType);
|
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const action: PetAction = actionType === 'explore' ? 'EXPLORING' : 'BATTLE';
|
const action: PetGatherAction = actionType === 'explore' ? 'EXPLORE' : 'BATTLE';
|
||||||
const updatedPet = await updatePetAction(pet.id, { gatherAction: action });
|
const updatedPet = await updatePetAction(pet.id, { gatherAction: action });
|
||||||
onPetUpdate(updatedPet);
|
onPetUpdate(updatedPet);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -126,7 +115,7 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const action: PetAction = `GATHERING_${resourceType.toUpperCase()}` as PetAction;
|
const action: PetGatherAction = `GATHERING_${resourceType.toUpperCase()}` as PetGatherAction;
|
||||||
const updatedPet = await updatePetAction(pet.id, { gatherAction: action });
|
const updatedPet = await updatePetAction(pet.id, { gatherAction: action });
|
||||||
onPetUpdate(updatedPet);
|
onPetUpdate(updatedPet);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -136,6 +125,10 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCollect = () => {
|
||||||
|
setGatheredResources([]);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 bg-gray-900 p-6 rounded-xl shadow-xl">
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 bg-gray-900 p-6 rounded-xl shadow-xl">
|
||||||
{remainingCooldown !== null && (
|
{remainingCooldown !== null && (
|
||||||
@ -175,7 +168,6 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
color="amber"
|
color="amber"
|
||||||
onActionClick={() => handleActionStart('gather')}
|
onActionClick={() => handleActionStart('gather')}
|
||||||
onActionComplete={handleGatherComplete}
|
onActionComplete={handleGatherComplete}
|
||||||
onResourcesUpdate={handleResourcesUpdate}
|
|
||||||
/>
|
/>
|
||||||
<ActionResourceButton
|
<ActionResourceButton
|
||||||
pet={pet}
|
pet={pet}
|
||||||
@ -185,7 +177,6 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
color="emerald"
|
color="emerald"
|
||||||
onActionClick={() => handleActionStart('explore')}
|
onActionClick={() => handleActionStart('explore')}
|
||||||
onActionComplete={handleGatherComplete}
|
onActionComplete={handleGatherComplete}
|
||||||
onResourcesUpdate={handleResourcesUpdate}
|
|
||||||
/>
|
/>
|
||||||
<ActionResourceButton
|
<ActionResourceButton
|
||||||
pet={pet}
|
pet={pet}
|
||||||
@ -195,7 +186,6 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
color="red"
|
color="red"
|
||||||
onActionClick={() => handleActionStart('battle')}
|
onActionClick={() => handleActionStart('battle')}
|
||||||
onActionComplete={handleGatherComplete}
|
onActionComplete={handleGatherComplete}
|
||||||
onResourcesUpdate={handleResourcesUpdate}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -204,6 +194,7 @@ export default function InteractionMenu({ pet, onPetUpdate }: InteractionMenuPro
|
|||||||
petId={pet.id}
|
petId={pet.id}
|
||||||
resources={gatheredResources}
|
resources={gatheredResources}
|
||||||
onCollect={handleCollect}
|
onCollect={handleCollect}
|
||||||
|
onPetUpdate={onPetUpdate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ApiService } from './index';
|
import { ApiService } from './index';
|
||||||
import { InvItemInteraction, Pet, Resources } from '../../types/Pet';
|
import { InvItemInteraction, Pet, Resources } from '../../types/Pet';
|
||||||
import { PetCreationRequest } from '../../types/PetCreationRequest';
|
import { PetCreationRequest } from '../../types/PetCreationRequest';
|
||||||
import { PetUpdateActionRequest } from '../../types/PetUpdateActionRequest';
|
import { PetActionGathered, PetUpdateActionRequest } from '../../types/PetAction';
|
||||||
import { PetSkill, Skill } from '../../types/Skills';
|
import { PetSkill, Skill } from '../../types/Skills';
|
||||||
|
|
||||||
// Get API service instance
|
// Get API service instance
|
||||||
@ -22,8 +22,8 @@ export async function updatePetAction(petId: string, data: PetUpdateActionReques
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPetGatheredResources(petId: string): Promise<Resources> {
|
export async function getPetGatheredResources(petId: string): Promise<PetActionGathered[]> {
|
||||||
const response = await api.get<Resources>(`/api/v1/pet/${petId}/resources/gathered`);
|
const response = await api.get<PetActionGathered[]>(`/api/v1/pet/${petId}/resources/gathered`);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { PetBasicAction, PetGatherAction } from "./PetUpdateActionRequest";
|
import { PetBasicAction, PetGatherAction } from "./PetAction";
|
||||||
|
|
||||||
export type PetClass = 'FOREST_SPIRIT' | 'OCEAN_GUARDIAN' | 'FIRE_ELEMENTAL' | 'MYTHICAL_BEAST' | 'SHADOW_WALKER' | 'CYBER_PET' | 'BIO_MECHANICAL';
|
export type PetClass = 'FOREST_SPIRIT' | 'OCEAN_GUARDIAN' | 'FIRE_ELEMENTAL' | 'MYTHICAL_BEAST' | 'SHADOW_WALKER' | 'CYBER_PET' | 'BIO_MECHANICAL';
|
||||||
|
|
||||||
|
22
src/types/PetAction.ts
Normal file
22
src/types/PetAction.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export type PetBasicAction = 'UNKNOWN' | 'FEED' | 'PLAY' | 'SLEEP';
|
||||||
|
export type PetGatherAction = 'IDLE' | 'GATHERING_WISDOM' | 'GATHERING_GOLD' | 'GATHERING_FOOD' | 'EXPLORE' | 'BATTLE';
|
||||||
|
|
||||||
|
export interface PetUpdateActionRequest {
|
||||||
|
basicAction?: PetBasicAction;
|
||||||
|
gatherAction?: PetGatherAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PetActionGathered {
|
||||||
|
petId: string;
|
||||||
|
resource: string;
|
||||||
|
itemId: number;
|
||||||
|
amount: number;
|
||||||
|
gameItem: PetGatheredItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PetGatheredItem {
|
||||||
|
id: number;
|
||||||
|
name: number;
|
||||||
|
type: string;
|
||||||
|
rarity: string;
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
export type PetBasicAction = 'UNKNOWN' | 'FEED' | 'PLAY' | 'SLEEP';
|
|
||||||
export type PetGatherAction = 'IDLE' | 'GATHERING_WISDOM' | 'GATHERING_GOLD' | 'GATHERING_FOOD';
|
|
||||||
|
|
||||||
export interface PetUpdateActionRequest {
|
|
||||||
basicAction?: PetBasicAction;
|
|
||||||
gatherAction?: PetGatherAction;
|
|
||||||
}
|
|
@ -1,34 +1,29 @@
|
|||||||
import { PetGatherAction } from '../types/PetUpdateActionRequest';
|
import { PetGatherAction } from '../types/PetAction';
|
||||||
|
|
||||||
export function isGatheringAction(action: PetGatherAction): boolean {
|
export function isGatheringAction(action: PetGatherAction): boolean {
|
||||||
return action.startsWith('GATHERING_');
|
return action.startsWith('GATHERING_');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getResourceFromAction(action: string): string | null {
|
export function isActionActive(currentAction: PetGatherAction, actionType: 'gather' | 'explore' | 'battle'): boolean {
|
||||||
if (!action) return null;
|
if (actionType === 'gather') {
|
||||||
|
return currentAction.startsWith('GATHERING_');
|
||||||
const patterns = ['GATHERING_', 'EXPLORING_', 'BATTLE_'];
|
}
|
||||||
for (const pattern of patterns) {
|
if (actionType === 'explore') {
|
||||||
if (action.startsWith(pattern)) {
|
return currentAction === 'EXPLORE';
|
||||||
return action.replace(pattern, '').toLowerCase();
|
}
|
||||||
}
|
if (actionType === 'battle') {
|
||||||
|
return currentAction === 'BATTLE';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getResourceFromAction(action: PetGatherAction): string | null {
|
||||||
|
if (action.startsWith('GATHERING_')) {
|
||||||
|
return action.replace('GATHERING_', '').toLowerCase();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatResourceName(resource: string): string {
|
export function formatResourceName(resource: string): string {
|
||||||
return resource.charAt(0).toUpperCase() + resource.slice(1);
|
return resource.charAt(0).toUpperCase() + resource.slice(1).toLowerCase();
|
||||||
}
|
|
||||||
|
|
||||||
export function isActionActive(action: string, actionType: string): boolean {
|
|
||||||
if (!action) return false;
|
|
||||||
|
|
||||||
const actionMap = {
|
|
||||||
'gather': 'GATHERING_',
|
|
||||||
'explore': 'EXPLORING_',
|
|
||||||
'battle': 'BATTLE_'
|
|
||||||
};
|
|
||||||
|
|
||||||
return action.startsWith(actionMap[actionType] || '');
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user