@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
|
@@ -1,16 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
IEquipmentSet,
|
|
3
|
+
IItem,
|
|
4
|
+
IMarketplaceBlueprintSearchRequest,
|
|
5
|
+
IMarketplaceBlueprintSummary,
|
|
6
|
+
IMarketplaceBuyOrderItem,
|
|
7
|
+
IMarketplaceItem,
|
|
8
|
+
IMarketplaceTransaction,
|
|
9
|
+
} from '@rpg-engine/shared';
|
|
10
|
+
import { Clock } from 'pixelarticons/react/Clock';
|
|
2
11
|
import { Settings2 } from 'pixelarticons/react/Settings2';
|
|
12
|
+
import { ShoppingBag } from 'pixelarticons/react/ShoppingBag';
|
|
13
|
+
import { ShoppingCart } from 'pixelarticons/react/ShoppingCart';
|
|
3
14
|
import { Store } from 'pixelarticons/react/Store';
|
|
4
|
-
import { User } from 'pixelarticons/react/User';
|
|
5
15
|
import React, { useState } from 'react';
|
|
6
16
|
import styled from 'styled-components';
|
|
7
17
|
import { DraggableContainer } from '../DraggableContainer';
|
|
8
18
|
import { Pager } from '../Pager';
|
|
9
19
|
import { RPGUIContainerTypes } from '../RPGUI/RPGUIContainer';
|
|
10
20
|
import { Tabs } from '../shared/Tabs';
|
|
11
|
-
import {
|
|
21
|
+
import { BlueprintSearchModal } from './BlueprintSearchModal';
|
|
22
|
+
import { BuyOrderPanel } from './BuyOrderPanel';
|
|
12
23
|
import { BuyPanel } from './BuyPanel';
|
|
24
|
+
import { HistoryPanel } from './HistoryPanel';
|
|
13
25
|
import { ManagmentPanel } from './ManagmentPanel';
|
|
26
|
+
import { MarketplacePaymentMethod } from './MarketplaceBuyModal';
|
|
14
27
|
import { MarketplaceAcceptedCurrency, MarketplaceSettingsPanel } from './MarketplaceSettingsPanel';
|
|
15
28
|
|
|
16
29
|
export interface IMarketPlaceProps {
|
|
@@ -32,12 +45,13 @@ export interface IMarketPlaceProps {
|
|
|
32
45
|
scale?: number;
|
|
33
46
|
equipmentSet?: IEquipmentSet | null;
|
|
34
47
|
onMarketPlaceItemBuy?: (marketPlaceItemId: string, paymentMethod?: MarketplacePaymentMethod) => void;
|
|
48
|
+
onFulfillBuyOrder?: (buyOrderId: string) => void;
|
|
35
49
|
onMarketPlaceItemRemove?: (marketPlaceItemId: string) => void;
|
|
36
50
|
availableGold: number;
|
|
37
51
|
selectedItemToSell: IItem | null;
|
|
38
52
|
onSelectedItemToSellRemove: (item: IItem) => void;
|
|
39
53
|
onYourPanelToggle: (yourPanel: boolean) => void;
|
|
40
|
-
onAddItemToMarketplace: (item: IItem, price: number) => void;
|
|
54
|
+
onAddItemToMarketplace: (item: IItem, price: number, acceptedCurrency?: MarketplaceAcceptedCurrency) => void;
|
|
41
55
|
characterId: string;
|
|
42
56
|
enableHotkeys?: () => void;
|
|
43
57
|
disableHotkeys?: () => void;
|
|
@@ -50,15 +64,91 @@ export interface IMarketPlaceProps {
|
|
|
50
64
|
dcToGoldSwapRate?: number;
|
|
51
65
|
acceptedCurrency?: MarketplaceAcceptedCurrency;
|
|
52
66
|
onAcceptedCurrencyChange?: (value: MarketplaceAcceptedCurrency) => void;
|
|
67
|
+
onActiveTabChange?: (tab: string) => void;
|
|
68
|
+
|
|
69
|
+
// Buy Order props
|
|
70
|
+
buyOrderSelectedBlueprint?: IMarketplaceBlueprintSummary;
|
|
71
|
+
buyOrderQuantity?: number;
|
|
72
|
+
buyOrderMaxPrice?: number;
|
|
73
|
+
buyOrderSelectedRarity?: string;
|
|
74
|
+
onBuyOrderQuantityChange?: (quantity: number) => void;
|
|
75
|
+
onBuyOrderMaxPriceChange?: (price: number) => void;
|
|
76
|
+
onBuyOrderRarityChange?: (rarity: string) => void;
|
|
77
|
+
onPlaceBuyOrder?: () => void;
|
|
78
|
+
onClearBuyOrderBlueprint?: () => void;
|
|
79
|
+
yourBuyOrders?: IMarketplaceBuyOrderItem[];
|
|
80
|
+
yourBuyOrdersTotal?: number;
|
|
81
|
+
yourBuyOrdersPage?: number;
|
|
82
|
+
onYourBuyOrdersPageChange?: (page: number) => void;
|
|
83
|
+
onCancelBuyOrder?: (buyOrderId: string) => void;
|
|
84
|
+
openBuyOrders?: IMarketplaceBuyOrderItem[];
|
|
85
|
+
openBuyOrdersTotal?: number;
|
|
86
|
+
openBuyOrdersPage?: number;
|
|
87
|
+
onOpenBuyOrdersPageChange?: (page: number) => void;
|
|
88
|
+
|
|
89
|
+
// Blueprint Search props
|
|
90
|
+
onBlueprintSearch?: (request: IMarketplaceBlueprintSearchRequest) => void;
|
|
91
|
+
onBlueprintSelect?: (blueprint: IMarketplaceBlueprintSummary) => void;
|
|
92
|
+
blueprintSearchResults?: IMarketplaceBlueprintSummary[];
|
|
93
|
+
blueprintSearchTotalCount?: number;
|
|
94
|
+
blueprintSearchCurrentPage?: number;
|
|
95
|
+
blueprintSearchIsLoading?: boolean;
|
|
96
|
+
|
|
97
|
+
// History props
|
|
98
|
+
historyTransactions?: IMarketplaceTransaction[];
|
|
99
|
+
historyTotalCount?: number;
|
|
100
|
+
historyCurrentPage?: number;
|
|
101
|
+
historyItemsPerPage?: number;
|
|
102
|
+
historySelectedType?: string;
|
|
103
|
+
onHistoryTypeChange?: (type: string) => void;
|
|
104
|
+
onHistoryPageChange?: (page: number) => void;
|
|
53
105
|
}
|
|
54
106
|
|
|
55
|
-
type ActiveTab = 'marketplace' | '
|
|
107
|
+
type ActiveTab = 'marketplace' | 'sell' | 'buy-orders' | 'history' | 'settings';
|
|
56
108
|
|
|
57
109
|
export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
58
|
-
const {
|
|
110
|
+
const {
|
|
111
|
+
onClose,
|
|
112
|
+
scale,
|
|
113
|
+
onYourPanelToggle,
|
|
114
|
+
onActiveTabChange,
|
|
115
|
+
acceptedCurrency: acceptedCurrencyProp,
|
|
116
|
+
onAcceptedCurrencyChange,
|
|
117
|
+
// Buy Order
|
|
118
|
+
buyOrderSelectedBlueprint,
|
|
119
|
+
buyOrderQuantity = 0,
|
|
120
|
+
buyOrderMaxPrice = 0,
|
|
121
|
+
buyOrderSelectedRarity = '',
|
|
122
|
+
onBuyOrderQuantityChange,
|
|
123
|
+
onBuyOrderMaxPriceChange,
|
|
124
|
+
onBuyOrderRarityChange,
|
|
125
|
+
onPlaceBuyOrder,
|
|
126
|
+
onClearBuyOrderBlueprint,
|
|
127
|
+
yourBuyOrders = [],
|
|
128
|
+
yourBuyOrdersTotal = 0,
|
|
129
|
+
yourBuyOrdersPage = 1,
|
|
130
|
+
onYourBuyOrdersPageChange,
|
|
131
|
+
onCancelBuyOrder,
|
|
132
|
+
// Blueprint Search
|
|
133
|
+
onBlueprintSearch,
|
|
134
|
+
onBlueprintSelect,
|
|
135
|
+
blueprintSearchResults = [],
|
|
136
|
+
blueprintSearchTotalCount = 0,
|
|
137
|
+
blueprintSearchCurrentPage = 1,
|
|
138
|
+
blueprintSearchIsLoading = false,
|
|
139
|
+
// History
|
|
140
|
+
historyTransactions = [],
|
|
141
|
+
historyTotalCount = 0,
|
|
142
|
+
historyCurrentPage = 1,
|
|
143
|
+
historyItemsPerPage = 10,
|
|
144
|
+
historySelectedType = 'All',
|
|
145
|
+
onHistoryTypeChange,
|
|
146
|
+
onHistoryPageChange,
|
|
147
|
+
} = props;
|
|
59
148
|
|
|
60
149
|
const [activeTab, setActiveTab] = useState<ActiveTab>('marketplace');
|
|
61
|
-
const [acceptedCurrency, setAcceptedCurrency] = useState<MarketplaceAcceptedCurrency>(acceptedCurrencyProp ??
|
|
150
|
+
const [acceptedCurrency, setAcceptedCurrency] = useState<MarketplaceAcceptedCurrency>(acceptedCurrencyProp ?? MarketplaceAcceptedCurrency.GoldOrDc);
|
|
151
|
+
const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
|
|
62
152
|
|
|
63
153
|
const handleCurrencyChange = (value: MarketplaceAcceptedCurrency) => {
|
|
64
154
|
setAcceptedCurrency(value);
|
|
@@ -68,9 +158,17 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
68
158
|
const handleTabChange = (tabId: string) => {
|
|
69
159
|
const tab = tabId as ActiveTab;
|
|
70
160
|
setActiveTab(tab);
|
|
71
|
-
onYourPanelToggle(tab === '
|
|
161
|
+
onYourPanelToggle(tab === 'sell');
|
|
162
|
+
onActiveTabChange?.(tab);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const handleBlueprintSelect = (blueprint: IMarketplaceBlueprintSummary) => {
|
|
166
|
+
setIsBlueprintSearchOpen(false);
|
|
167
|
+
onBlueprintSelect?.(blueprint);
|
|
72
168
|
};
|
|
73
169
|
|
|
170
|
+
const showSharedPager = activeTab === 'sell';
|
|
171
|
+
|
|
74
172
|
return (
|
|
75
173
|
<DraggableContainer
|
|
76
174
|
type={RPGUIContainerTypes.Framed}
|
|
@@ -89,9 +187,19 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
89
187
|
icon: <Store width={18} height={18} />,
|
|
90
188
|
},
|
|
91
189
|
{
|
|
92
|
-
id: '
|
|
93
|
-
label: '
|
|
94
|
-
icon: <
|
|
190
|
+
id: 'sell',
|
|
191
|
+
label: 'Sell',
|
|
192
|
+
icon: <ShoppingBag width={18} height={18} />,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: 'buy-orders',
|
|
196
|
+
label: 'Buy',
|
|
197
|
+
icon: <ShoppingCart width={18} height={18} />,
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: 'history',
|
|
201
|
+
label: 'History',
|
|
202
|
+
icon: <Clock width={18} height={18} />,
|
|
95
203
|
},
|
|
96
204
|
{
|
|
97
205
|
id: 'settings',
|
|
@@ -103,30 +211,77 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
103
211
|
onTabChange={handleTabChange}
|
|
104
212
|
/>
|
|
105
213
|
|
|
106
|
-
{activeTab === '
|
|
107
|
-
|
|
108
|
-
|
|
214
|
+
{activeTab === 'marketplace' && (
|
|
215
|
+
<BuyPanel {...props} />
|
|
216
|
+
)}
|
|
109
217
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
</PagerContainer>
|
|
113
|
-
</>
|
|
218
|
+
{activeTab === 'sell' && (
|
|
219
|
+
<ManagmentPanel {...props} acceptedCurrency={acceptedCurrency} />
|
|
114
220
|
)}
|
|
115
|
-
{activeTab === 'marketplace' && (
|
|
116
|
-
<>
|
|
117
|
-
<BuyPanel {...props} />
|
|
118
221
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
222
|
+
{activeTab === 'buy-orders' && (
|
|
223
|
+
<>
|
|
224
|
+
<BuyOrderPanel
|
|
225
|
+
atlasJSON={props.atlasJSON}
|
|
226
|
+
atlasIMG={props.atlasIMG}
|
|
227
|
+
selectedBlueprint={buyOrderSelectedBlueprint}
|
|
228
|
+
onOpenBlueprintSearch={() => setIsBlueprintSearchOpen(true)}
|
|
229
|
+
onCloseDetails={onClearBuyOrderBlueprint}
|
|
230
|
+
onQuantityChange={onBuyOrderQuantityChange ?? (() => {})}
|
|
231
|
+
onMaxPriceChange={onBuyOrderMaxPriceChange ?? (() => {})}
|
|
232
|
+
onRarityChange={onBuyOrderRarityChange ?? (() => {})}
|
|
233
|
+
onPlaceBuyOrder={onPlaceBuyOrder ?? (() => {})}
|
|
234
|
+
currentQuantity={buyOrderQuantity}
|
|
235
|
+
currentMaxPrice={buyOrderMaxPrice}
|
|
236
|
+
selectedRarity={buyOrderSelectedRarity}
|
|
237
|
+
yourBuyOrders={yourBuyOrders}
|
|
238
|
+
yourBuyOrdersTotal={yourBuyOrdersTotal}
|
|
239
|
+
yourBuyOrdersPage={yourBuyOrdersPage}
|
|
240
|
+
onYourBuyOrdersPageChange={onYourBuyOrdersPageChange ?? (() => {})}
|
|
241
|
+
onCancelBuyOrder={onCancelBuyOrder ?? (() => {})}
|
|
242
|
+
/>
|
|
243
|
+
<BlueprintSearchModal
|
|
244
|
+
isOpen={isBlueprintSearchOpen}
|
|
245
|
+
onClose={() => setIsBlueprintSearchOpen(false)}
|
|
246
|
+
onSelect={handleBlueprintSelect}
|
|
247
|
+
onSearch={onBlueprintSearch ?? (() => {})}
|
|
248
|
+
blueprints={blueprintSearchResults}
|
|
249
|
+
totalCount={blueprintSearchTotalCount}
|
|
250
|
+
currentPage={blueprintSearchCurrentPage}
|
|
251
|
+
isLoading={blueprintSearchIsLoading}
|
|
252
|
+
atlasJSON={props.atlasJSON}
|
|
253
|
+
atlasIMG={props.atlasIMG}
|
|
254
|
+
/>
|
|
122
255
|
</>
|
|
123
256
|
)}
|
|
257
|
+
|
|
258
|
+
{activeTab === 'history' && (
|
|
259
|
+
<HistoryPanel
|
|
260
|
+
transactions={historyTransactions}
|
|
261
|
+
totalCount={historyTotalCount}
|
|
262
|
+
currentPage={historyCurrentPage}
|
|
263
|
+
itemsPerPage={historyItemsPerPage}
|
|
264
|
+
selectedType={historySelectedType}
|
|
265
|
+
onTypeChange={onHistoryTypeChange ?? (() => {})}
|
|
266
|
+
onPageChange={onHistoryPageChange ?? (() => {})}
|
|
267
|
+
atlasJSON={props.atlasJSON}
|
|
268
|
+
atlasIMG={props.atlasIMG}
|
|
269
|
+
dcToGoldSwapRate={props.dcToGoldSwapRate}
|
|
270
|
+
/>
|
|
271
|
+
)}
|
|
272
|
+
|
|
124
273
|
{activeTab === 'settings' && (
|
|
125
274
|
<MarketplaceSettingsPanel
|
|
126
275
|
acceptedCurrency={acceptedCurrency}
|
|
127
276
|
onAcceptedCurrencyChange={handleCurrencyChange}
|
|
128
277
|
/>
|
|
129
278
|
)}
|
|
279
|
+
|
|
280
|
+
{showSharedPager && (
|
|
281
|
+
<PagerContainer>
|
|
282
|
+
<Pager {...props} />
|
|
283
|
+
</PagerContainer>
|
|
284
|
+
)}
|
|
130
285
|
</DraggableContainer>
|
|
131
286
|
);
|
|
132
287
|
};
|
|
@@ -136,10 +291,6 @@ const PagerContainer = styled.div`
|
|
|
136
291
|
justify-content: center;
|
|
137
292
|
align-items: center;
|
|
138
293
|
width: 95%;
|
|
139
|
-
margin:
|
|
140
|
-
padding:
|
|
141
|
-
background: rgba(0, 0, 0, 0.3);
|
|
142
|
-
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
143
|
-
border-radius: 6px;
|
|
144
|
-
box-sizing: border-box;
|
|
294
|
+
margin: 6px auto 0 auto;
|
|
295
|
+
padding: 4px 10px;
|
|
145
296
|
`;
|
|
@@ -15,6 +15,7 @@ import { onRenderGems } from '../Item/Inventory/ItemGem';
|
|
|
15
15
|
import { rarityColor } from '../Item/Inventory/ItemSlotRarity';
|
|
16
16
|
import { CTAButton } from '../shared/CTAButton/CTAButton';
|
|
17
17
|
import { Ellipsis } from '../shared/Ellipsis';
|
|
18
|
+
import { SimpleTooltip } from '../shared/SimpleTooltip';
|
|
18
19
|
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
19
20
|
|
|
20
21
|
export interface IMarketPlaceRowsPropos {
|
|
@@ -92,17 +93,31 @@ export const MarketplaceRows: React.FC<IMarketPlaceRowsPropos> = ({
|
|
|
92
93
|
<PriceRow>
|
|
93
94
|
<GoldPriceRow>
|
|
94
95
|
<GoldIcon>
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
<SimpleTooltip content="Gold Coin" direction="top">
|
|
97
|
+
<SpriteFromAtlas
|
|
98
|
+
atlasIMG={atlasIMG}
|
|
99
|
+
atlasJSON={atlasJSON}
|
|
100
|
+
spriteKey="others/gold-coin-qty-5.png"
|
|
101
|
+
imgScale={1}
|
|
102
|
+
/>
|
|
103
|
+
</SimpleTooltip>
|
|
101
104
|
</GoldIcon>
|
|
102
105
|
<GoldPrice>{itemPrice}</GoldPrice>
|
|
103
106
|
</GoldPriceRow>
|
|
104
107
|
{dcEquivalentPrice !== undefined && (
|
|
105
|
-
<
|
|
108
|
+
<DCPriceRow>
|
|
109
|
+
<DCCoinWrapper>
|
|
110
|
+
<SimpleTooltip content="Definya Coin" direction="top">
|
|
111
|
+
<SpriteFromAtlas
|
|
112
|
+
atlasIMG={atlasIMG}
|
|
113
|
+
atlasJSON={atlasJSON}
|
|
114
|
+
spriteKey="others/definya-coin.png"
|
|
115
|
+
imgScale={1}
|
|
116
|
+
/>
|
|
117
|
+
</SimpleTooltip>
|
|
118
|
+
</DCCoinWrapper>
|
|
119
|
+
<DCPrice>{formatDCAmount(dcEquivalentPrice)}</DCPrice>
|
|
120
|
+
</DCPriceRow>
|
|
106
121
|
)}
|
|
107
122
|
</PriceRow>
|
|
108
123
|
</ItemDetails>
|
|
@@ -327,14 +342,30 @@ const GoldIcon = styled.span`
|
|
|
327
342
|
|
|
328
343
|
const GoldPrice = styled.span`
|
|
329
344
|
font-family: 'Press Start 2P', cursive;
|
|
330
|
-
font-size: 0.6rem;
|
|
345
|
+
font-size: 0.6rem !important;
|
|
331
346
|
color: #fef08a;
|
|
332
347
|
line-height: 1;
|
|
333
348
|
`;
|
|
334
349
|
|
|
350
|
+
const DCPriceRow = styled.div`
|
|
351
|
+
display: flex;
|
|
352
|
+
align-items: center;
|
|
353
|
+
gap: 0.3rem;
|
|
354
|
+
margin-left: 0.5rem;
|
|
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
|
+
|
|
335
366
|
const DCPrice = styled.span`
|
|
336
367
|
font-family: 'Press Start 2P', cursive;
|
|
337
|
-
font-size: 0.
|
|
368
|
+
font-size: 0.6rem !important;
|
|
338
369
|
color: rgba(254, 240, 138, 0.65);
|
|
339
370
|
white-space: nowrap;
|
|
340
371
|
`;
|
|
@@ -348,7 +379,7 @@ const QuantityContainer = styled.p`
|
|
|
348
379
|
position: absolute;
|
|
349
380
|
display: block;
|
|
350
381
|
top: 15px;
|
|
351
|
-
left:
|
|
382
|
+
left: -8px;
|
|
352
383
|
font-size: ${uiFonts.size.xsmall} !important;
|
|
353
384
|
`;
|
|
354
385
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { MarketplaceAcceptedCurrency } from '@rpg-engine/shared';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import styled from 'styled-components';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
+
export { MarketplaceAcceptedCurrency };
|
|
5
6
|
|
|
6
7
|
export interface IMarketplaceSettingsPanelProps {
|
|
7
8
|
acceptedCurrency: MarketplaceAcceptedCurrency;
|
|
@@ -10,12 +11,12 @@ export interface IMarketplaceSettingsPanelProps {
|
|
|
10
11
|
|
|
11
12
|
const CURRENCY_OPTIONS: { value: MarketplaceAcceptedCurrency; label: string; description: string }[] = [
|
|
12
13
|
{
|
|
13
|
-
value:
|
|
14
|
+
value: MarketplaceAcceptedCurrency.GoldOrDc,
|
|
14
15
|
label: 'Gold or DC',
|
|
15
16
|
description: 'Accept both Gold and Definya Coin as payment',
|
|
16
17
|
},
|
|
17
18
|
{
|
|
18
|
-
value:
|
|
19
|
+
value: MarketplaceAcceptedCurrency.Gold,
|
|
19
20
|
label: 'Gold only',
|
|
20
21
|
description: 'Only accept Gold as payment',
|
|
21
22
|
},
|
|
@@ -61,6 +61,11 @@ export const CartView: React.FC<ICartViewProps> = ({
|
|
|
61
61
|
0
|
|
62
62
|
);
|
|
63
63
|
|
|
64
|
+
const dcTotal = cartItems.reduce(
|
|
65
|
+
(sum, ci) => sum + (ci.item.dcPrice ?? 0) * ci.quantity,
|
|
66
|
+
0
|
|
67
|
+
);
|
|
68
|
+
|
|
64
69
|
const formatPrice = (price: number) => price.toFixed(2);
|
|
65
70
|
|
|
66
71
|
const handlePurchase = async () => {
|
|
@@ -154,6 +159,12 @@ export const CartView: React.FC<ICartViewProps> = ({
|
|
|
154
159
|
<span>Total:</span>
|
|
155
160
|
<span>${formatPrice(total)}</span>
|
|
156
161
|
</TotalRow>
|
|
162
|
+
{dcTotal > 0 && (
|
|
163
|
+
<TotalRow>
|
|
164
|
+
<span>DC:</span>
|
|
165
|
+
<span>{dcTotal.toLocaleString()} DC</span>
|
|
166
|
+
</TotalRow>
|
|
167
|
+
)}
|
|
157
168
|
{error && <ErrorMessage>{error}</ErrorMessage>}
|
|
158
169
|
</TotalInfo>
|
|
159
170
|
<CTAButton
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { FaTimes } from 'react-icons/fa';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import ModalPortal from '../Abstractions/ModalPortal';
|
|
@@ -6,6 +6,7 @@ import { Button, ButtonTypes } from '../Button';
|
|
|
6
6
|
|
|
7
7
|
export interface IPaymentMethodModalProps {
|
|
8
8
|
dcBalance: number;
|
|
9
|
+
dcRequired?: number;
|
|
9
10
|
onPayWithDC: () => void;
|
|
10
11
|
onPayWithCard: () => void;
|
|
11
12
|
onClose: () => void;
|
|
@@ -15,12 +16,21 @@ type PaymentMethod = 'dc' | 'card';
|
|
|
15
16
|
|
|
16
17
|
export const PaymentMethodModal: React.FC<IPaymentMethodModalProps> = ({
|
|
17
18
|
dcBalance,
|
|
19
|
+
dcRequired,
|
|
18
20
|
onPayWithDC,
|
|
19
21
|
onPayWithCard,
|
|
20
22
|
onClose,
|
|
21
23
|
}) => {
|
|
22
24
|
const [selected, setSelected] = useState<PaymentMethod>('card');
|
|
23
25
|
|
|
26
|
+
const dcDisabled = dcRequired !== undefined && dcBalance < dcRequired;
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (dcDisabled && selected === 'dc') {
|
|
30
|
+
setSelected('card');
|
|
31
|
+
}
|
|
32
|
+
}, [dcDisabled, selected]);
|
|
33
|
+
|
|
24
34
|
const stopPropagation = useCallback(
|
|
25
35
|
(e: React.MouseEvent | React.TouchEvent | React.PointerEvent) => {
|
|
26
36
|
e.stopPropagation();
|
|
@@ -29,12 +39,17 @@ export const PaymentMethodModal: React.FC<IPaymentMethodModalProps> = ({
|
|
|
29
39
|
);
|
|
30
40
|
|
|
31
41
|
const handleConfirm = useCallback(() => {
|
|
32
|
-
if (selected === 'dc') {
|
|
42
|
+
if (selected === 'dc' && !dcDisabled) {
|
|
33
43
|
onPayWithDC();
|
|
34
44
|
} else {
|
|
35
45
|
onPayWithCard();
|
|
36
46
|
}
|
|
37
|
-
}, [selected, onPayWithDC, onPayWithCard]);
|
|
47
|
+
}, [selected, dcDisabled, onPayWithDC, onPayWithCard]);
|
|
48
|
+
|
|
49
|
+
const dcSubText =
|
|
50
|
+
dcRequired !== undefined
|
|
51
|
+
? `${dcBalance.toLocaleString()} DC available · ${dcRequired.toLocaleString()} DC needed`
|
|
52
|
+
: `${dcBalance.toLocaleString()} DC available`;
|
|
38
53
|
|
|
39
54
|
return (
|
|
40
55
|
<ModalPortal>
|
|
@@ -66,12 +81,13 @@ export const PaymentMethodModal: React.FC<IPaymentMethodModalProps> = ({
|
|
|
66
81
|
|
|
67
82
|
<RadioOption
|
|
68
83
|
$selected={selected === 'dc'}
|
|
69
|
-
|
|
84
|
+
$disabled={dcDisabled}
|
|
85
|
+
onPointerDown={dcDisabled ? undefined : () => setSelected('dc')}
|
|
70
86
|
>
|
|
71
87
|
<RadioCircle $selected={selected === 'dc'} />
|
|
72
88
|
<OptionText>
|
|
73
89
|
<OptionLabel>Definya Coin</OptionLabel>
|
|
74
|
-
<OptionSub>{
|
|
90
|
+
<OptionSub>{dcSubText}</OptionSub>
|
|
75
91
|
</OptionText>
|
|
76
92
|
</RadioOption>
|
|
77
93
|
</Options>
|
|
@@ -157,7 +173,7 @@ const Options = styled.div`
|
|
|
157
173
|
gap: 8px;
|
|
158
174
|
`;
|
|
159
175
|
|
|
160
|
-
const RadioOption = styled.div<{ $selected: boolean }>`
|
|
176
|
+
const RadioOption = styled.div<{ $selected: boolean; $disabled?: boolean }>`
|
|
161
177
|
display: flex;
|
|
162
178
|
align-items: center;
|
|
163
179
|
gap: 12px;
|
|
@@ -165,11 +181,12 @@ const RadioOption = styled.div<{ $selected: boolean }>`
|
|
|
165
181
|
border: 1px solid ${({ $selected }) => ($selected ? '#f59e0b' : 'rgba(255,255,255,0.15)')};
|
|
166
182
|
border-radius: 6px;
|
|
167
183
|
background: ${({ $selected }) => ($selected ? 'rgba(245,158,11,0.1)' : 'transparent')};
|
|
168
|
-
cursor: pointer;
|
|
169
|
-
|
|
184
|
+
cursor: ${({ $disabled }) => ($disabled ? 'not-allowed' : 'pointer')};
|
|
185
|
+
opacity: ${({ $disabled }) => ($disabled ? 0.4 : 1)};
|
|
186
|
+
transition: border-color 0.15s, background 0.15s, opacity 0.15s;
|
|
170
187
|
|
|
171
188
|
&:hover {
|
|
172
|
-
border-color: #f59e0b;
|
|
189
|
+
border-color: ${({ $disabled }) => ($disabled ? 'rgba(255,255,255,0.15)' : '#f59e0b')};
|
|
173
190
|
}
|
|
174
191
|
`;
|
|
175
192
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
export interface ILabelPillProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
background?: string;
|
|
7
|
+
borderColor?: string;
|
|
8
|
+
color?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const LabelPill: React.FC<ILabelPillProps> = ({
|
|
13
|
+
children,
|
|
14
|
+
background = 'rgba(255,255,255,0.08)',
|
|
15
|
+
borderColor = 'rgba(255,255,255,0.08)',
|
|
16
|
+
color = '#fff',
|
|
17
|
+
className,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<Pill
|
|
21
|
+
className={className}
|
|
22
|
+
$background={background}
|
|
23
|
+
$borderColor={borderColor}
|
|
24
|
+
$color={color}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</Pill>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const Pill = styled.span<{
|
|
32
|
+
$background: string;
|
|
33
|
+
$borderColor: string;
|
|
34
|
+
$color: string;
|
|
35
|
+
}>`
|
|
36
|
+
font-family: 'Press Start 2P', cursive;
|
|
37
|
+
font-size: 0.45rem !important;
|
|
38
|
+
color: ${({ $color }) => $color};
|
|
39
|
+
text-transform: uppercase;
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
background: ${({ $background }) => $background};
|
|
42
|
+
padding: 2px 6px;
|
|
43
|
+
border-radius: 8px;
|
|
44
|
+
border: 1px solid ${({ $borderColor }) => $borderColor};
|
|
45
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LabelPill';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
export interface ISegmentedToggleOption {
|
|
5
|
+
id: string;
|
|
6
|
+
label: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ISegmentedToggleProps {
|
|
10
|
+
options: ISegmentedToggleOption[];
|
|
11
|
+
activeId: string;
|
|
12
|
+
onChange: (id: string) => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const SegmentedToggle: React.FC<ISegmentedToggleProps> = ({
|
|
17
|
+
options,
|
|
18
|
+
activeId,
|
|
19
|
+
onChange,
|
|
20
|
+
className,
|
|
21
|
+
}) => {
|
|
22
|
+
return (
|
|
23
|
+
<Container className={className}>
|
|
24
|
+
{options.map(option => (
|
|
25
|
+
<OptionButton
|
|
26
|
+
key={option.id}
|
|
27
|
+
type="button"
|
|
28
|
+
$active={option.id === activeId}
|
|
29
|
+
onClick={() => onChange(option.id)}
|
|
30
|
+
>
|
|
31
|
+
{option.label}
|
|
32
|
+
</OptionButton>
|
|
33
|
+
))}
|
|
34
|
+
</Container>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const Container = styled.div`
|
|
39
|
+
display: inline-flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: 8px;
|
|
42
|
+
flex-wrap: wrap;
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const OptionButton = styled.button<{ $active: boolean }>`
|
|
46
|
+
border: 1px solid ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.75)' : 'rgba(255, 255, 255, 0.08)')};
|
|
47
|
+
background: ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.16)' : 'rgba(0, 0, 0, 0.18)')};
|
|
48
|
+
color: ${({ $active }) => ($active ? '#fde68a' : '#cfcfcf')};
|
|
49
|
+
border-radius: 999px;
|
|
50
|
+
padding: 8px 12px;
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
font-size: 0.56rem;
|
|
53
|
+
text-transform: uppercase;
|
|
54
|
+
letter-spacing: 0.8px;
|
|
55
|
+
transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
|
|
56
|
+
|
|
57
|
+
&:hover {
|
|
58
|
+
border-color: rgba(245, 158, 11, 0.45);
|
|
59
|
+
color: #fde68a;
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './SegmentedToggle';
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { GRID_HEIGHT, GRID_WIDTH } from '@rpg-engine/shared';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import styled, { css } from 'styled-components';
|
|
4
|
+
import {
|
|
5
|
+
NO_IMAGE_SPRITE_KEY,
|
|
6
|
+
resolveAtlasSpriteKey,
|
|
7
|
+
} from '../../utils/atlasUtils';
|
|
4
8
|
import { toUppercaseHexColor } from '../../utils/colorUtils';
|
|
5
9
|
|
|
6
10
|
interface IProps {
|
|
@@ -41,9 +45,10 @@ export const SpriteFromAtlas: React.FC<IProps> = ({
|
|
|
41
45
|
//! If an item is not showing, remember that you MUST run yarn atlas:copy everytime you add a new item to the atlas (it will sync our public folder atlas with src/atlas).
|
|
42
46
|
//!Due to React's limitations, we cannot import it from the public folder directly!
|
|
43
47
|
|
|
48
|
+
const resolvedSpriteKey = resolveAtlasSpriteKey(atlasJSON, spriteKey);
|
|
44
49
|
const spriteData =
|
|
45
|
-
atlasJSON?.frames?.[
|
|
46
|
-
atlasJSON?.frames?.[
|
|
50
|
+
(resolvedSpriteKey && atlasJSON?.frames?.[resolvedSpriteKey]) ||
|
|
51
|
+
atlasJSON?.frames?.[NO_IMAGE_SPRITE_KEY];
|
|
47
52
|
|
|
48
53
|
if (!spriteData) {
|
|
49
54
|
console.error(
|
package/src/index.tsx
CHANGED
|
@@ -38,6 +38,10 @@ export * from './components/Marketplace/Marketplace';
|
|
|
38
38
|
export * from './components/Marketplace/MarketplaceBuyModal';
|
|
39
39
|
export * from './components/Marketplace/MarketplaceRows';
|
|
40
40
|
export * from './components/Marketplace/MarketplaceSettingsPanel';
|
|
41
|
+
export * from './components/Marketplace/BuyOrderPanel';
|
|
42
|
+
export * from './components/Marketplace/BuyOrderRows';
|
|
43
|
+
export * from './components/Marketplace/HistoryPanel';
|
|
44
|
+
export * from './components/Marketplace/BlueprintSearchModal';
|
|
41
45
|
export * from './components/Multitab/TabBody';
|
|
42
46
|
export * from './components/Multitab/TabsContainer';
|
|
43
47
|
export * from './components/NPCDialog/NPCDialog';
|