diff --git a/apps/mobile/app/components/premium/component.js b/apps/mobile/app/components/premium/component.js index 122a32666..45495cbbd 100644 --- a/apps/mobile/app/components/premium/component.js +++ b/apps/mobile/app/components/premium/component.js @@ -165,7 +165,12 @@ export const Component = ({ close, promo }) => { }} size={SIZE.md} > - ({pricing?.product?.localizedPrice} / mo) + ( + {Platform.OS === "android" + ? pricing.product?.subscriptionOfferDetails[0].pricingPhases + .pricingPhaseList?.[0].formattedPrice + : pricing.product?.localizedPrice}{" "} + / mo) )} diff --git a/apps/mobile/app/components/premium/pricing-item.js b/apps/mobile/app/components/premium/pricing-item.tsx similarity index 73% rename from apps/mobile/app/components/premium/pricing-item.js rename to apps/mobile/app/components/premium/pricing-item.tsx index 70d04a485..56a2e5e85 100644 --- a/apps/mobile/app/components/premium/pricing-item.js +++ b/apps/mobile/app/components/premium/pricing-item.tsx @@ -18,13 +18,27 @@ along with this program. If not, see . */ import React from "react"; -import { View } from "react-native"; +import { Platform, View } from "react-native"; import { SIZE } from "../../utils/size"; import { PressableButton } from "../ui/pressable"; import Heading from "../ui/typography/heading"; import Paragraph from "../ui/typography/paragraph"; +import RNIap from "react-native-iap"; -export const PricingItem = ({ product, onPress, compact }) => { +export const PricingItem = ({ + product, + onPress, + compact +}: { + product: { + type: "yearly" | "monthly"; + data?: RNIap.Subscription; + info: string; + offerType?: "yearly" | "monthly"; + }; + onPress?: () => void; + compact?: boolean; +}) => { return ( { - {product?.data?.localizedPrice}/ + + {Platform.OS === "android" + ? (product.data as RNIap.SubscriptionAndroid) + ?.subscriptionOfferDetails[0].pricingPhases + .pricingPhaseList?.[0].formattedPrice + : (product.data as RNIap.SubscriptionIOS)?.localizedPrice} + {product?.type === "yearly" || product?.offerType === "yearly" ? "/year" : "/month"} diff --git a/apps/mobile/app/components/premium/pricing-plans.js b/apps/mobile/app/components/premium/pricing-plans.tsx similarity index 77% rename from apps/mobile/app/components/premium/pricing-plans.js rename to apps/mobile/app/components/premium/pricing-plans.tsx index c4fe4211b..c22ca30e8 100644 --- a/apps/mobile/app/components/premium/pricing-plans.js +++ b/apps/mobile/app/components/premium/pricing-plans.tsx @@ -47,11 +47,15 @@ import Heading from "../ui/typography/heading"; import Paragraph from "../ui/typography/paragraph"; import { Walkthrough } from "../walkthroughs"; import { PricingItem } from "./pricing-item"; +import { useSettingStore } from "../../stores/use-setting-store"; const promoCyclesMonthly = { 1: "first month", 2: "first 2 months", - 3: "first 3 months" + 3: "first 3 months", + 4: "first 4 months", + 5: "first 5 months", + 6: "first 3 months" }; const promoCyclesYearly = { @@ -65,10 +69,24 @@ export const PricingPlans = ({ marginTop, heading = true, compact = false +}: { + promo?: { + promoCode: string; + }; + marginTop?: any; + heading?: boolean; + compact?: boolean; }) => { const { colors } = useThemeColors(); const user = useUserStore((state) => state.user); - const [product, setProduct] = useState(null); + const [product, setProduct] = useState<{ + type: string; + offerType: "monthly" | "yearly"; + data: RNIap.Subscription; + cycleText: string; + info: string; + }>(); + const [buying, setBuying] = useState(false); const [loading, setLoading] = useState(false); const userCanRequestTrial = @@ -90,27 +108,40 @@ export const PricingPlans = ({ } }, [promo?.promoCode]); - const getPromo = async (code) => { + const getPromo = async (code: string) => { try { - let productId; + let skuId: string; if (code.startsWith("com.streetwriters.notesnook")) { - productId = code; + skuId = code; } else { - productId = await db.offers.getCode(code.split(":")[0], Platform.OS); + skuId = await db.offers?.getCode(code.split(":")[0], Platform.OS); } - let products = await PremiumService.getProducts(); - let product = products.find((p) => p.productId === productId); + const products = await PremiumService.getProducts(); + const product = products.find((p) => p.productId === skuId); if (!product) return false; - let isMonthly = product.productId.indexOf(".mo") > -1; - let cycleText = isMonthly + const isMonthly = product.productId.indexOf(".mo") > -1; + + const cycleText = isMonthly ? promoCyclesMonthly[ - product.introductoryPriceCyclesAndroid || - product.introductoryPriceNumberOfPeriodsIOS + (Platform.OS === "android" + ? (product as RNIap.SubscriptionAndroid) + .subscriptionOfferDetails[0]?.pricingPhases + .pricingPhaseList?.[0].billingCycleCount + : parseInt( + (product as RNIap.SubscriptionIOS) + .introductoryPriceNumberOfPeriodsIOS as string + )) as keyof typeof promoCyclesMonthly ] : promoCyclesYearly[ - product.introductoryPriceCyclesAndroid || - product.introductoryPriceNumberOfPeriodsIOS + (Platform.OS === "android" + ? (product as RNIap.SubscriptionAndroid) + .subscriptionOfferDetails[0]?.pricingPhases + .pricingPhaseList?.[0].billingCycleCount + : parseInt( + (product as RNIap.SubscriptionIOS) + .introductoryPriceNumberOfPeriodsIOS as string + )) as keyof typeof promoCyclesYearly ]; setProduct({ @@ -118,7 +149,7 @@ export const PricingPlans = ({ offerType: isMonthly ? "monthly" : "yearly", data: product, cycleText: cycleText, - info: "Pay monthly, cancel anytime" + info: `Pay ${isMonthly ? "monthly" : "yearly"}, cancel anytime` }); return true; } catch (e) { @@ -131,22 +162,37 @@ export const PricingPlans = ({ getSkus(); }, [getSkus]); - const buySubscription = async (product) => { - if (buying) return; + const buySubscription = async (product: RNIap.Subscription) => { + if (buying || !product) return; setBuying(true); try { if (!user) { setBuying(false); return; } - await RNIap.requestSubscription( - product?.productId, - false, - null, - -1, - user.id, - user.id - ); + useSettingStore.getState().setAppDidEnterBackgroundForAction(true); + const androidOfferToken = + Platform.OS === "android" + ? (product as RNIap.SubscriptionAndroid).subscriptionOfferDetails[0] + .offerToken + : null; + + await RNIap.requestSubscription({ + sku: product?.productId, + obfuscatedAccountIdAndroid: user.id, + obfuscatedProfileIdAndroid: user.id, + appAccountToken: user.id, + andDangerouslyFinishTransactionAutomaticallyIOS: false, + subscriptionOffers: androidOfferToken + ? [ + { + offerToken: androidOfferToken, + sku: product?.productId + } + ] + : undefined + }); + useSettingStore.getState().setAppDidEnterBackgroundForAction(false); setBuying(false); eSendEvent(eCloseSheet); eSendEvent(eClosePremiumDialog); @@ -198,7 +244,14 @@ export const PricingPlans = ({ }} size={SIZE.lg} > - {PremiumService.getMontlySub().localizedPrice} / mo + {(Platform.OS === "android" + ? (monthlyPlan?.product as RNIap.SubscriptionAndroid) + ?.subscriptionOfferDetails[0].pricingPhases + .pricingPhaseList?.[0].formattedPrice + : (monthlyPlan?.product as RNIap.SubscriptionIOS) + .localizedPrice) || + (PremiumService.getMontlySub() as any).localizedPrice} + / mo