PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.3.1
GiveWP – Donation Plugin and Fundraising Platform v3.3.1
4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / DonorDashboards / resources / js / app / components / subscription-manager / amount-control / index.js
give / src / DonorDashboards / resources / js / app / components / subscription-manager / amount-control Last commit date
index.js 4 years ago style.scss 4 years ago
index.js
152 lines
1 import {useCallback, useEffect, useState} from 'react';
2 import CurrencyInput, {formatValue} from 'react-currency-input-field';
3 import {__, sprintf} from '@wordpress/i18n';
4
5 import {toUniqueId} from '../../../utils';
6 import FieldRow from '../../field-row';
7 import SelectControl from '../../select-control';
8
9 import './style.scss';
10
11 const CUSTOM_AMOUNT = 'custom_amount';
12
13 /**
14 * Converts a float to minor currency.
15 *
16 * @param {string} float
17 * @param {number} precision
18 * @return {number}
19 */
20 const minorOfFloat = (float, precision) => Number.parseFloat(float) * Math.pow(10, precision);
21
22 /**
23 * Quick and cheap knock-off of the classnames package.
24 * Do not re-use. Just use the real package.
25 *
26 * @param {...any} className
27 * @return {string}
28 */
29 const cx = (...classNames) => classNames.filter(Boolean).join(' ');
30
31 /**
32 * This control provides preset options however it allows the user to specify a
33 * custom option.
34 *
35 * Heads up, you probably want to take a good look at what’s happening before
36 * using this elsewhere.
37 */
38 const AmountControl = ({currency, onChange, value, options, min, max}) => {
39 // This is the configuration for the CurrencyInput as well as formatting
40 // values in validation errors
41 const formatConfig = {
42 decimalScale: currency.numberDecimals,
43 decimalsLimit: currency.numberDecimals,
44 prefix: currency.currencyPosition === 'before' ? currency.symbol : null,
45 suffix: currency.currencyPosition === 'after' ? currency.symbol : null,
46 decimalSeparator: currency.decimalSeparator,
47 groupSeparator: currency.thousandsSeparator,
48 };
49
50 const [validationError, setValidationError] = useState();
51 const clearValidationError = () => setValidationError(null);
52
53 // The select value acts as a proxy for the actual value.
54 const [selectValue, setSelectValue] = useState(
55 // Determine whether the value is one of the predefined values and set
56 // the select input’s initial value accordingly.
57 () => (options.map((option) => option.value).includes(value) ? value : CUSTOM_AMOUNT)
58 );
59 // We only call the onChange if the value is one of the predefined values.
60 // Otherwise, we effectively delegate control to the currency input.
61 useEffect(() => {
62 if (selectValue !== CUSTOM_AMOUNT) {
63 onChange(selectValue);
64 // I’ve omitted this from the deps array since this shouldn’t run
65 // when the validationError changes. This is just checking to see if
66 // we need to clear it.
67 if (validationError) clearValidationError();
68 }
69 }, [selectValue, onChange]);
70
71 // Ideally, we’d just use the value from the event.target, however, that’s
72 // formatted all nicely and we want a float, so we can just use the
73 const validateCustomAmount = useCallback(() => {
74 if (value) {
75 const minorOfValue = minorOfFloat(value, currency.numberDecimals);
76 const minorOfMin = minorOfFloat(min, currency.numberDecimals);
77 const minorOfMax = minorOfFloat(max, currency.numberDecimals);
78
79 if (minorOfValue > minorOfMax) {
80 setValidationError(
81 sprintf(__('Amount must be less than %s.', 'give'), formatValue({value: max, ...formatConfig}))
82 );
83 } else if (minorOfValue < minorOfMin) {
84 setValidationError(
85 sprintf(__('Amount must be more than %s.', 'give'), formatValue({value: min, ...formatConfig}))
86 );
87 } else {
88 clearValidationError();
89 }
90 } else {
91 setValidationError(
92 sprintf(__('Amount must be more than %s.', 'give'), formatValue({value: min, ...formatConfig}))
93 );
94 }
95 }, [currency.numberDecimals, min, max, value]);
96
97 const customAmountInputId = toUniqueId();
98
99 return (
100 <div className="give-donor-dashboard-amount-inputs">
101 <FieldRow>
102 <div>
103 <SelectControl
104 label={__('Subscription Amount', 'give')}
105 options={options}
106 value={selectValue}
107 onChange={setSelectValue}
108 />
109 </div>
110 <div>
111 {selectValue === CUSTOM_AMOUNT && (
112 <div className="give-donor-dashboard-currency-control">
113 <label
114 className="give-donor-dashboard-currency-control__label"
115 htmlFor={customAmountInputId}
116 >
117 {__('Custom Amount', 'give')}
118 </label>
119 <div
120 className={cx(
121 'give-donor-dashboard-currency-control__input',
122 validationError && 'has-error'
123 )}
124 >
125 <CurrencyInput
126 id={customAmountInputId}
127 name="custom-amount"
128 placeholder={__('Enter amount...', 'give')}
129 value={value ?? ''}
130 onValueChange={onChange}
131 onBlur={validateCustomAmount}
132 allowNegativeValue={false}
133 {...formatConfig}
134 />
135 </div>
136 </div>
137 )}
138 </div>
139 </FieldRow>
140 {validationError && (
141 <FieldRow>
142 <div className="give-donor-dashboard-amount-inputs__validation-error-message">
143 {validationError}
144 </div>
145 </FieldRow>
146 )}
147 </div>
148 );
149 };
150
151 export default AmountControl;
152