diff --git a/src/DonationForms/resources/app/hooks/useDonationSummary.ts b/src/DonationForms/resources/app/hooks/useDonationSummary.ts
index 6770683263..bd14bdc6f4 100644
--- a/src/DonationForms/resources/app/hooks/useDonationSummary.ts
+++ b/src/DonationForms/resources/app/hooks/useDonationSummary.ts
@@ -1,21 +1,26 @@
import {
DonationSummaryLineItem,
useDonationSummaryContext,
- useDonationSummaryDispatch,
+ useDonationSummaryDispatch
} from '@givewp/forms/app/store/donation-summary';
import {
addAmountToTotal,
addItem,
removeAmountFromTotal,
- removeItem,
+ removeItem
} from '@givewp/forms/app/store/donation-summary/reducer';
import {useCallback} from '@wordpress/element';
/**
+ * The donation summary hook is used to interact with the donation summary context which wraps around our donation form.
+ * It provides methods to add and remove items from the summary, as well as to add and remove amounts from the total.
+ * It also provides the current items and totals from the context, making it easier to access form values specific to donations.
+ *
+ * @unreleased added getTotalSum
* @since 3.0.0
*/
export default function useDonationSummary() {
- const {items, totals} = useDonationSummaryContext();
+ const { items, totals } = useDonationSummaryContext();
const dispatch = useDonationSummaryDispatch();
return {
@@ -28,5 +33,14 @@ export default function useDonationSummary() {
[dispatch]
),
removeFromTotal: useCallback((itemId: string) => dispatch(removeAmountFromTotal(itemId)), [dispatch]),
+ getTotalSum: useCallback((amount: number) =>
+ Number(
+ Object.values({
+ ...totals,
+ amount
+ }).reduce((total: number, amount: number) => {
+ return total + amount;
+ }, 0)
+ ), [totals])
};
}
diff --git a/src/DonationForms/resources/app/hooks/useFormData.ts b/src/DonationForms/resources/app/hooks/useFormData.ts
new file mode 100644
index 0000000000..18e67687ff
--- /dev/null
+++ b/src/DonationForms/resources/app/hooks/useFormData.ts
@@ -0,0 +1,129 @@
+import type {DonationTotals} from '@givewp/forms/app/store/donation-summary';
+import type {
+ subscriptionPeriod
+} from '@givewp/forms/registrars/templates/groups/DonationAmount/subscriptionPeriod';
+import {
+ useDonationSummaryContext,
+} from '@givewp/forms/app/store/donation-summary';
+
+/**
+ * Zero decimal currencies are currencies that do not have a minor unit.
+ * For example, the Japanese Yen (JPY) does not have a minor unit.
+ * @unreleased
+ *
+ * @see https://stripe.com/docs/currencies#zero-decimal
+ */
+const zeroDecimalCurrencies = [
+ 'BIF',
+ 'CLP',
+ 'DJF',
+ 'GNF',
+ 'JPY',
+ 'KMF',
+ 'KRW',
+ 'MGA',
+ 'PYG',
+ 'RWF',
+ 'UGX',
+ 'VND',
+ 'VUV',
+ 'XAF',
+ 'XOF',
+ 'XPF',
+];
+
+/**
+ * Takes in an amount value in dollar units and returns the calculated cents (minor) amount
+ *
+ * @unreleased
+ */
+const amountToMinorUnit = (amount: string, currency: string) => {
+ if (zeroDecimalCurrencies.includes(currency)) {
+ return Math.round(parseFloat(amount));
+ }
+
+ return Math.round(parseFloat(amount) * 100);
+};
+
+/**
+ * Donation total calculation
+ *
+ * @unreleased
+ */
+const getDonationTotal = (totals: DonationTotals, amount: number) =>
+ Number(
+ Object.values({
+ ...totals,
+ amount,
+ }).reduce((total: number, amount: number) => {
+ return total + amount;
+ }, 0)
+ );
+
+/**
+ * Subscription total calculation
+ * TODO: figure out which totals will be included in subscriptions
+ *
+ * @unreleased
+ */
+const getSubscriptionTotal = (totals: DonationTotals, amount: number) => {
+ let total = 0;
+
+ // Subscriptions currently only support donation amount (TODO: and potentially feeRecovery values)
+ const allowedKeys = ['feeRecovery'];
+
+ for (const [key, value] of Object.entries(totals)) {
+ if (allowedKeys.includes(key)) {
+ total += value;
+ }
+ }
+
+ return Number(total + amount);
+}
+/**
+ * @unreleased
+ */
+export default function useFormData() {
+ const { totals } = useDonationSummaryContext();
+ const { useWatch } = window.givewp.form.hooks;
+
+ const firstName = useWatch({ name: 'firstName' }) as string;
+ const lastName = useWatch({ name: 'lastName' }) as string | undefined;
+ const email = useWatch({ name: 'email' }) as string;
+ const billingAddress = {
+ addressLine1: useWatch({name: 'address1'}) as string | undefined,
+ addressLine2: useWatch({name: 'address2'}) as string | undefined,
+ city: useWatch({name: 'city'}) as string | undefined,
+ state: useWatch({name: 'state'}) as string | undefined,
+ postalCode: useWatch({name: 'zip'}) as string | undefined,
+ country: useWatch({name: 'country'}) as string | undefined,
+ }
+ const amount = useWatch({ name: 'amount' }) as string;
+ const currency = useWatch({ name: 'currency' }) as string;
+ const subscriptionPeriod = useWatch({name: 'subscriptionPeriod'}) as subscriptionPeriod | undefined;
+ const subscriptionFrequency = useWatch({name: 'subscriptionFrequency'}) as number | undefined;
+ const subscriptionInstallments = useWatch({name: 'subscriptionInstallments'});
+ const donationType = useWatch({name: 'donationType'}) as "single" | "subscription" | undefined;
+
+ const donationAmountTotal = getDonationTotal(totals, Number(amount));
+ const subscriptionAmount = getSubscriptionTotal(totals, Number(amount))
+
+ return {
+ firstName,
+ lastName,
+ email,
+ billingAddress,
+ currency,
+ donationAmount: Number(amount),
+ donationAmountMinor: amountToMinorUnit(amount, currency),
+ donationAmountTotal,
+ donationAmountTotalMinor: amountToMinorUnit(donationAmountTotal.toString(), currency),
+ subscriptionAmount,
+ subscriptionAmountMinor: amountToMinorUnit(subscriptionAmount.toString(), currency),
+ donationIsOneTime: donationType === 'single',
+ donationIsRecurring: donationType === 'subscription',
+ subscriptionPeriod,
+ subscriptionFrequency,
+ subscriptionInstallments,
+ };
+}
diff --git a/src/DonationForms/resources/registrars/index.ts b/src/DonationForms/resources/registrars/index.ts
index 149d647e9d..80de7003f7 100644
--- a/src/DonationForms/resources/registrars/index.ts
+++ b/src/DonationForms/resources/registrars/index.ts
@@ -5,6 +5,7 @@ import defaultFormTemplates from './templates';
import useCurrencyFormatter from '@givewp/forms/app/hooks/useCurrencyFormatter';
import useDonationSummary from '@givewp/forms/app/hooks/useDonationSummary';
import {useDonationFormSettings} from '@givewp/forms/app/store/form-settings';
+import useFormData from '@givewp/forms/app/hooks/useFormData';
declare global {
interface Window {
@@ -21,6 +22,7 @@ declare global {
useCurrencyFormatter: typeof useCurrencyFormatter;
useDonationSummary: typeof useDonationSummary;
useDonationFormSettings: typeof useDonationFormSettings;
+ useFormData: typeof useFormData;
};
};
};
diff --git a/src/DonationForms/resources/registrars/templates/elements/DonationSummary.tsx b/src/DonationForms/resources/registrars/templates/elements/DonationSummary.tsx
index 85a0ea3d32..857d693ec4 100644
--- a/src/DonationForms/resources/registrars/templates/elements/DonationSummary.tsx
+++ b/src/DonationForms/resources/registrars/templates/elements/DonationSummary.tsx
@@ -3,32 +3,23 @@ import {__} from '@wordpress/i18n';
import {isSubscriptionPeriod, SubscriptionPeriod} from '../groups/DonationAmount/subscriptionPeriod';
import {createInterpolateElement} from '@wordpress/element';
-/**
- * @since 3.0.0
- */
-const getDonationTotal = (totals: any, amount: any) =>
- Number(
- Object.values({
- ...totals,
- amount: Number(amount),
- }).reduce((total: number, amount: number) => {
- return total + amount;
- }, 0)
- );
-
/**
* @since 3.0.0
*/
export default function DonationSummary() {
const DonationSummaryItemsTemplate = window.givewp.form.templates.layouts.donationSummaryItems;
- const {useWatch, useCurrencyFormatter, useDonationSummary} = window.givewp.form.hooks;
- const {items, totals} = useDonationSummary();
- const currency = useWatch({name: 'currency'});
- const formatter = useCurrencyFormatter(currency);
+ const { useCurrencyFormatter, useDonationSummary } = window.givewp.form.hooks;
+ const { items, getTotalSum } = useDonationSummary();
+ const {
+ currency,
+ donationAmount,
+ subscriptionPeriod: period,
+ subscriptionFrequency: frequency
+ } = window.givewp.form.hooks.useFormData();
- const amount = useWatch({name: 'amount'});
- const period = useWatch({name: 'subscriptionPeriod'});
- const frequency = useWatch({name: 'subscriptionFrequency'});
+ const donationAmountTotal = getTotalSum(donationAmount);
+
+ const formatter = useCurrencyFormatter(currency);
const givingFrequency = useMemo(() => {
if (isSubscriptionPeriod(period)) {
@@ -36,7 +27,7 @@ export default function DonationSummary() {
if (frequency > 1) {
return createInterpolateElement(__('Every