@rpg-engine/long-bow 0.8.141 → 0.8.145
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/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 +11529 -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 +11518 -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 +418 -0
- package/src/components/Marketplace/BuyOrderDetailsModal.tsx +307 -0
- package/src/components/Marketplace/BuyOrderPanel.tsx +266 -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 +207 -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 +107 -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,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IMarketplaceBlueprintSummary,
|
|
3
|
+
IMarketplaceBuyOrderItem,
|
|
4
|
+
MarketplaceBuyOrderStatus,
|
|
5
|
+
} from '@rpg-engine/shared';
|
|
6
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
7
|
+
import React, { useState } from 'react';
|
|
8
|
+
import { BuyOrderPanel } from '../../../components/Marketplace/BuyOrderPanel';
|
|
9
|
+
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
10
|
+
import atlasJSON from '../../../mocks/atlas/items/items.json';
|
|
11
|
+
import atlasIMG from '../../../mocks/atlas/items/items.png';
|
|
12
|
+
|
|
13
|
+
const meta = {
|
|
14
|
+
title: 'Features/Marketplace/BuyOrderPanel',
|
|
15
|
+
component: BuyOrderPanel,
|
|
16
|
+
parameters: {
|
|
17
|
+
layout: 'centered',
|
|
18
|
+
},
|
|
19
|
+
decorators: [
|
|
20
|
+
(Story) => (
|
|
21
|
+
<RPGUIRoot>
|
|
22
|
+
<div style={{ width: '800px' }}>
|
|
23
|
+
<Story />
|
|
24
|
+
</div>
|
|
25
|
+
</RPGUIRoot>
|
|
26
|
+
),
|
|
27
|
+
],
|
|
28
|
+
} satisfies Meta<typeof BuyOrderPanel>;
|
|
29
|
+
|
|
30
|
+
export default meta;
|
|
31
|
+
type Story = StoryObj<typeof BuyOrderPanel>;
|
|
32
|
+
|
|
33
|
+
const now = new Date();
|
|
34
|
+
const weeksAgo = (weeks: number): Date =>
|
|
35
|
+
new Date(now.getTime() - weeks * 7 * 24 * 60 * 60 * 1000);
|
|
36
|
+
|
|
37
|
+
const mockSelectedBlueprint: IMarketplaceBlueprintSummary = {
|
|
38
|
+
key: 'items/broad-sword',
|
|
39
|
+
name: 'Broad Sword',
|
|
40
|
+
type: 'Weapon',
|
|
41
|
+
subType: 'Sword',
|
|
42
|
+
tier: 1,
|
|
43
|
+
textureAtlas: 'items',
|
|
44
|
+
texturePath: 'swords/broad-sword.png',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const mockBuyOrders: IMarketplaceBuyOrderItem[] = [
|
|
48
|
+
{
|
|
49
|
+
_id: 'order-1',
|
|
50
|
+
owner: 'character-1',
|
|
51
|
+
itemBlueprintKey: 'items/broad-sword',
|
|
52
|
+
itemRarity: 'Rare',
|
|
53
|
+
maxPrice: 500,
|
|
54
|
+
escrowedGold: 500,
|
|
55
|
+
fee: 25,
|
|
56
|
+
status: MarketplaceBuyOrderStatus.Active,
|
|
57
|
+
createdAt: weeksAgo(1),
|
|
58
|
+
updatedAt: weeksAgo(1),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
_id: 'order-2',
|
|
62
|
+
owner: 'character-1',
|
|
63
|
+
itemBlueprintKey: 'swords/angelic-sword',
|
|
64
|
+
maxPrice: 2000,
|
|
65
|
+
escrowedGold: 2000,
|
|
66
|
+
fee: 100,
|
|
67
|
+
status: MarketplaceBuyOrderStatus.Fulfilled,
|
|
68
|
+
fulfilledBy: 'AnotherPlayer',
|
|
69
|
+
createdAt: weeksAgo(3),
|
|
70
|
+
updatedAt: weeksAgo(0),
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
_id: 'order-3',
|
|
74
|
+
owner: 'character-1',
|
|
75
|
+
itemBlueprintKey: 'armors/leather-armor',
|
|
76
|
+
maxPrice: 300,
|
|
77
|
+
escrowedGold: 0,
|
|
78
|
+
fee: 15,
|
|
79
|
+
status: MarketplaceBuyOrderStatus.Expired,
|
|
80
|
+
createdAt: weeksAgo(5),
|
|
81
|
+
updatedAt: weeksAgo(1),
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
const DefaultWrapper = () => {
|
|
86
|
+
const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>();
|
|
87
|
+
const [quantity, setQuantity] = useState(0);
|
|
88
|
+
const [maxPrice, setMaxPrice] = useState(0);
|
|
89
|
+
const [rarity, setRarity] = useState('');
|
|
90
|
+
const [yourOrders, setYourOrders] = useState<IMarketplaceBuyOrderItem[]>(mockBuyOrders);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<BuyOrderPanel
|
|
94
|
+
atlasJSON={atlasJSON}
|
|
95
|
+
atlasIMG={atlasIMG}
|
|
96
|
+
selectedBlueprint={selectedBlueprint}
|
|
97
|
+
onOpenBlueprintSearch={() => setSelectedBlueprint(mockSelectedBlueprint)}
|
|
98
|
+
onCloseDetails={() => {
|
|
99
|
+
setSelectedBlueprint(undefined);
|
|
100
|
+
setQuantity(0);
|
|
101
|
+
setMaxPrice(0);
|
|
102
|
+
setRarity('');
|
|
103
|
+
}}
|
|
104
|
+
onQuantityChange={setQuantity}
|
|
105
|
+
onMaxPriceChange={setMaxPrice}
|
|
106
|
+
onRarityChange={setRarity}
|
|
107
|
+
onPlaceBuyOrder={() => {
|
|
108
|
+
if (selectedBlueprint) {
|
|
109
|
+
const newOrder: IMarketplaceBuyOrderItem = {
|
|
110
|
+
_id: `order-${Date.now()}`,
|
|
111
|
+
owner: 'character-1',
|
|
112
|
+
itemBlueprintKey: selectedBlueprint.key,
|
|
113
|
+
itemRarity: rarity as any,
|
|
114
|
+
maxPrice,
|
|
115
|
+
escrowedGold: maxPrice,
|
|
116
|
+
fee: Math.floor(maxPrice * 0.05),
|
|
117
|
+
status: MarketplaceBuyOrderStatus.Active,
|
|
118
|
+
createdAt: new Date(),
|
|
119
|
+
updatedAt: new Date(),
|
|
120
|
+
};
|
|
121
|
+
setYourOrders(prev => [newOrder, ...prev]);
|
|
122
|
+
}
|
|
123
|
+
}}
|
|
124
|
+
currentQuantity={quantity}
|
|
125
|
+
currentMaxPrice={maxPrice}
|
|
126
|
+
selectedRarity={rarity}
|
|
127
|
+
yourBuyOrders={yourOrders}
|
|
128
|
+
yourBuyOrdersTotal={yourOrders.length}
|
|
129
|
+
yourBuyOrdersPage={1}
|
|
130
|
+
onYourBuyOrdersPageChange={(page) => console.log('Page:', page)}
|
|
131
|
+
onCancelBuyOrder={(id) => setYourOrders(prev => prev.filter(o => o._id !== id))}
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const WithBlueprintWrapper = () => {
|
|
137
|
+
const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>(mockSelectedBlueprint);
|
|
138
|
+
const [quantity, setQuantity] = useState(0);
|
|
139
|
+
const [maxPrice, setMaxPrice] = useState(0);
|
|
140
|
+
const [rarity, setRarity] = useState('');
|
|
141
|
+
const [yourOrders, setYourOrders] = useState<IMarketplaceBuyOrderItem[]>(mockBuyOrders);
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<BuyOrderPanel
|
|
145
|
+
atlasJSON={atlasJSON}
|
|
146
|
+
atlasIMG={atlasIMG}
|
|
147
|
+
selectedBlueprint={selectedBlueprint}
|
|
148
|
+
onOpenBlueprintSearch={() => setSelectedBlueprint(mockSelectedBlueprint)}
|
|
149
|
+
onCloseDetails={() => {
|
|
150
|
+
setSelectedBlueprint(undefined);
|
|
151
|
+
setQuantity(0);
|
|
152
|
+
setMaxPrice(0);
|
|
153
|
+
setRarity('');
|
|
154
|
+
}}
|
|
155
|
+
onQuantityChange={setQuantity}
|
|
156
|
+
onMaxPriceChange={setMaxPrice}
|
|
157
|
+
onRarityChange={setRarity}
|
|
158
|
+
onPlaceBuyOrder={() => console.log('place order')}
|
|
159
|
+
currentQuantity={quantity}
|
|
160
|
+
currentMaxPrice={maxPrice}
|
|
161
|
+
selectedRarity={rarity}
|
|
162
|
+
yourBuyOrders={yourOrders}
|
|
163
|
+
yourBuyOrdersTotal={yourOrders.length}
|
|
164
|
+
yourBuyOrdersPage={1}
|
|
165
|
+
onYourBuyOrdersPageChange={(page) => console.log('Page:', page)}
|
|
166
|
+
onCancelBuyOrder={(id) => setYourOrders(prev => prev.filter(o => o._id !== id))}
|
|
167
|
+
/>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const EmptyWrapper = () => {
|
|
172
|
+
const [quantity, setQuantity] = useState(0);
|
|
173
|
+
const [maxPrice, setMaxPrice] = useState(0);
|
|
174
|
+
const [rarity, setRarity] = useState('');
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<BuyOrderPanel
|
|
178
|
+
atlasJSON={atlasJSON}
|
|
179
|
+
atlasIMG={atlasIMG}
|
|
180
|
+
onOpenBlueprintSearch={() => console.log('Opening blueprint search...')}
|
|
181
|
+
onQuantityChange={setQuantity}
|
|
182
|
+
onMaxPriceChange={setMaxPrice}
|
|
183
|
+
onRarityChange={setRarity}
|
|
184
|
+
onPlaceBuyOrder={() => console.log('place order')}
|
|
185
|
+
currentQuantity={quantity}
|
|
186
|
+
currentMaxPrice={maxPrice}
|
|
187
|
+
selectedRarity={rarity}
|
|
188
|
+
yourBuyOrders={[]}
|
|
189
|
+
yourBuyOrdersTotal={0}
|
|
190
|
+
yourBuyOrdersPage={1}
|
|
191
|
+
onYourBuyOrdersPageChange={(page) => console.log('Page:', page)}
|
|
192
|
+
onCancelBuyOrder={(id) => console.log('Cancel:', id)}
|
|
193
|
+
/>
|
|
194
|
+
);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const Default: Story = {
|
|
198
|
+
render: () => <DefaultWrapper />,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const WithSelectedBlueprint: Story = {
|
|
202
|
+
render: () => <WithBlueprintWrapper />,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export const EmptyOrders: Story = {
|
|
206
|
+
render: () => <EmptyWrapper />,
|
|
207
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IMarketplaceTransaction,
|
|
3
|
+
MarketplaceTransactionType,
|
|
4
|
+
} from '@rpg-engine/shared';
|
|
5
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { HistoryPanel } from '../../../components/Marketplace/HistoryPanel';
|
|
8
|
+
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
9
|
+
import atlasJSON from '../../../mocks/atlas/items/items.json';
|
|
10
|
+
import atlasIMG from '../../../mocks/atlas/items/items.png';
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
title: 'Features/Marketplace/HistoryPanel',
|
|
14
|
+
component: HistoryPanel,
|
|
15
|
+
parameters: {
|
|
16
|
+
layout: 'centered',
|
|
17
|
+
},
|
|
18
|
+
decorators: [
|
|
19
|
+
(Story) => (
|
|
20
|
+
<RPGUIRoot>
|
|
21
|
+
<div style={{ width: '800px' }}>
|
|
22
|
+
<Story />
|
|
23
|
+
</div>
|
|
24
|
+
</RPGUIRoot>
|
|
25
|
+
),
|
|
26
|
+
],
|
|
27
|
+
} satisfies Meta<typeof HistoryPanel>;
|
|
28
|
+
|
|
29
|
+
export default meta;
|
|
30
|
+
type Story = StoryObj<typeof HistoryPanel>;
|
|
31
|
+
|
|
32
|
+
const now = new Date();
|
|
33
|
+
const daysAgo = (days: number): Date =>
|
|
34
|
+
new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
|
|
35
|
+
|
|
36
|
+
const mockTransactions: IMarketplaceTransaction[] = [
|
|
37
|
+
{
|
|
38
|
+
owner: 'character-1',
|
|
39
|
+
type: MarketplaceTransactionType.Purchase,
|
|
40
|
+
goldAmount: 500,
|
|
41
|
+
itemKey: 'items/iron-sword.png',
|
|
42
|
+
itemName: 'Iron Sword',
|
|
43
|
+
counterpartName: 'SomePlayer',
|
|
44
|
+
currency: 'gold',
|
|
45
|
+
createdAt: daysAgo(0),
|
|
46
|
+
updatedAt: daysAgo(0),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
owner: 'character-1',
|
|
50
|
+
type: MarketplaceTransactionType.Sale,
|
|
51
|
+
goldAmount: 1200,
|
|
52
|
+
itemKey: 'items/leather-armor.png',
|
|
53
|
+
itemName: 'Leather Armor',
|
|
54
|
+
counterpartName: 'AnotherPlayer',
|
|
55
|
+
currency: 'dc', // DC sale
|
|
56
|
+
createdAt: daysAgo(1),
|
|
57
|
+
updatedAt: daysAgo(1),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
owner: 'character-1',
|
|
61
|
+
type: MarketplaceTransactionType.Purchase,
|
|
62
|
+
goldAmount: 275000,
|
|
63
|
+
itemKey: 'items/angelic-sword.png',
|
|
64
|
+
itemName: 'Angelic Sword',
|
|
65
|
+
counterpartName: 'DCBuyer',
|
|
66
|
+
currency: 'dc', // DC purchase
|
|
67
|
+
createdAt: daysAgo(2),
|
|
68
|
+
updatedAt: daysAgo(2),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
owner: 'character-1',
|
|
72
|
+
type: MarketplaceTransactionType.ListingFee,
|
|
73
|
+
goldAmount: 60,
|
|
74
|
+
itemKey: 'items/leather-armor.png',
|
|
75
|
+
itemName: 'Leather Armor',
|
|
76
|
+
createdAt: daysAgo(1),
|
|
77
|
+
updatedAt: daysAgo(1),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
owner: 'character-1',
|
|
81
|
+
type: MarketplaceTransactionType.Withdrawal,
|
|
82
|
+
goldAmount: 1200,
|
|
83
|
+
createdAt: daysAgo(2),
|
|
84
|
+
updatedAt: daysAgo(2),
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
owner: 'character-1',
|
|
88
|
+
type: MarketplaceTransactionType.Expired,
|
|
89
|
+
goldAmount: 0,
|
|
90
|
+
itemKey: 'items/magic-staff.png',
|
|
91
|
+
itemName: 'Magic Staff',
|
|
92
|
+
createdAt: daysAgo(3),
|
|
93
|
+
updatedAt: daysAgo(3),
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
owner: 'character-1',
|
|
97
|
+
type: MarketplaceTransactionType.Unlisted,
|
|
98
|
+
goldAmount: 0,
|
|
99
|
+
itemKey: 'items/shield.png',
|
|
100
|
+
itemName: 'Wooden Shield',
|
|
101
|
+
createdAt: daysAgo(4),
|
|
102
|
+
updatedAt: daysAgo(4),
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
owner: 'character-1',
|
|
106
|
+
type: MarketplaceTransactionType.BuyOrderPlaced,
|
|
107
|
+
goldAmount: 800,
|
|
108
|
+
itemKey: 'items/angelic-sword.png',
|
|
109
|
+
itemName: 'Angelic Sword',
|
|
110
|
+
createdAt: daysAgo(5),
|
|
111
|
+
updatedAt: daysAgo(5),
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
owner: 'character-1',
|
|
115
|
+
type: MarketplaceTransactionType.BuyOrderFulfilled,
|
|
116
|
+
goldAmount: 800,
|
|
117
|
+
itemKey: 'items/angelic-sword.png',
|
|
118
|
+
itemName: 'Angelic Sword',
|
|
119
|
+
counterpartName: 'Fulfiller',
|
|
120
|
+
createdAt: daysAgo(6),
|
|
121
|
+
updatedAt: daysAgo(6),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
export const Default: Story = {
|
|
126
|
+
render: () => (
|
|
127
|
+
<HistoryPanel
|
|
128
|
+
transactions={mockTransactions}
|
|
129
|
+
totalCount={mockTransactions.length}
|
|
130
|
+
currentPage={1}
|
|
131
|
+
itemsPerPage={10}
|
|
132
|
+
selectedType="All"
|
|
133
|
+
onTypeChange={(type) => console.log('type change:', type)}
|
|
134
|
+
onPageChange={(page) => console.log('page change:', page)}
|
|
135
|
+
atlasJSON={atlasJSON}
|
|
136
|
+
atlasIMG={atlasIMG}
|
|
137
|
+
dcToGoldSwapRate={550000} // 1 DC = 550,000 GOLD
|
|
138
|
+
/>
|
|
139
|
+
),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const EmptyState: Story = {
|
|
143
|
+
render: () => (
|
|
144
|
+
<HistoryPanel
|
|
145
|
+
transactions={[]}
|
|
146
|
+
totalCount={0}
|
|
147
|
+
currentPage={1}
|
|
148
|
+
itemsPerPage={10}
|
|
149
|
+
selectedType="All"
|
|
150
|
+
onTypeChange={(type) => console.log('type change:', type)}
|
|
151
|
+
onPageChange={(page) => console.log('page change:', page)}
|
|
152
|
+
atlasJSON={atlasJSON}
|
|
153
|
+
atlasIMG={atlasIMG}
|
|
154
|
+
dcToGoldSwapRate={550000}
|
|
155
|
+
/>
|
|
156
|
+
),
|
|
157
|
+
};
|