diff --git a/src/Common/Types/index.tsx b/src/Common/Types/index.tsx index b5d55992..18a9ce45 100644 --- a/src/Common/Types/index.tsx +++ b/src/Common/Types/index.tsx @@ -227,6 +227,7 @@ export interface Gateways { paypal: Paypal; stripe: Stripe; offline?: Offline; + "planet-cash"?: PlanetCashGateway; } export interface Paypal { methods?: string[] | null; @@ -254,6 +255,13 @@ export interface Offline { account: string; } +export interface PlanetCashGateway { + account: string; + balance: number; + creditLimit: number; + available: number; +} + export interface OptionsEntity { id?: string; caption: string | null; diff --git a/src/Donations/Components/DonationsForm.tsx b/src/Donations/Components/DonationsForm.tsx index e43d4ce9..188ade15 100644 --- a/src/Donations/Components/DonationsForm.tsx +++ b/src/Donations/Components/DonationsForm.tsx @@ -35,6 +35,7 @@ import { import { PaymentMethod } from "@stripe/stripe-js/types/api/payment-methods"; import { PaymentRequest } from "@stripe/stripe-js/types/stripe-js/payment-request"; import { NON_GIFTABLE_PROJECT_PURPOSES } from "src/Utils/projects/constants"; +import { isPlanetCashAllowed } from "src/Utils/donationOptions"; function DonationsForm(): ReactElement { const { @@ -117,19 +118,14 @@ function DonationsForm(): ReactElement { const [isPaymentProcessing, setIsPaymentProcessing] = React.useState(false); const [paymentError, setPaymentError] = React.useState(""); //TODOO - confirm and remove - const canPayWithPlanetCash = - projectDetails !== null && - projectDetails.purpose !== "funds" && - projectDetails.purpose !== "planet-cash" && - paymentSetup?.unitType === "tree" && //Enables planetcash for restoration projects with unitType tree only (TEMP) - profile !== null && - isSignedUp && - profile.planetCash !== null && - projectDetails.taxDeductionCountries?.includes( - profile.planetCash.country - ) && - !(isGift && giftDetails.recipientName === "") && - !(onBehalf && onBehalfDonor.firstName === ""); + const canPayWithPlanetCash = isPlanetCashAllowed({ + profile, + isSignedUp, + projectDetails, + isGift, + giftDetails, + hasPlanetCashGateway: paymentSetup?.gateways["planet-cash"] !== undefined, + }); const canSendDirectGift = projectDetails !== null && @@ -298,11 +294,6 @@ function DonationsForm(): ReactElement { const handlePlanetCashDonate = async () => { if (projectDetails) { setShowDisablePlanetCashButton(true); - const _onBehalfDonor = { - firstname: onBehalfDonor.firstName, - lastname: onBehalfDonor.lastName, - email: onBehalfDonor.email, - }; const _metadata = { utm_campaign: utmCampaign, @@ -385,7 +376,6 @@ function DonationsForm(): ReactElement { {projectDetails.purpose !== "funds" && (

{t("donate")}

)} - {/* show PlanetCashSelector only if user is signed up and have a planetCash account */} {canPayWithPlanetCash && } {(canSendDirectGift && hasDirectGift) || canSendInvitationGift ? (
diff --git a/src/Layout/QueryParamContext.tsx b/src/Layout/QueryParamContext.tsx index a980387b..f15b3c6d 100644 --- a/src/Layout/QueryParamContext.tsx +++ b/src/Layout/QueryParamContext.tsx @@ -41,6 +41,7 @@ import ErrorPopup from "src/Common/ErrorPopup/ErrorPopup"; import { APIError, handleError, SerializedError } from "@planet-sdk/common"; import { PaymentRequest } from "@stripe/stripe-js/types/stripe-js/payment-request"; import { createProjectDetails } from "src/Utils/createProjectDetails"; +import { useDebouncedEffect } from "src/Utils/useDebouncedEffect"; export const QueryParamContext = createContext(null); @@ -346,23 +347,27 @@ const QueryParamProvider: FC = ({ children }) => { router.query.token, ]); - useEffect(() => { - const regex = /^pcash_/; - if ( - router.query.to && - !regex.test(router.query.to as string) && - country !== undefined && - country !== "" && - router.query.to?.toString().toLowerCase() !== "planetcash" - ) { - const to = String(router.query.to).replace(/\//g, ""); - loadPaymentSetup({ - projectGUID: to, - paymentSetupCountry: country, - shouldSetPaymentDetails: true, - }); - } - }, [router.query.to, country]); + useDebouncedEffect( + () => { + const regex = /^pcash_/; + if ( + router.query.to && + !regex.test(router.query.to as string) && + country !== undefined && + country !== "" && + router.query.to?.toString().toLowerCase() !== "planetcash" + ) { + const to = String(router.query.to).replace(/\//g, ""); + loadPaymentSetup({ + projectGUID: to, + paymentSetupCountry: country, + shouldSetPaymentDetails: true, + }); + } + }, + 1000, + [router.query.to, country, profile?.slug] + ); async function loadConfig() { try { @@ -488,11 +493,19 @@ const QueryParamProvider: FC = ({ children }) => { paymentSetupCountry: string; shouldSetPaymentDetails?: boolean; }) => { + const token = + profile === null + ? null + : queryToken || + (router.query.token as string) || + (await getAccessTokenSilently()); + setIsPaymentOptionsLoading(true); try { const requestParams = { url: `/app/paymentOptions/${projectGUID}?country=${paymentSetupCountry}`, setshowErrorCard, + token, tenant, locale: i18n.language, }; diff --git a/src/Utils/donationOptions.ts b/src/Utils/donationOptions.ts new file mode 100644 index 00000000..3badad02 --- /dev/null +++ b/src/Utils/donationOptions.ts @@ -0,0 +1,43 @@ +import { NoGift, User } from "@planet-sdk/common"; +import { + PLANETCASH_ALLOWED_PROJECT_PURPOSES, + PLANETCASH_DISALLOWED_PROJECT_CLASSIFICATIONS, +} from "./projects/constants"; +import { FetchedProjectDetails, GiftDetails } from "src/Common/Types"; + +interface PlanetCashAllowedParams { + profile: User | null; + isSignedUp: boolean; + projectDetails: FetchedProjectDetails | null; + isGift: boolean; + giftDetails: GiftDetails | NoGift; + hasPlanetCashGateway: boolean; +} + +/** + * Determines if Planet Cash is allowed for the current donation + */ +export const isPlanetCashAllowed = ({ + profile, + isSignedUp, + projectDetails, + isGift, + giftDetails, + hasPlanetCashGateway, +}: PlanetCashAllowedParams): boolean => { + return ( + profile !== null && + isSignedUp && + profile.planetCash !== null && + hasPlanetCashGateway && + projectDetails !== null && + PLANETCASH_ALLOWED_PROJECT_PURPOSES.includes(projectDetails.purpose) && + (projectDetails.classification === null || + !PLANETCASH_DISALLOWED_PROJECT_CLASSIFICATIONS.includes( + projectDetails.classification + )) && + projectDetails.taxDeductionCountries !== undefined && + projectDetails.taxDeductionCountries.includes(profile.planetCash.country) && + !(isGift && giftDetails.recipientName === "") + ); +}; diff --git a/src/Utils/projects/constants.ts b/src/Utils/projects/constants.ts index b42d0006..8e8ed20f 100644 --- a/src/Utils/projects/constants.ts +++ b/src/Utils/projects/constants.ts @@ -1 +1,17 @@ -export const NON_GIFTABLE_PROJECT_PURPOSES = ["planet-cash", "bouquet"]; +import { ProjectPurpose, TreeProjectClassification } from "@planet-sdk/common"; +import { FundsProjectClassification } from "src/Common/Types"; + +export const NON_GIFTABLE_PROJECT_PURPOSES: Array = [ + "planet-cash", + "bouquet", +]; + +export const PLANETCASH_ALLOWED_PROJECT_PURPOSES: Array = [ + "trees", + "conservation", + "funds", +]; + +export const PLANETCASH_DISALLOWED_PROJECT_CLASSIFICATIONS: Array< + FundsProjectClassification | TreeProjectClassification +> = ["membership", "endowment"];