import React, { useState, useEffect } from "react"; import { useSocket } from "../../../hooks/useSocket"; import GameDataManager from "../../../services/GameDataManager"; import "./styles/CraftingTab.css"; import CategorySelector from "../components/CategorySelector"; import CraftModal from "./components/CraftModal"; import { config } from "../../../config/api"; const CraftingTab = () => { const { socket } = useSocket(); const [categories, setCategories] = useState([]); const [recipes, setRecipes] = useState([]); const [userInventory, setUserInventory] = useState([]); const [activeCategory, setActiveCategory] = useState(""); const [selectedRecipe, setSelectedRecipe] = useState(null); const [activeCraft, setActiveCraft] = useState(null); useEffect(() => { const manifestCategories = GameDataManager.getRecipeCategories(); setCategories(manifestCategories); if (manifestCategories.length > 0 && !activeCategory) { setActiveCategory(manifestCategories[0].id); } }, []); useEffect(() => { if (activeCategory) { const filteredRecipes = GameDataManager.getRecipesByCategory(activeCategory); setRecipes(filteredRecipes); } }, [activeCategory]); useEffect(() => { if (!socket) return; socket.emit("player:get_inventory"); socket.emit("player:check_active_craft"); const handleInventory = (data) => setUserInventory(data); const handleCraftStarted = (data) => { const recipeData = GameDataManager.getRecipe(data.recipeId); const now = Date.now(); const diff = (data.finishAt - now) / 1000; if (diff <= 0) { setActiveCraft(null); return; } setActiveCraft({ recipeId: data.recipeId, name: recipeData?.displayName || data.recipeId, finishAt: data.finishAt, totalTime: data.totalTime || recipeData?.time_seconds || diff, timeLeft: Math.max(0, Math.ceil(diff)), }); if (recipeData) { setSelectedRecipe(recipeData); } }; const handleCraftSuccess = () => { setActiveCraft(null); setSelectedRecipe(null); socket.emit("player:get_inventory"); }; socket.on("player:inventory_data", handleInventory); socket.on("player:craft_started", handleCraftStarted); socket.on("player:craft_success", handleCraftSuccess); return () => { socket.off("player:inventory_data", handleInventory); socket.off("player:craft_started", handleCraftStarted); socket.off("player:craft_success", handleCraftSuccess); }; }, [socket]); useEffect(() => { if (!activeCraft) return; const timer = setInterval(() => { const now = Date.now(); const diff = Math.max(0, Math.ceil((activeCraft.finishAt - now) / 1000)); if (diff <= 0) { clearInterval(timer); setActiveCraft(null); } else { setActiveCraft((prev) => (prev ? { ...prev, timeLeft: diff } : null)); } }, 1000); return () => clearInterval(timer); }, [activeCraft?.finishAt]); const getOwnedAmount = (itemId) => { const item = userInventory.find((i) => (i.itemId || i.id) === itemId); return item ? item.quantity : 0; }; const handleStartCrafting = (recipe) => { if (activeCraft) return; socket.emit("player:craft_item", { recipeId: recipe.id }); }; return (
{activeCraft && (
Assembling:{" "} {activeCraft.name} {activeCraft.timeLeft}s
)}

Fabrication Unit

{recipes.map((recipe) => { const isThisRecipeCrafting = activeCraft?.recipeId === recipe.id; const canCraft = recipe.ingredients.every( (ing) => getOwnedAmount(ing.itemId) >= ing.quantity, ); return (
setSelectedRecipe(recipe)} >
{recipe.texture ? ( {recipe.displayName} ) : (
{recipe.displayName[0]}
)}
{recipe.displayName}
{recipe.time_seconds}s
{isThisRecipeCrafting && (
)}
); })}
!activeCraft && setSelectedRecipe(null)} onStartCraft={handleStartCrafting} activeCraft={activeCraft} getOwnedAmount={getOwnedAmount} />
); }; export default CraftingTab;