2025-07-01 12:13:03 +05:00
|
|
|
/*
|
|
|
|
|
This file is part of the Notesnook project (https://notesnook.com/)
|
|
|
|
|
|
|
|
|
|
Copyright (C) 2023 Streetwriters (Private) Limited
|
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2025-09-26 14:51:10 +05:00
|
|
|
import { Plan, SKUResponse } from "@notesnook/core";
|
2025-08-22 12:10:26 +05:00
|
|
|
import { strings } from "@notesnook/intl";
|
2025-09-29 10:01:59 +05:00
|
|
|
import { useThemeColors } from "@notesnook/theme";
|
|
|
|
|
import dayjs from "dayjs";
|
2025-09-26 14:51:10 +05:00
|
|
|
import React, { useEffect, useState } from "react";
|
2025-10-13 11:33:48 +05:00
|
|
|
import {
|
|
|
|
|
Linking,
|
|
|
|
|
ScrollView,
|
|
|
|
|
Text,
|
|
|
|
|
TouchableOpacity,
|
|
|
|
|
View
|
|
|
|
|
} from "react-native";
|
2025-08-22 12:10:26 +05:00
|
|
|
import Config from "react-native-config";
|
2025-07-01 12:13:03 +05:00
|
|
|
import * as RNIap from "react-native-iap";
|
2025-09-29 10:01:59 +05:00
|
|
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
2025-08-22 12:10:26 +05:00
|
|
|
import { WebView } from "react-native-webview";
|
|
|
|
|
import { db } from "../../../common/database";
|
2025-09-29 10:01:59 +05:00
|
|
|
import usePricingPlans from "../../../hooks/use-pricing-plans";
|
2025-09-25 09:16:11 +05:00
|
|
|
import { ToastManager } from "../../../services/event-manager";
|
2025-07-01 12:13:03 +05:00
|
|
|
import { openLinkInBrowser } from "../../../utils/functions";
|
2025-07-31 14:38:19 +05:00
|
|
|
import { AppFontSize, defaultBorderRadius } from "../../../utils/size";
|
|
|
|
|
import { DefaultAppStyles } from "../../../utils/styles";
|
2025-09-29 10:01:59 +05:00
|
|
|
import { Button } from "../../ui/button";
|
|
|
|
|
import Heading from "../../ui/typography/heading";
|
|
|
|
|
import Paragraph from "../../ui/typography/paragraph";
|
2025-08-22 08:46:17 +05:00
|
|
|
const isGithubRelease = Config.GITHUB_RELEASE === "true";
|
2025-07-01 12:13:03 +05:00
|
|
|
export const BuyPlan = (props: {
|
|
|
|
|
planId: string;
|
|
|
|
|
canActivateTrial?: boolean;
|
2025-09-26 14:51:10 +05:00
|
|
|
pricingPlans: ReturnType<typeof usePricingPlans>;
|
2025-07-01 12:13:03 +05:00
|
|
|
}) => {
|
|
|
|
|
const { colors } = useThemeColors();
|
2025-08-22 08:46:17 +05:00
|
|
|
const [checkoutUrl, setCheckoutUrl] = useState<string>();
|
2025-09-26 14:51:10 +05:00
|
|
|
const pricingPlans = props.pricingPlans;
|
2025-07-01 12:13:03 +05:00
|
|
|
|
|
|
|
|
const billingDuration = pricingPlans.getBillingDuration(
|
|
|
|
|
pricingPlans.selectedProduct as RNIap.Subscription,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
true
|
|
|
|
|
);
|
2025-08-22 08:46:17 +05:00
|
|
|
const is5YearPlanSelected = (
|
|
|
|
|
isGithubRelease
|
|
|
|
|
? (pricingPlans.selectedProduct as Plan)?.period
|
|
|
|
|
: (pricingPlans.selectedProduct as RNIap.Product)?.productId
|
|
|
|
|
)?.includes("5");
|
2025-07-01 12:13:03 +05:00
|
|
|
|
2025-08-22 08:46:17 +05:00
|
|
|
return checkoutUrl ? (
|
|
|
|
|
<View
|
|
|
|
|
style={{
|
2025-10-13 11:33:48 +05:00
|
|
|
flex: 1,
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: DefaultAppStyles.GAP_VERTICAL
|
2025-08-22 08:46:17 +05:00
|
|
|
}}
|
|
|
|
|
>
|
2025-10-13 11:33:48 +05:00
|
|
|
<Paragraph>{strings.finishPurchaseInBrowser()}</Paragraph>
|
2025-10-17 10:56:18 +05:00
|
|
|
<Button
|
|
|
|
|
title={strings.next()}
|
|
|
|
|
type="accent"
|
|
|
|
|
onPress={() => {
|
|
|
|
|
pricingPlans.finish();
|
|
|
|
|
}}
|
|
|
|
|
/>
|
2025-10-13 11:33:48 +05:00
|
|
|
<Button
|
|
|
|
|
title={strings.goBack()}
|
|
|
|
|
onPress={() => {
|
|
|
|
|
setCheckoutUrl(undefined);
|
2025-08-22 08:46:17 +05:00
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</View>
|
|
|
|
|
) : (
|
2025-07-01 12:13:03 +05:00
|
|
|
<ScrollView
|
|
|
|
|
contentContainerStyle={{
|
2025-07-23 12:32:37 +05:00
|
|
|
marginTop: DefaultAppStyles.GAP_VERTICAL
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
keyboardDismissMode="none"
|
|
|
|
|
keyboardShouldPersistTaps="always"
|
|
|
|
|
>
|
|
|
|
|
<View
|
|
|
|
|
style={{
|
2025-07-31 14:38:19 +05:00
|
|
|
paddingHorizontal: DefaultAppStyles.GAP,
|
|
|
|
|
gap: DefaultAppStyles.GAP_VERTICAL
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{[
|
2025-08-22 08:46:17 +05:00
|
|
|
Config.GITHUB_RELEASE === "true"
|
|
|
|
|
? "yearly"
|
|
|
|
|
: `notesnook.${props.planId}.yearly`,
|
|
|
|
|
Config.GITHUB_RELEASE === "true"
|
|
|
|
|
? "monthly"
|
|
|
|
|
: `notesnook.${props.planId}.monthly`,
|
2025-09-24 10:23:00 +05:00
|
|
|
...(props.planId === "essential" || pricingPlans.isSubscribed()
|
2025-07-01 12:13:03 +05:00
|
|
|
? []
|
2025-08-22 08:46:17 +05:00
|
|
|
: [
|
|
|
|
|
Config.GITHUB_RELEASE === "true"
|
|
|
|
|
? "5-year"
|
|
|
|
|
: `notesnook.${props.planId}.5year`
|
|
|
|
|
])
|
2025-07-01 12:13:03 +05:00
|
|
|
].map((item) => (
|
|
|
|
|
<ProductItem
|
|
|
|
|
key={item}
|
|
|
|
|
pricingPlans={pricingPlans}
|
|
|
|
|
productId={item}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
flexDirection: "row",
|
2025-07-23 12:32:37 +05:00
|
|
|
justifyContent: "space-between",
|
2025-07-31 14:38:19 +05:00
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: colors.primary.border,
|
|
|
|
|
padding: DefaultAppStyles.GAP,
|
|
|
|
|
borderRadius: defaultBorderRadius
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
>
|
2025-09-29 10:01:59 +05:00
|
|
|
<Heading color={colors.primary.paragraph} size={AppFontSize.sm}>
|
2025-08-22 12:10:26 +05:00
|
|
|
{strings.dueToday()}{" "}
|
2025-09-23 10:13:39 +05:00
|
|
|
{pricingPlans.hasTrialOffer(
|
|
|
|
|
props.planId,
|
|
|
|
|
(pricingPlans?.selectedProduct as RNIap.Product)?.productId ||
|
|
|
|
|
(pricingPlans?.selectedProduct as Plan)?.period
|
|
|
|
|
) ? (
|
2025-07-01 12:13:03 +05:00
|
|
|
<Text
|
|
|
|
|
style={{
|
|
|
|
|
color: colors.primary.accent
|
|
|
|
|
}}
|
|
|
|
|
>
|
2025-08-22 12:10:26 +05:00
|
|
|
({strings.daysFree(`${billingDuration?.duration || 0}`)})
|
2025-07-01 12:13:03 +05:00
|
|
|
</Text>
|
|
|
|
|
) : null}
|
|
|
|
|
</Heading>
|
|
|
|
|
|
|
|
|
|
<Paragraph color={colors.primary.paragraph}>
|
2025-09-23 10:13:39 +05:00
|
|
|
{pricingPlans.hasTrialOffer(
|
|
|
|
|
props.planId,
|
|
|
|
|
(pricingPlans?.selectedProduct as RNIap.Product)?.productId ||
|
|
|
|
|
(pricingPlans?.selectedProduct as Plan)?.period
|
|
|
|
|
)
|
2025-07-31 14:38:19 +05:00
|
|
|
? "FREE"
|
2025-07-01 12:13:03 +05:00
|
|
|
: pricingPlans.getStandardPrice(
|
|
|
|
|
pricingPlans.selectedProduct as RNIap.Subscription
|
|
|
|
|
)}
|
|
|
|
|
</Paragraph>
|
|
|
|
|
</View>
|
|
|
|
|
|
2025-09-10 11:20:46 +05:00
|
|
|
{pricingPlans.hasTrialOffer(
|
|
|
|
|
props.planId,
|
2025-09-12 14:52:39 +05:00
|
|
|
(pricingPlans?.selectedProduct as RNIap.Product)?.productId ||
|
|
|
|
|
(pricingPlans?.selectedProduct as Plan)?.period
|
2025-09-10 11:20:46 +05:00
|
|
|
) ? (
|
2025-07-01 12:13:03 +05:00
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
flexDirection: "row",
|
2025-07-31 14:38:19 +05:00
|
|
|
justifyContent: "space-between",
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: colors.primary.border,
|
|
|
|
|
padding: DefaultAppStyles.GAP,
|
|
|
|
|
borderRadius: defaultBorderRadius
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Paragraph color={colors.secondary.paragraph}>
|
2025-08-22 12:10:26 +05:00
|
|
|
{strings.due(
|
|
|
|
|
dayjs()
|
|
|
|
|
.add(billingDuration?.duration || 0, "day")
|
|
|
|
|
.format("DD MMMM")
|
|
|
|
|
)}
|
2025-07-01 12:13:03 +05:00
|
|
|
</Paragraph>
|
|
|
|
|
<Paragraph color={colors.secondary.paragraph}>
|
|
|
|
|
{pricingPlans.getStandardPrice(
|
|
|
|
|
pricingPlans.selectedProduct as RNIap.Subscription
|
|
|
|
|
)}
|
|
|
|
|
</Paragraph>
|
|
|
|
|
</View>
|
|
|
|
|
) : null}
|
|
|
|
|
|
2025-09-10 11:20:46 +05:00
|
|
|
{pricingPlans.hasTrialOffer(
|
|
|
|
|
props.planId,
|
2025-09-12 14:52:39 +05:00
|
|
|
(pricingPlans.selectedProduct as RNIap.Product)?.productId ||
|
|
|
|
|
(pricingPlans.selectedProduct as Plan)?.period
|
|
|
|
|
) || is5YearPlanSelected ? (
|
2025-07-31 14:38:19 +05:00
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
gap: DefaultAppStyles.GAP_VERTICAL,
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: colors.primary.border,
|
|
|
|
|
padding: DefaultAppStyles.GAP,
|
|
|
|
|
borderRadius: defaultBorderRadius
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{(is5YearPlanSelected
|
2025-08-22 12:10:26 +05:00
|
|
|
? strings["5yearPlanConditions"]()
|
2025-07-31 14:38:19 +05:00
|
|
|
: [
|
2025-08-22 12:10:26 +05:00
|
|
|
strings.trialPlanConditions[0](
|
|
|
|
|
billingDuration?.duration as number
|
|
|
|
|
),
|
|
|
|
|
strings.trialPlanConditions[1](0)
|
2025-07-31 14:38:19 +05:00
|
|
|
]
|
|
|
|
|
).map((item) => (
|
|
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
flexDirection: "row",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: 10
|
|
|
|
|
}}
|
|
|
|
|
key={item}
|
|
|
|
|
>
|
|
|
|
|
<Icon
|
|
|
|
|
color={colors.primary.accent}
|
|
|
|
|
size={AppFontSize.lg}
|
|
|
|
|
name="check"
|
|
|
|
|
/>
|
|
|
|
|
<Paragraph>{item}</Paragraph>
|
|
|
|
|
</View>
|
|
|
|
|
))}
|
|
|
|
|
</View>
|
|
|
|
|
) : null}
|
|
|
|
|
|
2025-07-01 12:13:03 +05:00
|
|
|
<Button
|
|
|
|
|
width="100%"
|
|
|
|
|
type="accent"
|
|
|
|
|
loading={pricingPlans.loading}
|
|
|
|
|
title={
|
2025-08-22 08:46:17 +05:00
|
|
|
is5YearPlanSelected
|
2025-08-22 12:10:26 +05:00
|
|
|
? strings.purchase()
|
2025-07-01 12:13:03 +05:00
|
|
|
: pricingPlans?.userCanRequestTrial
|
2025-08-22 12:10:26 +05:00
|
|
|
? strings.subscribeAndStartTrial()
|
|
|
|
|
: strings.subscribe()
|
2025-07-01 12:13:03 +05:00
|
|
|
}
|
2025-08-22 08:46:17 +05:00
|
|
|
onPress={async () => {
|
|
|
|
|
if (isGithubRelease) {
|
2025-10-13 11:33:48 +05:00
|
|
|
const url = await db.subscriptions.checkoutUrl(
|
|
|
|
|
(pricingPlans.selectedProduct as Plan).plan,
|
|
|
|
|
(pricingPlans.selectedProduct as Plan).period
|
2025-08-22 08:46:17 +05:00
|
|
|
);
|
2025-10-13 11:33:48 +05:00
|
|
|
if (url) {
|
|
|
|
|
setCheckoutUrl(url);
|
|
|
|
|
Linking.openURL(url);
|
|
|
|
|
}
|
2025-08-22 08:46:17 +05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-01 12:13:03 +05:00
|
|
|
const offerToken = pricingPlans.getOfferTokenAndroid(
|
|
|
|
|
pricingPlans.selectedProduct as RNIap.SubscriptionAndroid,
|
|
|
|
|
0
|
|
|
|
|
);
|
|
|
|
|
pricingPlans.subscribe(
|
|
|
|
|
pricingPlans.selectedProduct as RNIap.Subscription,
|
|
|
|
|
offerToken
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
|
2025-09-25 09:16:11 +05:00
|
|
|
<Paragraph
|
2025-09-29 10:01:59 +05:00
|
|
|
style={{
|
|
|
|
|
textAlign: "center"
|
|
|
|
|
}}
|
|
|
|
|
color={colors.secondary.paragraph}
|
|
|
|
|
size={AppFontSize.xs}
|
|
|
|
|
>
|
|
|
|
|
{is5YearPlanSelected
|
2025-08-22 12:10:26 +05:00
|
|
|
? strings.oneTimePurchase()
|
|
|
|
|
: strings.cancelAnytimeAlt()}
|
2025-09-25 09:16:11 +05:00
|
|
|
</Paragraph>
|
|
|
|
|
<Paragraph
|
2025-09-29 10:01:59 +05:00
|
|
|
style={{
|
|
|
|
|
textAlign: "center"
|
|
|
|
|
}}
|
|
|
|
|
color={colors.secondary.paragraph}
|
|
|
|
|
size={AppFontSize.xs}
|
|
|
|
|
>
|
2025-08-22 12:10:26 +05:00
|
|
|
{strings.subTerms[0]()}{" "}
|
2025-09-29 10:01:59 +05:00
|
|
|
<Text
|
2025-07-01 12:13:03 +05:00
|
|
|
style={{
|
2025-09-29 10:01:59 +05:00
|
|
|
textDecorationLine: "underline"
|
|
|
|
|
}}
|
|
|
|
|
onPress={() => {
|
|
|
|
|
openLinkInBrowser("https://notesnook.com/privacy");
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
>
|
2025-08-22 12:10:26 +05:00
|
|
|
{strings.subTerms[1]()}
|
2025-09-29 10:01:59 +05:00
|
|
|
</Text>{" "}
|
2025-08-22 12:10:26 +05:00
|
|
|
{strings.subTerms[2]()}{" "}
|
2025-09-29 10:01:59 +05:00
|
|
|
<Text
|
2025-07-01 12:13:03 +05:00
|
|
|
style={{
|
2025-09-29 10:01:59 +05:00
|
|
|
textDecorationLine: "underline"
|
|
|
|
|
}}
|
|
|
|
|
onPress={() => {
|
|
|
|
|
openLinkInBrowser("https://notesnook.com/tos");
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
>
|
2025-08-22 12:10:26 +05:00
|
|
|
{strings.subTerms[3]()}
|
2025-09-29 10:01:59 +05:00
|
|
|
</Text>
|
2025-09-25 09:16:11 +05:00
|
|
|
</Paragraph>
|
2025-07-01 12:13:03 +05:00
|
|
|
</View>
|
|
|
|
|
</ScrollView>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const ProductItem = (props: {
|
|
|
|
|
pricingPlans: ReturnType<typeof usePricingPlans>;
|
|
|
|
|
productId: string;
|
|
|
|
|
}) => {
|
|
|
|
|
const { colors } = useThemeColors();
|
2025-09-26 14:51:10 +05:00
|
|
|
const [regionalDiscount, setRegionaDiscount] = useState<SKUResponse>();
|
2025-07-01 12:13:03 +05:00
|
|
|
const product =
|
2025-09-26 14:51:10 +05:00
|
|
|
props.pricingPlans?.currentPlan?.subscriptions?.[
|
|
|
|
|
regionalDiscount?.sku || props.productId
|
|
|
|
|
] ||
|
2025-08-22 08:46:17 +05:00
|
|
|
props.pricingPlans?.currentPlan?.products?.[props.productId] ||
|
|
|
|
|
props.pricingPlans?.getWebPlan(
|
|
|
|
|
props.pricingPlans?.currentPlan?.id as string,
|
|
|
|
|
props.productId as "monthly" | "yearly"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const isAnnual = isGithubRelease
|
|
|
|
|
? (product as Plan)?.period === "yearly"
|
2025-09-26 14:51:10 +05:00
|
|
|
: (product as RNIap.Subscription)?.productId?.includes("yearly");
|
2025-08-22 08:46:17 +05:00
|
|
|
|
|
|
|
|
const isSelected = isGithubRelease
|
|
|
|
|
? (product as Plan)?.period ===
|
|
|
|
|
(props.pricingPlans.selectedProduct as Plan)?.period
|
|
|
|
|
: (product as RNIap.Subscription)?.productId ===
|
|
|
|
|
(props.pricingPlans.selectedProduct as RNIap.Subscription)?.productId;
|
|
|
|
|
|
|
|
|
|
const is5YearProduct = (
|
|
|
|
|
isGithubRelease
|
|
|
|
|
? (product as Plan)?.period
|
|
|
|
|
: (product as RNIap.Product)?.productId
|
|
|
|
|
)?.includes("5");
|
2025-07-01 12:13:03 +05:00
|
|
|
|
2025-09-24 10:23:00 +05:00
|
|
|
const isSubscribed =
|
|
|
|
|
props.pricingPlans.isSubscribed() &&
|
2025-09-26 14:51:10 +05:00
|
|
|
(props.pricingPlans.user?.subscription?.productId ===
|
|
|
|
|
(product as RNIap.Subscription)?.productId ||
|
2025-12-10 10:11:21 +05:00
|
|
|
props.pricingPlans.user?.subscription?.productId?.startsWith(
|
2025-09-26 14:51:10 +05:00
|
|
|
(product as RNIap.Subscription)?.productId
|
|
|
|
|
) ||
|
|
|
|
|
props.pricingPlans.user?.subscription?.productId ===
|
|
|
|
|
(product as Plan).id);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
props.pricingPlans
|
|
|
|
|
?.getRegionalDiscount(
|
|
|
|
|
props.pricingPlans.currentPlan?.id as string,
|
|
|
|
|
props.pricingPlans.isGithubRelease
|
|
|
|
|
? ((product as Plan)?.period as string)
|
|
|
|
|
: props.productId
|
|
|
|
|
)
|
|
|
|
|
.then((value) => {
|
|
|
|
|
if (
|
|
|
|
|
value &&
|
|
|
|
|
value.sku?.startsWith(
|
|
|
|
|
(props.pricingPlans.selectedProduct as RNIap.Subscription)
|
|
|
|
|
?.productId
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
props.pricingPlans.selectProduct(value?.sku as string);
|
|
|
|
|
}
|
|
|
|
|
setRegionaDiscount(value);
|
|
|
|
|
});
|
|
|
|
|
}, []);
|
|
|
|
|
|
2025-07-01 12:13:03 +05:00
|
|
|
return (
|
|
|
|
|
<TouchableOpacity
|
|
|
|
|
style={{
|
|
|
|
|
flexDirection: "row",
|
2025-09-25 09:16:11 +05:00
|
|
|
gap: 10,
|
|
|
|
|
opacity: isSubscribed ? 0.5 : 1
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
activeOpacity={0.9}
|
|
|
|
|
onPress={() => {
|
2025-09-25 09:16:11 +05:00
|
|
|
if (isSubscribed) {
|
|
|
|
|
ToastManager.show({
|
|
|
|
|
message: strings.alreadySubscribed(),
|
|
|
|
|
type: "info"
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-07-31 14:38:19 +05:00
|
|
|
if (!product) return;
|
2025-08-22 08:46:17 +05:00
|
|
|
props.pricingPlans.selectProduct(
|
|
|
|
|
isGithubRelease
|
|
|
|
|
? (product as Plan)?.period
|
|
|
|
|
: (product as RNIap.Subscription)?.productId
|
|
|
|
|
);
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Icon
|
|
|
|
|
name={isSelected ? "radiobox-marked" : "radiobox-blank"}
|
|
|
|
|
color={isSelected ? colors.primary.accent : colors.secondary.icon}
|
2025-09-29 10:01:59 +05:00
|
|
|
size={AppFontSize.lg}
|
2025-07-01 12:13:03 +05:00
|
|
|
/>
|
2025-07-23 12:32:37 +05:00
|
|
|
<View>
|
2025-07-01 12:13:03 +05:00
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
flexDirection: "row",
|
2025-07-23 12:32:37 +05:00
|
|
|
gap: DefaultAppStyles.GAP_VERTICAL_SMALL
|
2025-07-01 12:13:03 +05:00
|
|
|
}}
|
|
|
|
|
>
|
2025-09-29 10:01:59 +05:00
|
|
|
<Heading size={AppFontSize.md}>
|
2025-07-01 12:13:03 +05:00
|
|
|
{isAnnual
|
2025-08-22 12:20:41 +05:00
|
|
|
? strings.yearly()
|
2025-08-22 08:46:17 +05:00
|
|
|
: is5YearProduct
|
2025-08-22 12:20:41 +05:00
|
|
|
? strings.fiveYearPlan()
|
|
|
|
|
: strings.monthly()}
|
2025-07-01 12:13:03 +05:00
|
|
|
</Heading>
|
|
|
|
|
|
2025-08-22 08:46:17 +05:00
|
|
|
{(isAnnual && !isGithubRelease) ||
|
|
|
|
|
(isGithubRelease && (product as Plan)?.discount?.amount) ? (
|
2025-07-01 12:13:03 +05:00
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
backgroundColor: colors.static.red,
|
2025-09-24 10:23:00 +05:00
|
|
|
borderRadius: defaultBorderRadius,
|
2025-07-01 12:13:03 +05:00
|
|
|
paddingHorizontal: 6,
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "center"
|
|
|
|
|
}}
|
|
|
|
|
>
|
2025-09-29 10:01:59 +05:00
|
|
|
<Heading color={colors.static.white} size={AppFontSize.xs}>
|
2025-08-22 12:10:26 +05:00
|
|
|
{strings.bestValue()} -{" "}
|
|
|
|
|
{strings.percentOff(
|
2025-09-26 14:51:10 +05:00
|
|
|
(regionalDiscount
|
|
|
|
|
? regionalDiscount.discount
|
|
|
|
|
: isGithubRelease
|
2025-08-22 12:10:26 +05:00
|
|
|
? (product as Plan).discount?.amount
|
|
|
|
|
: props.pricingPlans.compareProductPrice(
|
|
|
|
|
props.pricingPlans.currentPlan?.id as string,
|
|
|
|
|
`notesnook.${props.pricingPlans.currentPlan?.id}.yearly`,
|
|
|
|
|
`notesnook.${props.pricingPlans.currentPlan?.id}.monthly`
|
|
|
|
|
)) as string
|
|
|
|
|
)}
|
2025-07-01 12:13:03 +05:00
|
|
|
</Heading>
|
|
|
|
|
</View>
|
|
|
|
|
) : null}
|
2025-09-24 10:23:00 +05:00
|
|
|
|
|
|
|
|
{isSubscribed ? (
|
|
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
backgroundColor: colors.primary.accent,
|
|
|
|
|
borderRadius: defaultBorderRadius,
|
|
|
|
|
paddingHorizontal: 6,
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "center"
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Heading color={colors.static.white} size={AppFontSize.xs}>
|
|
|
|
|
{strings.currentPlan()}
|
|
|
|
|
</Heading>
|
|
|
|
|
</View>
|
|
|
|
|
) : null}
|
2025-07-01 12:13:03 +05:00
|
|
|
</View>
|
|
|
|
|
|
2025-07-31 14:38:19 +05:00
|
|
|
<Paragraph size={AppFontSize.md}>
|
2025-08-22 08:46:17 +05:00
|
|
|
{isAnnual || is5YearProduct
|
2025-07-31 14:38:19 +05:00
|
|
|
? `${props.pricingPlans.getPrice(
|
2025-07-01 12:13:03 +05:00
|
|
|
product as RNIap.Subscription,
|
2025-08-22 08:46:17 +05:00
|
|
|
props.pricingPlans.hasTrialOffer(
|
|
|
|
|
undefined,
|
|
|
|
|
(product as RNIap.Subscription)?.productId
|
|
|
|
|
)
|
2025-07-31 14:38:19 +05:00
|
|
|
? 1
|
|
|
|
|
: 0,
|
2025-07-01 12:13:03 +05:00
|
|
|
isAnnual
|
2025-08-22 12:20:41 +05:00
|
|
|
)}/${strings.month()}`
|
2025-07-31 14:38:19 +05:00
|
|
|
: null}
|
|
|
|
|
|
2025-08-22 08:46:17 +05:00
|
|
|
{!isAnnual && !is5YearProduct
|
2025-07-31 14:38:19 +05:00
|
|
|
? `${props.pricingPlans.getStandardPrice(
|
|
|
|
|
product as RNIap.Subscription
|
2025-08-22 12:10:26 +05:00
|
|
|
)}/${strings.month()}`
|
2025-07-01 12:13:03 +05:00
|
|
|
: null}
|
|
|
|
|
</Paragraph>
|
|
|
|
|
</View>
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
);
|
|
|
|
|
};
|