import { CreateLinkEvent, PetRespectComposer, PetType } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState, useCallback } from 'react'; import { FaTimes } from 'react-icons/fa'; import { AvatarInfoPet, ConvertSeconds, GetConfigurationValue, LocalizeText, SendMessageComposer } from '../../../../../api'; import { Button, Column, Flex, LayoutCounterTimeView, LayoutPetImageView, LayoutRarityLevelView, Text, UserProfileIconView } from '../../../../../common'; import { useRoom, useSessionInfo } from '../../../../../hooks'; // TypeScript interface for AvatarInfoPet interface AvatarInfoPet { id: number; name: string; petType: number; petBreed: number; petFigure: string; posture: string; level: number; maximumLevel: number; age: number; ownerId: number; ownerName: string; respect: number; dead?: boolean; energy?: number; maximumEnergy?: number; happyness?: number; maximumHappyness?: number; experience?: number; levelExperienceGoal?: number; remainingGrowTime?: number; remainingTimeToLive?: number; maximumTimeToLive?: number; rarityLevel?: number; isOwner?: boolean; } interface InfoStandWidgetPetViewProps { avatarInfo: AvatarInfoPet; onClose: () => void; } const PetHeader: FC<{ name: string; petType: number; petBreed: number; onClose: () => void }> = ({ name, petType, petBreed, onClose }) => (
{name} {LocalizeText(`pet.breed.${petType}.${petBreed}`)}
); const MonsterplantStats: FC<{ avatarInfo: AvatarInfoPet; remainingGrowTime: number; remainingTimeToLive: number; }> = ({ avatarInfo, remainingGrowTime, remainingTimeToLive }) => ( <>
{!avatarInfo.dead && ( {LocalizeText('pet.level', ['level', 'maxlevel'], [avatarInfo.level.toString(), avatarInfo.maximumLevel.toString()])} )} {LocalizeText('infostand.pet.text.wellbeing')}
{avatarInfo.dead || remainingTimeToLive <= 0 ? '00:00:00' : `${ConvertSeconds(remainingTimeToLive).split(':')[1]}:${ConvertSeconds(remainingTimeToLive).split(':')[2]}:${ConvertSeconds(remainingTimeToLive).split(':')[3]}`}
{remainingGrowTime > 0 && ( {LocalizeText('infostand.pet.text.growth')} )} {LocalizeText('infostand.pet.text.raritylevel', ['level'], [LocalizeText(`infostand.pet.raritylevel.${avatarInfo.rarityLevel}`)])}
{LocalizeText('pet.age', ['age'], [avatarInfo.age.toString()])}
); // Sub-component: Regular Pet Stats const RegularPetStats: FC<{ avatarInfo: AvatarInfoPet }> = ({ avatarInfo }) => ( <>
{LocalizeText('pet.level', ['level', 'maxlevel'], [avatarInfo.level.toString(), avatarInfo.maximumLevel.toString()])} {LocalizeText('infostand.pet.text.happiness')}
{avatarInfo.happyness + '/' + avatarInfo.maximumHappyness}
{LocalizeText('infostand.pet.text.experience')}
{avatarInfo.experience + '/' + avatarInfo.levelExperienceGoal}
{LocalizeText('infostand.pet.text.energy')}
{avatarInfo.energy + '/' + avatarInfo.maximumEnergy}

{LocalizeText('infostand.text.petrespect', ['count'], [avatarInfo.respect.toString()])} {LocalizeText('pet.age', ['age'], [avatarInfo.age.toString()])}
); export const InfoStandWidgetPetView: FC = ({ avatarInfo, onClose }) => { const [remainingGrowTime, setRemainingGrowTime] = useState(0); const [remainingTimeToLive, setRemainingTimeToLive] = useState(0); const { roomSession = null } = useRoom(); const { petRespectRemaining = 0, respectPet = null } = useSessionInfo(); useEffect(() => { setRemainingGrowTime(avatarInfo.remainingGrowTime || 0); setRemainingTimeToLive(avatarInfo.remainingTimeToLive || 0); }, [avatarInfo]); useEffect(() => { if (avatarInfo.petType !== PetType.MONSTERPLANT || avatarInfo.dead) return; const interval = setInterval(() => { setRemainingGrowTime((prev) => (prev <= 0 ? 0 : prev - 1)); setRemainingTimeToLive((prev) => (prev <= 0 ? 0 : prev - 1)); }, 1000); return () => clearInterval(interval); }, [avatarInfo]); const processButtonAction = useCallback( async (action: string) => { try { let hideMenu = true; if (!action) return; switch (action) { case 'respect': await respectPet(avatarInfo.id); if (petRespectRemaining - 1 >= 1) hideMenu = false; break; case 'buyfood': CreateLinkEvent('catalog/open/' + GetConfigurationValue('catalog.links')['pets.buy_food']); break; case 'train': roomSession?.requestPetCommands(avatarInfo.id); break; case 'treat': SendMessageComposer(new PetRespectComposer(avatarInfo.id)); break; case 'compost': roomSession?.compostPlant(avatarInfo.id); break; case 'pick_up': roomSession?.pickupPet(avatarInfo.id); break; } if (hideMenu) onClose(); } catch (error) { console.error(`Failed to process action ${action}:`, error); } }, [avatarInfo, petRespectRemaining, respectPet, roomSession, onClose] ); const buttons = [ { action: 'buyfood', label: LocalizeText('infostand.button.buyfood'), condition: avatarInfo.petType !== PetType.MONSTERPLANT, }, { action: 'train', label: LocalizeText('infostand.button.train'), condition: avatarInfo.isOwner && avatarInfo.petType !== PetType.MONSTERPLANT, }, { action: 'treat', label: LocalizeText('infostand.button.pettreat'), condition: !avatarInfo.dead && avatarInfo.petType === PetType.MONSTERPLANT && avatarInfo.energy / avatarInfo.maximumEnergy < 0.98, }, { action: 'compost', label: LocalizeText('infostand.button.compost'), condition: roomSession?.isRoomOwner && avatarInfo.petType === PetType.MONSTERPLANT, }, { action: 'pick_up', label: LocalizeText('inventory.pets.pickup'), condition: avatarInfo.isOwner, }, { action: 'respect', label: LocalizeText('infostand.button.petrespect', ['count'], [petRespectRemaining.toString()]), condition: petRespectRemaining > 0 && avatarInfo.petType !== PetType.MONSTERPLANT, }, ]; if (!avatarInfo) return {LocalizeText('generic.loading')}; return ( {avatarInfo.petType === PetType.MONSTERPLANT ? ( ) : ( )}
{LocalizeText('infostand.text.petowner', ['name'], [avatarInfo.ownerName])}
{buttons.map( (button) => button.condition && ( ) )}
); };