@rpg-engine/long-bow 0.8.212 → 0.8.214
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/dist/components/Store/Store.d.ts +4 -0
- package/dist/long-bow.cjs.development.js +36 -30
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +36 -30
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Marketplace/Marketplace.tsx +2 -1
- package/src/components/Store/Store.tsx +45 -24
- package/src/components/shared/Tabs/Tabs.tsx +5 -0
- package/src/stories/Features/store/Store.stories.tsx +43 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpg-engine/long-bow",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.214",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"build": "tsdx build",
|
|
25
25
|
"test": "tsdx test --passWithNoTests",
|
|
26
26
|
"lint": "tsdx lint",
|
|
27
|
-
"prepare": "
|
|
27
|
+
"prepare": "tsdx build",
|
|
28
28
|
"size": "size-limit",
|
|
29
29
|
"analyze": "size-limit --why",
|
|
30
30
|
"storybook": "start-storybook -p 6006",
|
|
@@ -236,7 +236,8 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
236
236
|
if (onClose) onClose();
|
|
237
237
|
}}
|
|
238
238
|
isFullScreen={fullScreen}
|
|
239
|
-
width="
|
|
239
|
+
width="1050px"
|
|
240
|
+
minWidth="750px"
|
|
240
241
|
cancelDrag="#MarketContainer, .rpgui-dropdown-imp, input, .empty-slot, button"
|
|
241
242
|
scale={scale}
|
|
242
243
|
>
|
|
@@ -49,6 +49,10 @@ export interface IStoreProps {
|
|
|
49
49
|
customHistoryContent?: React.ReactNode;
|
|
50
50
|
/** When true the store renders full-screen (useful on mobile). */
|
|
51
51
|
fullScreen?: boolean;
|
|
52
|
+
/** Override the DraggableContainer width (e.g. "90vw"). Defaults to "1000px". */
|
|
53
|
+
containerWidth?: string;
|
|
54
|
+
/** Override the DraggableContainer height (e.g. "80vh"). Defaults to "auto". */
|
|
55
|
+
containerHeight?: string;
|
|
52
56
|
packsBadge?: string;
|
|
53
57
|
featuredItems?: IFeaturedItem[];
|
|
54
58
|
onQuickBuy?: (item: IProductBlueprint, quantity?: number) => void;
|
|
@@ -110,6 +114,8 @@ export const Store: React.FC<IStoreProps> = ({
|
|
|
110
114
|
customWalletContent,
|
|
111
115
|
customHistoryContent,
|
|
112
116
|
fullScreen = false,
|
|
117
|
+
containerWidth,
|
|
118
|
+
containerHeight,
|
|
113
119
|
packsTabLabel = 'Packs',
|
|
114
120
|
packsBadge,
|
|
115
121
|
featuredItems,
|
|
@@ -135,11 +141,18 @@ export const Store: React.FC<IStoreProps> = ({
|
|
|
135
141
|
const defaultTabOrder: TabId[] = ['premium', 'packs', 'items'];
|
|
136
142
|
const [selectedPack, setSelectedPack] = useState<IItemPack | null>(null);
|
|
137
143
|
const [activeTab, setActiveTab] = useState<TabId>(() => {
|
|
138
|
-
const
|
|
139
|
-
|
|
144
|
+
const allTabIds: TabId[] = [
|
|
145
|
+
...(tabOrder ?? defaultTabOrder),
|
|
146
|
+
...(customCharactersContent ? ['characters' as TabId] : []),
|
|
147
|
+
...(onRedeem ? ['redeem' as TabId] : []),
|
|
148
|
+
...((onShowWallet || customWalletContent) ? ['wallet' as TabId] : []),
|
|
149
|
+
...((onShowHistory || customHistoryContent) ? ['history' as TabId] : []),
|
|
150
|
+
];
|
|
151
|
+
const validTabs = Array.from(new Set(allTabIds.filter(id => !(hidePremiumTab && id === 'premium'))));
|
|
152
|
+
if (defaultActiveTab && validTabs.includes(defaultActiveTab)) {
|
|
140
153
|
return defaultActiveTab;
|
|
141
154
|
}
|
|
142
|
-
return
|
|
155
|
+
return validTabs[0] ?? (hidePremiumTab ? 'items' : 'premium');
|
|
143
156
|
});
|
|
144
157
|
const {
|
|
145
158
|
cartItems,
|
|
@@ -355,7 +368,7 @@ export const Store: React.FC<IStoreProps> = ({
|
|
|
355
368
|
},
|
|
356
369
|
characters: {
|
|
357
370
|
id: 'characters',
|
|
358
|
-
title: '
|
|
371
|
+
title: 'Char Trade',
|
|
359
372
|
icon: <FaUsers size={16} />,
|
|
360
373
|
content: customCharactersContent ?? null,
|
|
361
374
|
},
|
|
@@ -397,9 +410,9 @@ export const Store: React.FC<IStoreProps> = ({
|
|
|
397
410
|
<DraggableContainer
|
|
398
411
|
title="Store"
|
|
399
412
|
onCloseButton={onClose}
|
|
400
|
-
width="
|
|
401
|
-
minWidth="
|
|
402
|
-
height="auto"
|
|
413
|
+
width={containerWidth ?? "1000px"}
|
|
414
|
+
minWidth="700px"
|
|
415
|
+
height={containerHeight ?? "auto"}
|
|
403
416
|
type={RPGUIContainerTypes.Framed}
|
|
404
417
|
cancelDrag="[class*='Store__Container'], [class*='CartView'], [class*='StoreItemDetails'], .close-button"
|
|
405
418
|
isFullScreen={fullScreen}
|
|
@@ -417,7 +430,7 @@ export const Store: React.FC<IStoreProps> = ({
|
|
|
417
430
|
onRemoveFromCart={handleRemoveFromCartTracked}
|
|
418
431
|
onClose={closeCart}
|
|
419
432
|
onPurchase={async () => {
|
|
420
|
-
|
|
433
|
+
handleCartPurchase(onPurchase);
|
|
421
434
|
return true;
|
|
422
435
|
}}
|
|
423
436
|
atlasJSON={atlasJSON}
|
|
@@ -482,21 +495,23 @@ export const Store: React.FC<IStoreProps> = ({
|
|
|
482
495
|
)}
|
|
483
496
|
<MainContent>
|
|
484
497
|
<HeaderRow>
|
|
485
|
-
<
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
498
|
+
<TabsFlexWrapper>
|
|
499
|
+
<Tabs
|
|
500
|
+
options={availableTabIds.map(id => ({ id, label: tabsMap[id]?.title, icon: tabsMap[id]?.icon }))}
|
|
501
|
+
activeTabId={activeTab}
|
|
502
|
+
onTabChange={(tabId) => {
|
|
503
|
+
const nextTab = tabId as TabId;
|
|
504
|
+
setActiveTab(nextTab);
|
|
505
|
+
if (onTabChange) {
|
|
506
|
+
const itemCount = nextTab === 'items' ? filteredItems.items.length
|
|
507
|
+
: nextTab === 'premium' ? filteredItems.premium.length
|
|
508
|
+
: nextTab === 'packs' ? packs.length
|
|
509
|
+
: 0;
|
|
510
|
+
onTabChange(nextTab, itemCount);
|
|
511
|
+
}
|
|
512
|
+
}}
|
|
513
|
+
/>
|
|
514
|
+
</TabsFlexWrapper>
|
|
500
515
|
<CartButtonWrapper>
|
|
501
516
|
<CTAButton
|
|
502
517
|
icon={<FaShoppingCart />}
|
|
@@ -548,15 +563,21 @@ const Container = styled.div`
|
|
|
548
563
|
|
|
549
564
|
const HeaderRow = styled.div`
|
|
550
565
|
display: flex;
|
|
551
|
-
align-items:
|
|
566
|
+
align-items: flex-end;
|
|
552
567
|
justify-content: space-between;
|
|
553
568
|
margin-bottom: 0.25rem;
|
|
554
569
|
padding-top: 10px;
|
|
555
570
|
padding-right: 12px;
|
|
556
571
|
`;
|
|
557
572
|
|
|
573
|
+
const TabsFlexWrapper = styled.div`
|
|
574
|
+
flex: 1;
|
|
575
|
+
min-width: 0;
|
|
576
|
+
`;
|
|
577
|
+
|
|
558
578
|
const CartButtonWrapper = styled.div`
|
|
559
579
|
position: relative;
|
|
580
|
+
flex-shrink: 0;
|
|
560
581
|
`;
|
|
561
582
|
|
|
562
583
|
const CartBadge = styled.div`
|
|
@@ -37,6 +37,11 @@ const TabsContainer = styled.div`
|
|
|
37
37
|
margin: 0 auto 15px auto;
|
|
38
38
|
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
|
|
39
39
|
padding-bottom: 10px;
|
|
40
|
+
overflow-x: auto;
|
|
41
|
+
scrollbar-width: none;
|
|
42
|
+
&::-webkit-scrollbar {
|
|
43
|
+
display: none;
|
|
44
|
+
}
|
|
40
45
|
`;
|
|
41
46
|
|
|
42
47
|
const TabButton = styled.button<{ $active: boolean }>`
|
|
@@ -299,7 +299,7 @@ const mockPacks: IItemPack[] = [
|
|
|
299
299
|
|
|
300
300
|
];
|
|
301
301
|
|
|
302
|
-
// Create the story with the static mock data
|
|
302
|
+
// Create the story with the static mock data — all tabs enabled so layout breaks are visible
|
|
303
303
|
export const Default: Story = {
|
|
304
304
|
render: () => (
|
|
305
305
|
<Store
|
|
@@ -310,6 +310,11 @@ export const Default: Story = {
|
|
|
310
310
|
console.log('Purchase details:', purchase);
|
|
311
311
|
return Promise.resolve(true);
|
|
312
312
|
}}
|
|
313
|
+
customCharactersContent={
|
|
314
|
+
<div style={{ padding: '1rem', color: '#fff', fontFamily: "'Press Start 2P', cursive", fontSize: '0.6rem', textAlign: 'center', marginTop: '2rem' }}>
|
|
315
|
+
Character trading content (consumer-provided)
|
|
316
|
+
</div>
|
|
317
|
+
}
|
|
313
318
|
customWalletContent={<DCWalletContent
|
|
314
319
|
dcBalance={150000000} // 150M
|
|
315
320
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
@@ -328,11 +333,14 @@ export const Default: Story = {
|
|
|
328
333
|
loading={false}
|
|
329
334
|
onRequestHistory={() => {}}
|
|
330
335
|
/>}
|
|
336
|
+
onRedeem={async (code: string) => {
|
|
337
|
+
if (code === 'CHB-550-ABCDEF1234') return { success: true, dcAmount: 550 };
|
|
338
|
+
return { success: false, error: 'Invalid voucher code.' };
|
|
339
|
+
}}
|
|
331
340
|
onClose={() => console.log('Store closed')}
|
|
332
341
|
atlasJSON={itemsAtlasJSON}
|
|
333
342
|
atlasIMG={itemsAtlasIMG}
|
|
334
|
-
|
|
335
|
-
tabOrder={['items', 'packs']}
|
|
343
|
+
tabOrder={['premium', 'packs', 'items']}
|
|
336
344
|
defaultActiveTab="packs"
|
|
337
345
|
textInputItemKeys={['original-greater-life-potion-2', 'original-angelic-sword-1', 'character-name-change']}
|
|
338
346
|
packsBadge="SAVE"
|
|
@@ -653,6 +661,38 @@ export const INR: Story = {
|
|
|
653
661
|
),
|
|
654
662
|
};
|
|
655
663
|
|
|
664
|
+
export const WithCharTradeTab: Story = {
|
|
665
|
+
render: () => (
|
|
666
|
+
<Store
|
|
667
|
+
items={allStoreItems}
|
|
668
|
+
packs={mockPacks}
|
|
669
|
+
userAccountType={UserAccountTypes.Free}
|
|
670
|
+
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
671
|
+
console.log('Purchase details:', purchase);
|
|
672
|
+
return Promise.resolve(true);
|
|
673
|
+
}}
|
|
674
|
+
customCharactersContent={
|
|
675
|
+
<div style={{ padding: '1rem', color: '#fff', fontFamily: "'Press Start 2P', cursive", fontSize: '0.6rem', textAlign: 'center', marginTop: '2rem' }}>
|
|
676
|
+
Character trading content goes here (provided by consumer)
|
|
677
|
+
</div>
|
|
678
|
+
}
|
|
679
|
+
onClose={() => console.log('Store closed')}
|
|
680
|
+
atlasJSON={itemsAtlasJSON}
|
|
681
|
+
atlasIMG={itemsAtlasIMG}
|
|
682
|
+
hidePremiumTab={true}
|
|
683
|
+
tabOrder={['items', 'packs']}
|
|
684
|
+
defaultActiveTab="characters"
|
|
685
|
+
onTabChange={(tab, count) => console.log('[tracking] tab_change', { tab, count })}
|
|
686
|
+
onCartOpen={() => console.log('[tracking] cart_opened')}
|
|
687
|
+
onAddToCart={(item, qty) => console.log('[tracking] add_to_cart', { key: item.key, qty })}
|
|
688
|
+
onRemoveFromCart={(key) => console.log('[tracking] remove_from_cart', { key })}
|
|
689
|
+
onCheckoutStart={(items, total) => console.log('[tracking] checkout_start', { items, total })}
|
|
690
|
+
onPurchaseSuccess={(items, total) => console.log('[tracking] purchase_success', { items, total })}
|
|
691
|
+
onPurchaseError={(error) => console.log('[tracking] purchase_error', { error })}
|
|
692
|
+
/>
|
|
693
|
+
),
|
|
694
|
+
};
|
|
695
|
+
|
|
656
696
|
export const WithRedeemTab: Story = {
|
|
657
697
|
render: () => (
|
|
658
698
|
<Store
|