@rpg-engine/long-bow 0.8.140 → 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 (68) 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 +4 -3
  8. package/dist/components/Marketplace/Marketplace.d.ts +38 -2
  9. package/dist/components/Marketplace/MarketplaceRows.d.ts +13 -1
  10. package/dist/components/Marketplace/MarketplaceSettingsPanel.d.ts +8 -0
  11. package/dist/components/Store/PaymentMethodModal.d.ts +1 -0
  12. package/dist/components/shared/LabelPill/LabelPill.d.ts +9 -0
  13. package/dist/components/shared/LabelPill/index.d.ts +1 -0
  14. package/dist/components/shared/SegmentedToggle/SegmentedToggle.d.ts +12 -0
  15. package/dist/components/shared/SegmentedToggle/index.d.ts +1 -0
  16. package/dist/components/shared/Tabs/Tabs.d.ts +13 -0
  17. package/dist/components/shared/Tabs/index.d.ts +1 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/long-bow.cjs.development.js +12074 -1449
  20. package/dist/long-bow.cjs.development.js.map +1 -1
  21. package/dist/long-bow.cjs.production.min.js +1 -1
  22. package/dist/long-bow.cjs.production.min.js.map +1 -1
  23. package/dist/long-bow.esm.js +12060 -1450
  24. package/dist/long-bow.esm.js.map +1 -1
  25. package/dist/stories/Features/marketplace/BlueprintSearchModal.stories.d.ts +1 -0
  26. package/dist/stories/Features/marketplace/BuyOrderPanel.stories.d.ts +1 -0
  27. package/dist/stories/Features/marketplace/BuyOrderRows.stories.d.ts +1 -0
  28. package/dist/stories/Features/marketplace/HistoryPanel.stories.d.ts +1 -0
  29. package/dist/stories/Features/trading/MarketplaceRows.stories.d.ts +2 -1
  30. package/dist/stories/UI/buttonsAndInputs/SegmentedToggle.stories.d.ts +6 -0
  31. package/dist/stories/UI/text/LabelPill.stories.d.ts +7 -0
  32. package/dist/utils/atlasUtils.d.ts +2 -0
  33. package/package.json +3 -2
  34. package/src/components/ConfirmModal.tsx +50 -27
  35. package/src/components/Marketplace/BlueprintSearchModal.tsx +418 -0
  36. package/src/components/Marketplace/BuyOrderDetailsModal.tsx +307 -0
  37. package/src/components/Marketplace/BuyOrderPanel.tsx +266 -0
  38. package/src/components/Marketplace/BuyOrderRows.tsx +287 -0
  39. package/src/components/Marketplace/BuyPanel.tsx +486 -170
  40. package/src/components/Marketplace/HistoryPanel.tsx +422 -0
  41. package/src/components/Marketplace/ManagmentPanel.tsx +176 -98
  42. package/src/components/Marketplace/Marketplace.tsx +227 -40
  43. package/src/components/Marketplace/MarketplaceBuyModal.tsx +1 -0
  44. package/src/components/Marketplace/MarketplaceRows.tsx +274 -80
  45. package/src/components/Marketplace/MarketplaceSettingsPanel.tsx +128 -0
  46. package/src/components/Store/CartView.tsx +11 -0
  47. package/src/components/Store/PaymentMethodModal.tsx +26 -9
  48. package/src/components/shared/LabelPill/LabelPill.tsx +45 -0
  49. package/src/components/shared/LabelPill/index.ts +1 -0
  50. package/src/components/shared/SegmentedToggle/SegmentedToggle.tsx +61 -0
  51. package/src/components/shared/SegmentedToggle/index.ts +1 -0
  52. package/src/components/shared/SpriteFromAtlas.tsx +7 -2
  53. package/src/components/shared/Tabs/Tabs.tsx +60 -0
  54. package/src/components/shared/Tabs/index.ts +1 -0
  55. package/src/index.tsx +5 -0
  56. package/src/mocks/atlas/items/items.json +33998 -25238
  57. package/src/mocks/atlas/items/items.png +0 -0
  58. package/src/mocks/itemContainer.mocks.ts +31 -0
  59. package/src/stories/Features/marketplace/BlueprintSearchModal.stories.tsx +145 -0
  60. package/src/stories/Features/marketplace/BuyOrderPanel.stories.tsx +207 -0
  61. package/src/stories/Features/marketplace/BuyOrderRows.stories.tsx +116 -0
  62. package/src/stories/Features/marketplace/HistoryPanel.stories.tsx +157 -0
  63. package/src/stories/Features/trading/Marketplace.stories.tsx +109 -0
  64. package/src/stories/Features/trading/MarketplaceRows.stories.tsx +11 -0
  65. package/src/stories/UI/buttonsAndInputs/SegmentedToggle.stories.tsx +54 -0
  66. package/src/stories/UI/text/LabelPill.stories.tsx +43 -0
  67. package/src/utils/__test__/atlasUtils.spec.ts +26 -0
  68. package/src/utils/atlasUtils.ts +80 -0
@@ -0,0 +1,422 @@
1
+ import {
2
+ formatDCAmount,
3
+ goldToDC,
4
+ IMarketplaceTransaction,
5
+ MarketplaceTransactionType,
6
+ } from '@rpg-engine/shared';
7
+ import React from 'react';
8
+ import styled from 'styled-components';
9
+ import { uiColors } from '../../constants/uiColors';
10
+ import { Dropdown } from '../Dropdown';
11
+ import { IOptionsProps } from '../Dropdown';
12
+ import { Pager } from '../Pager';
13
+ import { Ellipsis } from '../shared/Ellipsis';
14
+ import { SimpleTooltip } from '../shared/SimpleTooltip';
15
+ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
16
+
17
+ export interface IHistoryPanelProps {
18
+ transactions: IMarketplaceTransaction[];
19
+ totalCount: number;
20
+ currentPage: number;
21
+ itemsPerPage: number;
22
+ selectedType: string;
23
+ onTypeChange: (type: string) => void;
24
+ onPageChange: (page: number) => void;
25
+ atlasJSON?: any;
26
+ atlasIMG?: any;
27
+ dcToGoldSwapRate?: number;
28
+ }
29
+
30
+ const HISTORY_ITEMS_PER_PAGE = 10;
31
+
32
+ const TRANSACTION_TYPE_FILTER_ALL = 'All';
33
+
34
+ // Format "BuyOrderPlaced" → "BUY ORDER PLACED", "ListingFee" → "LISTING FEE"
35
+ const formatTransactionLabel = (type: string): string => {
36
+ const words = type.split(/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/);
37
+ return words.join(' ').toUpperCase();
38
+ };
39
+
40
+ const transactionTypeOptions: IOptionsProps[] = [
41
+ {
42
+ id: 1,
43
+ value: TRANSACTION_TYPE_FILTER_ALL,
44
+ option: TRANSACTION_TYPE_FILTER_ALL,
45
+ },
46
+ ...Object.values(MarketplaceTransactionType).map((type, index) => ({
47
+ id: index + 2,
48
+ value: type as string,
49
+ option: formatTransactionLabel(type as string),
50
+ })),
51
+ ];
52
+
53
+ const TRANSACTION_TYPE_COLORS: Record<MarketplaceTransactionType, string> = {
54
+ [MarketplaceTransactionType.Purchase]: uiColors.red,
55
+ [MarketplaceTransactionType.Sale]: uiColors.lightGreen,
56
+ [MarketplaceTransactionType.ListingFee]: uiColors.red,
57
+ [MarketplaceTransactionType.Withdrawal]: uiColors.lightGreen,
58
+ [MarketplaceTransactionType.Expired]: uiColors.cardinal,
59
+ [MarketplaceTransactionType.Unlisted]: uiColors.lightGray,
60
+ [MarketplaceTransactionType.BuyOrderPlaced]: uiColors.red,
61
+ [MarketplaceTransactionType.BuyOrderFulfilled]: uiColors.lightGreen,
62
+ [MarketplaceTransactionType.BuyOrderExpired]: uiColors.cardinal,
63
+ [MarketplaceTransactionType.BuyOrderCancelled]: uiColors.lightGreen,
64
+ };
65
+
66
+ const formatDate = (date: Date): string => {
67
+ const d = new Date(date);
68
+ return d.toLocaleDateString('en-US', {
69
+ month: 'short',
70
+ day: '2-digit',
71
+ year: '2-digit',
72
+ hour: '2-digit',
73
+ minute: '2-digit',
74
+ });
75
+ };
76
+
77
+ const getGoldSign = (type: MarketplaceTransactionType): string => {
78
+ const positive: MarketplaceTransactionType[] = [
79
+ MarketplaceTransactionType.Sale,
80
+ MarketplaceTransactionType.Withdrawal,
81
+ MarketplaceTransactionType.BuyOrderCancelled,
82
+ ];
83
+ const negative: MarketplaceTransactionType[] = [
84
+ MarketplaceTransactionType.Purchase,
85
+ MarketplaceTransactionType.ListingFee,
86
+ MarketplaceTransactionType.BuyOrderPlaced,
87
+ ];
88
+
89
+ if (positive.includes(type)) return '+';
90
+ if (negative.includes(type)) return '-';
91
+ return '';
92
+ };
93
+
94
+ export const HistoryPanel: React.FC<IHistoryPanelProps> = ({
95
+ transactions,
96
+ totalCount,
97
+ currentPage,
98
+ itemsPerPage,
99
+ selectedType,
100
+ onTypeChange,
101
+ onPageChange,
102
+ atlasJSON,
103
+ atlasIMG,
104
+ dcToGoldSwapRate = 0,
105
+ }) => {
106
+ const getDCEquivalentPrice = (goldPrice: number): number =>
107
+ dcToGoldSwapRate > 0 ? goldToDC(goldPrice) : 0;
108
+ return (
109
+ <PanelWrapper>
110
+ {/* ── Filter row — outside scroll so dropdown isn't clipped ── */}
111
+ <FilterRow>
112
+ <FilterLabel>FILTER BY TYPE</FilterLabel>
113
+ <StyledDropdown
114
+ key={selectedType}
115
+ options={transactionTypeOptions}
116
+ onChange={onTypeChange}
117
+ width="200px"
118
+ />
119
+ </FilterRow>
120
+
121
+ {/* ── Scrollable transaction list ── */}
122
+ <ScrollArea id="MarketContainer">
123
+ {transactions.length === 0 ? (
124
+ <EmptyState>No transactions yet</EmptyState>
125
+ ) : (
126
+ transactions.map((tx, index) => (
127
+ <RowWrapper key={index} $even={index % 2 === 0} $accentColor={TRANSACTION_TYPE_COLORS[tx.type]}>
128
+ <ItemSection>
129
+ <ItemDetails>
130
+ {tx.itemName ? (
131
+ <ItemName>
132
+ <Ellipsis maxLines={1} maxWidth="200px" fontSize="10px">
133
+ {tx.itemName}
134
+ </Ellipsis>
135
+ </ItemName>
136
+ ) : (
137
+ <ItemName>
138
+ <NoItemText>
139
+ {tx.type === MarketplaceTransactionType.Withdrawal
140
+ ? 'Gold Withdrawal'
141
+ : '--'}
142
+ </NoItemText>
143
+ </ItemName>
144
+ )}
145
+ <MetaRow>
146
+ <Label
147
+ $bg={TRANSACTION_TYPE_COLORS[tx.type]}
148
+ >
149
+ {formatTransactionLabel(tx.type)}
150
+ </Label>
151
+ <SecondaryText>{formatDate(tx.createdAt)}</SecondaryText>
152
+ {tx.counterpartName && (
153
+ <SecondaryText>
154
+ w/ {tx.counterpartName}
155
+ </SecondaryText>
156
+ )}
157
+ </MetaRow>
158
+ </ItemDetails>
159
+ </ItemSection>
160
+
161
+ {tx.goldAmount > 0 && (
162
+ <PriceSection>
163
+ {tx.currency === 'dc' ? (
164
+ // Show DC only
165
+ <DCPriceRow>
166
+ {atlasIMG && atlasJSON && (
167
+ <DCCoinWrapper>
168
+ <SimpleTooltip content="Definya Coin" direction="top">
169
+ <SpriteFromAtlas
170
+ atlasIMG={atlasIMG}
171
+ atlasJSON={atlasJSON}
172
+ spriteKey="others/definya-coin.png"
173
+ imgScale={1}
174
+ />
175
+ </SimpleTooltip>
176
+ </DCCoinWrapper>
177
+ )}
178
+ <DCPrice $type={tx.type}>
179
+ {getGoldSign(tx.type)}
180
+ {formatDCAmount(getDCEquivalentPrice(tx.goldAmount))}
181
+ </DCPrice>
182
+ </DCPriceRow>
183
+ ) : (
184
+ // Show Gold only
185
+ <GoldPriceRow>
186
+ {atlasIMG && atlasJSON && (
187
+ <GoldIcon>
188
+ <SimpleTooltip content="Gold Coin" direction="top">
189
+ <SpriteFromAtlas
190
+ atlasIMG={atlasIMG}
191
+ atlasJSON={atlasJSON}
192
+ spriteKey="others/gold-coin-qty-5.png"
193
+ imgScale={1}
194
+ />
195
+ </SimpleTooltip>
196
+ </GoldIcon>
197
+ )}
198
+ <GoldAmount $type={tx.type}>
199
+ {getGoldSign(tx.type)}
200
+ {tx.goldAmount}g
201
+ </GoldAmount>
202
+ </GoldPriceRow>
203
+ )}
204
+ </PriceSection>
205
+ )}
206
+ </RowWrapper>
207
+ ))
208
+ )}
209
+ </ScrollArea>
210
+
211
+ <PagerContainer>
212
+ <Pager
213
+ totalItems={totalCount}
214
+ currentPage={currentPage}
215
+ itemsPerPage={itemsPerPage}
216
+ onPageChange={onPageChange}
217
+ />
218
+ </PagerContainer>
219
+ </PanelWrapper>
220
+ );
221
+ };
222
+
223
+ // ── Styled components matching MarketplaceRows / BuyOrderRows layout ──
224
+
225
+ const PanelWrapper = styled.div`
226
+ display: flex;
227
+ flex-direction: column;
228
+ gap: 8px;
229
+ padding: 0 2.5%;
230
+ width: 100%;
231
+ box-sizing: border-box;
232
+ `;
233
+
234
+ const FilterRow = styled.div`
235
+ display: flex;
236
+ align-items: center;
237
+ gap: 12px;
238
+ background: rgba(0, 0, 0, 0.15);
239
+ border-radius: 4px;
240
+ border: 1px solid rgba(255, 255, 255, 0.05);
241
+ padding: 8px 12px;
242
+ `;
243
+
244
+ const FilterLabel = styled.p`
245
+ margin: 0;
246
+ font-size: 0.7rem;
247
+ color: #ccc;
248
+ text-transform: uppercase;
249
+ letter-spacing: 1px;
250
+ white-space: nowrap;
251
+ `;
252
+
253
+ const StyledDropdown = styled(Dropdown)`
254
+ margin: 0px !important;
255
+ `;
256
+
257
+ const ScrollArea = styled.div`
258
+ display: flex;
259
+ flex-direction: column;
260
+ gap: 2px;
261
+ overflow-y: scroll;
262
+ max-height: 420px;
263
+ `;
264
+
265
+ const RowWrapper = styled.div<{ $even?: boolean; $accentColor?: string }>`
266
+ display: flex;
267
+ align-items: center;
268
+ justify-content: space-between;
269
+ padding: 0.4rem 0.8rem;
270
+ box-sizing: border-box;
271
+ background: ${({ $even }) => $even ? 'rgba(0, 0, 0, 0.25)' : 'rgba(0, 0, 0, 0.15)'};
272
+ border: 1px solid rgba(255, 255, 255, 0.05);
273
+ border-radius: 6px;
274
+ border-left: 4px solid ${({ $accentColor }) => $accentColor || 'transparent'};
275
+ transition: all 0.2s ease-in-out;
276
+
277
+ &:hover {
278
+ background: rgba(245, 158, 11, 0.08);
279
+ border-color: rgba(245, 158, 11, 0.2);
280
+ border-left-color: #f59e0b;
281
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
282
+ transform: translateY(-1px);
283
+ }
284
+ `;
285
+
286
+ const ItemSection = styled.div`
287
+ display: flex;
288
+ align-items: center;
289
+ gap: 0.75rem;
290
+ flex: 1;
291
+ min-width: 0;
292
+ `;
293
+
294
+ const ItemDetails = styled.div`
295
+ display: flex;
296
+ flex-direction: column;
297
+ gap: 0.2rem;
298
+ min-width: 0;
299
+ `;
300
+
301
+ const ItemName = styled.div`
302
+ font-family: 'Press Start 2P', cursive;
303
+ font-size: 0.65rem !important;
304
+ color: #ffffff;
305
+ `;
306
+
307
+ const NoItemText = styled.span`
308
+ color: #888;
309
+ `;
310
+
311
+ const MetaRow = styled.div`
312
+ display: flex;
313
+ flex-direction: row;
314
+ align-items: center;
315
+ gap: 0.5rem;
316
+ margin-top: 0.2rem;
317
+ `;
318
+
319
+ const Label = styled.span<{ $bg: string }>`
320
+ font-family: 'Press Start 2P', cursive;
321
+ font-size: 0.5rem !important;
322
+ color: #fff;
323
+ text-transform: uppercase;
324
+ white-space: nowrap;
325
+ background: ${({ $bg }) => $bg};
326
+ padding: 2px 6px;
327
+ border-radius: 8px;
328
+ `;
329
+
330
+ const SecondaryText = styled.span`
331
+ font-family: 'Press Start 2P', cursive;
332
+ font-size: 0.5rem !important;
333
+ color: rgba(255, 255, 255, 0.5) !important;
334
+ white-space: nowrap;
335
+ `;
336
+
337
+ const PriceSection = styled.div`
338
+ flex-shrink: 0;
339
+ margin-left: 0.75rem;
340
+ display: flex;
341
+ flex-direction: column;
342
+ gap: 0.2rem;
343
+ `;
344
+
345
+ const GoldPriceRow = styled.div`
346
+ display: flex;
347
+ align-items: center;
348
+ gap: 0.3rem;
349
+ `;
350
+
351
+ const DCPriceRow = styled.div`
352
+ display: flex;
353
+ align-items: center;
354
+ gap: 0.3rem;
355
+ `;
356
+
357
+ const DCCoinWrapper = styled.span`
358
+ display: flex;
359
+ align-items: center;
360
+ justify-content: center;
361
+ position: relative;
362
+ top: -0.6rem;
363
+ left: -0.5rem;
364
+ `;
365
+
366
+ const DCPrice = styled.span<{ $type: MarketplaceTransactionType }>`
367
+ font-family: 'Press Start 2P', cursive;
368
+ font-size: 0.55rem !important;
369
+ color: rgba(254, 240, 138, 0.65);
370
+ white-space: nowrap;
371
+ `;
372
+
373
+ const GoldIcon = styled.span`
374
+ display: flex;
375
+ align-items: center;
376
+ justify-content: center;
377
+ position: relative;
378
+ top: -0.6rem;
379
+ left: -0.5rem;
380
+ `;
381
+
382
+ const GoldAmount = styled.span<{ $type: MarketplaceTransactionType }>`
383
+ font-family: 'Press Start 2P', cursive;
384
+ font-size: 0.6rem !important;
385
+ color: ${({ $type }) => {
386
+ const positive: MarketplaceTransactionType[] = [
387
+ MarketplaceTransactionType.Sale,
388
+ MarketplaceTransactionType.Withdrawal,
389
+ MarketplaceTransactionType.BuyOrderCancelled,
390
+ MarketplaceTransactionType.BuyOrderFulfilled,
391
+ ];
392
+ const negative: MarketplaceTransactionType[] = [
393
+ MarketplaceTransactionType.Purchase,
394
+ MarketplaceTransactionType.ListingFee,
395
+ MarketplaceTransactionType.BuyOrderPlaced,
396
+ ];
397
+ if (positive.includes($type)) return `${uiColors.lightGreen} !important`;
398
+ if (negative.includes($type)) return `${uiColors.red} !important`;
399
+ return '#888 !important';
400
+ }};
401
+ `;
402
+
403
+ const EmptyState = styled.div`
404
+ display: flex;
405
+ align-items: center;
406
+ justify-content: center;
407
+ height: 45px;
408
+ font-size: 0.5rem;
409
+ color: #555;
410
+ text-transform: uppercase;
411
+ letter-spacing: 1px;
412
+ background: rgba(0, 0, 0, 0.15);
413
+ border-radius: 4px;
414
+ `;
415
+
416
+ const PagerContainer = styled.div`
417
+ display: flex;
418
+ justify-content: center;
419
+ margin-top: 4px;
420
+ `;
421
+
422
+ export { HISTORY_ITEMS_PER_PAGE, TRANSACTION_TYPE_FILTER_ALL };