@blocklet/payment-react 1.23.10 → 1.23.11

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.
@@ -95,42 +95,76 @@ export default function ProductItem({
95
95
  refreshDeps: [isCreditProduct, userDid, creditCurrency?.id]
96
96
  }
97
97
  );
98
- const getInitialQuantity = () => {
98
+ const canAdjustQuantity = adjustableQuantity.enabled && mode === "normal";
99
+ const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
100
+ const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
101
+ const maxQuantity = quantityAvailable ? Math.min(adjustableQuantity.maximum || Infinity, quantityAvailable) : adjustableQuantity.maximum || Infinity;
102
+ const getMinQuantityForPending = useMemo(() => {
103
+ if (!isCreditProduct || !pendingAmount) return null;
104
+ const pendingAmountBN = new BN(pendingAmount || "0");
105
+ if (!pendingAmountBN.gt(new BN(0))) return null;
106
+ const creditAmountBN = fromTokenToUnit(creditAmount, creditCurrency?.decimal || 2);
107
+ return Math.ceil(pendingAmountBN.mul(new BN(100)).div(creditAmountBN).toNumber() / 100);
108
+ }, [isCreditProduct, pendingAmount, creditAmount, creditCurrency?.decimal]);
109
+ const initialQuantity = useMemo(() => {
99
110
  const urlQuantity = getRecommendedQuantityFromUrl(item.price.id);
100
111
  if (urlQuantity && urlQuantity > 0) {
112
+ if (canAdjustQuantity && getMinQuantityForPending) {
113
+ return Math.max(urlQuantity, getMinQuantityForPending, minQuantity);
114
+ }
101
115
  return urlQuantity;
102
116
  }
103
117
  if (userDid) {
104
118
  const preferredQuantity = getUserQuantityPreference(userDid, item.price.id);
105
119
  if (preferredQuantity && preferredQuantity > 0) {
120
+ if (canAdjustQuantity && getMinQuantityForPending) {
121
+ return Math.max(preferredQuantity, getMinQuantityForPending, minQuantity);
122
+ }
106
123
  return preferredQuantity;
107
124
  }
108
125
  }
109
- return item.quantity;
110
- };
111
- const [localQuantity, setLocalQuantity] = useState(getInitialQuantity());
112
- const canAdjustQuantity = adjustableQuantity.enabled && mode === "normal";
113
- const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
114
- const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
115
- const maxQuantity = quantityAvailable ? Math.min(adjustableQuantity.maximum || Infinity, quantityAvailable) : adjustableQuantity.maximum || Infinity;
126
+ let baseQuantity = item.quantity;
127
+ if (canAdjustQuantity && getMinQuantityForPending) {
128
+ baseQuantity = Math.max(baseQuantity, getMinQuantityForPending, minQuantity);
129
+ }
130
+ return baseQuantity;
131
+ }, [item.quantity, item.price.id, userDid, getMinQuantityForPending, canAdjustQuantity, minQuantity]);
132
+ const [localQuantity, setLocalQuantity] = useState(initialQuantity);
116
133
  const localQuantityNum = localQuantity || 0;
117
134
  useEffect(() => {
118
- const initialQuantity = getInitialQuantity();
119
- if (initialQuantity !== item.quantity && initialQuantity && initialQuantity > 1) {
120
- onQuantityChange(item.price_id, initialQuantity);
135
+ if (initialQuantity && initialQuantity > 0) {
136
+ if (initialQuantity !== localQuantity) {
137
+ setLocalQuantity(initialQuantity);
138
+ }
139
+ if (initialQuantity !== item.quantity) {
140
+ onQuantityChange(item.price_id, initialQuantity);
141
+ }
142
+ if (isCreditProduct && pendingAmount && getMinQuantityForPending) {
143
+ setPayable(initialQuantity >= getMinQuantityForPending);
144
+ } else {
145
+ setPayable(true);
146
+ }
121
147
  }
122
- }, []);
148
+ }, [initialQuantity, isCreditProduct, pendingAmount, getMinQuantityForPending]);
123
149
  const handleQuantityChange = (newQuantity) => {
124
150
  if (!newQuantity) {
125
151
  setLocalQuantity(void 0);
126
152
  setPayable(false);
127
153
  return;
128
154
  }
129
- setPayable(true);
130
155
  if (newQuantity >= minQuantity && newQuantity <= maxQuantity) {
131
156
  if (formatQuantityInventory(item.price, newQuantity, locale)) {
132
157
  return;
133
158
  }
159
+ if (isCreditProduct && pendingAmount && getMinQuantityForPending) {
160
+ if (newQuantity < getMinQuantityForPending) {
161
+ setPayable(false);
162
+ setLocalQuantity(newQuantity);
163
+ onQuantityChange(item.price_id, newQuantity);
164
+ return;
165
+ }
166
+ }
167
+ setPayable(true);
134
168
  setLocalQuantity(newQuantity);
135
169
  onQuantityChange(item.price_id, newQuantity);
136
170
  if (userDid && newQuantity > 0) {
@@ -204,7 +238,7 @@ export default function ProductItem({
204
238
  }
205
239
  const pendingAmountBN = new BN(pendingAmount || "0");
206
240
  const creditAmountBN = fromTokenToUnit(creditAmount, creditCurrency?.decimal || 2);
207
- const minQuantityNeeded = Math.ceil(pendingAmountBN.mul(new BN(100)).div(creditAmountBN).toNumber() / 100);
241
+ const minQuantityNeeded = getMinQuantityForPending || 0;
208
242
  const currentPurchaseCreditBN = creditAmountBN.mul(new BN(localQuantity || 0));
209
243
  const actualAvailable = currentPurchaseCreditBN.sub(pendingAmountBN).toString();
210
244
  if (!new BN(actualAvailable).gt(new BN(0))) {
@@ -103,42 +103,76 @@ function ProductItem({
103
103
  }, {
104
104
  refreshDeps: [isCreditProduct, userDid, creditCurrency?.id]
105
105
  });
106
- const getInitialQuantity = () => {
106
+ const canAdjustQuantity = adjustableQuantity.enabled && mode === "normal";
107
+ const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
108
+ const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
109
+ const maxQuantity = quantityAvailable ? Math.min(adjustableQuantity.maximum || Infinity, quantityAvailable) : adjustableQuantity.maximum || Infinity;
110
+ const getMinQuantityForPending = (0, _react.useMemo)(() => {
111
+ if (!isCreditProduct || !pendingAmount) return null;
112
+ const pendingAmountBN = new _util.BN(pendingAmount || "0");
113
+ if (!pendingAmountBN.gt(new _util.BN(0))) return null;
114
+ const creditAmountBN = (0, _util.fromTokenToUnit)(creditAmount, creditCurrency?.decimal || 2);
115
+ return Math.ceil(pendingAmountBN.mul(new _util.BN(100)).div(creditAmountBN).toNumber() / 100);
116
+ }, [isCreditProduct, pendingAmount, creditAmount, creditCurrency?.decimal]);
117
+ const initialQuantity = (0, _react.useMemo)(() => {
107
118
  const urlQuantity = getRecommendedQuantityFromUrl(item.price.id);
108
119
  if (urlQuantity && urlQuantity > 0) {
120
+ if (canAdjustQuantity && getMinQuantityForPending) {
121
+ return Math.max(urlQuantity, getMinQuantityForPending, minQuantity);
122
+ }
109
123
  return urlQuantity;
110
124
  }
111
125
  if (userDid) {
112
126
  const preferredQuantity = getUserQuantityPreference(userDid, item.price.id);
113
127
  if (preferredQuantity && preferredQuantity > 0) {
128
+ if (canAdjustQuantity && getMinQuantityForPending) {
129
+ return Math.max(preferredQuantity, getMinQuantityForPending, minQuantity);
130
+ }
114
131
  return preferredQuantity;
115
132
  }
116
133
  }
117
- return item.quantity;
118
- };
119
- const [localQuantity, setLocalQuantity] = (0, _react.useState)(getInitialQuantity());
120
- const canAdjustQuantity = adjustableQuantity.enabled && mode === "normal";
121
- const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
122
- const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
123
- const maxQuantity = quantityAvailable ? Math.min(adjustableQuantity.maximum || Infinity, quantityAvailable) : adjustableQuantity.maximum || Infinity;
134
+ let baseQuantity = item.quantity;
135
+ if (canAdjustQuantity && getMinQuantityForPending) {
136
+ baseQuantity = Math.max(baseQuantity, getMinQuantityForPending, minQuantity);
137
+ }
138
+ return baseQuantity;
139
+ }, [item.quantity, item.price.id, userDid, getMinQuantityForPending, canAdjustQuantity, minQuantity]);
140
+ const [localQuantity, setLocalQuantity] = (0, _react.useState)(initialQuantity);
124
141
  const localQuantityNum = localQuantity || 0;
125
142
  (0, _react.useEffect)(() => {
126
- const initialQuantity = getInitialQuantity();
127
- if (initialQuantity !== item.quantity && initialQuantity && initialQuantity > 1) {
128
- onQuantityChange(item.price_id, initialQuantity);
143
+ if (initialQuantity && initialQuantity > 0) {
144
+ if (initialQuantity !== localQuantity) {
145
+ setLocalQuantity(initialQuantity);
146
+ }
147
+ if (initialQuantity !== item.quantity) {
148
+ onQuantityChange(item.price_id, initialQuantity);
149
+ }
150
+ if (isCreditProduct && pendingAmount && getMinQuantityForPending) {
151
+ setPayable(initialQuantity >= getMinQuantityForPending);
152
+ } else {
153
+ setPayable(true);
154
+ }
129
155
  }
130
- }, []);
156
+ }, [initialQuantity, isCreditProduct, pendingAmount, getMinQuantityForPending]);
131
157
  const handleQuantityChange = newQuantity => {
132
158
  if (!newQuantity) {
133
159
  setLocalQuantity(void 0);
134
160
  setPayable(false);
135
161
  return;
136
162
  }
137
- setPayable(true);
138
163
  if (newQuantity >= minQuantity && newQuantity <= maxQuantity) {
139
164
  if ((0, _util2.formatQuantityInventory)(item.price, newQuantity, locale)) {
140
165
  return;
141
166
  }
167
+ if (isCreditProduct && pendingAmount && getMinQuantityForPending) {
168
+ if (newQuantity < getMinQuantityForPending) {
169
+ setPayable(false);
170
+ setLocalQuantity(newQuantity);
171
+ onQuantityChange(item.price_id, newQuantity);
172
+ return;
173
+ }
174
+ }
175
+ setPayable(true);
142
176
  setLocalQuantity(newQuantity);
143
177
  onQuantityChange(item.price_id, newQuantity);
144
178
  if (userDid && newQuantity > 0) {
@@ -204,7 +238,7 @@ function ProductItem({
204
238
  }
205
239
  const pendingAmountBN = new _util.BN(pendingAmount || "0");
206
240
  const creditAmountBN = (0, _util.fromTokenToUnit)(creditAmount, creditCurrency?.decimal || 2);
207
- const minQuantityNeeded = Math.ceil(pendingAmountBN.mul(new _util.BN(100)).div(creditAmountBN).toNumber() / 100);
241
+ const minQuantityNeeded = getMinQuantityForPending || 0;
208
242
  const currentPurchaseCreditBN = creditAmountBN.mul(new _util.BN(localQuantity || 0));
209
243
  const actualAvailable = currentPurchaseCreditBN.sub(pendingAmountBN).toString();
210
244
  if (!new _util.BN(actualAvailable).gt(new _util.BN(0))) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.23.10",
3
+ "version": "1.23.11",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -96,7 +96,7 @@
96
96
  "@babel/core": "^7.27.4",
97
97
  "@babel/preset-env": "^7.27.2",
98
98
  "@babel/preset-react": "^7.27.1",
99
- "@blocklet/payment-types": "1.23.10",
99
+ "@blocklet/payment-types": "1.23.11",
100
100
  "@storybook/addon-essentials": "^7.6.20",
101
101
  "@storybook/addon-interactions": "^7.6.20",
102
102
  "@storybook/addon-links": "^7.6.20",
@@ -127,5 +127,5 @@
127
127
  "vite-plugin-babel": "^1.3.1",
128
128
  "vite-plugin-node-polyfills": "^0.23.0"
129
129
  },
130
- "gitHead": "9d058650e81ae43ffafb3e1253b50b6245d510ac"
130
+ "gitHead": "72af80fc6e91e88058665212985002966f55787c"
131
131
  }
@@ -127,40 +127,69 @@ export default function ProductItem({
127
127
  }
128
128
  );
129
129
 
130
- // calculate initial quantity: priority URL recommendation > user preference > item.quantity
131
- const getInitialQuantity = (): number | undefined => {
130
+ const canAdjustQuantity = adjustableQuantity.enabled && mode === 'normal';
131
+ const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
132
+ const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
133
+ const maxQuantity = quantityAvailable
134
+ ? Math.min(adjustableQuantity.maximum || Infinity, quantityAvailable)
135
+ : adjustableQuantity.maximum || Infinity;
136
+
137
+ const getMinQuantityForPending = useMemo(() => {
138
+ if (!isCreditProduct || !pendingAmount) return null;
139
+ const pendingAmountBN = new BN(pendingAmount || '0');
140
+ if (!pendingAmountBN.gt(new BN(0))) return null;
141
+ const creditAmountBN = fromTokenToUnit(creditAmount, creditCurrency?.decimal || 2);
142
+ return Math.ceil(pendingAmountBN.mul(new BN(100)).div(creditAmountBN).toNumber() / 100);
143
+ }, [isCreditProduct, pendingAmount, creditAmount, creditCurrency?.decimal]);
144
+
145
+ const initialQuantity = useMemo(() => {
132
146
  const urlQuantity = getRecommendedQuantityFromUrl(item.price.id);
133
147
  if (urlQuantity && urlQuantity > 0) {
148
+ if (canAdjustQuantity && getMinQuantityForPending) {
149
+ return Math.max(urlQuantity, getMinQuantityForPending, minQuantity);
150
+ }
134
151
  return urlQuantity;
135
152
  }
136
153
 
137
154
  if (userDid) {
138
155
  const preferredQuantity = getUserQuantityPreference(userDid, item.price.id);
139
156
  if (preferredQuantity && preferredQuantity > 0) {
157
+ if (canAdjustQuantity && getMinQuantityForPending) {
158
+ return Math.max(preferredQuantity, getMinQuantityForPending, minQuantity);
159
+ }
140
160
  return preferredQuantity;
141
161
  }
142
162
  }
143
163
 
144
- return item.quantity;
145
- };
164
+ let baseQuantity = item.quantity;
146
165
 
147
- const [localQuantity, setLocalQuantity] = useState<number | undefined>(getInitialQuantity());
148
- const canAdjustQuantity = adjustableQuantity.enabled && mode === 'normal';
149
- const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
150
- const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
151
- const maxQuantity = quantityAvailable
152
- ? Math.min(adjustableQuantity.maximum || Infinity, quantityAvailable)
153
- : adjustableQuantity.maximum || Infinity;
166
+ if (canAdjustQuantity && getMinQuantityForPending) {
167
+ baseQuantity = Math.max(baseQuantity, getMinQuantityForPending, minQuantity);
168
+ }
169
+
170
+ return baseQuantity;
171
+ }, [item.quantity, item.price.id, userDid, getMinQuantityForPending, canAdjustQuantity, minQuantity]);
172
+
173
+ const [localQuantity, setLocalQuantity] = useState<number | undefined>(initialQuantity);
154
174
  const localQuantityNum = localQuantity || 0;
155
175
 
156
176
  useEffect(() => {
157
- const initialQuantity = getInitialQuantity();
158
- if (initialQuantity !== item.quantity && initialQuantity && initialQuantity > 1) {
159
- // need update checkout session
160
- onQuantityChange(item.price_id, initialQuantity);
177
+ if (initialQuantity && initialQuantity > 0) {
178
+ if (initialQuantity !== localQuantity) {
179
+ setLocalQuantity(initialQuantity);
180
+ }
181
+ if (initialQuantity !== item.quantity) {
182
+ onQuantityChange(item.price_id, initialQuantity);
183
+ }
184
+
185
+ if (isCreditProduct && pendingAmount && getMinQuantityForPending) {
186
+ setPayable(initialQuantity >= getMinQuantityForPending);
187
+ } else {
188
+ setPayable(true);
189
+ }
161
190
  }
162
191
  // eslint-disable-next-line react-hooks/exhaustive-deps
163
- }, []);
192
+ }, [initialQuantity, isCreditProduct, pendingAmount, getMinQuantityForPending]);
164
193
 
165
194
  const handleQuantityChange = (newQuantity: number) => {
166
195
  if (!newQuantity) {
@@ -168,11 +197,22 @@ export default function ProductItem({
168
197
  setPayable(false);
169
198
  return;
170
199
  }
171
- setPayable(true);
200
+
172
201
  if (newQuantity >= minQuantity && newQuantity <= maxQuantity) {
173
202
  if (formatQuantityInventory(item.price, newQuantity, locale)) {
174
203
  return;
175
204
  }
205
+
206
+ if (isCreditProduct && pendingAmount && getMinQuantityForPending) {
207
+ if (newQuantity < getMinQuantityForPending) {
208
+ setPayable(false);
209
+ setLocalQuantity(newQuantity);
210
+ onQuantityChange(item.price_id, newQuantity);
211
+ return;
212
+ }
213
+ }
214
+
215
+ setPayable(true);
176
216
  setLocalQuantity(newQuantity);
177
217
  onQuantityChange(item.price_id, newQuantity);
178
218
 
@@ -259,7 +299,7 @@ export default function ProductItem({
259
299
 
260
300
  const pendingAmountBN = new BN(pendingAmount || '0');
261
301
  const creditAmountBN = fromTokenToUnit(creditAmount, creditCurrency?.decimal || 2);
262
- const minQuantityNeeded = Math.ceil(pendingAmountBN.mul(new BN(100)).div(creditAmountBN).toNumber() / 100);
302
+ const minQuantityNeeded = getMinQuantityForPending || 0;
263
303
  const currentPurchaseCreditBN = creditAmountBN.mul(new BN(localQuantity || 0));
264
304
  const actualAvailable = currentPurchaseCreditBN.sub(pendingAmountBN).toString();
265
305