@rpg-engine/long-bow 0.8.145 → 0.8.148

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.
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  IMarketplaceBlueprintSummary,
3
3
  IMarketplaceBuyOrderItem,
4
+ MarketplaceBuyOrderStatus,
4
5
  } from '@rpg-engine/shared';
5
6
  import { Search } from 'pixelarticons/react/Search';
6
- import React from 'react';
7
+ import React, { useEffect, useState } from 'react';
7
8
  import styled from 'styled-components';
8
9
  import { Pager } from '../Pager';
9
10
  import { CTAButton } from '../shared/CTAButton/CTAButton';
11
+ import { SegmentedToggle } from '../shared/SegmentedToggle';
10
12
  import { rarityColor } from '../Item/Inventory/ItemSlotRarity';
11
13
  import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
12
14
  import { BuyOrderDetailsModal } from './BuyOrderDetailsModal';
@@ -31,6 +33,8 @@ export interface IBuyOrderPanelProps {
31
33
  yourBuyOrdersPage: number;
32
34
  onYourBuyOrdersPageChange: (page: number) => void;
33
35
  onCancelBuyOrder: (buyOrderId: string) => void;
36
+ enableHotkeys?: () => void;
37
+ disableHotkeys?: () => void;
34
38
  }
35
39
 
36
40
  const BUY_ORDERS_PER_PAGE = 5;
@@ -54,25 +58,48 @@ export const BuyOrderPanel: React.FC<IBuyOrderPanelProps> = (props) => {
54
58
  yourBuyOrdersPage,
55
59
  onYourBuyOrdersPageChange,
56
60
  onCancelBuyOrder,
61
+ enableHotkeys,
62
+ disableHotkeys,
57
63
  } = props;
58
64
 
65
+ // Local blueprint display: cleared immediately on Place Request so the
66
+ // panel returns to "Select Item" without waiting for the consumer to update
67
+ // the prop. Cancel keeps it shown so the user can reopen the modal.
68
+ const [displayedBlueprint, setDisplayedBlueprint] = useState(selectedBlueprint);
69
+ const [isDetailsOpen, setIsDetailsOpen] = useState(!!selectedBlueprint);
70
+ const [statusFilter, setStatusFilter] = useState<'Active' | 'Fulfilled' | 'Expired' | 'All'>('Active');
71
+
72
+ // Sync when consumer provides a new blueprint (e.g. after search selection)
73
+ useEffect(() => {
74
+ if (selectedBlueprint) {
75
+ setDisplayedBlueprint(selectedBlueprint);
76
+ setIsDetailsOpen(true);
77
+ }
78
+ }, [selectedBlueprint]);
79
+
80
+ // Place request: clear display + close modal, then notify consumer
59
81
  const handleConfirm = () => {
60
82
  onPlaceBuyOrder();
83
+ setDisplayedBlueprint(undefined);
84
+ setIsDetailsOpen(false);
61
85
  onCloseDetails?.();
86
+ enableHotkeys?.();
62
87
  };
63
88
 
89
+ // Cancel: just close the modal, keep blueprint displayed for reopening
64
90
  const handleCloseDetails = () => {
65
- onCloseDetails?.();
91
+ setIsDetailsOpen(false);
92
+ enableHotkeys?.();
66
93
  };
67
94
 
68
95
  return (
69
96
  <PanelWrapper>
70
97
  {/* ── Details modal ── */}
71
- {selectedBlueprint && (
98
+ {displayedBlueprint && isDetailsOpen && (
72
99
  <BuyOrderDetailsModal
73
100
  isOpen
74
101
  onClose={handleCloseDetails}
75
- blueprint={selectedBlueprint}
102
+ blueprint={displayedBlueprint}
76
103
  quantity={currentQuantity}
77
104
  maxPrice={currentMaxPrice}
78
105
  rarity={selectedRarity}
@@ -82,18 +109,20 @@ export const BuyOrderPanel: React.FC<IBuyOrderPanelProps> = (props) => {
82
109
  onConfirm={handleConfirm}
83
110
  atlasJSON={atlasJSON}
84
111
  atlasIMG={atlasIMG}
112
+ enableHotkeys={enableHotkeys}
113
+ disableHotkeys={disableHotkeys}
85
114
  />
86
115
  )}
87
116
 
88
117
  {/* ── Form row — outside scroll so dropdown isn't clipped ── */}
89
118
  <FormRow>
90
- {selectedBlueprint ? (
119
+ {displayedBlueprint ? (
91
120
  <SelectedBlueprintDisplay onPointerDown={onOpenBlueprintSearch}>
92
121
  <RarityContainer $rarity={selectedRarity}>
93
122
  <SpriteFromAtlas
94
123
  atlasIMG={atlasIMG}
95
124
  atlasJSON={atlasJSON}
96
- spriteKey={selectedBlueprint.texturePath || selectedBlueprint.key}
125
+ spriteKey={displayedBlueprint.texturePath || displayedBlueprint.key}
97
126
  width={32}
98
127
  height={32}
99
128
  imgScale={2}
@@ -101,7 +130,7 @@ export const BuyOrderPanel: React.FC<IBuyOrderPanelProps> = (props) => {
101
130
  />
102
131
  </RarityContainer>
103
132
  <ChangeTextWrapper>
104
- <BlueprintName>{selectedBlueprint.name}</BlueprintName>
133
+ <BlueprintName>{displayedBlueprint.name}</BlueprintName>
105
134
  <ChangeText>change</ChangeText>
106
135
  </ChangeTextWrapper>
107
136
  </SelectedBlueprintDisplay>
@@ -116,23 +145,40 @@ export const BuyOrderPanel: React.FC<IBuyOrderPanelProps> = (props) => {
116
145
  </FormRow>
117
146
 
118
147
  {/* ── Scrollable lists ──────────────────────────────── */}
148
+ <FilterRow>
149
+ <SectionTitle>Your Buy Requests</SectionTitle>
150
+ <SegmentedToggle
151
+ options={[
152
+ { id: 'Active', label: 'Active' },
153
+ { id: 'Fulfilled', label: 'Fulfilled' },
154
+ { id: 'Expired', label: 'Expired' },
155
+ { id: 'All', label: 'All' },
156
+ ]}
157
+ activeId={statusFilter}
158
+ onChange={(id) => setStatusFilter(id as typeof statusFilter)}
159
+ />
160
+ </FilterRow>
119
161
  <ScrollArea id="MarketContainer">
120
162
  <Section>
121
- <SectionTitle>Your Buy Requests</SectionTitle>
122
- {yourBuyOrders.length === 0 ? (
123
- <EmptyState>No requests yet</EmptyState>
124
- ) : (
125
- yourBuyOrders.map((order) => (
126
- <BuyOrderRow
127
- key={order._id}
128
- buyOrder={order}
129
- atlasJSON={atlasJSON}
130
- atlasIMG={atlasIMG}
131
- isOwn
132
- onCancel={onCancelBuyOrder}
133
- />
134
- ))
135
- )}
163
+ {(() => {
164
+ const filtered = statusFilter === 'All'
165
+ ? yourBuyOrders
166
+ : yourBuyOrders.filter(o => o.status === MarketplaceBuyOrderStatus[statusFilter as keyof typeof MarketplaceBuyOrderStatus]);
167
+ return filtered.length === 0 ? (
168
+ <EmptyState>No requests yet</EmptyState>
169
+ ) : (
170
+ filtered.map((order) => (
171
+ <BuyOrderRow
172
+ key={order._id}
173
+ buyOrder={order}
174
+ atlasJSON={atlasJSON}
175
+ atlasIMG={atlasIMG}
176
+ isOwn
177
+ onCancel={onCancelBuyOrder}
178
+ />
179
+ ))
180
+ );
181
+ })()}
136
182
  {yourBuyOrdersTotal > BUY_ORDERS_PER_PAGE && (
137
183
  <PagerRow>
138
184
  <Pager
@@ -170,6 +216,13 @@ const FormRow = styled.div`
170
216
  overflow: visible;
171
217
  `;
172
218
 
219
+ const FilterRow = styled.div`
220
+ display: flex;
221
+ align-items: center;
222
+ justify-content: space-between;
223
+ padding: 0 4px;
224
+ `;
225
+
173
226
  const ScrollArea = styled.div`
174
227
  display: flex;
175
228
  flex-direction: column;
@@ -160,7 +160,7 @@ export const HistoryPanel: React.FC<IHistoryPanelProps> = ({
160
160
 
161
161
  {tx.goldAmount > 0 && (
162
162
  <PriceSection>
163
- {tx.currency === 'dc' ? (
163
+ {tx.metadata?.['currency'] === 'dc' ? (
164
164
  // Show DC only
165
165
  <DCPriceRow>
166
166
  {atlasIMG && atlasJSON && (
@@ -164,6 +164,7 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
164
164
 
165
165
  const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
166
166
  setIsBlueprintSearchOpen(false);
167
+ props.enableHotkeys?.();
167
168
  onBlueprintSelect?.(blueprint);
168
169
  };
169
170
 
@@ -239,10 +240,12 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
239
240
  yourBuyOrdersPage={yourBuyOrdersPage}
240
241
  onYourBuyOrdersPageChange={onYourBuyOrdersPageChange ?? (() => {})}
241
242
  onCancelBuyOrder={onCancelBuyOrder ?? (() => {})}
243
+ enableHotkeys={props.enableHotkeys}
244
+ disableHotkeys={props.disableHotkeys}
242
245
  />
243
246
  <BlueprintSearchModal
244
247
  isOpen={isBlueprintSearchOpen}
245
- onClose={() => setIsBlueprintSearchOpen(false)}
248
+ onClose={() => { setIsBlueprintSearchOpen(false); props.enableHotkeys?.(); }}
246
249
  onSelect={handleBlueprintSelect}
247
250
  onSearch={onBlueprintSearch ?? (() => {})}
248
251
  blueprints={blueprintSearchResults}
@@ -251,6 +254,8 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
251
254
  isLoading={blueprintSearchIsLoading}
252
255
  atlasJSON={props.atlasJSON}
253
256
  atlasIMG={props.atlasIMG}
257
+ enableHotkeys={props.enableHotkeys}
258
+ disableHotkeys={props.disableHotkeys}
254
259
  />
255
260
  </>
256
261
  )}
@@ -1,10 +1,12 @@
1
1
  import {
2
+ IMarketplaceBlueprintSearchRequest,
2
3
  IMarketplaceBlueprintSummary,
3
4
  IMarketplaceBuyOrderItem,
4
5
  MarketplaceBuyOrderStatus,
5
6
  } from '@rpg-engine/shared';
6
7
  import type { Meta, StoryObj } from '@storybook/react';
7
8
  import React, { useState } from 'react';
9
+ import { BlueprintSearchModal } from '../../../components/Marketplace/BlueprintSearchModal';
8
10
  import { BuyOrderPanel } from '../../../components/Marketplace/BuyOrderPanel';
9
11
  import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
10
12
  import atlasJSON from '../../../mocks/atlas/items/items.json';
@@ -44,6 +46,36 @@ const mockSelectedBlueprint: IMarketplaceBlueprintSummary = {
44
46
  texturePath: 'swords/broad-sword.png',
45
47
  };
46
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
+
47
79
  const mockBuyOrders: IMarketplaceBuyOrderItem[] = [
48
80
  {
49
81
  _id: 'order-1',
@@ -84,113 +116,197 @@ const mockBuyOrders: IMarketplaceBuyOrderItem[] = [
84
116
 
85
117
  const DefaultWrapper = () => {
86
118
  const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>();
119
+ const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
87
120
  const [quantity, setQuantity] = useState(0);
88
121
  const [maxPrice, setMaxPrice] = useState(0);
89
122
  const [rarity, setRarity] = useState('');
90
123
  const [yourOrders, setYourOrders] = useState<IMarketplaceBuyOrderItem[]>(mockBuyOrders);
91
124
 
125
+ const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
126
+ setIsBlueprintSearchOpen(false);
127
+ setSelectedBlueprint(blueprint);
128
+ };
129
+
92
130
  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
- />
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
+ </>
133
185
  );
134
186
  };
135
187
 
136
188
  const WithBlueprintWrapper = () => {
137
189
  const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>(mockSelectedBlueprint);
190
+ const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
138
191
  const [quantity, setQuantity] = useState(0);
139
192
  const [maxPrice, setMaxPrice] = useState(0);
140
193
  const [rarity, setRarity] = useState('');
141
194
  const [yourOrders, setYourOrders] = useState<IMarketplaceBuyOrderItem[]>(mockBuyOrders);
142
195
 
196
+ const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
197
+ setIsBlueprintSearchOpen(false);
198
+ setSelectedBlueprint(blueprint);
199
+ };
200
+
143
201
  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
- />
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
+ </>
168
256
  );
169
257
  };
170
258
 
171
259
  const EmptyWrapper = () => {
260
+ const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
261
+ const [selectedBlueprint, setSelectedBlueprint] = useState<IMarketplaceBlueprintSummary | undefined>();
172
262
  const [quantity, setQuantity] = useState(0);
173
263
  const [maxPrice, setMaxPrice] = useState(0);
174
264
  const [rarity, setRarity] = useState('');
175
265
 
266
+ const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
267
+ setIsBlueprintSearchOpen(false);
268
+ setSelectedBlueprint(blueprint);
269
+ };
270
+
176
271
  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
- />
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
+ </>
194
310
  );
195
311
  };
196
312
 
@@ -41,7 +41,7 @@ const mockTransactions: IMarketplaceTransaction[] = [
41
41
  itemKey: 'items/iron-sword.png',
42
42
  itemName: 'Iron Sword',
43
43
  counterpartName: 'SomePlayer',
44
- currency: 'gold',
44
+ metadata: { currency: 'gold' },
45
45
  createdAt: daysAgo(0),
46
46
  updatedAt: daysAgo(0),
47
47
  },
@@ -52,7 +52,7 @@ const mockTransactions: IMarketplaceTransaction[] = [
52
52
  itemKey: 'items/leather-armor.png',
53
53
  itemName: 'Leather Armor',
54
54
  counterpartName: 'AnotherPlayer',
55
- currency: 'dc', // DC sale
55
+ metadata: { currency: 'dc' },
56
56
  createdAt: daysAgo(1),
57
57
  updatedAt: daysAgo(1),
58
58
  },
@@ -63,7 +63,7 @@ const mockTransactions: IMarketplaceTransaction[] = [
63
63
  itemKey: 'items/angelic-sword.png',
64
64
  itemName: 'Angelic Sword',
65
65
  counterpartName: 'DCBuyer',
66
- currency: 'dc', // DC purchase
66
+ metadata: { currency: 'dc' },
67
67
  createdAt: daysAgo(2),
68
68
  updatedAt: daysAgo(2),
69
69
  },
@@ -49,9 +49,9 @@ const mockOpenBuyOrders: IMarketplaceBuyOrderItem[] = [
49
49
  ];
50
50
 
51
51
  const mockTransactions: IMarketplaceTransaction[] = [
52
- { owner: 'player-1', type: MarketplaceTransactionType.Purchase, goldAmount: 450, itemKey: 'items/broad-sword', itemName: 'Broad Sword', counterpartName: 'MerchantKing', currency: 'gold', createdAt: daysAgo(1), updatedAt: daysAgo(1) },
53
- { owner: 'player-1', type: MarketplaceTransactionType.Sale, goldAmount: 1200, itemKey: 'items/angelic-sword', itemName: 'Angelic Sword', counterpartName: 'ShadowBlade', currency: 'dc', createdAt: daysAgo(2), updatedAt: daysAgo(2) },
54
- { owner: 'player-1', type: MarketplaceTransactionType.Purchase, goldAmount: 275000, itemKey: 'items/angelic-sword', itemName: 'Angelic Sword', counterpartName: 'DCBuyer', currency: 'dc', createdAt: daysAgo(3), updatedAt: daysAgo(3) },
52
+ { owner: 'player-1', type: MarketplaceTransactionType.Purchase, goldAmount: 450, itemKey: 'items/broad-sword', itemName: 'Broad Sword', counterpartName: 'MerchantKing', metadata: { currency: 'gold' }, createdAt: daysAgo(1), updatedAt: daysAgo(1) },
53
+ { owner: 'player-1', type: MarketplaceTransactionType.Sale, goldAmount: 1200, itemKey: 'items/angelic-sword', itemName: 'Angelic Sword', counterpartName: 'ShadowBlade', metadata: { currency: 'dc' }, createdAt: daysAgo(2), updatedAt: daysAgo(2) },
54
+ { owner: 'player-1', type: MarketplaceTransactionType.Purchase, goldAmount: 275000, itemKey: 'items/angelic-sword', itemName: 'Angelic Sword', counterpartName: 'DCBuyer', metadata: { currency: 'dc' }, createdAt: daysAgo(3), updatedAt: daysAgo(3) },
55
55
  { owner: 'player-1', type: MarketplaceTransactionType.ListingFee, goldAmount: 60, itemKey: 'items/angelic-sword', itemName: 'Angelic Sword', createdAt: daysAgo(2), updatedAt: daysAgo(2) },
56
56
  { owner: 'player-1', type: MarketplaceTransactionType.Withdrawal, goldAmount: 3200, createdAt: daysAgo(4), updatedAt: daysAgo(4) },
57
57
  { owner: 'player-1', type: MarketplaceTransactionType.Expired, goldAmount: 0, itemKey: 'items/leather-armor', itemName: 'Leather Armor', createdAt: daysAgo(7), updatedAt: daysAgo(7) },
@@ -69,6 +69,7 @@ const Template: Story = () => {
69
69
  const [blueprintResults, setBlueprintResults] = React.useState<IMarketplaceBlueprintSummary[]>([]);
70
70
  const [blueprintLoading, setBlueprintLoading] = React.useState(false);
71
71
  const [historyType, setHistoryType] = React.useState('All');
72
+ const [yourBuyOrders, setYourBuyOrders] = React.useState<IMarketplaceBuyOrderItem[]>(mockYourBuyOrders);
72
73
 
73
74
  const handleBlueprintSearch = (request: any) => {
74
75
  console.log('blueprint search:', request);
@@ -132,12 +133,34 @@ const Template: Story = () => {
132
133
  onBuyOrderQuantityChange={setQuantity}
133
134
  onBuyOrderMaxPriceChange={setMaxPrice}
134
135
  onBuyOrderRarityChange={setSelectedRarity}
135
- onPlaceBuyOrder={() => console.log('place buy order:', selectedBlueprint?.name, quantity, maxPrice, selectedRarity)}
136
- yourBuyOrders={mockYourBuyOrders}
137
- yourBuyOrdersTotal={mockYourBuyOrders.length}
136
+ onPlaceBuyOrder={() => {
137
+ if (selectedBlueprint) {
138
+ const newOrder: IMarketplaceBuyOrderItem = {
139
+ _id: `bo-${Date.now()}`,
140
+ owner: 'player-1',
141
+ itemBlueprintKey: selectedBlueprint.key,
142
+ itemRarity: selectedRarity as any,
143
+ maxPrice,
144
+ escrowedGold: maxPrice,
145
+ fee: Math.floor(maxPrice * 0.05),
146
+ status: MarketplaceBuyOrderStatus.Active,
147
+ createdAt: new Date(),
148
+ updatedAt: new Date(),
149
+ };
150
+ setYourBuyOrders(prev => [newOrder, ...prev]);
151
+ }
152
+ }}
153
+ onClearBuyOrderBlueprint={() => {
154
+ setSelectedBlueprint(undefined);
155
+ setQuantity(1);
156
+ setMaxPrice(0);
157
+ setSelectedRarity('');
158
+ }}
159
+ yourBuyOrders={yourBuyOrders}
160
+ yourBuyOrdersTotal={yourBuyOrders.length}
138
161
  yourBuyOrdersPage={1}
139
162
  onYourBuyOrdersPageChange={p => console.log('your orders page:', p)}
140
- onCancelBuyOrder={id => console.log('cancel order:', id)}
163
+ onCancelBuyOrder={id => setYourBuyOrders(prev => prev.filter(o => o._id !== id))}
141
164
  openBuyOrders={mockOpenBuyOrders}
142
165
  openBuyOrdersTotal={mockOpenBuyOrders.length}
143
166
  openBuyOrdersPage={1}