@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.
Files changed (62) hide show
  1. package/dist/components/Marketplace/BlueprintSearchModal.d.ts +17 -0
  2. package/dist/components/Marketplace/BuyOrderDetailsModal.d.ts +17 -0
  3. package/dist/components/Marketplace/BuyOrderPanel.d.ts +24 -0
  4. package/dist/components/Marketplace/BuyOrderRows.d.ts +13 -0
  5. package/dist/components/Marketplace/BuyPanel.d.ts +9 -1
  6. package/dist/components/Marketplace/HistoryPanel.d.ts +18 -0
  7. package/dist/components/Marketplace/ManagmentPanel.d.ts +3 -2
  8. package/dist/components/Marketplace/Marketplace.d.ts +35 -2
  9. package/dist/components/Marketplace/MarketplaceSettingsPanel.d.ts +2 -1
  10. package/dist/components/Store/PaymentMethodModal.d.ts +1 -0
  11. package/dist/components/shared/LabelPill/LabelPill.d.ts +9 -0
  12. package/dist/components/shared/LabelPill/index.d.ts +1 -0
  13. package/dist/components/shared/SegmentedToggle/SegmentedToggle.d.ts +12 -0
  14. package/dist/components/shared/SegmentedToggle/index.d.ts +1 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/long-bow.cjs.development.js +11529 -1288
  17. package/dist/long-bow.cjs.development.js.map +1 -1
  18. package/dist/long-bow.cjs.production.min.js +1 -1
  19. package/dist/long-bow.cjs.production.min.js.map +1 -1
  20. package/dist/long-bow.esm.js +11518 -1290
  21. package/dist/long-bow.esm.js.map +1 -1
  22. package/dist/stories/Features/marketplace/BlueprintSearchModal.stories.d.ts +1 -0
  23. package/dist/stories/Features/marketplace/BuyOrderPanel.stories.d.ts +1 -0
  24. package/dist/stories/Features/marketplace/BuyOrderRows.stories.d.ts +1 -0
  25. package/dist/stories/Features/marketplace/HistoryPanel.stories.d.ts +1 -0
  26. package/dist/stories/Features/trading/MarketplaceRows.stories.d.ts +2 -1
  27. package/dist/stories/UI/buttonsAndInputs/SegmentedToggle.stories.d.ts +6 -0
  28. package/dist/stories/UI/text/LabelPill.stories.d.ts +7 -0
  29. package/dist/utils/atlasUtils.d.ts +2 -0
  30. package/package.json +2 -2
  31. package/src/components/Marketplace/BlueprintSearchModal.tsx +418 -0
  32. package/src/components/Marketplace/BuyOrderDetailsModal.tsx +307 -0
  33. package/src/components/Marketplace/BuyOrderPanel.tsx +266 -0
  34. package/src/components/Marketplace/BuyOrderRows.tsx +287 -0
  35. package/src/components/Marketplace/BuyPanel.tsx +406 -166
  36. package/src/components/Marketplace/HistoryPanel.tsx +422 -0
  37. package/src/components/Marketplace/ManagmentPanel.tsx +13 -15
  38. package/src/components/Marketplace/Marketplace.tsx +181 -30
  39. package/src/components/Marketplace/MarketplaceBuyModal.tsx +1 -0
  40. package/src/components/Marketplace/MarketplaceRows.tsx +41 -10
  41. package/src/components/Marketplace/MarketplaceSettingsPanel.tsx +4 -3
  42. package/src/components/Store/CartView.tsx +11 -0
  43. package/src/components/Store/PaymentMethodModal.tsx +26 -9
  44. package/src/components/shared/LabelPill/LabelPill.tsx +45 -0
  45. package/src/components/shared/LabelPill/index.ts +1 -0
  46. package/src/components/shared/SegmentedToggle/SegmentedToggle.tsx +61 -0
  47. package/src/components/shared/SegmentedToggle/index.ts +1 -0
  48. package/src/components/shared/SpriteFromAtlas.tsx +7 -2
  49. package/src/index.tsx +4 -0
  50. package/src/mocks/atlas/items/items.json +33998 -25238
  51. package/src/mocks/atlas/items/items.png +0 -0
  52. package/src/mocks/itemContainer.mocks.ts +31 -0
  53. package/src/stories/Features/marketplace/BlueprintSearchModal.stories.tsx +145 -0
  54. package/src/stories/Features/marketplace/BuyOrderPanel.stories.tsx +207 -0
  55. package/src/stories/Features/marketplace/BuyOrderRows.stories.tsx +116 -0
  56. package/src/stories/Features/marketplace/HistoryPanel.stories.tsx +157 -0
  57. package/src/stories/Features/trading/Marketplace.stories.tsx +107 -0
  58. package/src/stories/Features/trading/MarketplaceRows.stories.tsx +11 -0
  59. package/src/stories/UI/buttonsAndInputs/SegmentedToggle.stories.tsx +54 -0
  60. package/src/stories/UI/text/LabelPill.stories.tsx +43 -0
  61. package/src/utils/__test__/atlasUtils.spec.ts +26 -0
  62. 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
+ };