"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { AnimatedPetSprite } from "@/components/pet/animated-pet-sprite"; import { PetEmotionCaption } from "@/components/pet/pet-emotion-caption"; import { ParallaxRoomBackground } from "@/components/pet/parallax-room-background"; import { PixelGauge } from "@/components/pet/pixel-gauge"; import type { AvatarCustomization } from "@/lib/avatar-customization-storage"; import { defaultAvatarCondition, type AvatarCondition, } from "@/lib/avatar-state"; import { HABIT_PET_DATA_UPDATED_EVENT } from "@/lib/app-events"; import { getAvatarConditionForToday } from "@/lib/daily-quiz-storage"; import { PET_EMOTION_DISPLAY_MS } from "@/lib/pet-status"; import { normalizeRoomBackgroundId, type RoomBackgroundId, } from "@/lib/room-backgrounds"; import { cn } from "@/lib/utils"; type PetHabitatProps = { customization: AvatarCustomization; className?: string; fillViewport?: boolean; /** Bit name in the LCD top-right (landing preview). */ nameInLcd?: boolean; petScale?: number; lcdClassName?: string; lcdRef?: React.Ref; }; export function PetHabitat({ customization, className, fillViewport = false, nameInLcd = false, petScale, lcdClassName: lcdClassNameOverride, lcdRef, }: PetHabitatProps) { const [condition, setCondition] = useState( defaultAvatarCondition, ); const [isReady, setIsReady] = useState(false); const [emotionVisible, setEmotionVisible] = useState(false); const emotionTimeoutRef = useRef(null); const roomId = normalizeRoomBackgroundId(customization.roomBackground); const interactive = fillViewport; const clearEmotionTimeout = useCallback(() => { if (emotionTimeoutRef.current !== null) { window.clearTimeout(emotionTimeoutRef.current); emotionTimeoutRef.current = null; } }, []); const showEmotionBriefly = useCallback(() => { clearEmotionTimeout(); setEmotionVisible(true); emotionTimeoutRef.current = window.setTimeout(() => { setEmotionVisible(false); emotionTimeoutRef.current = null; }, PET_EMOTION_DISPLAY_MS); }, [clearEmotionTimeout]); const loadStatus = useCallback(async () => { setCondition((await getAvatarConditionForToday()) ?? defaultAvatarCondition); setIsReady(true); }, []); useEffect(() => { void loadStatus(); return () => { clearEmotionTimeout(); }; }, [loadStatus, clearEmotionTimeout]); useEffect(() => { const handleDataUpdated = () => { void loadStatus(); }; window.addEventListener(HABIT_PET_DATA_UPDATED_EVENT, handleDataUpdated); return () => { window.removeEventListener(HABIT_PET_DATA_UPDATED_EVENT, handleDataUpdated); }; }, [loadStatus]); const shellClassName = cn( "tamagotchi-shell overflow-hidden p-3 sm:p-4", fillViewport && "tamagotchi-shell-fill", className, ); const lcdClassName = cn( "tamagotchi-lcd relative", fillViewport ? "tamagotchi-lcd-pet-fill" : (lcdClassNameOverride ?? "tamagotchi-lcd-pet-match"), ); const gaugeOverlaySize = fillViewport ? "responsive" : "md"; const showNameAboveShell = !fillViewport && !nameInLcd; const showNameInLcdOverlay = fillViewport || nameInLcd; if (!isReady) { return (

Waking up your bit...

); } return (
{showNameAboveShell ? (

{customization.name}

) : null}
{showNameInLcdOverlay ? (

{customization.name}

) : null}
); }