Client/client/src/views/GameInterface/tabs/DatapackTab.jsx
2026-04-18 18:42:50 +03:00

158 lines
5.3 KiB
JavaScript

import React, { useState, useEffect } from "react";
import GameDataManager from "../../../services/GameDataManager";
import MeteorRegion from "../../../components/Meteor/MeteorRegion.jsx";
import { config } from "../../../config/api";
import DatapackDetailsModal from "./components/DatapackDetailsModal";
import "./styles/DatapackTab.css";
const DatapackTab = () => {
const [activeSection, setActiveSection] = useState("items");
const [searchQuery, setSearchQuery] = useState("");
const [displayList, setDisplayList] = useState([]);
const [selectedItem, setSelectedItem] = useState(null);
const sections = [
{ id: "items", label: "Items", icon: "fa-box" },
{ id: "hostiles", label: "Hostiles", icon: "fa-biohazard" },
{ id: "dungeons", label: "Dungeons", icon: "fa-dungeon" },
{ id: "recipes", label: "Recipes", icon: "fa-scroll" },
];
useEffect(() => {
let data = [];
switch (activeSection) {
case "items":
data = Array.from(GameDataManager.items.values()).map((i) =>
GameDataManager.getItem(i.id),
);
break;
case "hostiles":
data = Array.from(GameDataManager.hostiles.values()).map((h) =>
GameDataManager.getHostile(h.id),
);
break;
case "dungeons":
data = Array.from(GameDataManager.dungeons.values()).map((d) =>
GameDataManager.getDungeon(d.id),
);
break;
case "recipes":
data = Array.from(GameDataManager.recipes.values()).map((r) =>
GameDataManager.getRecipe(r.id),
);
break;
default:
data = [];
}
if (searchQuery) {
const query = searchQuery.toLowerCase();
data = data.filter(
(item) =>
item.displayName?.toLowerCase().includes(query) ||
item.id?.toLowerCase().includes(query),
);
}
setDisplayList(data);
}, [activeSection, searchQuery]);
return (
<div className="tab-content active datapack-tab-wrapper">
<MeteorRegion>
<div className="datapack-controls">
<div className="section-selector">
{sections.map((s) => (
<button
key={s.id}
className={`section-btn ${activeSection === s.id ? "active" : ""}`}
onClick={() => setActiveSection(s.id)}
>
<i className={`fas ${s.icon}`}></i>
<span>{s.label}</span>
</button>
))}
</div>
<div className="search-bar">
<i className="fas fa-search"></i>
<input
type="text"
placeholder="Search ID or Name..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
</div>
<div className="datapack-content">
<div className="datapack-grid">
{displayList.map((item) => (
<div
key={item.id}
className={`datapack-card ${activeSection === "hostiles" ? "hostile-card" : ""}`}
onClick={() =>
setSelectedItem({ ...item, sectionType: activeSection })
}
>
<div className="card-icon">
{item.texture ? (
<img
src={`${config.serverUrl}/static/${item.texture}`}
alt=""
/>
) : (
<div className="fallback-icon">
{item.displayName?.[0] || "?"}
</div>
)}
</div>
<div className="card-info">
<span className="card-name">{item.displayName}</span>
<span className="card-id">{item.id}</span>
{activeSection === "hostiles" &&
item.loot &&
item.loot.length > 0 && (
<div className="card-loot-preview">
{item.loot.map((lootEntry, idx) => {
const lootData = GameDataManager.getItem(
lootEntry.id,
);
return (
<div
key={`${item.id}-loot-${idx}`}
className="loot-mini-slot-text"
title={`${lootData?.displayName || lootEntry.id} (${(lootEntry.chance * 100).toFixed(0)}%)`}
>
<i
className="fas fa-box-open"
style={{ fontSize: "10px", marginRight: "4px" }}
></i>
<span>
{lootData?.displayName ||
lootEntry.id.split(":").pop()}
</span>
</div>
);
})}
</div>
)}
</div>
</div>
))}
</div>
</div>
</MeteorRegion>
{selectedItem && (
<DatapackDetailsModal
data={selectedItem}
onClose={() => setSelectedItem(null)}
/>
)}
</div>
);
};
export default DatapackTab;