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
|
@@ -1,65 +1,74 @@
|
|
|
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 CurrencyComponent: React.FC<{
|
|
7
|
-
configData
|
|
6
|
+
configData: CollectionConfigData<"Currency">;
|
|
8
7
|
}> = ({ configData }) => {
|
|
9
8
|
return (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
|
|
10
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
11
|
+
|
|
12
|
+
<div style={{ marginBottom: '20px', textAlign: 'center' }}>
|
|
13
|
+
<p style={{ fontStyle: 'italic', marginBottom: '10px' }}>{configData.Desc}</p>
|
|
14
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', justifyContent: 'center' }}>
|
|
15
|
+
<span className="badge">Max: {configData.MaxAmount}</span>
|
|
16
|
+
{configData.Rarity && <span className="badge" style={{ borderColor: (configData.Rarity.Color as string) }}>Rarity: {configData.Rarity.DisplayName}</span>}
|
|
17
|
+
{configData.Tradable && <span className="badge">Tradable</span>}
|
|
18
|
+
{configData.IsWorldCurrency && <span className="badge">World Currency</span>}
|
|
19
|
+
{configData.PermitAutoLootScaling && <span className="badge">Auto Loot</span>}
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div style={{ marginBottom: '20px' }}>
|
|
24
|
+
<h3 style={{ fontSize: '1.2em', borderBottom: '1px solid #eee', paddingBottom: '5px' }}>Tiers</h3>
|
|
25
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))", gap: "10px", marginTop: '15px' }}>
|
|
26
|
+
{configData.Tiers.map((tier, index) => (
|
|
27
|
+
<div key={index}>
|
|
28
|
+
<ItemCard
|
|
29
|
+
id={tier.tierName}
|
|
30
|
+
amount={tier.value}
|
|
31
|
+
label={tier.tierName}
|
|
32
|
+
itemData={{
|
|
33
|
+
icon: tier.orbImage,
|
|
34
|
+
rarity: configData.Rarity,
|
|
35
|
+
name: tier.tierName
|
|
36
|
+
}}
|
|
37
|
+
rarityColor={(configData.Rarity?.Color as string) || null}
|
|
38
|
+
/>
|
|
39
|
+
<div style={{ textAlign: 'center', fontSize: '0.8em', color: '#666', marginTop: '4px' }}>
|
|
40
|
+
Order: {tier.Order}
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
))}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
{configData.BagTiers && (
|
|
14
48
|
<div>
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<p>Order: {tier.Order}</p>
|
|
30
|
-
<p>Value: {tier.value}</p>
|
|
31
|
-
<ImageComponent
|
|
32
|
-
src={tier.imageOutline}
|
|
33
|
-
alt={`${tier.tierName} outline`}
|
|
34
|
-
/>
|
|
35
|
-
{tier.isBottom && <p>Is Bottom: Yes</p>}
|
|
36
|
-
<ImageComponent
|
|
37
|
-
src={tier.tinyImage}
|
|
38
|
-
alt={`${tier.tierName} tiny`}
|
|
49
|
+
<h3 style={{ fontSize: '1.2em', borderBottom: '1px solid #eee', paddingBottom: '5px' }}>Bag Tiers</h3>
|
|
50
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))", gap: "10px", marginTop: '15px' }}>
|
|
51
|
+
{configData.BagTiers.map((bagTier, index) => (
|
|
52
|
+
<div key={index}>
|
|
53
|
+
<ItemCard
|
|
54
|
+
id={`bag-tier-${index}`}
|
|
55
|
+
amount={bagTier.value}
|
|
56
|
+
label={`Bag Tier ${index + 1}`}
|
|
57
|
+
itemData={{
|
|
58
|
+
icon: bagTier.image,
|
|
59
|
+
rarity: configData.Rarity,
|
|
60
|
+
name: `Bag Tier ${index + 1}`
|
|
61
|
+
}}
|
|
62
|
+
rarityColor={(configData.Rarity?.Color as string) || null}
|
|
39
63
|
/>
|
|
40
|
-
</
|
|
64
|
+
</div>
|
|
41
65
|
))}
|
|
42
|
-
</
|
|
43
|
-
{data.BagTiers && (
|
|
44
|
-
<div>
|
|
45
|
-
<h3>Bag Tiers:</h3>
|
|
46
|
-
<ul>
|
|
47
|
-
{data.BagTiers.map((bagTier, index) => (
|
|
48
|
-
<li key={index}>
|
|
49
|
-
<ImageComponent
|
|
50
|
-
src={bagTier.image}
|
|
51
|
-
alt={`Bag tier ${index + 1}`}
|
|
52
|
-
/>
|
|
53
|
-
<p>Value: {bagTier.value}</p>
|
|
54
|
-
</li>
|
|
55
|
-
))}
|
|
56
|
-
</ul>
|
|
57
|
-
</div>
|
|
58
|
-
)}
|
|
66
|
+
</div>
|
|
59
67
|
</div>
|
|
60
68
|
)}
|
|
61
|
-
|
|
69
|
+
</div>
|
|
62
70
|
);
|
|
63
71
|
};
|
|
64
72
|
|
|
73
|
+
|
|
65
74
|
export default CurrencyComponent;
|
|
@@ -1,23 +1,190 @@
|
|
|
1
|
-
import React, { lazy, Suspense } from "react";
|
|
2
|
-
import { useParams } from "react-router-dom";
|
|
3
|
-
import { CollectionName } from "ps99-api";
|
|
1
|
+
import React, { lazy, Suspense, useState } from "react";
|
|
2
|
+
import { useParams, useNavigate } from "react-router-dom";
|
|
3
|
+
import { CollectionName, CollectionConfigData } from "ps99-api";
|
|
4
|
+
import { GenericFetchComponent } from "./GenericFetchComponent";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
interface DynamicCollectionConfigDataProps {
|
|
7
|
+
collectionName?: CollectionName;
|
|
8
|
+
configName?: string;
|
|
9
|
+
render?: (configData: CollectionConfigData<any>) => React.ReactNode; // Add render prop
|
|
10
|
+
additionalProps?: any; // Add additional props to pass to the rendered component
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DynamicCollectionConfigData: React.FC<
|
|
14
|
+
DynamicCollectionConfigDataProps
|
|
15
|
+
> = (props) => {
|
|
16
|
+
const params = useParams<{
|
|
7
17
|
collectionName: CollectionName;
|
|
8
18
|
configName: string;
|
|
9
19
|
}>();
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
const navigate = useNavigate();
|
|
22
|
+
const collectionName = props.collectionName || params.collectionName;
|
|
23
|
+
const configName = props.configName || params.configName;
|
|
24
|
+
|
|
25
|
+
const [viewMode, setViewMode] = useState<'render' | 'schema'>('render');
|
|
26
|
+
|
|
27
|
+
/*
|
|
28
|
+
* We need to use useMemo here to prevent the component from being re-created
|
|
29
|
+
* on every render. This usage of useMemo is safe because the import path
|
|
30
|
+
* depends only on collectionName, and we want to re-create the component
|
|
31
|
+
* only when collectionName changes.
|
|
32
|
+
*/
|
|
33
|
+
const Component = React.useMemo(() => {
|
|
34
|
+
if (!collectionName) return null;
|
|
35
|
+
return lazy(() => import(`./${collectionName}Component`));
|
|
36
|
+
}, [collectionName]);
|
|
37
|
+
|
|
38
|
+
if (!collectionName || !configName || !Component) {
|
|
12
39
|
return <div>Invalid collection or config name</div>;
|
|
13
40
|
}
|
|
14
41
|
|
|
15
|
-
const Component = lazy(() => import(`./${collectionName}Component`));
|
|
16
|
-
|
|
17
42
|
return (
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
43
|
+
<div style={{ display: "flex", flexDirection: "column", height: "100%", width: "100%" }}>
|
|
44
|
+
{/* Header with Close Button */}
|
|
45
|
+
<div style={{
|
|
46
|
+
padding: "15px 20px",
|
|
47
|
+
borderBottom: "4px solid #333",
|
|
48
|
+
display: "flex",
|
|
49
|
+
alignItems: "center",
|
|
50
|
+
justifyContent: "space-between",
|
|
51
|
+
backgroundColor: "#fff",
|
|
52
|
+
flexShrink: 0,
|
|
53
|
+
}}>
|
|
54
|
+
<div
|
|
55
|
+
style={{ display: "flex", alignItems: "center", gap: "10px", cursor: "pointer" }}
|
|
56
|
+
onClick={() => {
|
|
57
|
+
navigator.clipboard.writeText(window.location.href);
|
|
58
|
+
// visual feedback could be added here, e.g. a small alert or changing the icon color briefly
|
|
59
|
+
const icon = document.getElementById('link-icon-path');
|
|
60
|
+
if (icon) icon.style.fill = '#4caf50';
|
|
61
|
+
setTimeout(() => { if (icon) icon.style.fill = '#ccc'; }, 1000);
|
|
62
|
+
}}
|
|
63
|
+
title="Click to copy link to this item"
|
|
64
|
+
onMouseEnter={(e) => {
|
|
65
|
+
const icon = e.currentTarget.querySelector('.link-icon');
|
|
66
|
+
if (icon) (icon as HTMLElement).style.opacity = '1';
|
|
67
|
+
}}
|
|
68
|
+
onMouseLeave={(e) => {
|
|
69
|
+
const icon = e.currentTarget.querySelector('.link-icon');
|
|
70
|
+
if (icon) (icon as HTMLElement).style.opacity = '0';
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<h2 style={{
|
|
74
|
+
margin: 0,
|
|
75
|
+
fontSize: "2rem",
|
|
76
|
+
fontWeight: "900",
|
|
77
|
+
color: "#333",
|
|
78
|
+
textShadow: "2px 2px 0px #eee",
|
|
79
|
+
fontFamily: "'Fredoka One', cursive, sans-serif",
|
|
80
|
+
textTransform: "capitalize",
|
|
81
|
+
}}>
|
|
82
|
+
{configName}
|
|
83
|
+
</h2>
|
|
84
|
+
<svg
|
|
85
|
+
className="link-icon"
|
|
86
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
87
|
+
width="24"
|
|
88
|
+
height="24"
|
|
89
|
+
viewBox="0 0 24 24"
|
|
90
|
+
fill="none"
|
|
91
|
+
stroke="#ccc"
|
|
92
|
+
strokeWidth="2"
|
|
93
|
+
strokeLinecap="round"
|
|
94
|
+
strokeLinejoin="round"
|
|
95
|
+
style={{ opacity: 0, transition: 'opacity 0.2s' }}
|
|
96
|
+
>
|
|
97
|
+
<path id="link-icon-path" d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
|
|
98
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
|
|
99
|
+
</svg>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div style={{ display: 'flex', gap: '10px' }}>
|
|
103
|
+
<button
|
|
104
|
+
onClick={() => setViewMode(prev => prev === 'render' ? 'schema' : 'render')}
|
|
105
|
+
style={{
|
|
106
|
+
width: "48px",
|
|
107
|
+
height: "48px",
|
|
108
|
+
borderRadius: "12px",
|
|
109
|
+
backgroundColor: viewMode === 'render' ? "#2196f3" : "#4caf50",
|
|
110
|
+
color: "white",
|
|
111
|
+
border: `4px solid ${viewMode === 'render' ? "#1565c0" : "#2e7d32"}`,
|
|
112
|
+
fontSize: "20px",
|
|
113
|
+
fontWeight: "900",
|
|
114
|
+
display: "flex",
|
|
115
|
+
alignItems: "center",
|
|
116
|
+
justifyContent: "center",
|
|
117
|
+
cursor: "pointer",
|
|
118
|
+
boxShadow: `inset 0 4px 4px rgba(255,255,255,0.4), 0 4px 0 ${viewMode === 'render' ? "#0d47a1" : "#1b5e20"}`,
|
|
119
|
+
fontFamily: "monospace"
|
|
120
|
+
}}
|
|
121
|
+
title={viewMode === 'render' ? "View Raw Schema" : "View Rendered Item"}
|
|
122
|
+
>
|
|
123
|
+
{viewMode === 'render' ? "{}" : "👁️"}
|
|
124
|
+
</button>
|
|
125
|
+
|
|
126
|
+
<button
|
|
127
|
+
onClick={() => navigate(`/collections/${collectionName}`)}
|
|
128
|
+
style={{
|
|
129
|
+
width: "48px",
|
|
130
|
+
height: "48px",
|
|
131
|
+
borderRadius: "12px",
|
|
132
|
+
backgroundColor: "#ff0055",
|
|
133
|
+
color: "white",
|
|
134
|
+
border: "4px solid #900",
|
|
135
|
+
fontSize: "24px",
|
|
136
|
+
fontWeight: "900",
|
|
137
|
+
display: "flex",
|
|
138
|
+
alignItems: "center",
|
|
139
|
+
justifyContent: "center",
|
|
140
|
+
cursor: "pointer",
|
|
141
|
+
boxShadow: "inset 0 4px 4px rgba(255,255,255,0.4), 0 4px 0 #500",
|
|
142
|
+
}}
|
|
143
|
+
>
|
|
144
|
+
X
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<div style={{ flex: 1, overflowY: "auto", padding: "20px" }}>
|
|
150
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
151
|
+
<GenericFetchComponent
|
|
152
|
+
// We use the key prop to force a re-mount of the component when the
|
|
153
|
+
// collectionName or configName changes. This ensures that the internal
|
|
154
|
+
// state of the GenericFetchComponent is reset and the new data is
|
|
155
|
+
// fetched correctly, preventing stale data from being passed to the
|
|
156
|
+
// child component.
|
|
157
|
+
key={`${collectionName}-${configName}`}
|
|
158
|
+
collectionName={collectionName}
|
|
159
|
+
configName={configName}
|
|
160
|
+
render={
|
|
161
|
+
(configData: CollectionConfigData<any>) => {
|
|
162
|
+
if (viewMode === 'schema') {
|
|
163
|
+
return (
|
|
164
|
+
<div style={{
|
|
165
|
+
padding: '20px',
|
|
166
|
+
background: '#1e1e1e',
|
|
167
|
+
color: '#d4d4d4',
|
|
168
|
+
borderRadius: '12px',
|
|
169
|
+
overflow: 'auto',
|
|
170
|
+
height: '100%',
|
|
171
|
+
fontFamily: 'Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
|
|
172
|
+
fontSize: '0.9rem',
|
|
173
|
+
textAlign: 'left',
|
|
174
|
+
boxShadow: 'inset 0 0 20px rgba(0,0,0,0.5)',
|
|
175
|
+
border: '2px solid #333'
|
|
176
|
+
}}>
|
|
177
|
+
<pre style={{ margin: 0 }}>{JSON.stringify(configData, null, 2)}</pre>
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return props.render ? props.render(configData) : <Component configData={configData} {...props.additionalProps} />;
|
|
182
|
+
}
|
|
183
|
+
} // Use render prop if provided
|
|
184
|
+
/>
|
|
185
|
+
</Suspense>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
21
188
|
);
|
|
22
189
|
};
|
|
23
190
|
|
|
@@ -1,61 +1,94 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import { GenericFetchComponent } from "./GenericFetchComponent";
|
|
4
3
|
import ImageComponent from "./ImageComponent";
|
|
4
|
+
import ItemCard from "./ItemCard";
|
|
5
|
+
import { useItemResolution } from "../hooks/useItemResolution";
|
|
5
6
|
|
|
6
7
|
const EggsComponent: React.FC<{
|
|
7
|
-
configData
|
|
8
|
+
configData: CollectionConfigData<"Eggs">;
|
|
8
9
|
}> = ({ configData }) => {
|
|
10
|
+
const { getRarityColor, resolveItem } = useItemResolution();
|
|
11
|
+
const rarityColor = configData.rarity ? getRarityColor(configData.rarity) : null;
|
|
12
|
+
|
|
9
13
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
<div style={{ width: "100%", height: "100%", boxSizing: "border-box" }}>
|
|
15
|
+
<div style={{ width: '300px', margin: '0 auto 20px 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
|
+
typeId={(configData as any)._index}
|
|
27
|
+
/>
|
|
28
|
+
</div>
|
|
29
|
+
<p>Currency: {configData.currency}</p>
|
|
30
|
+
<p>Override Cost: {configData.overrideCost}</p>
|
|
31
|
+
{configData.isCustomEgg && <p>Custom Egg: Yes</p>}
|
|
32
|
+
{configData.bestEgg && <p>Best Egg: Yes</p>}
|
|
33
|
+
{configData.disableGold && <p>Disable Gold: Yes</p>}
|
|
34
|
+
{configData.disableRainbow && <p>Disable Rainbow: Yes</p>}
|
|
35
|
+
{configData.disableShiny && <p>Disable Shiny: Yes</p>}
|
|
36
|
+
{configData.disableModifiers && <p>Disable Modifiers: Yes</p>}
|
|
37
|
+
{configData.goldChance && <p>Gold Chance: {configData.goldChance}</p>}
|
|
38
|
+
{configData.rainbowChance && (
|
|
39
|
+
<p>Rainbow Chance: {configData.rainbowChance}</p>
|
|
40
|
+
)}
|
|
41
|
+
{configData.shinyChance && <p>Shiny Chance: {configData.shinyChance}</p>}
|
|
42
|
+
{configData.rarity && (
|
|
43
|
+
<div>
|
|
44
|
+
<p>Rarity: {configData.rarity.DisplayName}</p>
|
|
45
|
+
<p>Rarity Number: {configData.rarity.RarityNumber}</p>
|
|
46
|
+
</div>
|
|
47
|
+
)}
|
|
48
|
+
<h3>Pets:</h3>
|
|
49
|
+
<div style={{ marginTop: '15px' }}>
|
|
50
|
+
<h3 style={{ borderBottom: '1px solid #eee', paddingBottom: '5px' }}>Pets</h3>
|
|
51
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))', gap: '16px' }}>
|
|
52
|
+
{configData.pets.map((pet, index) => {
|
|
53
|
+
const petName = pet[0];
|
|
54
|
+
const chance = pet[1];
|
|
55
|
+
// The 3rd element appears to be the tier (tn), based on existing code usage
|
|
56
|
+
const tn = pet[2];
|
|
57
|
+
const resolvedItem = resolveItem(petName, tn);
|
|
58
|
+
const rarityColor = resolvedItem?.rarity ? getRarityColor(resolvedItem.rarity) : null;
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div key={index} style={{
|
|
62
|
+
// Auto-sizing handled by grid
|
|
63
|
+
}}>
|
|
64
|
+
<ItemCard
|
|
65
|
+
id={petName}
|
|
66
|
+
// Formatting chance as string to include %
|
|
67
|
+
amount={`${chance}%`}
|
|
68
|
+
label={resolvedItem?.name || petName}
|
|
69
|
+
itemData={resolvedItem}
|
|
70
|
+
rarityColor={rarityColor}
|
|
71
|
+
tn={tn}
|
|
72
|
+
// weight or typeId not strictly needed here unless we want debug info
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
})}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
{configData.productIds && (
|
|
14
80
|
<div>
|
|
15
|
-
<
|
|
16
|
-
<ImageComponent src={data.icon} alt={data.name} />
|
|
17
|
-
<p>Currency: {data.currency}</p>
|
|
18
|
-
<p>Override Cost: {data.overrideCost}</p>
|
|
19
|
-
{data.isCustomEgg && <p>Custom Egg: Yes</p>}
|
|
20
|
-
{data.bestEgg && <p>Best Egg: Yes</p>}
|
|
21
|
-
{data.disableGold && <p>Disable Gold: Yes</p>}
|
|
22
|
-
{data.disableRainbow && <p>Disable Rainbow: Yes</p>}
|
|
23
|
-
{data.disableShiny && <p>Disable Shiny: Yes</p>}
|
|
24
|
-
{data.disableModifiers && <p>Disable Modifiers: Yes</p>}
|
|
25
|
-
{data.goldChance && <p>Gold Chance: {data.goldChance}</p>}
|
|
26
|
-
{data.rainbowChance && <p>Rainbow Chance: {data.rainbowChance}</p>}
|
|
27
|
-
{data.shinyChance && <p>Shiny Chance: {data.shinyChance}</p>}
|
|
28
|
-
{data.rarity && (
|
|
29
|
-
<div>
|
|
30
|
-
<p>Rarity: {data.rarity.DisplayName}</p>
|
|
31
|
-
<p>Rarity Number: {data.rarity.RarityNumber}</p>
|
|
32
|
-
</div>
|
|
33
|
-
)}
|
|
34
|
-
<h3>Pets:</h3>
|
|
81
|
+
<h3>Product IDs:</h3>
|
|
35
82
|
<ul>
|
|
36
|
-
{
|
|
37
|
-
<li key={
|
|
38
|
-
|
|
39
|
-
<p>Chance: {pet[1]}</p>
|
|
40
|
-
{pet[2] && <p>Tier: {pet[2]}</p>}
|
|
83
|
+
{Object.entries(configData.productIds).map(([key, value]) => (
|
|
84
|
+
<li key={key}>
|
|
85
|
+
{key}: {value}
|
|
41
86
|
</li>
|
|
42
87
|
))}
|
|
43
88
|
</ul>
|
|
44
|
-
{data.productIds && (
|
|
45
|
-
<div>
|
|
46
|
-
<h3>Product IDs:</h3>
|
|
47
|
-
<ul>
|
|
48
|
-
{Object.entries(data.productIds).map(([key, value]) => (
|
|
49
|
-
<li key={key}>
|
|
50
|
-
{key}: {value}
|
|
51
|
-
</li>
|
|
52
|
-
))}
|
|
53
|
-
</ul>
|
|
54
|
-
</div>
|
|
55
|
-
)}
|
|
56
89
|
</div>
|
|
57
90
|
)}
|
|
58
|
-
|
|
91
|
+
</div>
|
|
59
92
|
);
|
|
60
93
|
};
|
|
61
94
|
|
|
@@ -1,45 +1,95 @@
|
|
|
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 EnchantsComponent: React.FC<{
|
|
7
|
-
configData
|
|
7
|
+
configData: CollectionConfigData<"Enchants">;
|
|
8
8
|
}> = ({ configData }) => {
|
|
9
|
+
const { getRarityColor } = useItemResolution();
|
|
10
|
+
|
|
9
11
|
return (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<p>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
12
|
+
|
|
13
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
14
|
+
<div style={{ textAlign: 'left', marginBottom: '20px', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '10px' }}>
|
|
15
|
+
<p><strong>Base Tier:</strong> {configData.BaseTier}</p>
|
|
16
|
+
<p><strong>Max Tier:</strong> {configData.MaxTier}</p>
|
|
17
|
+
<p><strong>Max Page:</strong> {configData.MaxPage}</p>
|
|
18
|
+
{configData.DiminishPowerThreshold && (
|
|
19
|
+
<p><strong>Diminish Threshold:</strong> {configData.DiminishPowerThreshold}</p>
|
|
20
|
+
)}
|
|
21
|
+
{configData.EmpoweredBoost && (
|
|
22
|
+
<p><strong>Empowered Boost:</strong> {configData.EmpoweredBoost}</p>
|
|
23
|
+
)}
|
|
24
|
+
{configData.ProductId && <p><strong>Product ID:</strong> {configData.ProductId}</p>}
|
|
25
|
+
</div>
|
|
26
|
+
<h3>Tiers:</h3>
|
|
27
|
+
<div style={{ display: "flex", flexWrap: "wrap", gap: "1em" }}>
|
|
28
|
+
{configData.Tiers.map((tier, index) => {
|
|
29
|
+
const rarityColor = tier.Rarity ? getRarityColor(tier.Rarity) : null;
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
key={index}
|
|
33
|
+
style={{
|
|
34
|
+
flex: "1 1 300px",
|
|
35
|
+
maxWidth: "350px",
|
|
36
|
+
margin: "0 auto"
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
<ItemCard
|
|
40
|
+
id={tier.DisplayName}
|
|
41
|
+
amount={1}
|
|
42
|
+
label={tier.DisplayName}
|
|
43
|
+
tn={index + 1}
|
|
44
|
+
itemData={{
|
|
45
|
+
icon: tier.Icon,
|
|
46
|
+
rarity: tier.Rarity,
|
|
47
|
+
name: tier.DisplayName
|
|
48
|
+
}}
|
|
49
|
+
rarityColor={rarityColor}
|
|
50
|
+
/>
|
|
51
|
+
<div style={{ marginTop: '10px', fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
52
|
+
<p>{tier.Desc}</p>
|
|
34
53
|
<p>Power: {tier.Power}</p>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
})}
|
|
58
|
+
<h3>Tiers</h3>
|
|
59
|
+
<div style={{ display: "grid", gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))', gap: "15px" }}>
|
|
60
|
+
{configData.Tiers.map((tier, index) => {
|
|
61
|
+
const rarityColor = tier.Rarity ? getRarityColor(tier.Rarity) : null;
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
key={index}
|
|
65
|
+
style={{
|
|
66
|
+
display: 'flex',
|
|
67
|
+
flexDirection: 'column',
|
|
68
|
+
height: '100%'
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<ItemCard
|
|
72
|
+
id={tier.DisplayName}
|
|
73
|
+
amount={1}
|
|
74
|
+
label={tier.DisplayName}
|
|
75
|
+
tn={index + 1}
|
|
76
|
+
itemData={{
|
|
77
|
+
icon: tier.Icon,
|
|
78
|
+
rarity: tier.Rarity,
|
|
79
|
+
name: tier.DisplayName
|
|
80
|
+
}}
|
|
81
|
+
rarityColor={rarityColor}
|
|
82
|
+
/>
|
|
83
|
+
<div style={{ marginTop: '10px', fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
84
|
+
<p>{tier.Desc}</p>
|
|
85
|
+
<p style={{ fontWeight: 'bold', color: '#333' }}>Power: {tier.Power}</p>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
})}
|
|
40
90
|
</div>
|
|
41
|
-
|
|
42
|
-
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
43
93
|
);
|
|
44
94
|
};
|
|
45
95
|
|