@kiva/kv-components 3.73.2 → 3.74.0
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/CHANGELOG.md +18 -0
- package/package.json +2 -2
- package/tests/unit/specs/utils/loanUtils.spec.js +124 -0
- package/utils/loanUtils.js +98 -0
- package/vue/KvLendCta.vue +5 -64
- package/vue/stories/KvLendCta.stories.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [3.74.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.73.2...@kiva/kv-components@3.74.0) (2024-04-23)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* adjusted comment ([e73e6a8](https://github.com/kiva/kv-ui-elements/commit/e73e6a842486ec5ce951a3130348cb1e3428288d))
|
|
12
|
+
* extracted CTA dropdown methods and added unit tests ([4ef99de](https://github.com/kiva/kv-ui-elements/commit/4ef99deb24399fcb619c41d20370ad79812f1b00))
|
|
13
|
+
* removed duplicate test ([838d6d4](https://github.com/kiva/kv-ui-elements/commit/838d6d48c85bbfd7759fd5266498219817e00cd7))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* $1000 lend CTA options ([4f89352](https://github.com/kiva/kv-ui-elements/commit/4f8935237acb9c1f1655b77cc604fe68b21ab077))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
6
24
|
## [3.73.2](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.73.1...@kiva/kv-components@3.73.2) (2024-04-23)
|
|
7
25
|
|
|
8
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kiva/kv-components",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.74.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"optional": true
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "db1d9c79b08cf5489aa474fddaa610c365526ab7"
|
|
79
79
|
}
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
isBetween25And50,
|
|
3
3
|
isLessThan25,
|
|
4
4
|
getLendCtaSelectedOption,
|
|
5
|
+
getDropdownPriceArray,
|
|
5
6
|
ERL_COOKIE_NAME,
|
|
6
7
|
TOP_UP_CAMPAIGN,
|
|
7
8
|
BASE_CAMPAIGN,
|
|
@@ -310,4 +311,127 @@ describe('loanUtils', () => {
|
|
|
310
311
|
expect(mockCookieStoreSet).toHaveBeenCalledTimes(0);
|
|
311
312
|
});
|
|
312
313
|
});
|
|
314
|
+
|
|
315
|
+
describe('getDropdownPriceArray', () => {
|
|
316
|
+
it('should return less than 25', () => {
|
|
317
|
+
const result = getDropdownPriceArray('15.00', true, 15);
|
|
318
|
+
|
|
319
|
+
expect(result).toEqual(['15']);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should return non-25 increments', () => {
|
|
323
|
+
const result = getDropdownPriceArray('30.00', true);
|
|
324
|
+
|
|
325
|
+
expect(result).toEqual(['25', '30']);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should return dropdown values', () => {
|
|
329
|
+
const result = getDropdownPriceArray('100.00');
|
|
330
|
+
|
|
331
|
+
expect(result).toEqual(['25', '50', '75', '100']);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('should return huge dropdown values between 500 and 1000', () => {
|
|
335
|
+
const result = getDropdownPriceArray('650.00', false, 25, false, true, false);
|
|
336
|
+
|
|
337
|
+
expect(result).toEqual([
|
|
338
|
+
'25',
|
|
339
|
+
'50',
|
|
340
|
+
'75',
|
|
341
|
+
'100',
|
|
342
|
+
'125',
|
|
343
|
+
'150',
|
|
344
|
+
'175',
|
|
345
|
+
'200',
|
|
346
|
+
'225',
|
|
347
|
+
'250',
|
|
348
|
+
'275',
|
|
349
|
+
'300',
|
|
350
|
+
'325',
|
|
351
|
+
'350',
|
|
352
|
+
'375',
|
|
353
|
+
'400',
|
|
354
|
+
'425',
|
|
355
|
+
'450',
|
|
356
|
+
'475',
|
|
357
|
+
'500',
|
|
358
|
+
'600',
|
|
359
|
+
'650',
|
|
360
|
+
]);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('should return huge dropdown values up to 10,000', () => {
|
|
364
|
+
const result = getDropdownPriceArray('11000.00', false, 25, false, true, false);
|
|
365
|
+
|
|
366
|
+
expect(result).toEqual([
|
|
367
|
+
'25',
|
|
368
|
+
'50',
|
|
369
|
+
'75',
|
|
370
|
+
'100',
|
|
371
|
+
'125',
|
|
372
|
+
'150',
|
|
373
|
+
'175',
|
|
374
|
+
'200',
|
|
375
|
+
'225',
|
|
376
|
+
'250',
|
|
377
|
+
'275',
|
|
378
|
+
'300',
|
|
379
|
+
'325',
|
|
380
|
+
'350',
|
|
381
|
+
'375',
|
|
382
|
+
'400',
|
|
383
|
+
'425',
|
|
384
|
+
'450',
|
|
385
|
+
'475',
|
|
386
|
+
'500',
|
|
387
|
+
'600',
|
|
388
|
+
'700',
|
|
389
|
+
'800',
|
|
390
|
+
'900',
|
|
391
|
+
'1,000',
|
|
392
|
+
'2,000',
|
|
393
|
+
'3,000',
|
|
394
|
+
'4,000',
|
|
395
|
+
'5,000',
|
|
396
|
+
'6,000',
|
|
397
|
+
'7,000',
|
|
398
|
+
'8,000',
|
|
399
|
+
'9,000',
|
|
400
|
+
'10,000',
|
|
401
|
+
]);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it('should return not huge dropdown values for visitor', () => {
|
|
405
|
+
const result = getDropdownPriceArray('650.00', false, 25, false, true, true);
|
|
406
|
+
|
|
407
|
+
expect(result).toEqual([
|
|
408
|
+
'25',
|
|
409
|
+
'50',
|
|
410
|
+
'75',
|
|
411
|
+
'100',
|
|
412
|
+
'125',
|
|
413
|
+
'150',
|
|
414
|
+
'175',
|
|
415
|
+
'200',
|
|
416
|
+
'225',
|
|
417
|
+
'250',
|
|
418
|
+
'275',
|
|
419
|
+
'300',
|
|
420
|
+
'325',
|
|
421
|
+
'350',
|
|
422
|
+
'375',
|
|
423
|
+
'400',
|
|
424
|
+
'425',
|
|
425
|
+
'450',
|
|
426
|
+
'475',
|
|
427
|
+
'500',
|
|
428
|
+
]);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('should return 5 dollar notes', () => {
|
|
432
|
+
const result = getDropdownPriceArray('30.00', true, 25, true);
|
|
433
|
+
|
|
434
|
+
expect(result).toEqual(['5', '10', '15', '20', '25', '30']);
|
|
435
|
+
});
|
|
436
|
+
});
|
|
313
437
|
});
|
package/utils/loanUtils.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import numeral from 'numeral';
|
|
2
|
+
|
|
1
3
|
export const ERL_COOKIE_NAME = 'kverlfivedollarnotes';
|
|
2
4
|
export const TOP_UP_CAMPAIGN = 'TOPUP-VB-BALANCE-MPV1';
|
|
3
5
|
export const BASE_CAMPAIGN = 'BASE-VB_BALANCE_MPV1';
|
|
@@ -109,3 +111,99 @@ export function getLendCtaSelectedOption(
|
|
|
109
111
|
// $25 is the fallback default selected option
|
|
110
112
|
return '25';
|
|
111
113
|
}
|
|
114
|
+
|
|
115
|
+
function buildHugePriceArray(amountLeft) {
|
|
116
|
+
const priceArray = [];
|
|
117
|
+
|
|
118
|
+
// Add $100 options up to $1,000
|
|
119
|
+
let minAmount = 100;
|
|
120
|
+
let limitAmount = amountLeft > 1000 ? 1000 : amountLeft;
|
|
121
|
+
let optionCount = limitAmount / minAmount;
|
|
122
|
+
for (let i = 1; i <= optionCount; i += 1) {
|
|
123
|
+
const price = minAmount * i + 500;
|
|
124
|
+
if (price > limitAmount) break;
|
|
125
|
+
priceArray.push(numeral(price).format('0,0'));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Add $1000 options up to $10,000
|
|
129
|
+
minAmount = 1000;
|
|
130
|
+
limitAmount = amountLeft > 10000 ? 10000 : amountLeft;
|
|
131
|
+
optionCount = limitAmount / minAmount;
|
|
132
|
+
for (let i = 1; i <= optionCount; i += 1) {
|
|
133
|
+
const price = minAmount * i + 1000;
|
|
134
|
+
if (price > limitAmount) break;
|
|
135
|
+
priceArray.push(numeral(price).format('0,0'));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Ensure final option is added
|
|
139
|
+
if (!priceArray.includes(numeral(limitAmount).format('0,0'))) {
|
|
140
|
+
priceArray.push(numeral(limitAmount).format('0,0'));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return priceArray;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function build5DollarsPriceArray(amountLeft) {
|
|
147
|
+
const limit5Notes = amountLeft < 50 ? amountLeft : 50;
|
|
148
|
+
const numberOf5 = limit5Notes / 5;
|
|
149
|
+
const numberOf25 = Math.ceil((amountLeft - limit5Notes) / 25) + 1;
|
|
150
|
+
const priceArray = [];
|
|
151
|
+
for (let i = 1; i <= numberOf5; i += 1) {
|
|
152
|
+
priceArray.push(numeral(5 * i).format('0,0'));
|
|
153
|
+
}
|
|
154
|
+
if (amountLeft > limit5Notes) {
|
|
155
|
+
for (let i = 3; i <= numberOf25; i += 1) {
|
|
156
|
+
priceArray.push(numeral(25 * i).format('0,0'));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return priceArray;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function buildPriceArray(amountLeft, minAmount) {
|
|
163
|
+
// Get count of shares based on available remaining amount
|
|
164
|
+
const optionCount = amountLeft / minAmount;
|
|
165
|
+
// Convert this to formatted array for our select element
|
|
166
|
+
const priceArray = []; // ex. priceArray = ['25', '50', '75']
|
|
167
|
+
for (let i = 1; i <= optionCount; i += 1) {
|
|
168
|
+
priceArray.push(numeral(minAmount * i).format('0,0'));
|
|
169
|
+
}
|
|
170
|
+
return priceArray;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Gets the dropdown price values for the lend CTA
|
|
175
|
+
*
|
|
176
|
+
* @param {string} unreservedAmount The unreserved amount of the loan
|
|
177
|
+
* @param {boolean} isCompleteLoanActive Whether to include option that would complete loan
|
|
178
|
+
* @param {number} minAmount The min amount to show in the dropdown
|
|
179
|
+
* @param {boolean} enableFiveDollarsNotes Whether five dollar notes are enabled
|
|
180
|
+
* @param {boolean} enableHugeAmount Whether huge loan amounts are enabled
|
|
181
|
+
* @param {boolean} isVisitor Whether the current user is a visitor
|
|
182
|
+
* @param {boolean} inPfp Whether the loan is in PFP
|
|
183
|
+
* @returns {string[]} Price value array for the CTA dropdown
|
|
184
|
+
*/
|
|
185
|
+
export function getDropdownPriceArray(
|
|
186
|
+
unreservedAmount,
|
|
187
|
+
isCompleteLoanActive = false,
|
|
188
|
+
minAmount = 25,
|
|
189
|
+
enableFiveDollarsNotes = false,
|
|
190
|
+
enableHugeAmount = false,
|
|
191
|
+
isVisitor = true,
|
|
192
|
+
inPfp = false,
|
|
193
|
+
) {
|
|
194
|
+
const parsedAmountLeft = parseFloat(unreservedAmount);
|
|
195
|
+
let priceArray = (enableFiveDollarsNotes && !inPfp)
|
|
196
|
+
? build5DollarsPriceArray(parsedAmountLeft).slice(0, 28)
|
|
197
|
+
: buildPriceArray(parsedAmountLeft, minAmount).slice(0, 20);
|
|
198
|
+
|
|
199
|
+
if (enableHugeAmount && parsedAmountLeft > 500 && !isVisitor) {
|
|
200
|
+
const hugePriceArray = buildHugePriceArray(parsedAmountLeft);
|
|
201
|
+
priceArray = priceArray.concat(hugePriceArray);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (isCompleteLoanActive && !priceArray.includes(Number(unreservedAmount).toFixed())) {
|
|
205
|
+
priceArray.push(Number(unreservedAmount).toFixed());
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return priceArray;
|
|
209
|
+
}
|
package/vue/KvLendCta.vue
CHANGED
|
@@ -126,13 +126,12 @@
|
|
|
126
126
|
</template>
|
|
127
127
|
|
|
128
128
|
<script>
|
|
129
|
-
import numeral from 'numeral';
|
|
130
129
|
import { mdiChevronRight } from '@mdi/js';
|
|
131
130
|
import KvLendAmountButton from './KvLendAmountButton.vue';
|
|
132
131
|
import KvUiSelect from './KvSelect.vue';
|
|
133
132
|
import KvUiButton from './KvButton.vue';
|
|
134
133
|
import KvMaterialIcon from './KvMaterialIcon.vue';
|
|
135
|
-
import { getLendCtaSelectedOption } from '../utils/loanUtils';
|
|
134
|
+
import { getLendCtaSelectedOption, getDropdownPriceArray } from '../utils/loanUtils';
|
|
136
135
|
|
|
137
136
|
export default {
|
|
138
137
|
name: 'KvLendCta',
|
|
@@ -251,15 +250,14 @@ export default {
|
|
|
251
250
|
// If we wanted to show this interface on loans with less than 25 remaining they would see the selector
|
|
252
251
|
const minAmount = parseFloat(this.unreservedAmount < 25 ? this.minNoteSize : 25);
|
|
253
252
|
// Limit price options
|
|
254
|
-
|
|
253
|
+
return getDropdownPriceArray(
|
|
255
254
|
this.unreservedAmount,
|
|
255
|
+
this.isCompleteLoanActive,
|
|
256
256
|
minAmount,
|
|
257
257
|
this.enableFiveDollarsNotes,
|
|
258
|
+
this.enableHugeAmount,
|
|
259
|
+
this.isVisitor,
|
|
258
260
|
);
|
|
259
|
-
if (this.isCompleteLoanActive && !priceArray.includes(Number(this.unreservedAmount).toFixed())) {
|
|
260
|
-
priceArray.push(Number(this.unreservedAmount).toFixed());
|
|
261
|
-
}
|
|
262
|
-
return priceArray;
|
|
263
261
|
},
|
|
264
262
|
ctaButtonText() {
|
|
265
263
|
if (this.isCompleteLoanActive) {
|
|
@@ -403,63 +401,6 @@ export default {
|
|
|
403
401
|
this.loanId,
|
|
404
402
|
);
|
|
405
403
|
},
|
|
406
|
-
build5DollarsPriceArray(amountLeft) {
|
|
407
|
-
const limit5Notes = amountLeft < 50 ? amountLeft : 50;
|
|
408
|
-
const numberOf5 = limit5Notes / 5;
|
|
409
|
-
const numberOf25 = Math.ceil((amountLeft - limit5Notes) / 25) + 1;
|
|
410
|
-
const priceArray = [];
|
|
411
|
-
for (let i = 1; i <= numberOf5; i += 1) {
|
|
412
|
-
priceArray.push(numeral(5 * i).format('0,0'));
|
|
413
|
-
}
|
|
414
|
-
if (amountLeft > limit5Notes) {
|
|
415
|
-
for (let i = 3; i <= numberOf25; i += 1) {
|
|
416
|
-
priceArray.push(numeral(25 * i).format('0,0'));
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
return priceArray;
|
|
420
|
-
},
|
|
421
|
-
buildPriceArray(amountLeft, minAmount) {
|
|
422
|
-
// get count of shares based on available remaining amount.
|
|
423
|
-
const N = amountLeft / minAmount;
|
|
424
|
-
// convert this to formatted array for our select element
|
|
425
|
-
const priceArray = []; // ex. priceArray = ['25', '50', '75']
|
|
426
|
-
for (let i = 1; i <= N; i += 1) {
|
|
427
|
-
priceArray.push(numeral(minAmount * i).format('0,0'));
|
|
428
|
-
}
|
|
429
|
-
return priceArray;
|
|
430
|
-
},
|
|
431
|
-
buildHugePriceArray(amountLeft) {
|
|
432
|
-
const minAmount = 100;
|
|
433
|
-
const limitAmount = amountLeft > 1000 ? 1000 : amountLeft;
|
|
434
|
-
const N = limitAmount / minAmount;
|
|
435
|
-
|
|
436
|
-
const priceArray = [];
|
|
437
|
-
for (let i = 1; i <= N; i += 1) {
|
|
438
|
-
const price = minAmount * i + 500;
|
|
439
|
-
if (price > limitAmount) break;
|
|
440
|
-
priceArray.push(numeral(price).format('0,0'));
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (!priceArray.includes(numeral(limitAmount).format('0,0'))) {
|
|
444
|
-
priceArray.push(numeral(limitAmount).format('0,0'));
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
return priceArray;
|
|
448
|
-
},
|
|
449
|
-
getDropdownPriceArray(unreservedAmount, minAmount, enableFiveDollarsNotes, inPfp = false) {
|
|
450
|
-
const parsedAmountLeft = parseFloat(unreservedAmount);
|
|
451
|
-
let combinedPricesArray = [];
|
|
452
|
-
const priceArray = (enableFiveDollarsNotes && !inPfp)
|
|
453
|
-
? this.build5DollarsPriceArray(parsedAmountLeft).slice(0, 28)
|
|
454
|
-
: this.buildPriceArray(parsedAmountLeft, minAmount).slice(0, 20);
|
|
455
|
-
|
|
456
|
-
const showHugeAmount = this.enableHugeAmount && parsedAmountLeft > 500 && !this.isVisitor;
|
|
457
|
-
if (showHugeAmount) {
|
|
458
|
-
const hugePriceArray = this.buildHugePriceArray(parsedAmountLeft);
|
|
459
|
-
combinedPricesArray = priceArray.concat(hugePriceArray);
|
|
460
|
-
}
|
|
461
|
-
return showHugeAmount ? combinedPricesArray : priceArray;
|
|
462
|
-
},
|
|
463
404
|
},
|
|
464
405
|
};
|
|
465
406
|
|
|
@@ -70,7 +70,7 @@ export const Dropdown = story({
|
|
|
70
70
|
kvTrackFunction,
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
export const
|
|
73
|
+
export const HugeAmount = story({
|
|
74
74
|
isLoading: false,
|
|
75
75
|
loan: {
|
|
76
76
|
id: 1,
|
|
@@ -81,7 +81,7 @@ export const HugeLentAmount = story({
|
|
|
81
81
|
isVisitor: false,
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
export const
|
|
84
|
+
export const HugeAmountUnder1000 = story({
|
|
85
85
|
isLoading: false,
|
|
86
86
|
loan: {
|
|
87
87
|
id: 1,
|