Files
echoes-of-the-ash/pwa/REFACTORING_SUMMARY.md
2025-11-27 16:27:01 +01:00

9.7 KiB

Game.tsx Refactoring - Component Summary

COMPLETED COMPONENTS

1. types.ts (89 lines)

  • All TypeScript interfaces
  • Single source of truth for type definitions
  • Exports: PlayerState, Location, Profile, CombatState, Equipment, DirectionDetail, CombatLogEntry, LocationMessage, WorkbenchTab, MobileMenuState

2. useGameEngine.ts (600+ lines)

  • Core state management hook
  • All game state (30+ state variables)
  • Fully implemented handlers:
    • fetchGameData, fetchLocationData, fetchPlayerState
    • handleMove, handlePickup
    • handleOpenCrafting, handleCloseCrafting
    • addLocationMessage
  • Placeholder handlers (need implementation from Game.tsx):
    • handleUseItem, handleEquipItem, handleUnequipItem, handleDropItem
    • handleCraft, handleOpenRepair, handleRepairFromMenu, handleUncraft
    • handleSwitchWorkbenchTab
    • handleInitiateCombat, handleCombatAction, handlePvPAction, handlePvPAcknowledge, handleFlee
    • handleInteract, handleViewCorpseDetails, handleLootCorpse, handleLootCorpseItem
    • handleSpendPoint

3. MovementControls.tsx (168 lines)

  • 8-direction compass navigation
  • Special movements (up, down, enter, exit, inside, outside)
  • Stamina cost display
  • Movement cooldown indicators
  • Helper functions for direction details

4. CombatView.tsx (225 lines)

  • PvP combat display (opponent/player cards, turn indicators, time remaining)
  • PvE combat display (enemy image, HP bars, turn messages)
  • Combat log with timestamps
  • Combat action buttons (attack, flee, exit)
  • Combat over states (victory, defeat, fled)

5. LocationView.tsx (340 lines)

  • Location header with name, danger level, tags
  • Location image and description
  • Message display and recent activity log
  • Entity sections:
    • Enemies with fight buttons
    • Corpses with examine/loot interface
    • Friendly NPCs
    • Items on ground with pickup options (single, quantity, all)
    • Other players with PvP buttons
  • Corpse detail expansion with lootable items
  • Item tooltips with stats (weight, volume, damage, durability, tier)

6. PlayerSidebar.tsx (240 lines)

  • Character stats with HP/Stamina/XP bars
  • Stat display (STR, AGI, END, INT) with + buttons for unspent points
  • Equipment display with unequip buttons
  • Inventory list with filters (name, category)
  • Item actions (use, equip, drop)
  • Capacity indicators (weight, volume)

7. Workbench.tsx (340 lines)

  • Three tabs: Craft, Repair, Salvage
  • Craft tab:
    • Filters (name, category)
    • Craftable items with materials, tools, level requirements
    • Visual indicators for missing requirements
  • Repair tab:
    • Repairable items from inventory/equipment
    • Durability bars
    • Repair materials and tools display
  • Salvage tab:
    • Uncraftable items
    • Durability-based yield calculation
    • Loss chance warnings
    • Confirmation dialog with preview

📊 SIZE REDUCTION

File Original Extracted Reduction
Game.tsx 3,315 lines TBD (~200-300 target) ~91-94%
MovementControls - 168 lines NEW
CombatView - 225 lines NEW
LocationView - 340 lines NEW
PlayerSidebar - 240 lines NEW
Workbench - 340 lines NEW
types.ts - 89 lines NEW
useGameEngine.ts - 600+ lines NEW

Total extracted: ~2,000+ lines into focused, reusable components Target Game.tsx: ~200-300 lines (orchestration only)


🔧 REMAINING WORK

1. Complete useGameEngine Handlers

Copy implementations from original Game.tsx (lines 900-1350):

  • handleCraft (line 900)
  • handleOpenRepair (line 921)
  • handleRepairFromMenu (line 931)
  • handleUncraft (line 948)
  • handleSwitchWorkbenchTab (line 973)
  • handleSpendPoint (line 990)
  • handleUseItem (line 1002)
  • handleEquipItem (line 1039)
  • handleUnequipItem (line 1051)
  • handleDropItem (line 1063)
  • handleInteract (line 1075)
  • handleViewCorpseDetails (line 1105)
  • handleLootCorpseItem (line 1116)
  • handleLootCorpse (line 1149)
  • handleInitiateCombat (line 1155)
  • handleCombatAction (line 1186)
  • handleExitCombat (line 1295)
  • handleExitPvPCombat (line 1301)
  • handleInitiatePvP (line 1316)

2. Refactor Main Game.tsx

Create new Game.tsx structure:

import useGameEngine from './hooks/useGameEngine'
import CombatView from './CombatView'
import LocationView from './LocationView'
import MovementControls from './MovementControls'
import PlayerSidebar from './PlayerSidebar'
import Workbench from './Workbench'

function Game({ token }: { token: string }) {
  const [state, actions] = useGameEngine(token, handleWebSocketMessage)

  // Death overlay
  if (state.profile?.is_dead) return <DeathOverlay />

  // Loading
  if (state.loading) return <Loading />

  return (
    <div className="game-container">
      <header>...</header>
      
      {/* Left sidebar: Movement + Location */}
      <div className="left-sidebar">
        <MovementControls 
          location={state.location}
          profile={state.profile}
          combatState={state.combatState}
          movementCooldown={state.movementCooldown}
          onMove={actions.handleMove}
        />
        {!state.combatState && (
          <LocationView 
            location={state.location}
            playerState={state.playerState}
            combatState={state.combatState}
            message={state.message}
            locationMessages={state.locationMessages}
            expandedCorpse={state.expandedCorpse}
            corpseDetails={state.corpseDetails}
            mobileMenuOpen={state.mobileMenuOpen}
            onSetMessage={actions.setMessage}
            onInitiateCombat={actions.handleInitiateCombat}
            onInitiatePvP={actions.handleInitiatePvP}
            onPickup={actions.handlePickup}
            onLootCorpse={actions.handleLootCorpse}
            onLootCorpseItem={actions.handleLootCorpseItem}
            onSetExpandedCorpse={actions.setExpandedCorpse}
          />
        )}
      </div>

      {/* Center: Combat view or empty */}
      {state.combatState && (
        <CombatView 
          combatState={state.combatState}
          combatLog={state.combatLog}
          profile={state.profile}
          playerState={state.playerState}
          equipment={state.equipment}
          enemyName={state.enemyName}
          enemyImage={state.enemyImage}
          enemyTurnMessage={state.enemyTurnMessage}
          pvpTimeRemaining={state.pvpTimeRemaining}
          onCombatAction={actions.handleCombatAction}
          onFlee={actions.handleFlee}
          onPvPAction={actions.handlePvPAction}
          onExitCombat={actions.handleExitCombat}
          onExitPvPCombat={actions.handleExitPvPCombat}
        />
      )}

      {/* Right sidebar: Stats + Inventory */}
      <PlayerSidebar 
        playerState={state.playerState}
        profile={state.profile}
        equipment={state.equipment}
        inventoryFilter={state.inventoryFilter}
        inventoryCategoryFilter={state.inventoryCategoryFilter}
        mobileMenuOpen={state.mobileMenuOpen}
        onSetInventoryFilter={actions.setInventoryFilter}
        onSetInventoryCategoryFilter={actions.setInventoryCategoryFilter}
        onUseItem={actions.handleUseItem}
        onEquipItem={actions.handleEquipItem}
        onUnequipItem={actions.handleUnequipItem}
        onDropItem={actions.handleDropItem}
        onSpendPoint={actions.handleSpendPoint}
      />

      {/* Workbench modal */}
      <Workbench 
        showCraftingMenu={state.showCraftingMenu}
        showRepairMenu={state.showRepairMenu}
        workbenchTab={state.workbenchTab}
        craftableItems={state.craftableItems}
        repairableItems={state.repairableItems}
        uncraftableItems={state.uncraftableItems}
        craftFilter={state.craftFilter}
        repairFilter={state.repairFilter}
        uncraftFilter={state.uncraftFilter}
        craftCategoryFilter={state.craftCategoryFilter}
        profile={state.profile}
        onCloseCrafting={actions.handleCloseCrafting}
        onSwitchTab={actions.handleSwitchWorkbenchTab}
        onSetCraftFilter={actions.setCraftFilter}
        onSetRepairFilter={actions.setRepairFilter}
        onSetUncraftFilter={actions.setUncraftFilter}
        onSetCraftCategoryFilter={actions.setCraftCategoryFilter}
        onCraft={actions.handleCraft}
        onRepair={actions.handleRepairFromMenu}
        onUncraft={actions.handleUncraft}
      />

      {/* Mobile navigation */}
      <MobileNav />
    </div>
  )
}

BENEFITS ACHIEVED

  1. Modularity: Each component has single responsibility
  2. Reusability: Components can be used independently
  3. Maintainability: Easy to locate and fix bugs
  4. Testing: Components can be tested in isolation
  5. Type Safety: Strong TypeScript interfaces for props
  6. Performance: Smaller component re-renders
  7. Readability: ~200-300 line Game.tsx vs 3,315 lines
  8. Scalability: Easy to add new features per component

📝 NOTES

  • All lint errors expected (JSX runtime) - will resolve when integrated
  • useGameEngine hook needs handler implementations copied from original
  • Workbench has location tags feature (workbench, repair_station tags)
  • Mobile menu state managed in useGameEngine
  • WebSocket message handling stays in Game.tsx
  • Combat log timestamping preserved
  • PvP timer tracking with useRef
  • Interactable cooldowns tracked per location

🚀 NEXT STEPS

  1. PRIORITY: Copy handler implementations from Game.tsx to useGameEngine.ts
  2. Create new minimal Game.tsx that imports all components
  3. Wire up all props from state/actions to components
  4. Test complete integration
  5. Remove old Game.tsx code
  6. Update documentation

Estimated final Game.tsx: ~200-300 lines (91-94% reduction!)