ps99-api 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/.github/workflows/release-on-main.yml +1 -2
  2. package/.idea/runConfigurations/test_changing.xml +1 -1
  3. package/debug_currency.json +57 -0
  4. package/debug_goals.json +271 -0
  5. package/dist/ps99-api.d.ts +2 -0
  6. package/dist/ps99-api.js +4 -1
  7. package/dist/ps99-api.js.map +1 -1
  8. package/dist/request-client/axios.js +6 -1
  9. package/dist/request-client/axios.js.map +1 -1
  10. package/dist/responses/collection/index.d.ts +1 -0
  11. package/dist/responses/collection/index.js +15 -0
  12. package/dist/responses/collection/index.js.map +1 -1
  13. package/dist/responses/collection/rarity.d.ts +1 -0
  14. package/example-web/react/package-lock.json +1504 -1470
  15. package/example-web/react2/package-lock.json +3089 -2766
  16. package/example-web/react2/package.json +6 -1
  17. package/example-web/react2/public/assets/gold_variant_icon.png +0 -0
  18. package/example-web/react2/public/assets/hot_cocoa_egg.png +0 -0
  19. package/example-web/react2/public/index.html +34 -31
  20. package/example-web/react2/src/App.tsx +15 -15
  21. package/example-web/react2/src/assets/guild_placeholder.png +0 -0
  22. package/example-web/react2/src/components/AchievementsComponent.tsx +74 -19
  23. package/example-web/react2/src/components/AutoSizer.tsx +49 -0
  24. package/example-web/react2/src/components/BoostsComponent.tsx +16 -5
  25. package/example-web/react2/src/components/BoothsComponent.tsx +22 -52
  26. package/example-web/react2/src/components/BoxesComponent.tsx +48 -16
  27. package/example-web/react2/src/components/BuffsComponent.tsx +82 -34
  28. package/example-web/react2/src/components/CharmsComponent.tsx +84 -24
  29. package/example-web/react2/src/components/CollectionConfigIndex.tsx +867 -33
  30. package/example-web/react2/src/components/CollectionsIndex.tsx +380 -27
  31. package/example-web/react2/src/components/CollectionsLayout.tsx +60 -0
  32. package/example-web/react2/src/components/CurrencyComponent.tsx +57 -39
  33. package/example-web/react2/src/components/DynamicCollectionConfigData.tsx +172 -15
  34. package/example-web/react2/src/components/EggsComponent.tsx +50 -12
  35. package/example-web/react2/src/components/EnchantsComponent.tsx +88 -42
  36. package/example-web/react2/src/components/FishingRodsComponent.tsx +36 -22
  37. package/example-web/react2/src/components/Footer.tsx +18 -8
  38. package/example-web/react2/src/components/FruitsComponent.tsx +40 -17
  39. package/example-web/react2/src/components/GenericFetchComponent.tsx +9 -1
  40. package/example-web/react2/src/components/GuildBattlesComponent.tsx +41 -34
  41. package/example-web/react2/src/components/Header.tsx +39 -52
  42. package/example-web/react2/src/components/HomePage.tsx +15 -17
  43. package/example-web/react2/src/components/HoverboardsComponent.tsx +23 -99
  44. package/example-web/react2/src/components/ImageComponent.tsx +255 -45
  45. package/example-web/react2/src/components/ItemCard.tsx +240 -0
  46. package/example-web/react2/src/components/LootboxesComponent.tsx +22 -7
  47. package/example-web/react2/src/components/MasteryComponent.tsx +165 -30
  48. package/example-web/react2/src/components/MerchantsComponent.tsx +41 -16
  49. package/example-web/react2/src/components/MiscItemsComponent.tsx +26 -31
  50. package/example-web/react2/src/components/PetsComponent.tsx +100 -61
  51. package/example-web/react2/src/components/PotionsComponent.tsx +121 -27
  52. package/example-web/react2/src/components/RandomEventsComponent.tsx +32 -23
  53. package/example-web/react2/src/components/RanksComponent.tsx +187 -62
  54. package/example-web/react2/src/components/RarityComponent.tsx +123 -5
  55. package/example-web/react2/src/components/ReactWindowMock.tsx +73 -0
  56. package/example-web/react2/src/components/RebirthsComponent.tsx +36 -19
  57. package/example-web/react2/src/components/SecretRoomsComponent.tsx +5 -4
  58. package/example-web/react2/src/components/SeedsComponent.tsx +41 -21
  59. package/example-web/react2/src/components/ShovelsComponent.tsx +21 -9
  60. package/example-web/react2/src/components/Sidebar.tsx +105 -0
  61. package/example-web/react2/src/components/SprinklersComponent.tsx +25 -10
  62. package/example-web/react2/src/components/Tooltip.tsx +36 -0
  63. package/example-web/react2/src/components/UltimatesComponent.tsx +28 -16
  64. package/example-web/react2/src/components/UpgradesComponent.tsx +97 -47
  65. package/example-web/react2/src/components/WateringCansComponent.tsx +20 -14
  66. package/example-web/react2/src/components/WorldsComponent.tsx +21 -11
  67. package/example-web/react2/src/components/XPPotionsComponent.tsx +28 -11
  68. package/example-web/react2/src/components/ZoneFlagsComponent.tsx +25 -14
  69. package/example-web/react2/src/components/ZonesComponent.tsx +43 -60
  70. package/example-web/react2/src/constants/collectionIcons.ts +29 -0
  71. package/example-web/react2/src/context/CollectionDataContext.tsx +62 -0
  72. package/example-web/react2/src/context/ScrollContext.tsx +35 -0
  73. package/example-web/react2/src/hooks/useCollapsibleHeader.ts +69 -0
  74. package/example-web/react2/src/hooks/useExpandableList.ts +38 -0
  75. package/example-web/react2/src/hooks/useItemResolution.ts +351 -0
  76. package/example-web/react2/src/index.css +257 -0
  77. package/example-web/react2/src/index.tsx +2 -1
  78. package/example-web/react2/src/utils/gigantix.ts +40 -0
  79. package/example-web/react2/temp_model.rbxm +0 -0
  80. package/example-web/react2/webpack.config.js +103 -47
  81. package/package.json +11 -11
  82. package/ranks.json +1 -0
  83. package/repro_collection_fetch.ts +33 -0
  84. package/repro_image_fetch.ts +50 -0
  85. package/src/__tests__/__snapshots__/ps99-api-changes.ts.snap +34841 -10439
  86. package/src/__tests__/__snapshots__/ps99-api-live.ts.snap +160667 -67217
  87. package/src/ps99-api.ts +9 -5
  88. package/src/request-client/axios.ts +6 -2
  89. package/src/responses/collection/index.ts +1 -0
  90. package/src/responses/collection/rarity.ts +1 -0
  91. package/tsconfig.json +1 -1
  92. package/example-web/react2/public/service-worker.js +0 -63
@@ -1,33 +1,386 @@
1
- import React, { useEffect, useState } from "react";
2
- import { Link } from "react-router-dom";
1
+ import React, { useEffect, useState, useRef } from "react";
2
+ import { Link, useNavigate } from "react-router-dom";
3
3
  import { PetSimulator99API, CollectionName } from "ps99-api";
4
+ import { COLLECTION_ICONS } from "../constants/collectionIcons";
5
+ import { FixedSizeGrid, FixedSizeList } from "./ReactWindowMock";
6
+ import AutoSizer from "./AutoSizer";
7
+ import { useScrollPersistence } from "../context/ScrollContext";
8
+ import { useCollapsibleHeader } from '../hooks/useCollapsibleHeader';
9
+
10
+ const FixedSizeGridAny = FixedSizeGrid;
11
+ const FixedSizeListAny = FixedSizeList;
12
+
13
+ // --- Grid Cell Renderer ---
14
+ const GridCellRenderer = ({ columnIndex, rowIndex, style, data }: any) => {
15
+ const { items, columnCount, navigate, GAP } = data;
16
+ const index = rowIndex * columnCount + columnIndex;
17
+ if (index >= items.length) return null;
18
+ const collection = items[index];
19
+ const icon = COLLECTION_ICONS[collection] || "📦";
20
+
21
+ return (
22
+ <div style={style}>
23
+ <div style={{
24
+ position: 'absolute',
25
+ top: GAP / 2,
26
+ left: GAP / 2,
27
+ right: GAP / 2,
28
+ bottom: GAP / 2,
29
+ }}>
30
+ <div
31
+ onClick={() => navigate(`/collections/${collection}`)}
32
+ style={{
33
+ display: "flex",
34
+ flexDirection: "column",
35
+ alignItems: "center",
36
+ justifyContent: "center",
37
+ backgroundColor: "#fff",
38
+ borderRadius: "24px",
39
+ cursor: "pointer",
40
+ height: "100%",
41
+ border: "4px solid #333",
42
+ boxShadow: "0 6px 0 #ccc",
43
+ transition: "transform 0.1s ease, box-shadow 0.1s ease",
44
+ }}
45
+ onMouseEnter={(e) => {
46
+ e.currentTarget.style.transform = "translateY(4px)";
47
+ e.currentTarget.style.boxShadow = "0 2px 0 #ccc";
48
+ }}
49
+ onMouseLeave={(e) => {
50
+ e.currentTarget.style.transform = "translateY(0)";
51
+ e.currentTarget.style.boxShadow = "0 6px 0 #ccc";
52
+ }}
53
+ >
54
+ <span style={{ fontSize: "3rem", marginBottom: "8px" }}>
55
+ {icon}
56
+ </span>
57
+ <span style={{
58
+ fontSize: "1.2rem",
59
+ fontWeight: "900",
60
+ color: "#333",
61
+ textAlign: "center",
62
+ fontFamily: "'Fredoka One', cursive, sans-serif",
63
+ }}>
64
+ {collection}
65
+ </span>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ );
70
+ };
71
+
72
+ // --- List Row Renderer ---
73
+ const ListRowRenderer = ({ index, style, data }: any) => {
74
+ const { items, navigate } = data;
75
+ const collection = items[index];
76
+ const icon = COLLECTION_ICONS[collection] || "📦";
77
+
78
+ return (
79
+ <div style={{ ...style, padding: "5px 10px", boxSizing: "border-box" }}>
80
+ <div
81
+ onClick={() => navigate(`/collections/${collection}`)}
82
+ style={{
83
+ display: "flex",
84
+ alignItems: "center",
85
+ backgroundColor: "#f9f9f9",
86
+ borderRadius: "12px",
87
+ padding: "8px 15px",
88
+ height: "calc(100% - 10px)",
89
+ cursor: "pointer",
90
+ border: `2px solid #e0e0e0`,
91
+ boxShadow: "0 2px 5px rgba(0,0,0,0.05)",
92
+ borderLeft: `6px solid #333`, // Accent color
93
+ transition: "transform 0.1s active",
94
+ }}
95
+ onMouseDown={(e) => e.currentTarget.style.transform = "scale(0.98)"}
96
+ onMouseUp={(e) => e.currentTarget.style.transform = "scale(1)"}
97
+ onMouseLeave={(e) => e.currentTarget.style.transform = "scale(1)"}
98
+ >
99
+ <div style={{
100
+ width: "48px",
101
+ height: "48px",
102
+ marginRight: "15px",
103
+ flexShrink: 0,
104
+ borderRadius: "8px",
105
+ backgroundColor: "#fff",
106
+ border: "1px solid #eee",
107
+ display: "flex", alignItems: "center", justifyContent: "center",
108
+ fontSize: "1.8rem"
109
+ }}>
110
+ {icon}
111
+ </div>
112
+
113
+ <div style={{ flex: 1, overflow: "hidden" }}>
114
+ <div style={{
115
+ fontSize: "1.1rem",
116
+ fontWeight: "700",
117
+ color: "#333",
118
+ whiteSpace: "nowrap",
119
+ overflow: "hidden",
120
+ textOverflow: "ellipsis",
121
+ fontFamily: "'Fredoka One', cursive, sans-serif",
122
+ }}>
123
+ {collection}
124
+ </div>
125
+ </div>
126
+
127
+ <div style={{ marginLeft: "10px", color: "#ccc", fontWeight: "bold", fontSize: "1.2rem" }}>
128
+
129
+ </div>
130
+ </div>
131
+ </div>
132
+ );
133
+ };
4
134
 
5
135
  const CollectionsIndex: React.FC = () => {
6
- const [collections, setCollections] = useState<CollectionName[]>([]);
7
-
8
- useEffect(() => {
9
- const fetchCollections = async () => {
10
- const api = new PetSimulator99API();
11
- const response = await api.getCollections();
12
- if (response.status === "ok") {
13
- setCollections(response.data);
14
- }
15
- };
16
- fetchCollections();
17
- }, []);
18
-
19
- return (
20
- <div>
21
- <h2>Collections</h2>
22
- <ul>
23
- {collections.map((collection, index) => (
24
- <li key={index}>
25
- <Link to={`/collections/${collection}`}>{collection}</Link>
26
- </li>
27
- ))}
28
- </ul>
29
- </div>
30
- );
136
+ const navigate = useNavigate();
137
+ const [collections, setCollections] = useState<CollectionName[]>([]);
138
+ const [searchTerm, setSearchTerm] = useState("");
139
+ const [windowWidth, setWindowWidth] = useState(window.innerWidth);
140
+ const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
141
+ const { showHeader, handleScroll, scrollRef, headerRef, headerHeight, contentPadding } = useCollapsibleHeader({ deps: [collections] });
142
+
143
+ useEffect(() => {
144
+ const fetchCollections = async () => {
145
+ const api = new PetSimulator99API();
146
+ const response = await api.getCollections();
147
+ if (response.status === "ok") {
148
+ setCollections(response.data);
149
+ }
150
+ };
151
+ fetchCollections();
152
+ }, []);
153
+
154
+ useEffect(() => {
155
+ const handleResize = () => setWindowWidth(window.innerWidth);
156
+ window.addEventListener("resize", handleResize);
157
+ return () => window.removeEventListener("resize", handleResize);
158
+ }, []);
159
+
160
+ const isMobile = windowWidth < 768;
161
+
162
+ // Scroll Persistence
163
+ const { saveScrollPosition, getScrollPosition } = useScrollPersistence();
164
+ const scrollKey = `collections_index_${viewMode}`;
165
+ // const scrollRef = useRef<number>(0); // Removed duplicate definition
166
+ const initialScrollOffset = getScrollPosition(scrollKey);
167
+
168
+ // Save on unmount or key change
169
+ useEffect(() => {
170
+ return () => {
171
+ saveScrollPosition(scrollKey, scrollRef.current);
172
+ };
173
+ }, [saveScrollPosition, scrollKey]);
174
+
175
+ useEffect(() => {
176
+ if (isMobile) {
177
+ setViewMode('list');
178
+ } else {
179
+ setViewMode('grid');
180
+ }
181
+ }, [isMobile]);
182
+
183
+ const filteredCollections = collections.filter(c =>
184
+ c.toLowerCase().includes(searchTerm.toLowerCase())
185
+ );
186
+
187
+ if (collections.length === 0) {
188
+ return (
189
+ <div style={{
190
+ display: "flex",
191
+ justifyContent: "center",
192
+ alignItems: "center",
193
+ height: "100vh",
194
+ fontSize: "1.5rem",
195
+ fontWeight: "bold",
196
+ color: "#333"
197
+ }}>
198
+ Loading Collections...
199
+ </div>
200
+ );
201
+ }
202
+
203
+ return (
204
+ <div style={{
205
+ display: "flex",
206
+ justifyContent: "center",
207
+ alignItems: "center",
208
+ minHeight: isMobile ? "100vh" : "calc(100vh - 140px)",
209
+ padding: isMobile ? "0" : "20px",
210
+ }}>
211
+ <div style={{
212
+ width: "100%",
213
+ maxWidth: "1200px",
214
+ height: isMobile ? "100vh" : "80vh",
215
+ backgroundColor: "#fff",
216
+ borderRadius: isMobile ? "0" : "24px",
217
+ boxShadow: isMobile ? "none" : "0 10px 40px rgba(0,0,0,0.2)",
218
+ overflow: "hidden",
219
+ position: "relative",
220
+ border: isMobile ? "none" : "4px solid #333",
221
+ display: "flex",
222
+ flexDirection: "column",
223
+ }}>
224
+ {/* Header */}
225
+ <div
226
+ ref={headerRef}
227
+ style={{
228
+ padding: isMobile ? "10px 15px" : "15px 20px",
229
+ borderBottom: "4px solid #333",
230
+ display: "flex",
231
+ flexDirection: "column",
232
+ gap: isMobile ? "10px" : "0px",
233
+ backgroundColor: "#fff",
234
+ position: "absolute", // Changed to absolute for hiding
235
+ top: 0,
236
+ left: 0,
237
+ right: 0,
238
+ zIndex: 10,
239
+ transition: "transform 0.3s ease-in-out",
240
+ transform: showHeader ? "translateY(0)" : "translateY(-100%)",
241
+ }}>
242
+ <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }}>
243
+ <h2 style={{
244
+ margin: 0,
245
+ fontSize: isMobile ? "2rem" : "2.5rem",
246
+ fontWeight: "900",
247
+ color: "#333",
248
+ textShadow: isMobile ? "1px 1px 0px #eee" : "3px 3px 0px #eee",
249
+ fontFamily: "'Fredoka One', cursive, sans-serif",
250
+ letterSpacing: "1px",
251
+ }}>
252
+ Collections
253
+ </h2>
254
+
255
+ {!isMobile && (
256
+ <div style={{ position: "relative", margin: "0 20px", flex: 1, display: "flex", justifyContent: "flex-end" }}>
257
+ <input
258
+ type="text"
259
+ placeholder="Search"
260
+ value={searchTerm}
261
+ onChange={(e) => setSearchTerm(e.target.value)}
262
+ style={{
263
+ padding: "10px 20px",
264
+ borderRadius: "50px",
265
+ border: "3px solid #ccc",
266
+ outline: "none",
267
+ fontSize: "1.2rem",
268
+ width: "100%",
269
+ maxWidth: "400px",
270
+ fontWeight: "800",
271
+ backgroundColor: "#f9f9f9",
272
+ color: "#333",
273
+ }}
274
+ />
275
+ </div>
276
+ )}
277
+
278
+ <button
279
+ onClick={() => navigate("/")}
280
+ style={{
281
+ width: isMobile ? "40px" : "48px",
282
+ height: isMobile ? "40px" : "48px",
283
+ borderRadius: "12px",
284
+ backgroundColor: "#ff0055",
285
+ color: "white",
286
+ border: isMobile ? "3px solid #900" : "4px solid #900",
287
+ fontSize: "20px",
288
+ fontWeight: "900",
289
+ display: "flex",
290
+ alignItems: "center",
291
+ justifyContent: "center",
292
+ cursor: "pointer",
293
+ boxShadow: "inset 0 4px 4px rgba(255,255,255,0.4), 0 4px 0 #500",
294
+ textShadow: "2px 2px 0 #900",
295
+ marginLeft: isMobile ? "0" : "20px"
296
+ }}
297
+ >
298
+ X
299
+ </button>
300
+ </div>
301
+
302
+ {isMobile && (
303
+ <div style={{ width: "100%" }}>
304
+ <input
305
+ type="text"
306
+ placeholder="Search Collections..."
307
+ value={searchTerm}
308
+ onChange={(e) => setSearchTerm(e.target.value)}
309
+ style={{
310
+ padding: "10px 15px",
311
+ borderRadius: "12px",
312
+ border: "3px solid #ccc",
313
+ outline: "none",
314
+ fontSize: "1rem",
315
+ width: "100%",
316
+ fontWeight: "700",
317
+ backgroundColor: "#f5f5f5",
318
+ color: "#333",
319
+ boxSizing: "border-box"
320
+ }}
321
+ />
322
+ </div>
323
+ )}
324
+ </div>
325
+ {/* Content */}
326
+ <div style={{ height: "100%", width: "100%", flex: 1, paddingTop: isMobile ? contentPadding : "0px", transition: "padding-top 0.3s ease-in-out" }}>
327
+ {/* @ts-ignore */}
328
+ <AutoSizer style={{ width: "100%", height: "100%" }} renderProp={({ height, width }: { height: number, width: number }) => {
329
+ const GAP = 20;
330
+
331
+ if (viewMode === 'list') {
332
+ return (
333
+ <FixedSizeListAny
334
+ height={height}
335
+ itemCount={filteredCollections.length}
336
+ itemSize={80}
337
+ width={width}
338
+ initialScrollOffset={initialScrollOffset}
339
+ onScroll={handleScroll}
340
+ itemData={{
341
+ items: filteredCollections,
342
+ navigate
343
+ }}
344
+ >
345
+ {ListRowRenderer}
346
+ </FixedSizeListAny>
347
+ );
348
+ } else {
349
+ // Grid Mode
350
+ const MIN_COL_WIDTH = 180;
351
+ const SCROLLBAR_WIDTH = 40;
352
+ const effectiveWidth = width - SCROLLBAR_WIDTH;
353
+ const columnCount = Math.floor(effectiveWidth / MIN_COL_WIDTH) || 1;
354
+ const columnWidth = effectiveWidth / columnCount;
355
+ const rowHeight = 220; // Aspect ratio ~1:1 plus padding
356
+ const rowCount = Math.ceil(filteredCollections.length / columnCount);
357
+
358
+ return (
359
+ <FixedSizeGridAny
360
+ columnCount={columnCount}
361
+ columnWidth={columnWidth}
362
+ height={height}
363
+ rowCount={rowCount}
364
+ rowHeight={rowHeight}
365
+ width={width}
366
+ initialScrollOffset={initialScrollOffset}
367
+ onScroll={handleScroll}
368
+ itemData={{
369
+ items: filteredCollections,
370
+ columnCount,
371
+ navigate,
372
+ GAP
373
+ }}
374
+ >
375
+ {GridCellRenderer}
376
+ </FixedSizeGridAny>
377
+ );
378
+ }
379
+ }} />
380
+ </div>
381
+ </div>
382
+ </div>
383
+ );
31
384
  };
32
385
 
33
386
  export default CollectionsIndex;
@@ -0,0 +1,60 @@
1
+ import React from "react";
2
+ import { Outlet } from "react-router-dom";
3
+ // import Sidebar from "./Sidebar"; // REMOVED per user request
4
+ import { useParams } from "react-router-dom";
5
+ import { CollectionDataProvider } from "../context/CollectionDataContext";
6
+
7
+ const CollectionsLayout: React.FC = () => {
8
+ const { collectionName } = useParams<{ collectionName: string }>();
9
+
10
+ const [isMobile, setIsMobile] = React.useState(window.innerWidth < 768);
11
+
12
+ React.useEffect(() => {
13
+ const handleResize = () => setIsMobile(window.innerWidth < 768);
14
+ window.addEventListener("resize", handleResize);
15
+ return () => window.removeEventListener("resize", handleResize);
16
+ }, []);
17
+
18
+ return (
19
+ <div
20
+ style={{
21
+ display: "flex",
22
+ justifyContent: "center",
23
+ alignItems: "center",
24
+ minHeight: isMobile ? "100vh" : "calc(100vh - 80px)",
25
+ padding: isMobile ? "0" : "10px",
26
+ height: "100%",
27
+ boxSizing: "border-box"
28
+ }}
29
+ >
30
+ <CollectionDataProvider>
31
+ {/* Main Window Container - Lifted from CollectionConfigIndex */}
32
+ <div
33
+ style={{
34
+ display: "flex",
35
+ width: "100%",
36
+ maxWidth: "1200px",
37
+ height: isMobile ? "100vh" : "85vh",
38
+ backgroundColor: "#fff",
39
+ borderRadius: isMobile ? "0" : "16px",
40
+ boxShadow: isMobile ? "none" : "0 10px 40px rgba(0,0,0,0.2)",
41
+ overflow: "hidden",
42
+ position: "relative",
43
+ border: isMobile ? "none" : "3px solid #333",
44
+ flexDirection: "column"
45
+ }}
46
+ >
47
+ {/* Persistent Sidebar REMOVED */}
48
+ {/* <Sidebar currentCollection={collectionName} /> */}
49
+
50
+ {/* Content Area */}
51
+ <div style={{ flex: 1, overflow: "hidden", display: "flex", flexDirection: "column" }}>
52
+ <Outlet />
53
+ </div>
54
+ </div>
55
+ </CollectionDataProvider>
56
+ </div>
57
+ );
58
+ };
59
+
60
+ export default CollectionsLayout;
@@ -1,58 +1,76 @@
1
1
  import React from "react";
2
2
  import { CollectionConfigData } from "ps99-api";
3
- import ImageComponent from "./ImageComponent";
3
+ import ItemCard from "./ItemCard";
4
+
5
+ import { formatGigantix } from "../utils/gigantix";
4
6
 
5
7
  const CurrencyComponent: React.FC<{
6
8
  configData: CollectionConfigData<"Currency">;
7
9
  }> = ({ configData }) => {
8
10
  return (
9
- <div>
10
- <h2>{configData.DisplayName}</h2>
11
- <p>Description: {configData.Desc}</p>
12
- <p>Max Amount: {configData.MaxAmount}</p>
13
- <p>Rarity: {configData.Rarity.DisplayName}</p>
14
- <p>Rarity Number: {configData.Rarity.RarityNumber}</p>
15
- {configData.Tradable && <p>Tradable: Yes</p>}
16
- {configData.IsWorldCurrency && <p>World Currency: Yes</p>}
17
- {configData.PermitAutoLootScaling && <p>Permit Auto Loot Scaling: Yes</p>}
18
- <h3>Tiers:</h3>
19
- <ul>
20
- {configData.Tiers.map((tier, index) => (
21
- <li key={index}>
22
- <ImageComponent src={tier.orbImage} alt={tier.tierName} />
23
- <p>Tier Name: {tier.tierName}</p>
24
- <p>Order: {tier.Order}</p>
25
- <p>Value: {tier.value}</p>
26
- <ImageComponent
27
- src={tier.imageOutline}
28
- alt={`${tier.tierName} outline`}
29
- />
30
- {tier.isBottom && <p>Is Bottom: Yes</p>}
31
- <ImageComponent
32
- src={tier.tinyImage}
33
- alt={`${tier.tierName} tiny`}
34
- />
35
- </li>
36
- ))}
37
- </ul>
11
+
12
+ <div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
13
+
14
+ <div style={{ marginBottom: '20px', textAlign: 'center' }}>
15
+ <p style={{ fontStyle: 'italic', marginBottom: '10px' }}>{configData.Desc}</p>
16
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', justifyContent: 'center' }}>
17
+ <span className="badge">Max: {formatGigantix(configData.MaxAmount)}</span>
18
+ {configData.Rarity && <span className="badge" style={{ borderColor: (configData.Rarity.Color as string) }}>Rarity: {configData.Rarity.DisplayName}</span>}
19
+ {configData.Tradable && <span className="badge">Tradable</span>}
20
+ {configData.IsWorldCurrency && <span className="badge">World Currency</span>}
21
+ {configData.PermitAutoLootScaling && <span className="badge">Auto Loot</span>}
22
+ </div>
23
+ </div>
24
+
25
+ <div style={{ marginBottom: '20px' }}>
26
+ <h3 style={{ fontSize: '1.2em', borderBottom: '1px solid #eee', paddingBottom: '5px' }}>Tiers</h3>
27
+ <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))", gap: "10px", marginTop: '15px' }}>
28
+ {configData.Tiers.map((tier, index) => (
29
+ <div key={index}>
30
+ <ItemCard
31
+ id={tier.tierName}
32
+ amount={tier.value}
33
+ label={tier.tierName}
34
+ itemData={{
35
+ icon: tier.orbImage,
36
+ rarity: configData.Rarity,
37
+ name: tier.tierName
38
+ }}
39
+ rarityColor={(configData.Rarity?.Color as string) || null}
40
+ />
41
+ <div style={{ textAlign: 'center', fontSize: '0.8em', color: '#666', marginTop: '4px' }}>
42
+ Order: {tier.Order}
43
+ </div>
44
+ </div>
45
+ ))}
46
+ </div>
47
+ </div>
48
+
38
49
  {configData.BagTiers && (
39
50
  <div>
40
- <h3>Bag Tiers:</h3>
41
- <ul>
51
+ <h3 style={{ fontSize: '1.2em', borderBottom: '1px solid #eee', paddingBottom: '5px' }}>Bag Tiers</h3>
52
+ <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))", gap: "10px", marginTop: '15px' }}>
42
53
  {configData.BagTiers.map((bagTier, index) => (
43
- <li key={index}>
44
- <ImageComponent
45
- src={bagTier.image}
46
- alt={`Bag tier ${index + 1}`}
54
+ <div key={index}>
55
+ <ItemCard
56
+ id={`bag-tier-${index}`}
57
+ amount={bagTier.value}
58
+ label={`Bag Tier ${index + 1}`}
59
+ itemData={{
60
+ icon: bagTier.image,
61
+ rarity: configData.Rarity,
62
+ name: `Bag Tier ${index + 1}`
63
+ }}
64
+ rarityColor={(configData.Rarity?.Color as string) || null}
47
65
  />
48
- <p>Value: {bagTier.value}</p>
49
- </li>
66
+ </div>
50
67
  ))}
51
- </ul>
68
+ </div>
52
69
  </div>
53
70
  )}
54
71
  </div>
55
72
  );
56
73
  };
57
74
 
75
+
58
76
  export default CurrencyComponent;