@rpg-engine/long-bow 0.8.141 → 0.8.146
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/Marketplace/BlueprintSearchModal.d.ts +17 -0
- package/dist/components/Marketplace/BlueprintTable.d.ts +9 -0
- package/dist/components/Marketplace/BuyOrderDetailsModal.d.ts +17 -0
- package/dist/components/Marketplace/BuyOrderPanel.d.ts +24 -0
- package/dist/components/Marketplace/BuyOrderRows.d.ts +13 -0
- package/dist/components/Marketplace/BuyPanel.d.ts +9 -1
- package/dist/components/Marketplace/HistoryPanel.d.ts +18 -0
- package/dist/components/Marketplace/ManagmentPanel.d.ts +3 -2
- package/dist/components/Marketplace/Marketplace.d.ts +35 -2
- package/dist/components/Marketplace/MarketplaceSettingsPanel.d.ts +2 -1
- package/dist/components/Store/PaymentMethodModal.d.ts +1 -0
- package/dist/components/shared/LabelPill/LabelPill.d.ts +9 -0
- package/dist/components/shared/LabelPill/index.d.ts +1 -0
- package/dist/components/shared/SegmentedToggle/SegmentedToggle.d.ts +12 -0
- package/dist/components/shared/SegmentedToggle/index.d.ts +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/long-bow.cjs.development.js +11573 -1288
- 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 +11562 -1290
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/Features/marketplace/BlueprintSearchModal.stories.d.ts +1 -0
- package/dist/stories/Features/marketplace/BuyOrderPanel.stories.d.ts +1 -0
- package/dist/stories/Features/marketplace/BuyOrderRows.stories.d.ts +1 -0
- package/dist/stories/Features/marketplace/HistoryPanel.stories.d.ts +1 -0
- package/dist/stories/Features/trading/MarketplaceRows.stories.d.ts +2 -1
- package/dist/stories/UI/buttonsAndInputs/SegmentedToggle.stories.d.ts +6 -0
- package/dist/stories/UI/text/LabelPill.stories.d.ts +7 -0
- package/dist/utils/atlasUtils.d.ts +2 -0
- package/package.json +2 -2
- package/src/components/Marketplace/BlueprintSearchModal.tsx +295 -0
- package/src/components/Marketplace/BlueprintTable.tsx +158 -0
- package/src/components/Marketplace/BuyOrderDetailsModal.tsx +306 -0
- package/src/components/Marketplace/BuyOrderPanel.tsx +284 -0
- package/src/components/Marketplace/BuyOrderRows.tsx +287 -0
- package/src/components/Marketplace/BuyPanel.tsx +406 -166
- package/src/components/Marketplace/HistoryPanel.tsx +422 -0
- package/src/components/Marketplace/ManagmentPanel.tsx +13 -15
- package/src/components/Marketplace/Marketplace.tsx +181 -30
- package/src/components/Marketplace/MarketplaceBuyModal.tsx +1 -0
- package/src/components/Marketplace/MarketplaceRows.tsx +41 -10
- package/src/components/Marketplace/MarketplaceSettingsPanel.tsx +4 -3
- package/src/components/Store/CartView.tsx +11 -0
- package/src/components/Store/PaymentMethodModal.tsx +26 -9
- package/src/components/shared/LabelPill/LabelPill.tsx +45 -0
- package/src/components/shared/LabelPill/index.ts +1 -0
- package/src/components/shared/SegmentedToggle/SegmentedToggle.tsx +61 -0
- package/src/components/shared/SegmentedToggle/index.ts +1 -0
- package/src/components/shared/SpriteFromAtlas.tsx +7 -2
- package/src/index.tsx +4 -0
- package/src/mocks/atlas/items/items.json +33998 -25238
- package/src/mocks/atlas/items/items.png +0 -0
- package/src/mocks/itemContainer.mocks.ts +31 -0
- package/src/stories/Features/marketplace/BlueprintSearchModal.stories.tsx +145 -0
- package/src/stories/Features/marketplace/BuyOrderPanel.stories.tsx +323 -0
- package/src/stories/Features/marketplace/BuyOrderRows.stories.tsx +116 -0
- package/src/stories/Features/marketplace/HistoryPanel.stories.tsx +157 -0
- package/src/stories/Features/trading/Marketplace.stories.tsx +130 -0
- package/src/stories/Features/trading/MarketplaceRows.stories.tsx +11 -0
- package/src/stories/UI/buttonsAndInputs/SegmentedToggle.stories.tsx +54 -0
- package/src/stories/UI/text/LabelPill.stories.tsx +43 -0
- package/src/utils/__test__/atlasUtils.spec.ts +26 -0
- package/src/utils/atlasUtils.ts +80 -0
|
Binary file
|
|
@@ -650,6 +650,37 @@ export const items: IItem[] = [
|
|
|
650
650
|
fullDescription: '',
|
|
651
651
|
usableEffectDescription: 'Regenerates 10 HP and Mana 5 times',
|
|
652
652
|
},
|
|
653
|
+
{
|
|
654
|
+
type: ItemType.Consumable,
|
|
655
|
+
subType: ItemSubType.Food,
|
|
656
|
+
rarity: 'Common',
|
|
657
|
+
textureAtlas: 'items',
|
|
658
|
+
allowedEquipSlotType: [],
|
|
659
|
+
maxStackSize: 100000,
|
|
660
|
+
isUsable: false,
|
|
661
|
+
isStorable: true,
|
|
662
|
+
isItemContainer: false,
|
|
663
|
+
isSolid: false,
|
|
664
|
+
requiredAmmoKeys: [],
|
|
665
|
+
isTwoHanded: false,
|
|
666
|
+
hasUseWith: false,
|
|
667
|
+
entityEffects: [],
|
|
668
|
+
entityEffectChance: 0,
|
|
669
|
+
_id: '99999-stack-test',
|
|
670
|
+
key: 'apple',
|
|
671
|
+
texturePath: 'foods/apple.png',
|
|
672
|
+
textureKey: 'apple',
|
|
673
|
+
isEquipable: false,
|
|
674
|
+
isStackable: true,
|
|
675
|
+
name: 'Apple',
|
|
676
|
+
description: 'A red apple.',
|
|
677
|
+
weight: 0.05,
|
|
678
|
+
stackQty: 99999,
|
|
679
|
+
attack: 0,
|
|
680
|
+
defense: 0,
|
|
681
|
+
fullDescription: '',
|
|
682
|
+
usableEffectDescription: 'Regenerates 10 HP and Mana 5 times',
|
|
683
|
+
},
|
|
653
684
|
];
|
|
654
685
|
|
|
655
686
|
export const itemContainerMock = (
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { IMarketplaceBlueprintSearchRequest, IMarketplaceBlueprintSummary } from '@rpg-engine/shared';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { BlueprintSearchModal } from '../../../components/Marketplace/BlueprintSearchModal';
|
|
5
|
+
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
6
|
+
import itemsAtlasJSON from '../../../mocks/atlas/items/items.json';
|
|
7
|
+
import itemsAtlasIMG from '../../../mocks/atlas/items/items.png';
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: 'Features/Marketplace/BlueprintSearchModal',
|
|
11
|
+
component: BlueprintSearchModal,
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'centered',
|
|
14
|
+
},
|
|
15
|
+
decorators: [
|
|
16
|
+
(Story) => (
|
|
17
|
+
<RPGUIRoot>
|
|
18
|
+
<div style={{ width: '800px', height: '600px', position: 'relative' }}>
|
|
19
|
+
<Story />
|
|
20
|
+
</div>
|
|
21
|
+
</RPGUIRoot>
|
|
22
|
+
),
|
|
23
|
+
],
|
|
24
|
+
} satisfies Meta<typeof BlueprintSearchModal>;
|
|
25
|
+
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<typeof BlueprintSearchModal>;
|
|
28
|
+
|
|
29
|
+
const mockBlueprints: IMarketplaceBlueprintSummary[] = [
|
|
30
|
+
{
|
|
31
|
+
key: 'items/broad-sword',
|
|
32
|
+
name: 'Broad Sword',
|
|
33
|
+
type: 'Weapon',
|
|
34
|
+
subType: 'Sword',
|
|
35
|
+
tier: 1,
|
|
36
|
+
textureAtlas: 'items',
|
|
37
|
+
texturePath: 'swords/broad-sword.png',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: 'items/angelic-sword',
|
|
41
|
+
name: 'Angelic Sword',
|
|
42
|
+
type: 'Weapon',
|
|
43
|
+
subType: 'Sword',
|
|
44
|
+
tier: 5,
|
|
45
|
+
textureAtlas: 'items',
|
|
46
|
+
texturePath: 'swords/angelic-sword.png',
|
|
47
|
+
rarity: 'Epic',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
key: 'items/leather-armor',
|
|
51
|
+
name: 'Leather Armor',
|
|
52
|
+
type: 'Armor',
|
|
53
|
+
subType: 'Body',
|
|
54
|
+
tier: 1,
|
|
55
|
+
textureAtlas: 'items',
|
|
56
|
+
texturePath: 'armors/leather-armor.png',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
key: 'items/wooden-staff',
|
|
60
|
+
name: 'Wooden Staff',
|
|
61
|
+
type: 'Weapon',
|
|
62
|
+
subType: 'Staff',
|
|
63
|
+
tier: 1,
|
|
64
|
+
textureAtlas: 'items',
|
|
65
|
+
texturePath: 'staffs/wooden-staff.png',
|
|
66
|
+
rarity: 'Rare',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
key: 'items/wooden-shield',
|
|
70
|
+
name: 'Wooden Shield',
|
|
71
|
+
type: 'Armor',
|
|
72
|
+
subType: 'Shield',
|
|
73
|
+
tier: 1,
|
|
74
|
+
textureAtlas: 'items',
|
|
75
|
+
texturePath: 'shields/wooden-shield.png',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
export const Default: Story = {
|
|
80
|
+
render: () => (
|
|
81
|
+
<BlueprintSearchModal
|
|
82
|
+
isOpen
|
|
83
|
+
onClose={() => console.log('close')}
|
|
84
|
+
onSelect={(blueprint) => console.log('selected:', blueprint.name)}
|
|
85
|
+
onSearch={(request: IMarketplaceBlueprintSearchRequest) => console.log('search:', request)}
|
|
86
|
+
blueprints={mockBlueprints}
|
|
87
|
+
totalCount={mockBlueprints.length}
|
|
88
|
+
currentPage={1}
|
|
89
|
+
isLoading={false}
|
|
90
|
+
atlasJSON={itemsAtlasJSON}
|
|
91
|
+
atlasIMG={itemsAtlasIMG}
|
|
92
|
+
/>
|
|
93
|
+
),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const LoadingState: Story = {
|
|
97
|
+
render: () => (
|
|
98
|
+
<BlueprintSearchModal
|
|
99
|
+
isOpen
|
|
100
|
+
onClose={() => console.log('close')}
|
|
101
|
+
onSelect={(blueprint) => console.log('selected:', blueprint.name)}
|
|
102
|
+
onSearch={(request: IMarketplaceBlueprintSearchRequest) => console.log('search:', request)}
|
|
103
|
+
blueprints={[]}
|
|
104
|
+
totalCount={0}
|
|
105
|
+
currentPage={1}
|
|
106
|
+
isLoading
|
|
107
|
+
atlasJSON={itemsAtlasJSON}
|
|
108
|
+
atlasIMG={itemsAtlasIMG}
|
|
109
|
+
/>
|
|
110
|
+
),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const EmptyResults: Story = {
|
|
114
|
+
render: () => (
|
|
115
|
+
<BlueprintSearchModal
|
|
116
|
+
isOpen
|
|
117
|
+
onClose={() => console.log('close')}
|
|
118
|
+
onSelect={(blueprint) => console.log('selected:', blueprint.name)}
|
|
119
|
+
onSearch={(request: IMarketplaceBlueprintSearchRequest) => console.log('search:', request)}
|
|
120
|
+
blueprints={[]}
|
|
121
|
+
totalCount={0}
|
|
122
|
+
currentPage={1}
|
|
123
|
+
isLoading={false}
|
|
124
|
+
atlasJSON={itemsAtlasJSON}
|
|
125
|
+
atlasIMG={itemsAtlasIMG}
|
|
126
|
+
/>
|
|
127
|
+
),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const Closed: Story = {
|
|
131
|
+
render: () => (
|
|
132
|
+
<BlueprintSearchModal
|
|
133
|
+
isOpen={false}
|
|
134
|
+
onClose={() => console.log('close')}
|
|
135
|
+
onSelect={(blueprint) => console.log('selected:', blueprint.name)}
|
|
136
|
+
onSearch={(request: IMarketplaceBlueprintSearchRequest) => console.log('search:', request)}
|
|
137
|
+
blueprints={mockBlueprints}
|
|
138
|
+
totalCount={mockBlueprints.length}
|
|
139
|
+
currentPage={1}
|
|
140
|
+
isLoading={false}
|
|
141
|
+
atlasJSON={itemsAtlasJSON}
|
|
142
|
+
atlasIMG={itemsAtlasIMG}
|
|
143
|
+
/>
|
|
144
|
+
),
|
|
145
|
+
};
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IMarketplaceBlueprintSearchRequest,
|
|
3
|
+
IMarketplaceBlueprintSummary,
|
|
4
|
+
IMarketplaceBuyOrderItem,
|
|
5
|
+
MarketplaceBuyOrderStatus,
|
|
6
|
+
} from '@rpg-engine/shared';
|
|
7
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
8
|
+
import React, { useState } from 'react';
|
|
9
|
+
import { BlueprintSearchModal } from '../../../components/Marketplace/BlueprintSearchModal';
|
|
10
|
+
import { BuyOrderPanel } from '../../../components/Marketplace/BuyOrderPanel';
|
|
11
|
+
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
12
|
+
import atlasJSON from '../../../mocks/atlas/items/items.json';
|
|
13
|
+
import atlasIMG from '../../../mocks/atlas/items/items.png';
|
|
14
|
+
|
|
15
|
+
const meta = {
|
|
16
|
+
title: 'Features/Marketplace/BuyOrderPanel',
|
|
17
|
+
component: BuyOrderPanel,
|
|
18
|
+
parameters: {
|
|
19
|
+
layout: 'centered',
|
|
20
|
+
},
|
|
21
|
+
decorators: [
|
|
22
|
+
(Story) => (
|
|
23
|
+
<RPGUIRoot>
|
|
24
|
+
<div style={{ width: '800px' }}>
|
|
25
|
+
<Story />
|
|
26
|
+
</div>
|
|
27
|
+
</RPGUIRoot>
|
|
28
|
+
),
|
|
29
|
+
],
|
|
30
|
+
} satisfies Meta<typeof BuyOrderPanel>;
|
|
31
|
+
|
|
32
|
+
export default meta;
|
|
33
|
+
type Story = StoryObj<typeof BuyOrderPanel>;
|
|
34
|
+
|
|
35
|
+
const now = new Date();
|
|
36
|
+
const weeksAgo = (weeks: number): Date =>
|
|
37
|
+
new Date(now.getTime() - weeks * 7 * 24 * 60 * 60 * 1000);
|
|
38
|
+
|
|
39
|
+
const mockSelectedBlueprint: IMarketplaceBlueprintSummary = {
|
|
40
|
+
key: 'items/broad-sword',
|
|
41
|
+
name: 'Broad Sword',
|
|
42
|
+
type: 'Weapon',
|
|
43
|
+
subType: 'Sword',
|
|
44
|
+
tier: 1,
|
|
45
|
+
textureAtlas: 'items',
|
|
46
|
+
texturePath: 'swords/broad-sword.png',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const mockBlueprintSearchResults: IMarketplaceBlueprintSummary[] = [
|
|
50
|
+
{
|
|
51
|
+
key: 'items/broad-sword',
|
|
52
|
+
name: 'Broad Sword',
|
|
53
|
+
type: 'Weapon',
|
|
54
|
+
subType: 'Sword',
|
|
55
|
+
tier: 1,
|
|
56
|
+
textureAtlas: 'items',
|
|
57
|
+
texturePath: 'swords/broad-sword.png',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
key: 'items/angelic-sword',
|
|
61
|
+
name: 'Angelic Sword',
|
|
62
|
+
type: 'Weapon',
|
|
63
|
+
subType: 'Sword',
|
|
64
|
+
tier: 5,
|
|
65
|
+
textureAtlas: 'items',
|
|
66
|
+
texturePath: 'swords/angelic-sword.png',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
key: 'items/leather-armor',
|
|
70
|
+
name: 'Leather Armor',
|
|
71
|
+
type: 'Armor',
|
|
72
|
+
subType: 'Body',
|
|
73
|
+
tier: 1,
|
|
74
|
+
textureAtlas: 'items',
|
|
75
|
+
texturePath: 'armors/leather-armor.png',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const mockBuyOrders: IMarketplaceBuyOrderItem[] = [
|
|
80
|
+
{
|
|
81
|
+
_id: 'order-1',
|
|
82
|
+
owner: 'character-1',
|
|
83
|
+
itemBlueprintKey: 'items/broad-sword',
|
|
84
|
+
itemRarity: 'Rare',
|
|
85
|
+
maxPrice: 500,
|
|
86
|
+
escrowedGold: 500,
|
|
87
|
+
fee: 25,
|
|
88
|
+
status: MarketplaceBuyOrderStatus.Active,
|
|
89
|
+
createdAt: weeksAgo(1),
|
|
90
|
+
updatedAt: weeksAgo(1),
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
_id: 'order-2',
|
|
94
|
+
owner: 'character-1',
|
|
95
|
+
itemBlueprintKey: 'swords/angelic-sword',
|
|
96
|
+
maxPrice: 2000,
|
|
97
|
+
escrowedGold: 2000,
|
|
98
|
+
fee: 100,
|
|
99
|
+
status: MarketplaceBuyOrderStatus.Fulfilled,
|
|
100
|
+
fulfilledBy: 'AnotherPlayer',
|
|
101
|
+
createdAt: weeksAgo(3),
|
|
102
|
+
updatedAt: weeksAgo(0),
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
_id: 'order-3',
|
|
106
|
+
owner: 'character-1',
|
|
107
|
+
itemBlueprintKey: 'armors/leather-armor',
|
|
108
|
+
maxPrice: 300,
|
|
109
|
+
escrowedGold: 0,
|
|
110
|
+
fee: 15,
|
|
111
|
+
status: MarketplaceBuyOrderStatus.Expired,
|
|
112
|
+
createdAt: weeksAgo(5),
|
|
113
|
+
updatedAt: weeksAgo(1),
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
const DefaultWrapper = () => {
|
|
118
|
+
const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>();
|
|
119
|
+
const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
|
|
120
|
+
const [quantity, setQuantity] = useState(0);
|
|
121
|
+
const [maxPrice, setMaxPrice] = useState(0);
|
|
122
|
+
const [rarity, setRarity] = useState('');
|
|
123
|
+
const [yourOrders, setYourOrders] = useState<IMarketplaceBuyOrderItem[]>(mockBuyOrders);
|
|
124
|
+
|
|
125
|
+
const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
|
|
126
|
+
setIsBlueprintSearchOpen(false);
|
|
127
|
+
setSelectedBlueprint(blueprint);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<>
|
|
132
|
+
<BuyOrderPanel
|
|
133
|
+
atlasJSON={atlasJSON}
|
|
134
|
+
atlasIMG={atlasIMG}
|
|
135
|
+
selectedBlueprint={selectedBlueprint}
|
|
136
|
+
onOpenBlueprintSearch={() => setIsBlueprintSearchOpen(true)}
|
|
137
|
+
onCloseDetails={() => {
|
|
138
|
+
setSelectedBlueprint(undefined);
|
|
139
|
+
setQuantity(0);
|
|
140
|
+
setMaxPrice(0);
|
|
141
|
+
setRarity('');
|
|
142
|
+
}}
|
|
143
|
+
onQuantityChange={setQuantity}
|
|
144
|
+
onMaxPriceChange={setMaxPrice}
|
|
145
|
+
onRarityChange={setRarity}
|
|
146
|
+
onPlaceBuyOrder={() => {
|
|
147
|
+
if (selectedBlueprint) {
|
|
148
|
+
const newOrder: IMarketplaceBuyOrderItem = {
|
|
149
|
+
_id: `order-${Date.now()}`,
|
|
150
|
+
owner: 'character-1',
|
|
151
|
+
itemBlueprintKey: selectedBlueprint.key,
|
|
152
|
+
itemRarity: rarity as any,
|
|
153
|
+
maxPrice,
|
|
154
|
+
escrowedGold: maxPrice,
|
|
155
|
+
fee: Math.floor(maxPrice * 0.05),
|
|
156
|
+
status: MarketplaceBuyOrderStatus.Active,
|
|
157
|
+
createdAt: new Date(),
|
|
158
|
+
updatedAt: new Date(),
|
|
159
|
+
};
|
|
160
|
+
setYourOrders(prev => [newOrder, ...prev]);
|
|
161
|
+
}
|
|
162
|
+
}}
|
|
163
|
+
currentQuantity={quantity}
|
|
164
|
+
currentMaxPrice={maxPrice}
|
|
165
|
+
selectedRarity={rarity}
|
|
166
|
+
yourBuyOrders={yourOrders}
|
|
167
|
+
yourBuyOrdersTotal={yourOrders.length}
|
|
168
|
+
yourBuyOrdersPage={1}
|
|
169
|
+
onYourBuyOrdersPageChange={(page) => console.log('Page:', page)}
|
|
170
|
+
onCancelBuyOrder={(id) => setYourOrders(prev => prev.filter(o => o._id !== id))}
|
|
171
|
+
/>
|
|
172
|
+
<BlueprintSearchModal
|
|
173
|
+
isOpen={isBlueprintSearchOpen}
|
|
174
|
+
onClose={() => setIsBlueprintSearchOpen(false)}
|
|
175
|
+
onSelect={handleBlueprintSelect}
|
|
176
|
+
onSearch={(req: IMarketplaceBlueprintSearchRequest) => console.log('search:', req)}
|
|
177
|
+
blueprints={mockBlueprintSearchResults}
|
|
178
|
+
totalCount={mockBlueprintSearchResults.length}
|
|
179
|
+
currentPage={1}
|
|
180
|
+
isLoading={false}
|
|
181
|
+
atlasJSON={atlasJSON}
|
|
182
|
+
atlasIMG={atlasIMG}
|
|
183
|
+
/>
|
|
184
|
+
</>
|
|
185
|
+
);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const WithBlueprintWrapper = () => {
|
|
189
|
+
const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>(mockSelectedBlueprint);
|
|
190
|
+
const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
|
|
191
|
+
const [quantity, setQuantity] = useState(0);
|
|
192
|
+
const [maxPrice, setMaxPrice] = useState(0);
|
|
193
|
+
const [rarity, setRarity] = useState('');
|
|
194
|
+
const [yourOrders, setYourOrders] = useState<IMarketplaceBuyOrderItem[]>(mockBuyOrders);
|
|
195
|
+
|
|
196
|
+
const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
|
|
197
|
+
setIsBlueprintSearchOpen(false);
|
|
198
|
+
setSelectedBlueprint(blueprint);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<>
|
|
203
|
+
<BuyOrderPanel
|
|
204
|
+
atlasJSON={atlasJSON}
|
|
205
|
+
atlasIMG={atlasIMG}
|
|
206
|
+
selectedBlueprint={selectedBlueprint}
|
|
207
|
+
onOpenBlueprintSearch={() => setIsBlueprintSearchOpen(true)}
|
|
208
|
+
onCloseDetails={() => {
|
|
209
|
+
setSelectedBlueprint(undefined);
|
|
210
|
+
setQuantity(0);
|
|
211
|
+
setMaxPrice(0);
|
|
212
|
+
setRarity('');
|
|
213
|
+
}}
|
|
214
|
+
onQuantityChange={setQuantity}
|
|
215
|
+
onMaxPriceChange={setMaxPrice}
|
|
216
|
+
onRarityChange={setRarity}
|
|
217
|
+
onPlaceBuyOrder={() => {
|
|
218
|
+
if (selectedBlueprint) {
|
|
219
|
+
const newOrder: IMarketplaceBuyOrderItem = {
|
|
220
|
+
_id: `order-${Date.now()}`,
|
|
221
|
+
owner: 'character-1',
|
|
222
|
+
itemBlueprintKey: selectedBlueprint.key,
|
|
223
|
+
itemRarity: rarity as any,
|
|
224
|
+
maxPrice,
|
|
225
|
+
escrowedGold: maxPrice,
|
|
226
|
+
fee: Math.floor(maxPrice * 0.05),
|
|
227
|
+
status: MarketplaceBuyOrderStatus.Active,
|
|
228
|
+
createdAt: new Date(),
|
|
229
|
+
updatedAt: new Date(),
|
|
230
|
+
};
|
|
231
|
+
setYourOrders(prev => [newOrder, ...prev]);
|
|
232
|
+
}
|
|
233
|
+
}}
|
|
234
|
+
currentQuantity={quantity}
|
|
235
|
+
currentMaxPrice={maxPrice}
|
|
236
|
+
selectedRarity={rarity}
|
|
237
|
+
yourBuyOrders={yourOrders}
|
|
238
|
+
yourBuyOrdersTotal={yourOrders.length}
|
|
239
|
+
yourBuyOrdersPage={1}
|
|
240
|
+
onYourBuyOrdersPageChange={(page) => console.log('Page:', page)}
|
|
241
|
+
onCancelBuyOrder={(id) => setYourOrders(prev => prev.filter(o => o._id !== id))}
|
|
242
|
+
/>
|
|
243
|
+
<BlueprintSearchModal
|
|
244
|
+
isOpen={isBlueprintSearchOpen}
|
|
245
|
+
onClose={() => setIsBlueprintSearchOpen(false)}
|
|
246
|
+
onSelect={handleBlueprintSelect}
|
|
247
|
+
onSearch={(req: IMarketplaceBlueprintSearchRequest) => console.log('search:', req)}
|
|
248
|
+
blueprints={mockBlueprintSearchResults}
|
|
249
|
+
totalCount={mockBlueprintSearchResults.length}
|
|
250
|
+
currentPage={1}
|
|
251
|
+
isLoading={false}
|
|
252
|
+
atlasJSON={atlasJSON}
|
|
253
|
+
atlasIMG={atlasIMG}
|
|
254
|
+
/>
|
|
255
|
+
</>
|
|
256
|
+
);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const EmptyWrapper = () => {
|
|
260
|
+
const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
|
|
261
|
+
const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>();
|
|
262
|
+
const [quantity, setQuantity] = useState(0);
|
|
263
|
+
const [maxPrice, setMaxPrice] = useState(0);
|
|
264
|
+
const [rarity, setRarity] = useState('');
|
|
265
|
+
|
|
266
|
+
const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
|
|
267
|
+
setIsBlueprintSearchOpen(false);
|
|
268
|
+
setSelectedBlueprint(blueprint);
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<>
|
|
273
|
+
<BuyOrderPanel
|
|
274
|
+
atlasJSON={atlasJSON}
|
|
275
|
+
atlasIMG={atlasIMG}
|
|
276
|
+
selectedBlueprint={selectedBlueprint}
|
|
277
|
+
onOpenBlueprintSearch={() => setIsBlueprintSearchOpen(true)}
|
|
278
|
+
onCloseDetails={() => {
|
|
279
|
+
setSelectedBlueprint(undefined);
|
|
280
|
+
setQuantity(0);
|
|
281
|
+
setMaxPrice(0);
|
|
282
|
+
setRarity('');
|
|
283
|
+
}}
|
|
284
|
+
onQuantityChange={setQuantity}
|
|
285
|
+
onMaxPriceChange={setMaxPrice}
|
|
286
|
+
onRarityChange={setRarity}
|
|
287
|
+
onPlaceBuyOrder={() => console.log('place order')}
|
|
288
|
+
currentQuantity={quantity}
|
|
289
|
+
currentMaxPrice={maxPrice}
|
|
290
|
+
selectedRarity={rarity}
|
|
291
|
+
yourBuyOrders={[]}
|
|
292
|
+
yourBuyOrdersTotal={0}
|
|
293
|
+
yourBuyOrdersPage={1}
|
|
294
|
+
onYourBuyOrdersPageChange={(page) => console.log('Page:', page)}
|
|
295
|
+
onCancelBuyOrder={(id) => console.log('Cancel:', id)}
|
|
296
|
+
/>
|
|
297
|
+
<BlueprintSearchModal
|
|
298
|
+
isOpen={isBlueprintSearchOpen}
|
|
299
|
+
onClose={() => setIsBlueprintSearchOpen(false)}
|
|
300
|
+
onSelect={handleBlueprintSelect}
|
|
301
|
+
onSearch={(req: IMarketplaceBlueprintSearchRequest) => console.log('search:', req)}
|
|
302
|
+
blueprints={mockBlueprintSearchResults}
|
|
303
|
+
totalCount={mockBlueprintSearchResults.length}
|
|
304
|
+
currentPage={1}
|
|
305
|
+
isLoading={false}
|
|
306
|
+
atlasJSON={atlasJSON}
|
|
307
|
+
atlasIMG={atlasIMG}
|
|
308
|
+
/>
|
|
309
|
+
</>
|
|
310
|
+
);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
export const Default: Story = {
|
|
314
|
+
render: () => <DefaultWrapper />,
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
export const WithSelectedBlueprint: Story = {
|
|
318
|
+
render: () => <WithBlueprintWrapper />,
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
export const EmptyOrders: Story = {
|
|
322
|
+
render: () => <EmptyWrapper />,
|
|
323
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { IMarketplaceBuyOrderItem, MarketplaceBuyOrderStatus } from '@rpg-engine/shared';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { BuyOrderRow } from '../../../components/Marketplace/BuyOrderRows';
|
|
5
|
+
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
6
|
+
import atlasJSON from '../../../mocks/atlas/items/items.json';
|
|
7
|
+
import atlasIMG from '../../../mocks/atlas/items/items.png';
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: 'Features/Marketplace/BuyOrderRows',
|
|
11
|
+
component: BuyOrderRow,
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'centered',
|
|
14
|
+
},
|
|
15
|
+
decorators: [
|
|
16
|
+
(Story) => (
|
|
17
|
+
<RPGUIRoot>
|
|
18
|
+
<div style={{ width: '800px' }}>
|
|
19
|
+
<Story />
|
|
20
|
+
</div>
|
|
21
|
+
</RPGUIRoot>
|
|
22
|
+
),
|
|
23
|
+
],
|
|
24
|
+
} satisfies Meta<typeof BuyOrderRow>;
|
|
25
|
+
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<typeof BuyOrderRow>;
|
|
28
|
+
|
|
29
|
+
const now = new Date();
|
|
30
|
+
const weeksAgo = (weeks: number): Date =>
|
|
31
|
+
new Date(now.getTime() - weeks * 7 * 24 * 60 * 60 * 1000);
|
|
32
|
+
|
|
33
|
+
const mockActiveBuyOrder: IMarketplaceBuyOrderItem = {
|
|
34
|
+
_id: 'order-1',
|
|
35
|
+
owner: 'character-1',
|
|
36
|
+
itemBlueprintKey: 'items/broad-sword',
|
|
37
|
+
itemRarity: 'Rare',
|
|
38
|
+
maxPrice: 500,
|
|
39
|
+
escrowedGold: 500,
|
|
40
|
+
fee: 25,
|
|
41
|
+
status: MarketplaceBuyOrderStatus.Active,
|
|
42
|
+
createdAt: weeksAgo(1),
|
|
43
|
+
updatedAt: weeksAgo(1),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const mockFulfilledBuyOrder: IMarketplaceBuyOrderItem = {
|
|
47
|
+
_id: 'order-2',
|
|
48
|
+
owner: 'character-1',
|
|
49
|
+
itemBlueprintKey: 'items/angelic-sword',
|
|
50
|
+
maxPrice: 2000,
|
|
51
|
+
escrowedGold: 2000,
|
|
52
|
+
fee: 100,
|
|
53
|
+
status: MarketplaceBuyOrderStatus.Fulfilled,
|
|
54
|
+
fulfilledBy: 'AnotherPlayer',
|
|
55
|
+
createdAt: weeksAgo(3),
|
|
56
|
+
updatedAt: weeksAgo(0),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const mockExpiredBuyOrder: IMarketplaceBuyOrderItem = {
|
|
60
|
+
_id: 'order-3',
|
|
61
|
+
owner: 'character-1',
|
|
62
|
+
itemBlueprintKey: 'items/leather-armor',
|
|
63
|
+
maxPrice: 300,
|
|
64
|
+
escrowedGold: 0,
|
|
65
|
+
fee: 15,
|
|
66
|
+
status: MarketplaceBuyOrderStatus.Expired,
|
|
67
|
+
createdAt: weeksAgo(5),
|
|
68
|
+
updatedAt: weeksAgo(1),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const ActiveOrder: Story = {
|
|
72
|
+
render: () => (
|
|
73
|
+
<BuyOrderRow
|
|
74
|
+
buyOrder={mockActiveBuyOrder}
|
|
75
|
+
atlasJSON={atlasJSON}
|
|
76
|
+
atlasIMG={atlasIMG}
|
|
77
|
+
isOwn
|
|
78
|
+
onCancel={(id) => console.log('cancel order:', id)}
|
|
79
|
+
/>
|
|
80
|
+
),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const FulfilledOrder: Story = {
|
|
84
|
+
render: () => (
|
|
85
|
+
<BuyOrderRow
|
|
86
|
+
buyOrder={mockFulfilledBuyOrder}
|
|
87
|
+
atlasJSON={atlasJSON}
|
|
88
|
+
atlasIMG={atlasIMG}
|
|
89
|
+
isOwn
|
|
90
|
+
/>
|
|
91
|
+
),
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const ExpiredOrder: Story = {
|
|
95
|
+
render: () => (
|
|
96
|
+
<BuyOrderRow
|
|
97
|
+
buyOrder={mockExpiredBuyOrder}
|
|
98
|
+
atlasJSON={atlasJSON}
|
|
99
|
+
atlasIMG={atlasIMG}
|
|
100
|
+
isOwn={false}
|
|
101
|
+
/>
|
|
102
|
+
),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const OpenOrderForSellers: Story = {
|
|
106
|
+
render: () => (
|
|
107
|
+
<BuyOrderRow
|
|
108
|
+
buyOrder={mockActiveBuyOrder}
|
|
109
|
+
atlasJSON={atlasJSON}
|
|
110
|
+
atlasIMG={atlasIMG}
|
|
111
|
+
isOwn={false}
|
|
112
|
+
onFulfill={(id) => console.log('fulfill order:', id)}
|
|
113
|
+
showRequestTag
|
|
114
|
+
/>
|
|
115
|
+
),
|
|
116
|
+
};
|