ps99-api 2.3.3 → 2.5.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.
- package/.github/workflows/release-on-main.yml +1 -2
- package/.idea/node-ps99-api.iml +1 -0
- package/.idea/runConfigurations/test_changing.xml +1 -1
- package/README.md +1 -1
- package/debug_currency.json +57 -0
- package/debug_goals.json +271 -0
- package/dist/ps99-api.d.ts +2 -0
- package/dist/ps99-api.js +4 -1
- package/dist/ps99-api.js.map +1 -1
- package/dist/request-client/axios.js +6 -1
- package/dist/request-client/axios.js.map +1 -1
- package/dist/responses/collection/achievement.d.ts +2 -0
- package/dist/responses/collection/guild-battle.d.ts +2 -4
- package/dist/responses/collection/index.d.ts +1 -0
- package/dist/responses/collection/index.js +15 -0
- package/dist/responses/collection/index.js.map +1 -1
- package/dist/responses/collection/rank.d.ts +1 -0
- package/dist/responses/collection/rarity.d.ts +1 -0
- package/dist/responses/collection/seed.d.ts +1 -0
- package/dist/responses/exists.d.ts +2 -0
- package/example-web/react/package-lock.json +1504 -1470
- package/example-web/react2/package-lock.json +3082 -2759
- package/example-web/react2/package.json +6 -1
- package/example-web/react2/public/assets/gold_variant_icon.png +0 -0
- package/example-web/react2/public/assets/hot_cocoa_egg.png +0 -0
- package/example-web/react2/public/index.html +34 -31
- package/example-web/react2/src/App.tsx +6 -9
- package/example-web/react2/src/assets/guild_placeholder.png +0 -0
- package/example-web/react2/src/components/AchievementsComponent.tsx +78 -30
- package/example-web/react2/src/components/BoostsComponent.tsx +18 -14
- package/example-web/react2/src/components/BoothsComponent.tsx +24 -22
- package/example-web/react2/src/components/BoxesComponent.tsx +46 -21
- package/example-web/react2/src/components/BuffsComponent.tsx +83 -13
- package/example-web/react2/src/components/CharmsComponent.tsx +47 -29
- package/example-web/react2/src/components/CollectionConfigIndex.tsx +398 -35
- package/example-web/react2/src/components/CollectionsIndex.tsx +132 -23
- package/example-web/react2/src/components/CollectionsLayout.tsx +50 -0
- package/example-web/react2/src/components/CurrencyComponent.tsx +59 -50
- package/example-web/react2/src/components/DynamicCollectionConfigData.tsx +178 -11
- package/example-web/react2/src/components/EggsComponent.tsx +77 -44
- package/example-web/react2/src/components/EnchantsComponent.tsx +84 -34
- package/example-web/react2/src/components/FishingRodsComponent.tsx +38 -31
- package/example-web/react2/src/components/Footer.tsx +75 -18
- package/example-web/react2/src/components/FruitsComponent.tsx +41 -25
- package/example-web/react2/src/components/GenericFetchComponent.tsx +40 -22
- package/example-web/react2/src/components/GuildBattlesComponent.tsx +93 -65
- package/example-web/react2/src/components/Header.tsx +5 -37
- package/example-web/react2/src/components/HomePage.tsx +16 -16
- package/example-web/react2/src/components/HoverboardsComponent.tsx +25 -37
- package/example-web/react2/src/components/ImageComponent.tsx +255 -45
- package/example-web/react2/src/components/ItemCard.tsx +240 -0
- package/example-web/react2/src/components/LootboxesComponent.tsx +24 -16
- package/example-web/react2/src/components/MasteryComponent.tsx +93 -37
- package/example-web/react2/src/components/MerchantsComponent.tsx +46 -28
- package/example-web/react2/src/components/MiscItemsComponent.tsx +28 -26
- package/example-web/react2/src/components/PetsComponent.tsx +115 -46
- package/example-web/react2/src/components/PotionsComponent.tsx +53 -36
- package/example-web/react2/src/components/RandomEventsComponent.tsx +39 -35
- package/example-web/react2/src/components/RanksComponent.tsx +187 -71
- package/example-web/react2/src/components/RarityComponent.tsx +124 -13
- package/example-web/react2/src/components/RebirthsComponent.tsx +37 -26
- package/example-web/react2/src/components/SecretRoomsComponent.tsx +7 -13
- package/example-web/react2/src/components/SeedsComponent.tsx +45 -32
- package/example-web/react2/src/components/ShovelsComponent.tsx +23 -18
- package/example-web/react2/src/components/Sidebar.tsx +105 -0
- package/example-web/react2/src/components/SprinklersComponent.tsx +27 -19
- package/example-web/react2/src/components/Tooltip.tsx +36 -0
- package/example-web/react2/src/components/UltimatesComponent.tsx +29 -24
- package/example-web/react2/src/components/UpgradesComponent.tsx +99 -55
- package/example-web/react2/src/components/WateringCansComponent.tsx +23 -21
- package/example-web/react2/src/components/WorldsComponent.tsx +27 -24
- package/example-web/react2/src/components/XPPotionsComponent.tsx +29 -19
- package/example-web/react2/src/components/ZoneFlagsComponent.tsx +27 -23
- package/example-web/react2/src/components/ZonesComponent.tsx +56 -73
- package/example-web/react2/src/constants/collectionIcons.ts +29 -0
- package/example-web/react2/src/context/CollectionDataContext.tsx +62 -0
- package/example-web/react2/src/hooks/useExpandableList.ts +38 -0
- package/example-web/react2/src/hooks/useItemResolution.ts +351 -0
- package/example-web/react2/src/index.css +257 -0
- package/example-web/react2/src/index.tsx +2 -1
- package/example-web/react2/temp_model.rbxm +0 -0
- package/example-web/react2/webpack.config.js +103 -47
- package/package.json +11 -11
- package/ranks.json +1 -0
- package/repro_collection_fetch.ts +33 -0
- package/repro_image_fetch.ts +50 -0
- package/src/__tests__/__snapshots__/ps99-api-changes.ts.snap +34841 -10439
- package/src/__tests__/__snapshots__/ps99-api-live.ts.snap +160667 -67217
- package/src/ps99-api.ts +9 -5
- package/src/request-client/axios.ts +6 -2
- package/src/responses/collection/achievement.ts +2 -0
- package/src/responses/collection/guild-battle.ts +2 -4
- package/src/responses/collection/index.ts +1 -0
- package/src/responses/collection/rank.ts +1 -0
- package/src/responses/collection/rarity.ts +1 -0
- package/src/responses/collection/seed.ts +1 -0
- package/src/responses/exists.ts +2 -0
- package/tsconfig.json +1 -1
- package/example-web/react2/public/service-worker.js +0 -63
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
RawStackKey,
|
|
7
7
|
LootTableData,
|
|
8
8
|
} from "ps99-api";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import ItemCard from "./ItemCard";
|
|
10
|
+
import { useItemResolution } from "../hooks/useItemResolution";
|
|
11
11
|
|
|
12
12
|
const parseRawStackKey = (rawStackKey: RawStackKey): LootTableData => {
|
|
13
13
|
try {
|
|
@@ -21,21 +21,25 @@ const parseRawStackKey = (rawStackKey: RawStackKey): LootTableData => {
|
|
|
21
21
|
const renderLootTable = (lootTable: LootTableRoot | LootTableRoot[]) => {
|
|
22
22
|
const lootTableArray = Array.isArray(lootTable) ? lootTable : [lootTable];
|
|
23
23
|
return lootTableArray.map((table, index) => (
|
|
24
|
-
<div key={index}>
|
|
24
|
+
<div key={index} style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '10px' }}>
|
|
25
25
|
{table.entries.map((entry: LootTableEntry, entryIndex: number) => {
|
|
26
26
|
const parsedStackKey = entry.Value._stackKey
|
|
27
27
|
? parseRawStackKey(entry.Value._stackKey)
|
|
28
28
|
: null;
|
|
29
29
|
return (
|
|
30
|
-
<div key={entryIndex}>
|
|
31
|
-
<
|
|
32
|
-
|
|
30
|
+
<div key={entryIndex} style={{ padding: '10px', border: '1px solid #eee', borderRadius: '8px', background: '#f9f9f9', textAlign: 'left' }}>
|
|
31
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '5px' }}>
|
|
32
|
+
<span style={{ fontWeight: 'bold', fontSize: '0.9em' }}>Entry {entryIndex + 1}</span>
|
|
33
|
+
<span className="badge">Weight: {entry.Weight}</span>
|
|
34
|
+
</div>
|
|
33
35
|
{parsedStackKey && (
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
<div style={{ fontSize: '0.85em', color: '#555' }}>
|
|
37
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
|
38
|
+
<span>ID: <strong>{parsedStackKey.id}</strong></span>
|
|
39
|
+
</div>
|
|
40
|
+
{parsedStackKey.tn && <div>Tier/TN: {parsedStackKey.tn}</div>}
|
|
41
|
+
{parsedStackKey._am && <div>Amount: {parsedStackKey._am}</div>}
|
|
42
|
+
</div>
|
|
39
43
|
)}
|
|
40
44
|
</div>
|
|
41
45
|
);
|
|
@@ -45,29 +49,38 @@ const renderLootTable = (lootTable: LootTableRoot | LootTableRoot[]) => {
|
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
const SeedComponent: React.FC<{
|
|
48
|
-
configData
|
|
52
|
+
configData: CollectionConfigData<"Seeds">;
|
|
49
53
|
}> = ({ configData }) => {
|
|
54
|
+
const { getRarityColor } = useItemResolution();
|
|
55
|
+
const rarityColor = configData.Rarity ? getRarityColor(configData.Rarity) : null;
|
|
56
|
+
|
|
50
57
|
return (
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
</
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
59
|
+
|
|
60
|
+
<div style={{ maxWidth: '300px', margin: '0 auto 15px auto' }}>
|
|
61
|
+
<ItemCard
|
|
62
|
+
id={configData.DisplayName}
|
|
63
|
+
amount={1}
|
|
64
|
+
label={configData.DisplayName}
|
|
65
|
+
itemData={{
|
|
66
|
+
icon: configData.Icon,
|
|
67
|
+
rarity: configData.Rarity,
|
|
68
|
+
name: configData.DisplayName
|
|
69
|
+
}}
|
|
70
|
+
rarityColor={rarityColor}
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div style={{ marginBottom: '20px', fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
75
|
+
<p>{configData.Desc}</p>
|
|
76
|
+
<p style={{ fontWeight: 'bold', marginTop: '5px' }}>Grow Time: {configData.GrowTime}s</p>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div style={{ borderTop: '1px solid #eee', paddingTop: '15px' }}>
|
|
80
|
+
<h3 style={{ textAlign: 'center', fontSize: '1.2em', marginBottom: '15px' }}>Loot Table</h3>
|
|
81
|
+
{renderLootTable(configData.LootTable)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
71
84
|
);
|
|
72
85
|
};
|
|
73
86
|
|
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import
|
|
4
|
-
import ImageComponent from "./ImageComponent";
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
5
4
|
|
|
6
5
|
const ShovelComponent: React.FC<{
|
|
7
|
-
configData
|
|
6
|
+
configData: CollectionConfigData<"Shovels">;
|
|
8
7
|
}> = ({ configData }) => {
|
|
9
8
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
10
|
+
|
|
11
|
+
<div style={{ maxWidth: '300px', margin: '0 auto 15px auto' }}>
|
|
12
|
+
<ItemCard
|
|
13
|
+
id={configData.DisplayName}
|
|
14
|
+
amount={1}
|
|
15
|
+
label={configData.DisplayName}
|
|
16
|
+
itemData={{
|
|
17
|
+
icon: configData.Icon,
|
|
18
|
+
rarity: undefined,
|
|
19
|
+
name: configData.DisplayName
|
|
20
|
+
}}
|
|
21
|
+
rarityColor={null}
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div style={{ fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
26
|
+
<p>{configData.Desc}</p>
|
|
27
|
+
{configData.MerchantSalePrice && <p style={{ marginTop: '10px' }}><strong>Sale Price:</strong> {configData.MerchantSalePrice}</p>}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
25
30
|
);
|
|
26
31
|
};
|
|
27
32
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { Link, useParams } from "react-router-dom";
|
|
3
|
+
import { PetSimulator99API, CollectionName } from "ps99-api";
|
|
4
|
+
|
|
5
|
+
import { COLLECTION_ICONS } from "../constants/collectionIcons";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
interface SidebarProps {
|
|
9
|
+
currentCollection?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const Sidebar: React.FC<SidebarProps> = ({ currentCollection }) => {
|
|
13
|
+
const [collections, setCollections] = useState<CollectionName[]>([]);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const fetchCollections = async () => {
|
|
17
|
+
const api = new PetSimulator99API();
|
|
18
|
+
const response = await api.getCollections();
|
|
19
|
+
if (response.status === "ok") {
|
|
20
|
+
// Filter out collections that might not have icons or just to keep it clean if needed
|
|
21
|
+
setCollections(response.data);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
fetchCollections();
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div style={{
|
|
29
|
+
width: "260px",
|
|
30
|
+
backgroundColor: "#fff",
|
|
31
|
+
borderRight: "4px solid #333",
|
|
32
|
+
display: "flex",
|
|
33
|
+
flexDirection: "column",
|
|
34
|
+
padding: "15px",
|
|
35
|
+
gap: "10px",
|
|
36
|
+
flexShrink: 0,
|
|
37
|
+
overflowY: "auto",
|
|
38
|
+
maxHeight: "100%",
|
|
39
|
+
}}>
|
|
40
|
+
<h3 style={{
|
|
41
|
+
textAlign: "center",
|
|
42
|
+
marginBottom: "15px",
|
|
43
|
+
color: "#333",
|
|
44
|
+
fontSize: "1.5rem",
|
|
45
|
+
fontWeight: "900",
|
|
46
|
+
textShadow: "2px 2px 0px #eee",
|
|
47
|
+
fontFamily: "'Fredoka One', cursive, sans-serif", // Assuming font availability or fallback
|
|
48
|
+
}}>
|
|
49
|
+
Terminal!
|
|
50
|
+
</h3>
|
|
51
|
+
|
|
52
|
+
<div style={{
|
|
53
|
+
display: "grid",
|
|
54
|
+
gridTemplateColumns: "1fr 1fr",
|
|
55
|
+
gap: "10px",
|
|
56
|
+
}}>
|
|
57
|
+
{collections.map((collection) => {
|
|
58
|
+
const isActive = currentCollection === collection;
|
|
59
|
+
const icon = COLLECTION_ICONS[collection] || "📦";
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Link
|
|
63
|
+
key={collection}
|
|
64
|
+
to={`/collections/${collection}`}
|
|
65
|
+
style={{
|
|
66
|
+
display: "flex",
|
|
67
|
+
flexDirection: "column",
|
|
68
|
+
alignItems: "center",
|
|
69
|
+
justifyContent: "center",
|
|
70
|
+
aspectRatio: "1/1",
|
|
71
|
+
backgroundColor: isActive ? "#00b894" : "#dfe6e9",
|
|
72
|
+
borderRadius: "16px",
|
|
73
|
+
textDecoration: "none",
|
|
74
|
+
color: isActive ? "#fff" : "#2d3436",
|
|
75
|
+
border: "3px solid #333",
|
|
76
|
+
boxShadow: isActive ? "inset 0 -4px 0 rgba(0,0,0,0.2)" : "0 4px 0 #b2bec3",
|
|
77
|
+
transition: "all 0.1s ease",
|
|
78
|
+
transform: isActive ? "translateY(2px)" : "translateY(0)",
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
<span style={{
|
|
82
|
+
fontSize: "2rem",
|
|
83
|
+
marginBottom: "4px",
|
|
84
|
+
filter: isActive ? "drop-shadow(0 2px 0 rgba(0,0,0,0.2))" : "none"
|
|
85
|
+
}}>
|
|
86
|
+
{icon}
|
|
87
|
+
</span>
|
|
88
|
+
<span style={{
|
|
89
|
+
fontSize: "0.8rem",
|
|
90
|
+
fontWeight: "800",
|
|
91
|
+
textAlign: "center",
|
|
92
|
+
lineHeight: "1.1",
|
|
93
|
+
textShadow: isActive ? "1px 1px 0 rgba(0,0,0,0.2)" : "none"
|
|
94
|
+
}}>
|
|
95
|
+
{collection}
|
|
96
|
+
</span>
|
|
97
|
+
</Link>
|
|
98
|
+
);
|
|
99
|
+
})}
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export default Sidebar;
|
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
4
|
+
import { useItemResolution } from "../hooks/useItemResolution";
|
|
5
5
|
|
|
6
6
|
const SprinklerComponent: React.FC<{
|
|
7
|
-
configData
|
|
7
|
+
configData: CollectionConfigData<"Sprinklers">;
|
|
8
8
|
}> = ({ configData }) => {
|
|
9
|
+
const { getRarityColor } = useItemResolution();
|
|
10
|
+
const rarityColor = configData.Rarity ? getRarityColor(configData.Rarity) : null;
|
|
11
|
+
|
|
9
12
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
14
|
+
|
|
15
|
+
<div style={{ maxWidth: '300px', margin: '0 auto 15px auto' }}>
|
|
16
|
+
<ItemCard
|
|
17
|
+
id={configData.Name}
|
|
18
|
+
amount={1}
|
|
19
|
+
label={configData.Name}
|
|
20
|
+
itemData={{
|
|
21
|
+
icon: configData.Icon,
|
|
22
|
+
rarity: configData.Rarity,
|
|
23
|
+
name: configData.Name
|
|
24
|
+
}}
|
|
25
|
+
rarityColor={rarityColor}
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div style={{ fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
30
|
+
<p>{configData.Desc}</p>
|
|
31
|
+
<p style={{ fontWeight: 'bold', marginTop: '5px' }}>Duration: {configData.Duration}s</p>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
26
34
|
);
|
|
27
35
|
};
|
|
28
36
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
interface TooltipProps {
|
|
4
|
+
content: React.ReactNode;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const Tooltip: React.FC<TooltipProps> = ({ content, children }) => {
|
|
9
|
+
const [active, setActive] = useState(false);
|
|
10
|
+
|
|
11
|
+
const showTip = () => {
|
|
12
|
+
setActive(true);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const hideTip = () => {
|
|
16
|
+
setActive(false);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
className="tooltip-wrapper"
|
|
22
|
+
onMouseEnter={showTip}
|
|
23
|
+
onMouseLeave={hideTip}
|
|
24
|
+
style={{ position: 'relative', display: 'inline-block' }}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
{active && (
|
|
28
|
+
<div className="tooltip-popover">
|
|
29
|
+
{content}
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default Tooltip;
|
|
@@ -1,34 +1,39 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
4
|
+
import { useItemResolution } from "../hooks/useItemResolution";
|
|
5
5
|
|
|
6
6
|
const UltimateComponent: React.FC<{
|
|
7
|
-
configData
|
|
7
|
+
configData: CollectionConfigData<"Ultimates">;
|
|
8
8
|
}> = ({ configData }) => {
|
|
9
|
+
const { getRarityColor } = useItemResolution();
|
|
10
|
+
const rarityColor = configData.Rarity ? getRarityColor(configData.Rarity) : null;
|
|
11
|
+
|
|
9
12
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
13
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
14
|
+
|
|
15
|
+
<div style={{ maxWidth: '300px', margin: '0 auto 15px auto' }}>
|
|
16
|
+
<ItemCard
|
|
17
|
+
id={configData.DisplayName}
|
|
18
|
+
amount={1}
|
|
19
|
+
label={configData.DisplayName}
|
|
20
|
+
itemData={{
|
|
21
|
+
icon: configData.Icon,
|
|
22
|
+
rarity: configData.Rarity,
|
|
23
|
+
name: configData.DisplayName
|
|
24
|
+
}}
|
|
25
|
+
rarityColor={rarityColor}
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div style={{ fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
30
|
+
<p style={{ marginBottom: '10px' }}>{configData.Desc}</p>
|
|
31
|
+
<div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
|
|
32
|
+
<span className="badge">Max Tier: {configData.MaxTier}</span>
|
|
33
|
+
{configData.Tradable && <span className="badge">Tradable</span>}
|
|
29
34
|
</div>
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
32
37
|
);
|
|
33
38
|
};
|
|
34
39
|
|
|
@@ -1,73 +1,117 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
4
4
|
import ImageComponent from "./ImageComponent";
|
|
5
|
+
import { useExpandableList } from "../hooks/useExpandableList";
|
|
5
6
|
|
|
6
7
|
const UpgradeComponent: React.FC<{
|
|
7
|
-
configData
|
|
8
|
+
configData: CollectionConfigData<"Upgrades">;
|
|
8
9
|
}> = ({ configData }) => {
|
|
10
|
+
const { expandedIndices, toggle, expandAll, collapseAll, isExpanded } = useExpandableList(configData.TierCurrencies.length);
|
|
11
|
+
|
|
9
12
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
14
|
+
{configData.Icon && (
|
|
15
|
+
<div style={{ maxWidth: '100px', margin: '0 auto 20px' }}>
|
|
16
|
+
<ImageComponent src={configData.Icon} alt="Upgrade Icon" />
|
|
17
|
+
</div>
|
|
18
|
+
)}
|
|
19
|
+
|
|
20
|
+
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px', marginBottom: '30px' }}>
|
|
14
21
|
<div>
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<li key={index}>
|
|
21
|
-
Tier {index + 1}: {power}
|
|
22
|
+
<h3 style={{ borderBottom: '1px solid #eee', paddingBottom: '5px' }}>Tier Powers</h3>
|
|
23
|
+
<ul style={{ listStyle: 'none', padding: 0, textAlign: 'left' }}>
|
|
24
|
+
{configData.TierPowers.map((power, index) => (
|
|
25
|
+
<li key={index} style={{ padding: '5px 0', borderBottom: '1px dashed #eee' }}>
|
|
26
|
+
<strong>Tier {index + 1}:</strong> {power}
|
|
22
27
|
</li>
|
|
23
28
|
))}
|
|
24
29
|
</ul>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
</div>
|
|
31
|
+
<div>
|
|
32
|
+
<h3 style={{ borderBottom: '1px solid #eee', paddingBottom: '5px' }}>Tier Costs</h3>
|
|
33
|
+
<ul style={{ listStyle: 'none', padding: 0, textAlign: 'left' }}>
|
|
34
|
+
{configData.TierCosts.map((cost, index) => (
|
|
35
|
+
<li key={index} style={{ padding: '5px 0', borderBottom: '1px dashed #eee' }}>
|
|
36
|
+
<strong>Tier {index + 1}:</strong> {cost}
|
|
30
37
|
</li>
|
|
31
38
|
))}
|
|
32
39
|
</ul>
|
|
33
|
-
<h3>Tier Currencies</h3>
|
|
34
|
-
{data.TierCurrencies.map((currency, index) => (
|
|
35
|
-
<div key={index}>
|
|
36
|
-
<h4>{currency.DisplayName}</h4>
|
|
37
|
-
<p>Rarity Number: {currency.Rarity.RarityNumber}</p>
|
|
38
|
-
<p>Description: {currency.Desc}</p>
|
|
39
|
-
{currency.Tradable && <p>Tradable</p>}
|
|
40
|
-
<p>Max Amount: {currency.MaxAmount}</p>
|
|
41
|
-
<h5>Bag Tiers</h5>
|
|
42
|
-
<ul>
|
|
43
|
-
{currency.BagTiers.map((bagTier, bagIndex) => (
|
|
44
|
-
<li key={bagIndex}>
|
|
45
|
-
<p>Value: {bagTier.value}</p>
|
|
46
|
-
<ImageComponent
|
|
47
|
-
src={bagTier.image}
|
|
48
|
-
alt={`Bag Tier ${bagTier.value}`}
|
|
49
|
-
/>
|
|
50
|
-
</li>
|
|
51
|
-
))}
|
|
52
|
-
</ul>
|
|
53
|
-
<h5>Tiers</h5>
|
|
54
|
-
<ul>
|
|
55
|
-
{currency.Tiers.map((tier, tierIndex) => (
|
|
56
|
-
<li key={tierIndex}>
|
|
57
|
-
<p>Tier Name: {tier.tierName}</p>
|
|
58
|
-
<p>Order: {tier.Order}</p>
|
|
59
|
-
<p>Value: {tier.value}</p>
|
|
60
|
-
{tier.isBottom && <p>Is Bottom</p>}
|
|
61
|
-
<ImageComponent src={tier.orbImage} alt="Orb" />
|
|
62
|
-
<ImageComponent src={tier.imageOutline} alt="Outline" />
|
|
63
|
-
</li>
|
|
64
|
-
))}
|
|
65
|
-
</ul>
|
|
66
|
-
</div>
|
|
67
|
-
))}
|
|
68
40
|
</div>
|
|
69
|
-
|
|
70
|
-
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div>
|
|
44
|
+
<h3 style={{ fontSize: '1.2em', marginBottom: '15px' }}>Tier Currencies</h3>
|
|
45
|
+
<div style={{ marginBottom: '20px', display: 'flex', gap: '10px', justifyContent: 'center' }}>
|
|
46
|
+
<button onClick={expandAll} style={{ padding: '8px 16px', borderRadius: '8px', border: '1px solid #ddd', background: '#fff', cursor: 'pointer' }}>Expand All</button>
|
|
47
|
+
<button onClick={collapseAll} style={{ padding: '8px 16px', borderRadius: '8px', border: '1px solid #ddd', background: '#fff', cursor: 'pointer' }}>Collapse All</button>
|
|
48
|
+
</div>
|
|
49
|
+
{configData.TierCurrencies.map((currency, index) => (
|
|
50
|
+
<div key={index} style={{ background: '#f9f9f9', padding: '15px', borderRadius: '12px', marginBottom: '20px' }}>
|
|
51
|
+
<div
|
|
52
|
+
onClick={() => toggle(index)}
|
|
53
|
+
style={{ cursor: 'pointer' }}
|
|
54
|
+
>
|
|
55
|
+
<h4 style={{ marginTop: 0, display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
56
|
+
{isExpanded(index) ? '▼' : '▶'} {currency.DisplayName}
|
|
57
|
+
</h4>
|
|
58
|
+
<div style={{ display: 'flex', gap: '10px', justifyContent: 'center', marginBottom: '10px' }}>
|
|
59
|
+
<span className="badge" style={{ borderColor: (currency.Rarity?.Color as string) || '#ccc' }}>{currency.Rarity?.DisplayName}</span>
|
|
60
|
+
{currency.Tradable && <span className="badge">Tradable</span>}
|
|
61
|
+
<span className="badge">Max: {currency.MaxAmount}</span>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
{isExpanded(index) && (
|
|
66
|
+
<>
|
|
67
|
+
<p style={{ fontStyle: 'italic', fontSize: '0.9em', color: '#666' }}>{currency.Desc}</p>
|
|
68
|
+
|
|
69
|
+
<h5 style={{ marginTop: '15px', borderBottom: '1px solid #e0e0e0' }}>Bag Tiers</h5>
|
|
70
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))", gap: "10px", marginTop: '10px' }}>
|
|
71
|
+
{currency.BagTiers.map((bagTier, bagIndex) => (
|
|
72
|
+
<div key={bagIndex}>
|
|
73
|
+
<ItemCard
|
|
74
|
+
id={`bag-tier-${bagIndex}`}
|
|
75
|
+
amount={bagTier.value}
|
|
76
|
+
label={`Bag Tier ${bagIndex + 1}`}
|
|
77
|
+
itemData={{
|
|
78
|
+
icon: bagTier.image,
|
|
79
|
+
rarity: currency.Rarity,
|
|
80
|
+
name: `Bag Tier ${bagIndex + 1}`
|
|
81
|
+
}}
|
|
82
|
+
rarityColor={(currency.Rarity?.Color as string) || null}
|
|
83
|
+
/>
|
|
84
|
+
</div>
|
|
85
|
+
))}
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<h5 style={{ marginTop: '15px', borderBottom: '1px solid #e0e0e0' }}>Tiers</h5>
|
|
89
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))", gap: "10px", marginTop: '10px' }}>
|
|
90
|
+
{currency.Tiers.map((tier, tierIndex) => (
|
|
91
|
+
<div key={tierIndex}>
|
|
92
|
+
<ItemCard
|
|
93
|
+
id={tier.tierName}
|
|
94
|
+
amount={tier.value}
|
|
95
|
+
label={tier.tierName}
|
|
96
|
+
itemData={{
|
|
97
|
+
icon: tier.orbImage,
|
|
98
|
+
rarity: currency.Rarity,
|
|
99
|
+
name: tier.tierName
|
|
100
|
+
}}
|
|
101
|
+
rarityColor={(currency.Rarity?.Color as string) || null}
|
|
102
|
+
/>
|
|
103
|
+
<div style={{ marginTop: '5px', fontSize: '0.8em', color: '#666', textAlign: 'center' }}>
|
|
104
|
+
Order: {tier.Order}
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
))}
|
|
108
|
+
</div>
|
|
109
|
+
</>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
))}
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
71
115
|
);
|
|
72
116
|
};
|
|
73
117
|
|
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import
|
|
4
|
-
import ImageComponent from "./ImageComponent";
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
5
4
|
|
|
6
5
|
const WateringCanComponent: React.FC<{
|
|
7
|
-
configData
|
|
6
|
+
configData: CollectionConfigData<"WateringCans">;
|
|
8
7
|
}> = ({ configData }) => {
|
|
9
8
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
9
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
10
|
+
|
|
11
|
+
<div style={{ maxWidth: '300px', margin: '0 auto 15px auto' }}>
|
|
12
|
+
<ItemCard
|
|
13
|
+
id={configData.DisplayName}
|
|
14
|
+
amount={1}
|
|
15
|
+
label={configData.DisplayName}
|
|
16
|
+
itemData={{
|
|
17
|
+
icon: configData.Icon,
|
|
18
|
+
rarity: undefined,
|
|
19
|
+
name: configData.DisplayName
|
|
20
|
+
}}
|
|
21
|
+
rarityColor={null}
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px', fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
26
|
+
<p><strong>Time Mult:</strong> {configData.PlantTimeMultiplier}x</p>
|
|
27
|
+
<p><strong>Duration:</strong> {configData.PlantTimeMultiplierDuration}</p>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
28
30
|
);
|
|
29
31
|
};
|
|
30
32
|
|