@rpg-engine/long-bow 0.8.141 → 0.8.146

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/components/Marketplace/BlueprintSearchModal.d.ts +17 -0
  2. package/dist/components/Marketplace/BlueprintTable.d.ts +9 -0
  3. package/dist/components/Marketplace/BuyOrderDetailsModal.d.ts +17 -0
  4. package/dist/components/Marketplace/BuyOrderPanel.d.ts +24 -0
  5. package/dist/components/Marketplace/BuyOrderRows.d.ts +13 -0
  6. package/dist/components/Marketplace/BuyPanel.d.ts +9 -1
  7. package/dist/components/Marketplace/HistoryPanel.d.ts +18 -0
  8. package/dist/components/Marketplace/ManagmentPanel.d.ts +3 -2
  9. package/dist/components/Marketplace/Marketplace.d.ts +35 -2
  10. package/dist/components/Marketplace/MarketplaceSettingsPanel.d.ts +2 -1
  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/index.d.ts +4 -0
  17. package/dist/long-bow.cjs.development.js +11573 -1288
  18. package/dist/long-bow.cjs.development.js.map +1 -1
  19. package/dist/long-bow.cjs.production.min.js +1 -1
  20. package/dist/long-bow.cjs.production.min.js.map +1 -1
  21. package/dist/long-bow.esm.js +11562 -1290
  22. package/dist/long-bow.esm.js.map +1 -1
  23. package/dist/stories/Features/marketplace/BlueprintSearchModal.stories.d.ts +1 -0
  24. package/dist/stories/Features/marketplace/BuyOrderPanel.stories.d.ts +1 -0
  25. package/dist/stories/Features/marketplace/BuyOrderRows.stories.d.ts +1 -0
  26. package/dist/stories/Features/marketplace/HistoryPanel.stories.d.ts +1 -0
  27. package/dist/stories/Features/trading/MarketplaceRows.stories.d.ts +2 -1
  28. package/dist/stories/UI/buttonsAndInputs/SegmentedToggle.stories.d.ts +6 -0
  29. package/dist/stories/UI/text/LabelPill.stories.d.ts +7 -0
  30. package/dist/utils/atlasUtils.d.ts +2 -0
  31. package/package.json +2 -2
  32. package/src/components/Marketplace/BlueprintSearchModal.tsx +295 -0
  33. package/src/components/Marketplace/BlueprintTable.tsx +158 -0
  34. package/src/components/Marketplace/BuyOrderDetailsModal.tsx +306 -0
  35. package/src/components/Marketplace/BuyOrderPanel.tsx +284 -0
  36. package/src/components/Marketplace/BuyOrderRows.tsx +287 -0
  37. package/src/components/Marketplace/BuyPanel.tsx +406 -166
  38. package/src/components/Marketplace/HistoryPanel.tsx +422 -0
  39. package/src/components/Marketplace/ManagmentPanel.tsx +13 -15
  40. package/src/components/Marketplace/Marketplace.tsx +181 -30
  41. package/src/components/Marketplace/MarketplaceBuyModal.tsx +1 -0
  42. package/src/components/Marketplace/MarketplaceRows.tsx +41 -10
  43. package/src/components/Marketplace/MarketplaceSettingsPanel.tsx +4 -3
  44. package/src/components/Store/CartView.tsx +11 -0
  45. package/src/components/Store/PaymentMethodModal.tsx +26 -9
  46. package/src/components/shared/LabelPill/LabelPill.tsx +45 -0
  47. package/src/components/shared/LabelPill/index.ts +1 -0
  48. package/src/components/shared/SegmentedToggle/SegmentedToggle.tsx +61 -0
  49. package/src/components/shared/SegmentedToggle/index.ts +1 -0
  50. package/src/components/shared/SpriteFromAtlas.tsx +7 -2
  51. package/src/index.tsx +4 -0
  52. package/src/mocks/atlas/items/items.json +33998 -25238
  53. package/src/mocks/atlas/items/items.png +0 -0
  54. package/src/mocks/itemContainer.mocks.ts +31 -0
  55. package/src/stories/Features/marketplace/BlueprintSearchModal.stories.tsx +145 -0
  56. package/src/stories/Features/marketplace/BuyOrderPanel.stories.tsx +323 -0
  57. package/src/stories/Features/marketplace/BuyOrderRows.stories.tsx +116 -0
  58. package/src/stories/Features/marketplace/HistoryPanel.stories.tsx +157 -0
  59. package/src/stories/Features/trading/Marketplace.stories.tsx +130 -0
  60. package/src/stories/Features/trading/MarketplaceRows.stories.tsx +11 -0
  61. package/src/stories/UI/buttonsAndInputs/SegmentedToggle.stories.tsx +54 -0
  62. package/src/stories/UI/text/LabelPill.stories.tsx +43 -0
  63. package/src/utils/__test__/atlasUtils.spec.ts +26 -0
  64. package/src/utils/atlasUtils.ts +80 -0
@@ -0,0 +1,287 @@
1
+ import { IMarketplaceBuyOrderItem, MarketplaceBuyOrderStatus } from '@rpg-engine/shared';
2
+ import { Delete } from 'pixelarticons/react/Delete';
3
+ import { ShoppingBag } from 'pixelarticons/react/ShoppingBag';
4
+ import React from 'react';
5
+ import styled from 'styled-components';
6
+ import { uiColors } from '../../constants/uiColors';
7
+ import { resolveAtlasSpriteKey } from '../../utils/atlasUtils';
8
+ import { LabelPill } from '../shared/LabelPill';
9
+ import { CTAButton } from '../shared/CTAButton/CTAButton';
10
+ import { Ellipsis } from '../shared/Ellipsis';
11
+ import { SimpleTooltip } from '../shared/SimpleTooltip';
12
+ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
13
+
14
+ export interface IBuyOrderRowProps {
15
+ buyOrder: IMarketplaceBuyOrderItem;
16
+ atlasJSON?: any;
17
+ atlasIMG?: any;
18
+ isOwn?: boolean;
19
+ onCancel?: (buyOrderId: string) => void;
20
+ onFulfill?: (buyOrderId: string) => void;
21
+ showRequestTag?: boolean;
22
+ requestTagLabel?: string;
23
+ }
24
+
25
+ const BUY_ORDER_DURATION_WEEKS = 4;
26
+
27
+ // Format "Active" → "ACTIVE", "Fulfilled" → "FULFILLED"
28
+ const formatStatusLabel = (status: string): string => {
29
+ const words = status.split(/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/);
30
+ return words.join(' ').toUpperCase();
31
+ };
32
+
33
+ const formatBlueprintKey = (key: string): string => {
34
+ const name = key.includes('/') ? key.split('/').pop()! : key;
35
+ return name.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
36
+ };
37
+
38
+ const getTimeRemaining = (createdAt: Date): string => {
39
+ const expiry = new Date(new Date(createdAt).getTime() + BUY_ORDER_DURATION_WEEKS * 7 * 24 * 60 * 60 * 1000);
40
+ const diffMs = expiry.getTime() - Date.now();
41
+ if (diffMs <= 0) return 'Expired';
42
+ const diffDays = Math.floor(diffMs / (24 * 60 * 60 * 1000));
43
+ const diffHours = Math.floor((diffMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
44
+ return diffDays > 0 ? `${diffDays}d ${diffHours}h` : `${diffHours}h`;
45
+ };
46
+
47
+ const RARITY_COLORS: Record<string, string> = {
48
+ Uncommon: 'rgba(13, 193, 13, 0.6)',
49
+ Rare: 'rgba(8, 104, 187, 0.6)',
50
+ Epic: 'rgba(191, 0, 255, 0.6)',
51
+ Legendary: 'rgba(255, 191, 0, 0.6)',
52
+ };
53
+
54
+ const STATUS_COLORS: Record<MarketplaceBuyOrderStatus, string> = {
55
+ [MarketplaceBuyOrderStatus.Active]: uiColors.lightGreen,
56
+ [MarketplaceBuyOrderStatus.Fulfilled]: uiColors.blue,
57
+ [MarketplaceBuyOrderStatus.Expired]: uiColors.cardinal,
58
+ [MarketplaceBuyOrderStatus.Cancelled]: uiColors.red,
59
+ };
60
+
61
+ export const BuyOrderRow: React.FC<IBuyOrderRowProps> = ({
62
+ buyOrder,
63
+ atlasJSON,
64
+ atlasIMG,
65
+ isOwn,
66
+ onCancel,
67
+ onFulfill,
68
+ showRequestTag = false,
69
+ requestTagLabel = 'Buy Request',
70
+ }) => {
71
+ const timeRemaining =
72
+ buyOrder.status === MarketplaceBuyOrderStatus.Active ? getTimeRemaining(buyOrder.createdAt) : null;
73
+ const spriteKey = resolveAtlasSpriteKey(atlasJSON, buyOrder.itemBlueprintKey);
74
+ const rarityGlow = buyOrder.itemRarity ? RARITY_COLORS[buyOrder.itemRarity] || null : null;
75
+
76
+ return (
77
+ <RowWrapper>
78
+ <ItemSection>
79
+ <SpriteContainer>
80
+ <RarityGlow $color={rarityGlow}>
81
+ {spriteKey && atlasIMG ? (
82
+ <SpriteFromAtlas
83
+ atlasIMG={atlasIMG}
84
+ atlasJSON={atlasJSON}
85
+ spriteKey={spriteKey}
86
+ imgScale={2}
87
+ imgClassname="sprite-from-atlas-img--item"
88
+ />
89
+ ) : (
90
+ <SpritePlaceholder />
91
+ )}
92
+ </RarityGlow>
93
+ </SpriteContainer>
94
+
95
+ <ItemDetails>
96
+ <ItemName>
97
+ <Ellipsis maxLines={1} maxWidth="200px" fontSize="10px">
98
+ {formatBlueprintKey(buyOrder.itemBlueprintKey)}
99
+ </Ellipsis>
100
+ </ItemName>
101
+ <MetaRow>
102
+ <GoldPriceRow>
103
+ {atlasIMG && atlasJSON && (
104
+ <GoldIcon>
105
+ <SimpleTooltip content="Gold Coin" direction="top">
106
+ <SpriteFromAtlas
107
+ atlasIMG={atlasIMG}
108
+ atlasJSON={atlasJSON}
109
+ spriteKey="others/gold-coin-qty-5.png"
110
+ imgScale={1}
111
+ />
112
+ </SimpleTooltip>
113
+ </GoldIcon>
114
+ )}
115
+ <GoldPrice>{buyOrder.maxPrice}</GoldPrice>
116
+ </GoldPriceRow>
117
+ {showRequestTag && (
118
+ <LabelPill
119
+ background="rgba(34, 197, 94, 0.16)"
120
+ borderColor="rgba(34, 197, 94, 0.4)"
121
+ color="#bbf7d0"
122
+ >
123
+ {requestTagLabel}
124
+ </LabelPill>
125
+ )}
126
+ {buyOrder.itemRarity && (
127
+ <LabelPill
128
+ background={rarityGlow ?? 'rgba(255,255,255,0.1)'}
129
+ borderColor="rgba(255,255,255,0.08)"
130
+ color="#fff"
131
+ >
132
+ {buyOrder.itemRarity}
133
+ </LabelPill>
134
+ )}
135
+ {isOwn && (
136
+ <LabelPill
137
+ background={STATUS_COLORS[buyOrder.status]}
138
+ borderColor="transparent"
139
+ color="#fff"
140
+ >
141
+ {formatStatusLabel(buyOrder.status)}
142
+ </LabelPill>
143
+ )}
144
+ {timeRemaining && (
145
+ <LabelPill
146
+ background="rgba(255,255,255,0.08)"
147
+ borderColor="rgba(255,255,255,0.08)"
148
+ color="#fff"
149
+ >
150
+ {timeRemaining}
151
+ </LabelPill>
152
+ )}
153
+ </MetaRow>
154
+ </ItemDetails>
155
+ </ItemSection>
156
+
157
+ {isOwn && buyOrder.status === MarketplaceBuyOrderStatus.Active && onCancel && (
158
+ <ActionSection>
159
+ <CTAButton
160
+ icon={<Delete width={18} height={18} />}
161
+ label="Cancel"
162
+ iconColor="#ef4444"
163
+ onClick={() => onCancel(buyOrder._id)}
164
+ />
165
+ </ActionSection>
166
+ )}
167
+
168
+ {!isOwn && buyOrder.status === MarketplaceBuyOrderStatus.Active && onFulfill && (
169
+ <ActionSection>
170
+ <CTAButton
171
+ icon={<ShoppingBag width={18} height={18} />}
172
+ label="Fulfill"
173
+ iconColor="#22c55e"
174
+ onClick={() => onFulfill(buyOrder._id)}
175
+ />
176
+ </ActionSection>
177
+ )}
178
+ </RowWrapper>
179
+ );
180
+ };
181
+
182
+ // ── Styled components matching MarketplaceRows layout ──
183
+
184
+ const RowWrapper = styled.div`
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: space-between;
188
+ padding: 0.4rem 0.8rem;
189
+ box-sizing: border-box;
190
+ background: rgba(0, 0, 0, 0.25);
191
+ border: 1px solid rgba(255, 255, 255, 0.05);
192
+ border-radius: 6px;
193
+ border-left: 4px solid transparent;
194
+ transition: all 0.2s ease-in-out;
195
+
196
+ &:hover {
197
+ background: rgba(245, 158, 11, 0.08);
198
+ border-color: rgba(245, 158, 11, 0.2);
199
+ border-left-color: #f59e0b;
200
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
201
+ transform: translateY(-1px);
202
+ }
203
+ `;
204
+
205
+ const ItemSection = styled.div`
206
+ display: flex;
207
+ align-items: center;
208
+ gap: 0.75rem;
209
+ flex: 1;
210
+ min-width: 0;
211
+ `;
212
+
213
+ const SpriteContainer = styled.div`
214
+ position: relative;
215
+ flex-shrink: 0;
216
+ min-width: 44px;
217
+ `;
218
+
219
+ const RarityGlow = styled.div<{ $color: string | null }>`
220
+ width: 32px;
221
+ height: 32px;
222
+ ${({ $color }) =>
223
+ $color
224
+ ? `
225
+ border-color: ${$color};
226
+ box-shadow: 0 0 5px 8px ${$color} inset, 0 0 8px 6px ${$color};
227
+ `
228
+ : ''}
229
+ `;
230
+
231
+ const SpritePlaceholder = styled.div`
232
+ width: 32px;
233
+ height: 32px;
234
+ background: rgba(255, 255, 255, 0.05);
235
+ border-radius: 4px;
236
+ border: 1px solid rgba(255, 255, 255, 0.08);
237
+ `;
238
+
239
+ const ItemDetails = styled.div`
240
+ display: flex;
241
+ flex-direction: column;
242
+ gap: 0.2rem;
243
+ min-width: 0;
244
+ margin-left: 1rem;
245
+ `;
246
+
247
+ const ItemName = styled.div`
248
+ font-family: 'Press Start 2P', cursive;
249
+ font-size: 0.65rem !important;
250
+ color: #ffffff;
251
+ `;
252
+
253
+ const MetaRow = styled.div`
254
+ display: flex;
255
+ flex-direction: row;
256
+ align-items: center;
257
+ gap: 0.5rem;
258
+ margin-top: 0.2rem;
259
+ `;
260
+
261
+ const GoldPriceRow = styled.div`
262
+ display: flex;
263
+ align-items: center;
264
+ gap: 0.3rem;
265
+ `;
266
+
267
+ const GoldIcon = styled.span`
268
+ display: flex;
269
+ align-items: center;
270
+ justify-content: center;
271
+ position: relative;
272
+ top: -0.6rem;
273
+ left: -0.5rem;
274
+ `;
275
+
276
+ const GoldPrice = styled.span`
277
+ font-family: 'Press Start 2P', cursive;
278
+ font-size: 0.6rem !important;
279
+ color: #fef08a;
280
+ line-height: 1;
281
+ `;
282
+
283
+
284
+ const ActionSection = styled.div`
285
+ flex-shrink: 0;
286
+ margin-left: 0.75rem;
287
+ `;