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"];