@rpg-engine/long-bow 0.7.82 → 0.7.84
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/TradingMenu/PremiumLabel.d.ts +7 -0
- package/dist/components/TradingMenu/useTradingGold.d.ts +16 -0
- package/dist/long-bow.cjs.development.js +189 -149
- 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 +189 -149
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Marketplace/MarketplaceRows.tsx +16 -0
- package/src/components/TradingMenu/PremiumLabel.tsx +62 -0
- package/src/components/TradingMenu/TradingItemRow.tsx +36 -88
- package/src/components/TradingMenu/TradingMenu.tsx +77 -136
- package/src/components/TradingMenu/useTradingGold.ts +64 -0
package/package.json
CHANGED
|
@@ -9,6 +9,7 @@ import { uiColors } from '../../constants/uiColors';
|
|
|
9
9
|
import { uiFonts } from '../../constants/uiFonts';
|
|
10
10
|
import { Button, ButtonTypes } from '../Button';
|
|
11
11
|
import { ItemInfoWrapper } from '../Item/Cards/ItemInfoWrapper';
|
|
12
|
+
import { onRenderGems } from '../Item/Inventory/ItemGem';
|
|
12
13
|
import { rarityColor } from '../Item/Inventory/ItemSlotRarity';
|
|
13
14
|
import { Ellipsis } from '../shared/Ellipsis';
|
|
14
15
|
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
@@ -36,6 +37,10 @@ export const MarketplaceRows: React.FC<IMarketPlaceRowsPropos> = ({
|
|
|
36
37
|
onMarketPlaceItemRemove,
|
|
37
38
|
disabled,
|
|
38
39
|
}) => {
|
|
40
|
+
const renderGems = (item: IItem) => {
|
|
41
|
+
return item.attachedGems && onRenderGems(item);
|
|
42
|
+
};
|
|
43
|
+
|
|
39
44
|
return (
|
|
40
45
|
<MarketplaceWrapper>
|
|
41
46
|
<ItemIconContainer>
|
|
@@ -47,6 +52,7 @@ export const MarketplaceRows: React.FC<IMarketPlaceRowsPropos> = ({
|
|
|
47
52
|
equipmentSet={equipmentSet}
|
|
48
53
|
scale={scale}
|
|
49
54
|
>
|
|
55
|
+
<GemContainer>{renderGems(item)}</GemContainer>
|
|
50
56
|
<RarityContainer item={item}>
|
|
51
57
|
<SpriteFromAtlas
|
|
52
58
|
atlasIMG={atlasIMG}
|
|
@@ -61,8 +67,10 @@ export const MarketplaceRows: React.FC<IMarketPlaceRowsPropos> = ({
|
|
|
61
67
|
atlasJSON
|
|
62
68
|
)}
|
|
63
69
|
imgScale={2}
|
|
70
|
+
imgClassname="sprite-from-atlas-img--item"
|
|
64
71
|
/>
|
|
65
72
|
</RarityContainer>
|
|
73
|
+
|
|
66
74
|
<QuantityContainer>
|
|
67
75
|
{item.stackQty &&
|
|
68
76
|
item.stackQty > 1 &&
|
|
@@ -139,6 +147,14 @@ const QuantityContainer = styled.p`
|
|
|
139
147
|
font-size: ${uiFonts.size.xsmall} !important;
|
|
140
148
|
`;
|
|
141
149
|
|
|
150
|
+
const GemContainer = styled.p`
|
|
151
|
+
position: absolute;
|
|
152
|
+
display: block;
|
|
153
|
+
top: -5px;
|
|
154
|
+
left: -10px;
|
|
155
|
+
font-size: ${uiFonts.size.xsmall} !important;
|
|
156
|
+
`;
|
|
157
|
+
|
|
142
158
|
const Flex = styled.div`
|
|
143
159
|
display: flex;
|
|
144
160
|
gap: 24px;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { UserAccountTypes } from '@rpg-engine/shared';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
interface IPremiumLabelProps {
|
|
6
|
+
accountType: UserAccountTypes;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const PremiumLabel: React.FC<IPremiumLabelProps> = ({ accountType }) => {
|
|
10
|
+
if (accountType === UserAccountTypes.Free) return null;
|
|
11
|
+
|
|
12
|
+
const getBackgroundColor = () => {
|
|
13
|
+
switch (accountType) {
|
|
14
|
+
case UserAccountTypes.PremiumBronze:
|
|
15
|
+
return '#CD7F32';
|
|
16
|
+
case UserAccountTypes.PremiumSilver:
|
|
17
|
+
return '#C0C0C0';
|
|
18
|
+
case UserAccountTypes.PremiumGold:
|
|
19
|
+
return '#FFD700';
|
|
20
|
+
case UserAccountTypes.PremiumUltimate:
|
|
21
|
+
return '#002E99';
|
|
22
|
+
default:
|
|
23
|
+
return 'transparent';
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getShortLabel = () => {
|
|
28
|
+
switch (accountType) {
|
|
29
|
+
case UserAccountTypes.PremiumBronze:
|
|
30
|
+
return 'Bronze PA';
|
|
31
|
+
case UserAccountTypes.PremiumSilver:
|
|
32
|
+
return 'Silver PA';
|
|
33
|
+
case UserAccountTypes.PremiumGold:
|
|
34
|
+
return 'Gold PA';
|
|
35
|
+
case UserAccountTypes.PremiumUltimate:
|
|
36
|
+
return 'Ultimate PA';
|
|
37
|
+
default:
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<StyledLabel backgroundColor={getBackgroundColor()}>
|
|
44
|
+
{getShortLabel()}
|
|
45
|
+
</StyledLabel>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const StyledLabel = styled.span<{ backgroundColor: string }>`
|
|
50
|
+
background-color: ${({ backgroundColor }) => backgroundColor};
|
|
51
|
+
color: ${({ backgroundColor }) =>
|
|
52
|
+
backgroundColor === '#002E99' ? 'white' : 'black'};
|
|
53
|
+
font-weight: bold;
|
|
54
|
+
padding: 0 0.4rem;
|
|
55
|
+
border-radius: 3px;
|
|
56
|
+
margin-right: 3px;
|
|
57
|
+
margin-bottom: 2px;
|
|
58
|
+
display: inline-block;
|
|
59
|
+
font-size: 0.5rem !important;
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
export default PremiumLabel;
|
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
getItemTextureKeyPath,
|
|
3
3
|
IEquipmentSet,
|
|
4
4
|
ITradeResponseItem,
|
|
5
|
-
UserAccountTypes,
|
|
6
5
|
} from '@rpg-engine/shared';
|
|
7
6
|
import capitalize from 'lodash/capitalize';
|
|
8
7
|
import React, { useEffect, useState } from 'react';
|
|
@@ -13,6 +12,8 @@ import SelectArrow from '../Arrow/SelectArrow';
|
|
|
13
12
|
import { ItemInfoWrapper } from '../Item/Cards/ItemInfoWrapper';
|
|
14
13
|
import { Ellipsis } from '../shared/Ellipsis';
|
|
15
14
|
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
15
|
+
import PremiumLabel from './PremiumLabel';
|
|
16
|
+
|
|
16
17
|
export interface ITradeComponentProps {
|
|
17
18
|
traderItem: ITradeResponseItem;
|
|
18
19
|
onQuantityChange: (
|
|
@@ -76,40 +77,9 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
76
77
|
|
|
77
78
|
const renderAccountTypeIndicator = () => {
|
|
78
79
|
if (isBuy && traderItem.canBePurchasedOnlyByPremiumPlans) {
|
|
79
|
-
return traderItem.canBePurchasedOnlyByPremiumPlans.map(accountType =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
let textColor = 'black';
|
|
83
|
-
|
|
84
|
-
switch (accountType) {
|
|
85
|
-
case UserAccountTypes.PremiumBronze:
|
|
86
|
-
backgroundColor = '#CD7F32';
|
|
87
|
-
break;
|
|
88
|
-
case UserAccountTypes.PremiumSilver:
|
|
89
|
-
backgroundColor = '#C0C0C0';
|
|
90
|
-
break;
|
|
91
|
-
case UserAccountTypes.PremiumGold:
|
|
92
|
-
backgroundColor = '#FFD700';
|
|
93
|
-
break;
|
|
94
|
-
case UserAccountTypes.PremiumUltimate:
|
|
95
|
-
backgroundColor = '#002E99';
|
|
96
|
-
break;
|
|
97
|
-
default:
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<PremiumLabel
|
|
103
|
-
backgroundColor={backgroundColor}
|
|
104
|
-
textColor={textColor}
|
|
105
|
-
key={accountType}
|
|
106
|
-
>
|
|
107
|
-
{capitalize(accountType) + ' PA'}
|
|
108
|
-
</PremiumLabel>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
});
|
|
80
|
+
return traderItem.canBePurchasedOnlyByPremiumPlans.map(accountType => (
|
|
81
|
+
<PremiumLabel key={accountType} accountType={accountType} />
|
|
82
|
+
));
|
|
113
83
|
}
|
|
114
84
|
return null;
|
|
115
85
|
};
|
|
@@ -137,7 +107,7 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
137
107
|
},
|
|
138
108
|
atlasJSON
|
|
139
109
|
)}
|
|
140
|
-
imgScale={2
|
|
110
|
+
imgScale={2}
|
|
141
111
|
/>
|
|
142
112
|
</ItemInfoWrapper>
|
|
143
113
|
</SpriteContainer>
|
|
@@ -146,7 +116,7 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
146
116
|
<ItemNameContainer>
|
|
147
117
|
<NameValue>
|
|
148
118
|
<p>
|
|
149
|
-
<Ellipsis maxLines={1} maxWidth="
|
|
119
|
+
<Ellipsis maxLines={1} maxWidth="180px">
|
|
150
120
|
{capitalize(traderItem.name)}
|
|
151
121
|
</Ellipsis>
|
|
152
122
|
</p>
|
|
@@ -156,17 +126,17 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
156
126
|
</ItemNameContainer>
|
|
157
127
|
<QuantityContainer>
|
|
158
128
|
<SelectArrow
|
|
159
|
-
size={
|
|
129
|
+
size={24}
|
|
160
130
|
className="arrow-selector"
|
|
161
131
|
direction="left"
|
|
162
|
-
onPointerDown={onLeftClick
|
|
163
|
-
scale={0.
|
|
132
|
+
onPointerDown={() => onLeftClick(outerQty)}
|
|
133
|
+
scale={0.7}
|
|
164
134
|
/>
|
|
165
135
|
<StyledArrow
|
|
166
|
-
size={
|
|
136
|
+
size={24}
|
|
167
137
|
className="arrow-selector"
|
|
168
138
|
direction="left"
|
|
169
|
-
onPointerDown={onLeftClick}
|
|
139
|
+
onPointerDown={() => onLeftClick()}
|
|
170
140
|
/>
|
|
171
141
|
<QuantityInput
|
|
172
142
|
type="text"
|
|
@@ -175,107 +145,85 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
175
145
|
onBlur={handleBlur}
|
|
176
146
|
/>
|
|
177
147
|
<StyledArrow
|
|
178
|
-
size={
|
|
148
|
+
size={24}
|
|
179
149
|
className="arrow-selector"
|
|
180
150
|
direction="right"
|
|
181
|
-
onPointerDown={onRightClick}
|
|
151
|
+
onPointerDown={() => onRightClick()}
|
|
182
152
|
/>
|
|
183
153
|
<SelectArrow
|
|
184
|
-
size={
|
|
154
|
+
size={24}
|
|
185
155
|
className="arrow-selector"
|
|
186
156
|
direction="right"
|
|
187
|
-
onPointerDown={onRightClick
|
|
188
|
-
scale={0.
|
|
157
|
+
onPointerDown={() => onRightClick(outerQty)}
|
|
158
|
+
scale={0.7}
|
|
189
159
|
/>
|
|
190
160
|
</QuantityContainer>
|
|
191
161
|
</ItemWrapper>
|
|
192
162
|
);
|
|
193
163
|
};
|
|
194
164
|
|
|
195
|
-
const PremiumLabel = styled.span<{
|
|
196
|
-
backgroundColor: string;
|
|
197
|
-
textColor: string;
|
|
198
|
-
}>`
|
|
199
|
-
background-color: ${({ backgroundColor }) => backgroundColor};
|
|
200
|
-
color: ${({ textColor }) => textColor};
|
|
201
|
-
font-weight: bold;
|
|
202
|
-
padding: 2px 5px;
|
|
203
|
-
border-radius: 5px;
|
|
204
|
-
margin-right: 5px;
|
|
205
|
-
margin-bottom: 5px;
|
|
206
|
-
display: inline-block;
|
|
207
|
-
`;
|
|
208
|
-
|
|
209
165
|
const StyledArrow = styled(SelectArrow)`
|
|
210
|
-
margin:
|
|
166
|
+
margin: 0 1.5rem;
|
|
211
167
|
`;
|
|
212
168
|
|
|
213
169
|
const ItemWrapper = styled.div`
|
|
214
170
|
width: 100%;
|
|
215
|
-
margin: auto;
|
|
216
171
|
display: flex;
|
|
217
172
|
justify-content: space-between;
|
|
218
|
-
margin-bottom:
|
|
173
|
+
margin-bottom: 0.5rem;
|
|
174
|
+
padding: 0.25rem;
|
|
219
175
|
|
|
220
176
|
&:hover {
|
|
221
177
|
background-color: ${uiColors.darkGray};
|
|
222
178
|
}
|
|
223
|
-
padding: 0.5rem;
|
|
224
179
|
`;
|
|
225
180
|
|
|
226
181
|
const ItemNameContainer = styled.div`
|
|
227
182
|
flex: 60%;
|
|
183
|
+
display: flex;
|
|
184
|
+
align-items: center;
|
|
228
185
|
`;
|
|
229
186
|
|
|
230
187
|
const ItemIconContainer = styled.div`
|
|
231
188
|
display: flex;
|
|
232
189
|
justify-content: flex-start;
|
|
233
190
|
align-items: center;
|
|
234
|
-
|
|
235
|
-
flex: 0 0 58px;
|
|
191
|
+
flex: 0 0 40px;
|
|
236
192
|
`;
|
|
237
193
|
|
|
238
194
|
const SpriteContainer = styled.div`
|
|
239
195
|
position: relative;
|
|
240
196
|
top: -0.5rem;
|
|
241
|
-
left: 0
|
|
197
|
+
left: 0;
|
|
242
198
|
`;
|
|
243
199
|
|
|
244
200
|
const NameValue = styled.div`
|
|
245
201
|
p {
|
|
246
|
-
font-size: 0.
|
|
202
|
+
font-size: 0.6rem;
|
|
247
203
|
margin: 0;
|
|
204
|
+
line-height: 1.2;
|
|
248
205
|
}
|
|
249
206
|
`;
|
|
250
207
|
|
|
251
|
-
|
|
252
|
-
percentageWidth?: number;
|
|
253
|
-
minWidth?: number;
|
|
254
|
-
style?: Record<string, any>;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const QuantityContainer = styled.div<IContainerProps>`
|
|
258
|
-
position: relative;
|
|
208
|
+
const QuantityContainer = styled.div`
|
|
259
209
|
display: flex;
|
|
260
|
-
|
|
261
|
-
min-width: 100px;
|
|
210
|
+
min-width: 90px;
|
|
262
211
|
width: 40%;
|
|
263
|
-
justify-content:
|
|
212
|
+
justify-content: flex-end;
|
|
264
213
|
align-items: center;
|
|
265
|
-
|
|
266
|
-
|
|
214
|
+
flex: 30%;
|
|
215
|
+
gap: 2px;
|
|
216
|
+
position: relative;
|
|
267
217
|
`;
|
|
268
218
|
|
|
269
219
|
const QuantityInput = styled.input`
|
|
270
|
-
width:
|
|
220
|
+
width: 30px;
|
|
271
221
|
text-align: center;
|
|
272
222
|
background-color: ${uiColors.darkGray};
|
|
273
223
|
color: white;
|
|
274
|
-
border: 1px solid ${uiColors.lightGray};
|
|
275
|
-
padding: 2px;
|
|
276
|
-
font-size: ${uiFonts.size.small};
|
|
277
224
|
border: none;
|
|
278
|
-
|
|
225
|
+
padding: 1px;
|
|
226
|
+
font-size: ${uiFonts.size.small};
|
|
279
227
|
position: relative;
|
|
280
|
-
|
|
228
|
+
right: 4px;
|
|
281
229
|
`;
|
|
@@ -4,12 +4,13 @@ import {
|
|
|
4
4
|
ITradeResponseItem,
|
|
5
5
|
TradeTransactionType,
|
|
6
6
|
} from '@rpg-engine/shared';
|
|
7
|
-
import React
|
|
7
|
+
import React from 'react';
|
|
8
8
|
import styled from 'styled-components';
|
|
9
9
|
import { Button, ButtonTypes } from '../Button';
|
|
10
10
|
import { DraggableContainer } from '../DraggableContainer';
|
|
11
11
|
import { RPGUIContainerTypes } from '../RPGUI/RPGUIContainer';
|
|
12
12
|
import { TradingItemRow } from './TradingItemRow';
|
|
13
|
+
import { useTradingGold } from './useTradingGold';
|
|
13
14
|
|
|
14
15
|
export interface ITradingMenu {
|
|
15
16
|
traderItems: ITradeResponseItem[];
|
|
@@ -34,187 +35,127 @@ export const TradingMenu: React.FC<ITradingMenu> = ({
|
|
|
34
35
|
equipmentSet,
|
|
35
36
|
scale,
|
|
36
37
|
}) => {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (qty) newSum += qty * item.price;
|
|
47
|
-
setSum(newSum);
|
|
48
|
-
});
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const isBuy = () => {
|
|
52
|
-
return type == 'buy';
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const hasGoldForSale = () => {
|
|
56
|
-
if (isBuy()) {
|
|
57
|
-
return !(sum > characterAvailableGold);
|
|
58
|
-
}
|
|
59
|
-
return true;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const getFinalGold = () => {
|
|
63
|
-
if (isBuy()) {
|
|
64
|
-
return characterAvailableGold - sum;
|
|
65
|
-
} else {
|
|
66
|
-
return characterAvailableGold + sum;
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const Capitalize = (word: string) => {
|
|
71
|
-
return word[0].toUpperCase() + word.substring(1);
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const onConfirmClick = () => {
|
|
75
|
-
const items: ITradeRequestItem[] = [];
|
|
76
|
-
|
|
77
|
-
traderItems.forEach(item => {
|
|
78
|
-
const qty = qtyMap.get(item.key);
|
|
79
|
-
if (qty) {
|
|
80
|
-
items.push(Object.assign({}, item, { qty: qty }));
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
onConfirm(items);
|
|
85
|
-
};
|
|
38
|
+
const {
|
|
39
|
+
sum,
|
|
40
|
+
qtyMap,
|
|
41
|
+
isBuy,
|
|
42
|
+
hasGoldForSale,
|
|
43
|
+
getFinalGold,
|
|
44
|
+
getTradeItems,
|
|
45
|
+
updateQuantity,
|
|
46
|
+
} = useTradingGold({ characterAvailableGold, type, traderItems });
|
|
86
47
|
|
|
87
48
|
return (
|
|
88
49
|
<DraggableContainer
|
|
89
50
|
type={RPGUIContainerTypes.Framed}
|
|
90
|
-
onCloseButton={
|
|
91
|
-
|
|
92
|
-
}}
|
|
93
|
-
width="600px"
|
|
51
|
+
onCloseButton={onClose}
|
|
52
|
+
width="500px"
|
|
94
53
|
cancelDrag="#TraderContainer"
|
|
95
54
|
scale={scale}
|
|
96
55
|
>
|
|
97
|
-
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
<TradingComponentScrollWrapper id="TraderContainer">
|
|
56
|
+
<Container>
|
|
57
|
+
<Title>{type.charAt(0).toUpperCase() + type.slice(1)} Menu</Title>
|
|
58
|
+
<hr className="golden" />
|
|
59
|
+
|
|
60
|
+
<ScrollWrapper id="TraderContainer">
|
|
103
61
|
{traderItems.map((tradeItem, index) => (
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</ItemWrapper>
|
|
62
|
+
<TradingItemRow
|
|
63
|
+
key={`${tradeItem.key}_${index}`}
|
|
64
|
+
atlasIMG={atlasIMG}
|
|
65
|
+
atlasJSON={atlasJSON}
|
|
66
|
+
onQuantityChange={updateQuantity}
|
|
67
|
+
traderItem={tradeItem}
|
|
68
|
+
selectedQty={qtyMap.get(tradeItem.key) ?? 0}
|
|
69
|
+
equipmentSet={equipmentSet}
|
|
70
|
+
scale={scale}
|
|
71
|
+
isBuy={isBuy()}
|
|
72
|
+
/>
|
|
116
73
|
))}
|
|
117
|
-
</
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
74
|
+
</ScrollWrapper>
|
|
75
|
+
|
|
76
|
+
<InfoSection>
|
|
77
|
+
<GoldInfo>
|
|
78
|
+
<p>Available Gold:</p>
|
|
79
|
+
<p>${characterAvailableGold.toFixed(2)}</p>
|
|
80
|
+
</GoldInfo>
|
|
81
|
+
<GoldInfo>
|
|
82
|
+
<p>Total:</p>
|
|
83
|
+
<p>${sum}</p>
|
|
84
|
+
</GoldInfo>
|
|
85
|
+
{!hasGoldForSale() ? (
|
|
86
|
+
<AlertText>Sorry, not enough money.</AlertText>
|
|
87
|
+
) : (
|
|
88
|
+
<GoldInfo>
|
|
89
|
+
<p>Final Gold:</p>
|
|
90
|
+
<p>${getFinalGold().toFixed(2)}</p>
|
|
91
|
+
</GoldInfo>
|
|
92
|
+
)}
|
|
93
|
+
</InfoSection>
|
|
136
94
|
|
|
137
95
|
<ButtonWrapper>
|
|
138
96
|
<Button
|
|
139
97
|
buttonType={ButtonTypes.RPGUIButton}
|
|
140
98
|
disabled={!hasGoldForSale()}
|
|
141
|
-
onPointerDown={() =>
|
|
99
|
+
onPointerDown={() => onConfirm(getTradeItems())}
|
|
142
100
|
>
|
|
143
101
|
Confirm
|
|
144
102
|
</Button>
|
|
145
|
-
<Button
|
|
146
|
-
buttonType={ButtonTypes.RPGUIButton}
|
|
147
|
-
onPointerDown={() => onClose()}
|
|
148
|
-
>
|
|
103
|
+
<Button buttonType={ButtonTypes.RPGUIButton} onPointerDown={onClose}>
|
|
149
104
|
Cancel
|
|
150
105
|
</Button>
|
|
151
106
|
</ButtonWrapper>
|
|
152
|
-
|
|
107
|
+
</Container>
|
|
153
108
|
</DraggableContainer>
|
|
154
109
|
);
|
|
155
110
|
};
|
|
156
111
|
|
|
112
|
+
const Container = styled.div`
|
|
113
|
+
width: 100%;
|
|
114
|
+
`;
|
|
115
|
+
|
|
157
116
|
const Title = styled.h1`
|
|
158
|
-
|
|
159
|
-
font-size: 0.6rem;
|
|
117
|
+
font-size: 0.7rem !important;
|
|
160
118
|
color: yellow !important;
|
|
119
|
+
text-align: center;
|
|
161
120
|
`;
|
|
162
121
|
|
|
163
|
-
const
|
|
122
|
+
const ScrollWrapper = styled.div`
|
|
164
123
|
overflow-y: scroll;
|
|
165
|
-
height:
|
|
124
|
+
height: 250px;
|
|
166
125
|
width: 100%;
|
|
167
|
-
margin-top:
|
|
126
|
+
margin-top: 0.3rem;
|
|
127
|
+
overflow-x: hidden;
|
|
128
|
+
padding: 0 0.3rem;
|
|
168
129
|
`;
|
|
169
130
|
|
|
170
|
-
const
|
|
171
|
-
margin:
|
|
172
|
-
|
|
173
|
-
justify-content: space-between;
|
|
131
|
+
const InfoSection = styled.div`
|
|
132
|
+
margin-top: 0.3rem;
|
|
133
|
+
padding: 0 0.5rem;
|
|
174
134
|
`;
|
|
175
135
|
|
|
176
|
-
const
|
|
177
|
-
margin-top: 1rem;
|
|
136
|
+
const GoldInfo = styled.div`
|
|
178
137
|
display: flex;
|
|
179
138
|
justify-content: space-between;
|
|
180
|
-
height:
|
|
181
|
-
p {
|
|
182
|
-
color: white !important;
|
|
183
|
-
}
|
|
139
|
+
height: 16px;
|
|
184
140
|
width: 100%;
|
|
185
|
-
margin
|
|
186
|
-
`;
|
|
187
|
-
|
|
188
|
-
const GoldWrapper = styled.div`
|
|
189
|
-
margin-top: 1rem;
|
|
190
|
-
display: flex;
|
|
191
|
-
justify-content: space-between;
|
|
192
|
-
height: 20px;
|
|
141
|
+
margin: 0.5rem 0;
|
|
193
142
|
p {
|
|
194
143
|
color: yellow !important;
|
|
144
|
+
margin: 0;
|
|
145
|
+
font-size: 0.6rem;
|
|
195
146
|
}
|
|
196
|
-
width: 100%;
|
|
197
|
-
margin-left: 0.8rem;
|
|
198
147
|
`;
|
|
199
148
|
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
height: 20px;
|
|
206
|
-
p {
|
|
207
|
-
color: red !important;
|
|
208
|
-
}
|
|
149
|
+
const AlertText = styled.p`
|
|
150
|
+
color: red !important;
|
|
151
|
+
text-align: center;
|
|
152
|
+
margin: 0.3rem 0;
|
|
153
|
+
font-size: 0.5rem;
|
|
209
154
|
`;
|
|
210
155
|
|
|
211
156
|
const ButtonWrapper = styled.div`
|
|
212
157
|
display: flex;
|
|
213
158
|
justify-content: space-around;
|
|
214
|
-
padding-top: 20px;
|
|
215
159
|
width: 100%;
|
|
216
|
-
margin-top:
|
|
217
|
-
button {
|
|
218
|
-
padding: 0px 50px;
|
|
219
|
-
}
|
|
160
|
+
margin-top: 0.5rem;
|
|
220
161
|
`;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ITradeRequestItem,
|
|
3
|
+
ITradeResponseItem,
|
|
4
|
+
TradeTransactionType,
|
|
5
|
+
} from '@rpg-engine/shared';
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
|
|
8
|
+
interface ITradingGoldHook {
|
|
9
|
+
characterAvailableGold: number;
|
|
10
|
+
type: TradeTransactionType;
|
|
11
|
+
traderItems: ITradeResponseItem[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const useTradingGold = ({
|
|
15
|
+
characterAvailableGold,
|
|
16
|
+
type,
|
|
17
|
+
traderItems,
|
|
18
|
+
}: ITradingGoldHook) => {
|
|
19
|
+
const [sum, setSum] = useState(0);
|
|
20
|
+
const [qtyMap, setQtyMap] = useState(new Map<string, number>());
|
|
21
|
+
|
|
22
|
+
const isBuy = () => type === 'buy';
|
|
23
|
+
|
|
24
|
+
const hasGoldForSale = () =>
|
|
25
|
+
isBuy() ? !(sum > characterAvailableGold) : true;
|
|
26
|
+
|
|
27
|
+
const getFinalGold = () =>
|
|
28
|
+
isBuy() ? characterAvailableGold - sum : characterAvailableGold + sum;
|
|
29
|
+
|
|
30
|
+
const getTradeItems = (): ITradeRequestItem[] => {
|
|
31
|
+
const items: ITradeRequestItem[] = [];
|
|
32
|
+
traderItems.forEach(item => {
|
|
33
|
+
const qty = qtyMap.get(item.key);
|
|
34
|
+
if (qty) {
|
|
35
|
+
items.push({
|
|
36
|
+
...item,
|
|
37
|
+
qty,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return items;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const updateQuantity = (item: ITradeResponseItem, selectedQty: number) => {
|
|
45
|
+
setQtyMap(new Map(qtyMap.set(item.key, selectedQty)));
|
|
46
|
+
|
|
47
|
+
let newSum = 0;
|
|
48
|
+
qtyMap.forEach((qty, key) => {
|
|
49
|
+
const item = traderItems.find(i => i.key === key);
|
|
50
|
+
if (item) newSum += qty * item.price;
|
|
51
|
+
});
|
|
52
|
+
setSum(newSum);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
sum,
|
|
57
|
+
qtyMap,
|
|
58
|
+
isBuy,
|
|
59
|
+
hasGoldForSale,
|
|
60
|
+
getFinalGold,
|
|
61
|
+
getTradeItems,
|
|
62
|
+
updateQuantity,
|
|
63
|
+
};
|
|
64
|
+
};
|