PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.2.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.2.0
2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 All 65 releases
← All changes | src/index.js +108 -107 1.11.0 → 2.2.0 View file →
@@ -1,5 +1,10 @@
1 -import { ExperimentalOrderMeta, registerCheckoutFilters, TotalsItem } from "@woocommerce/blocks-checkout";
1 +import {
2 + ExperimentalOrderMeta,
3 + registerCheckoutFilters,
4 + TotalsItem,
5 + TotalsWrapper,
6 +} from "@woocommerce/blocks-checkout";
2 7 import { FormattedMonetaryAmount } from "@woocommerce/blocks-components";
3 8 import { __, sprintf } from "@wordpress/i18n";
4 9 import { registerPlugin } from "@wordpress/plugins";
5 10
@@ -6,9 +11,8 @@
6 11 import { formatPrice, getCurrencyFromPriceResponse } from "@woocommerce/price-format";
7 12 // import { useStoreCart } from "@woocommerce/base-context/hooks";
8 13
9 14 const modifyCartItemPrice = (defaultValue, extensions, args, validation) => {
10 - const { sdevs_subscription } = extensions;
11 15 const { cartItem } = args;
12 16 const { totals } = cartItem;
13 17
14 18 if (totals === undefined) {
@@ -16,19 +20,10 @@
16 20 }
17 21 if (totals.line_total === "0") {
18 22 return `<price/> ${__("Due Today", "subscription")}`;
19 23 }
20 - if (sdevs_subscription && sdevs_subscription.type) {
21 - // Capitalize the first letter to match product page display
22 - const capitalizedType = sdevs_subscription.type.charAt(0).toUpperCase() + sdevs_subscription.type.slice(1);
23 -
24 - // Check max_no_payment - handle string, number, null, undefined
25 - const maxPayments = parseInt(sdevs_subscription.max_no_payment, 10);
26 - const paymentInfo = !isNaN(maxPayments) && maxPayments > 0 ? ` x ${maxPayments}` : "";
27 - return `<price/> / ${
28 - sdevs_subscription.time && sdevs_subscription.time > 1 ? " " + sdevs_subscription.time + "-" : ""
29 - }${capitalizedType}${paymentInfo}`;
30 - }
24 + // The per-unit price shows no cadence — the recurring cadence appears on the
25 + // line total (subtotalPriceFormat) and the "Recurring totals" summary.
31 26 return defaultValue;
32 27 };
33 28
34 29 const modifySubtotalPriceFormat = (defaultValue, extensions, args, validation) => {
@@ -70,112 +65,118 @@
70 65 const currency = getCurrencyFromPriceResponse(cartTotals);
71 66 const multiplier = Math.pow(10, currency.minorUnit);
72 67
73 68 return (
74 - <TotalsItem
75 - className="wc-block-components-totals-footer-item"
76 - label={__("Recurring totals", "subscription")}
77 - description={
78 - <div style={{ display: "grid" }}>
79 - {recurrings.map((recurring) => {
80 - // Capitalize the first letter to match product page display
81 - const capitalizedType = recurring.type.charAt(0).toUpperCase() + recurring.type.slice(1);
69 + <TotalsWrapper>
70 + <TotalsItem
71 + className="wc-block-components-totals-footer-item"
72 + label={__("Recurring totals", "subscription")}
73 + description={
74 + <div style={{ display: "grid" }}>
75 + {recurrings.map((recurring) => {
76 + // Capitalize the first letter to match product page display
77 + const capitalizedType = recurring.type.charAt(0).toUpperCase() + recurring.type.slice(1);
82 78
83 - const priceFormatArgs = {
84 - currency: currency.code,
85 - currency_symbol: currency.symbol,
86 - decimal_separator: currency.decimalSeparator,
87 - thousand_separator: currency.thousandSeparator,
88 - precision: currency.minorUnit,
89 - price_format: currency.priceFormat,
90 - };
79 + const priceFormatArgs = {
80 + currency: currency.code,
81 + currency_symbol: currency.symbol,
82 + decimal_separator: currency.decimalSeparator,
83 + thousand_separator: currency.thousandSeparator,
84 + precision: currency.minorUnit,
85 + price_format: currency.priceFormat,
86 + };
91 87
92 - /**
93 - * Format an amount the same way the surrounding totals are formatted.
94 - *
95 - * @param {number} amount Amount in major units.
96 - * @return {string} Formatted price.
97 - */
98 - const format = (amount) => formatPrice(Math.round(amount * multiplier), priceFormatArgs);
88 + /**
89 + * Format an amount the same way the surrounding totals are formatted.
90 + *
91 + * @param {number} amount Amount in major units.
92 + * @return {string} Formatted price.
93 + */
94 + const format = (amount) => formatPrice(Math.round(amount * multiplier), priceFormatArgs);
99 95
100 - const recurringLimit = parseInt(recurring.recurring_limit, 10) || 0;
96 + const recurringLimit = parseInt(recurring.recurring_limit, 10) || 0;
101 97
102 - // Billing period as plain text, so notes can quote a price the same way the row does.
103 - const periodLabel =
104 - recurring.time && recurring.time > 1 ? `${recurring.time}-${capitalizedType}` : capitalizedType;
98 + // Billing period as plain text, so notes can quote a price the same way the row does.
99 + const periodLabel =
100 + recurring.time && recurring.time > 1 ? `${recurring.time}-${capitalizedType}` : capitalizedType;
105 101
106 - return (
107 - <div style={{ margin: "20px 0", float: "right" }}>
108 - <div style={{ fontSize: "18px" }}>
109 - {recurring.has_recurring_discount && (
110 - <del aria-hidden="true" style={{ marginRight: "6px", opacity: 0.6 }}>
111 - {format(recurring.full_price)}
112 - </del>
102 + return (
103 + <div style={{ margin: "8px 0px 0px", float: "right" }}>
104 + <div style={{ fontSize: "18px" }}>
105 + {recurring.has_recurring_discount && (
106 + <del aria-hidden="true" style={{ marginRight: "6px", opacity: 0.6 }}>
107 + {format(recurring.full_price)}
108 + </del>
109 + )}
110 + <FormattedMonetaryAmount currency={currency} value={Math.round(recurring.price * multiplier)} />
111 + <span class="wpsubs-subscription-timing">
112 + &nbsp;/&nbsp;
113 + {recurring.time && recurring.time > 1
114 + ? `${recurring.time + "-" + capitalizedType} `
115 + : capitalizedType}
116 + </span>
117 + </div>
118 + <small>{recurring.description}</small>
119 + {recurring.has_one_time_discount && (
120 + <>
121 + <br />
122 + <small>
123 + {sprintf(
124 + // translators: 1: amount paid today, 2: amount charged on each renewal.
125 + __("You pay %1$s today. %2$s will be charged from the next renewal.", "subscription"),
126 + format(recurring.first_price),
127 + format(recurring.price),
128 + )}
129 + </small>
130 + </>
113 131 )}
114 - <FormattedMonetaryAmount currency={currency} value={Math.round(recurring.price * multiplier)} />
115 - <span class="wpsubs-subscription-timing">
116 - &nbsp;/&nbsp;
117 - {recurring.time && recurring.time > 1
118 - ? `${recurring.time + "-" + capitalizedType} `
119 - : capitalizedType}
120 - </span>
121 - </div>
122 - <small>{recurring.description}</small>
123 - {recurring.has_one_time_discount && (
124 - <>
125 - <br />
126 - <small>
127 - {sprintf(
128 - // translators: 1: amount paid today, 2: amount charged on each renewal.
129 - __("You pay %1$s today. %2$s will be charged from the next renewal.", "subscription"),
130 - format(recurring.first_price),
131 - format(recurring.price),
132 - )}
133 - </small>
134 - </>
135 - )}
136 - {recurring.has_recurring_discount && recurringLimit > 1 && (
137 - <>
138 - <br />
139 - <small>
140 - {sprintf(
141 - // translators: 1: number of discounted payments, 2: full price charged afterwards.
142 - __("Discount applies to your first %1$s payments. After that, %2$s.", "subscription"),
143 - recurringLimit,
144 - `${format(recurring.full_price)} / ${periodLabel}`,
145 - )}
146 - </small>
147 - </>
148 - )}
149 - {recurring.can_user_cancel === "yes" &&
150 - (recurring.max_no_payment === "" || parseInt(recurring.max_no_payment) === 0) && (
132 + {recurring.has_recurring_discount && recurringLimit > 1 && (
151 133 <>
152 134 <br />
153 - <small>{__("You can cancel subscription at any time!", "subscription")} </small>
135 + <small>
136 + {sprintf(
137 + // translators: 1: number of discounted payments, 2: full price charged afterwards.
138 + __("Discount applies to your first %1$s payments. After that, %2$s.", "subscription"),
139 + recurringLimit,
140 + `${format(recurring.full_price)} / ${periodLabel}`,
141 + )}
142 + </small>
154 143 </>
155 144 )}
156 - {parseInt(recurring.max_no_payment) > 0 && (
157 - <>
158 - <br />
159 - <small>
160 - {sprintf(
161 - // translators: 1: number of installments, 2: total amount.
162 - __(
163 - "This subscription will be billed in %1$s installments, for a total of %2$s.",
164 - "subscription",
165 - ),
166 - recurring.max_no_payment,
167 - format(recurring.price * parseInt(recurring.max_no_payment)),
168 - )}
169 - </small>
170 - </>
171 - )}
172 - </div>
173 - );
174 - })}
175 - </div>
176 - }
177 - ></TotalsItem>
145 + {recurring.can_user_cancel === "yes" &&
146 + (recurring.max_no_payment === "" || parseInt(recurring.max_no_payment) === 0) && (
147 + <>
148 + <br />
149 + <small>{__("You can cancel subscription at any time!", "subscription")} </small>
150 + </>
151 + )}
152 + {parseInt(recurring.max_no_payment) > 0 && (
153 + <>
154 + <br />
155 + <small>
156 + {sprintf(
157 + // translators: 1: number of installments, 2: total amount.
158 + __(
159 + "This subscription will be billed in %1$s installments, for a total of %2$s.",
160 + "subscription",
161 + ),
162 + recurring.max_no_payment,
163 + format(
164 + recurring.split_total != null
165 + ? recurring.split_total
166 + : recurring.price * parseInt(recurring.max_no_payment),
167 + ),
168 + )}
169 + </small>
170 + </>
171 + )}
172 + </div>
173 + );
174 + })}
175 + </div>
176 + }
177 + ></TotalsItem>
178 + </TotalsWrapper>
178 179 );
179 180 };
180 181
181 182 const render = () => {