diff --git a/apps/mobile/app/assets/images/assets.js b/apps/mobile/app/assets/images/assets.js
index 2f7a1c4bf..336ea015b 100644
--- a/apps/mobile/app/assets/images/assets.js
+++ b/apps/mobile/app/assets/images/assets.js
@@ -179,3 +179,134 @@ export const INTRO_ILLUSTRATION = ``;
+
+export const TRUST_BAR_SVG = ``;
diff --git a/apps/mobile/app/components/paywall/common.ts b/apps/mobile/app/components/paywall/common.ts
new file mode 100644
index 000000000..1b9dd4660
--- /dev/null
+++ b/apps/mobile/app/components/paywall/common.ts
@@ -0,0 +1,24 @@
+/*
+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 .
+*/
+export const Steps = {
+ select: 1,
+ buy: 2,
+ finish: 3,
+ buyWeb: 4
+};
diff --git a/apps/mobile/app/components/paywall/compare-plans.tsx b/apps/mobile/app/components/paywall/compare-plans.tsx
new file mode 100644
index 000000000..d02dd0687
--- /dev/null
+++ b/apps/mobile/app/components/paywall/compare-plans.tsx
@@ -0,0 +1,181 @@
+/*
+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 .
+*/
+
+import { getFeaturesTable } from "@notesnook/common";
+import { strings } from "@notesnook/intl";
+import { useThemeColors } from "@notesnook/theme";
+import React from "react";
+import { ScrollView, useWindowDimensions, View } from "react-native";
+import Icon from "react-native-vector-icons/MaterialCommunityIcons";
+//@ts-ignore
+import usePricingPlans from "../../hooks/use-pricing-plans";
+import { AppFontSize } from "../../utils/size";
+import { Button } from "../ui/button";
+import Heading from "../ui/typography/heading";
+import Paragraph from "../ui/typography/paragraph";
+import { Steps } from "./common";
+
+export const ComparePlans = React.memo(
+ (props: {
+ pricingPlans?: ReturnType;
+ setStep: (step: number) => void;
+ }) => {
+ const { colors } = useThemeColors();
+ const { width } = useWindowDimensions();
+ const isTablet = width > 600;
+
+ return (
+
+
+ {["Features", "Free", "Essential", "Pro", "Believer"].map(
+ (plan, index) => (
+
+ {plan}
+
+ )
+ )}
+
+
+ {getFeaturesTable().map((item, keyIndex) => {
+ return (
+
+ {item.map((featureItem, index) => (
+
+ {typeof featureItem === "string" ? (
+
+ {featureItem as string}
+
+ ) : (
+ <>
+ {typeof featureItem.caption === "string" ||
+ typeof featureItem.caption === "number" ? (
+
+ {featureItem.caption === "infinity"
+ ? "∞"
+ : featureItem.caption}
+
+ ) : typeof featureItem.caption === "boolean" ? (
+ <>
+ {featureItem.caption === true ? (
+
+ ) : (
+
+ )}
+ >
+ ) : null}
+ >
+ )}
+
+ ))}
+
+ );
+ })}
+
+
+ {["features", "free", "essential", "pro", "believer"].map(
+ (plan, index) => (
+
+ {plan !== "free" && plan !== "features" ? (
+
+ )
+ )}
+
+
+ );
+ },
+ () => true
+);
+ComparePlans.displayName = "ComparePlans";
diff --git a/apps/mobile/app/components/paywall/faq-item.tsx b/apps/mobile/app/components/paywall/faq-item.tsx
new file mode 100644
index 000000000..50103712c
--- /dev/null
+++ b/apps/mobile/app/components/paywall/faq-item.tsx
@@ -0,0 +1,73 @@
+/*
+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 .
+*/
+
+import { useThemeColors } from "@notesnook/theme";
+import React, { useState } from "react";
+import { TouchableOpacity, View } from "react-native";
+import Icon from "react-native-vector-icons/MaterialCommunityIcons";
+//@ts-ignore
+import { AppFontSize } from "../../utils/size";
+import Heading from "../ui/typography/heading";
+import Paragraph from "../ui/typography/paragraph";
+
+export const FAQItem = (props: { question: string; answer: string }) => {
+ const [expanded, setExpanded] = useState(false);
+ const { colors } = useThemeColors();
+ return (
+ {
+ setExpanded(!expanded);
+ }}
+ key={props.question}
+ >
+
+
+ {props.question}
+
+
+
+ {expanded ? (
+ {props.answer}
+ ) : null}
+
+ );
+};
diff --git a/apps/mobile/app/components/paywall/index.tsx b/apps/mobile/app/components/paywall/index.tsx
index cdc8d9bf8..f49ac90c8 100644
--- a/apps/mobile/app/components/paywall/index.tsx
+++ b/apps/mobile/app/components/paywall/index.tsx
@@ -17,48 +17,27 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import { getFeaturesTable } from "@notesnook/common";
import { EVENTS, Plan, SubscriptionPlan, User } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import {
- ActivityIndicator,
BackHandler,
- Image,
NativeEventSubscription,
ScrollView,
- Text,
- TouchableOpacity,
useWindowDimensions,
View
} from "react-native";
import Config from "react-native-config";
import * as RNIap from "react-native-iap";
import { SafeAreaView } from "react-native-safe-area-context";
-import Icon from "react-native-vector-icons/MaterialCommunityIcons";
-//@ts-ignore
-import ToggleSwitch from "toggle-switch-react-native";
-import {
- ANDROID_POLICE_SVG,
- APPLE_INSIDER_PNG,
- ITS_FOSS_NEWS_PNG,
- NESS_LABS_PNG,
- PRIVACY_GUIDES_SVG,
- TECHLORE_SVG,
- XDA_SVG
-} from "../../assets/images/assets";
+import { TRUST_BAR_SVG } from "../../assets/images/assets";
import { db } from "../../common/database";
+import { Radius, Spacing } from "../../common/design/spacing";
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
-import usePricingPlans, {
- PlanOverView,
- PricingPlan
-} from "../../hooks/use-pricing-plans";
+import usePricingPlans from "../../hooks/use-pricing-plans";
import Navigation, { NavigationProps } from "../../services/navigation";
-import PremiumService from "../../services/premium";
-import { getElevationStyle } from "../../utils/elevation";
-import { openLinkInBrowser } from "../../utils/functions";
-import { AppFontSize, defaultBorderRadius } from "../../utils/size";
+import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { AuthMode } from "../auth/common";
import { Header } from "../header";
@@ -67,21 +46,22 @@ import { Toast } from "../toast";
import AppIcon from "../ui/AppIcon";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
+import { Pressable } from "../ui/pressable";
import { SvgView } from "../ui/svg";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
-
-const Steps = {
- select: 1,
- buy: 2,
- finish: 3,
- buyWeb: 4
-};
+import { Steps } from "./common";
+import { ComparePlans } from "./compare-plans";
+import { FAQItem } from "./faq-item";
+import { PricingPlanCard } from "./plan-card";
+import { ReviewItem } from "./review-item";
const PayWall = (props: NavigationProps<"PayWall">) => {
const isGithubRelease = Config.GITHUB_RELEASE === "true";
const routeParams = props.route.params;
const { width } = useWindowDimensions();
+ const [planPageIndex, setPlanPageIndex] = useState(1);
+ const [testimonialIndex, setTestimonialIndex] = useState(0);
const isTablet = width > 600;
const { colors } = useThemeColors();
const pricingPlans = usePricingPlans({
@@ -178,6 +158,7 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
name="close"
testID="paywall-close"
color={colors.primary.icon}
+ size={25}
onPress={() => {
Navigation.navigate("FluidPanelsView", {});
}}
@@ -216,7 +197,6 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
width: "100%"
}}
contentContainerStyle={{
- gap: DefaultAppStyles.GAP_VERTICAL,
paddingBottom: 80
}}
keyboardDismissMode="none"
@@ -224,19 +204,16 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
>
) => {
{pricingPlans.isSubscribed()
? strings.changePlan()
: strings.notesnookPlans[0]() + " "}
- {pricingPlans.isSubscribed() ? null : (
-
- {strings.notesnookPlans[1]()}
-
- )}
+ {pricingPlans.isSubscribed()
+ ? null
+ : strings.notesnookPlans[1]()}
@@ -265,79 +237,159 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
-
- {
- setAnnualBilling((state) => !state);
- }}
+
+
- {strings.monthly()}
- {
- setAnnualBilling((state) => !state);
+
+
+ {
+ setAnnualBilling(true);
+ }}
+ style={{
+ width: 130,
+ flexDirection: "row",
+ paddingVertical: Spacing.LEVEL_1,
+ paddingHorizontal: Spacing.LEVEL_2,
+ gap: Spacing.LEVEL_1,
+ borderWidth: 0
+ }}
+ type={annualBilling ? "accent" : "transparent"}
+ >
+
+ {strings.yearly()}
+
+
+
+ -20%
+
+
+
+
+ {
+ const value = event.nativeEvent.contentOffset.x;
+ setPlanPageIndex(value > 600 ? 2 : value > 300 ? 1 : 0);
+ }}
+ contentOffset={{
+ x: 310,
+ y: 0
+ }}
+ >
+ {pricingPlans.pricingPlans.map((plan, index) =>
+ plan.id !== "free" ? (
+
+ {
+ if (!pricingPlans.user) {
+ Navigation.navigate("Auth", {
+ mode: AuthMode.login,
+ state: {
+ planId: pricingPlans.currentPlan?.id,
+ productId:
+ (
+ pricingPlans.selectedProduct as RNIap.Subscription
+ )?.productId ||
+ (pricingPlans.selectedProduct as Plan)
+ ?.period,
+ billingType: annualBilling
+ ? "annual"
+ : "monthly"
+ }
+ });
+ return;
+ }
+ setStep(step);
+ }}
+ pricingPlans={pricingPlans}
+ annualBilling={annualBilling}
+ />
+
+ ) : null
+ )}
+
- {pricingPlans.pricingPlans.map((plan) =>
- plan.id !== "free" ? (
- {
- if (!pricingPlans.user) {
- Navigation.navigate("Auth", {
- mode: AuthMode.login,
- state: {
- planId: pricingPlans.currentPlan?.id,
- productId:
- (
- pricingPlans.selectedProduct as RNIap.Subscription
- )?.productId ||
- (pricingPlans.selectedProduct as Plan)?.period,
- billingType: annualBilling ? "annual" : "monthly"
- }
- });
- return;
- }
- setStep(step);
- }}
- pricingPlans={pricingPlans}
- annualBilling={annualBilling}
- />
- ) : null
- )}
+ {[0, 1, 2].map((item) => (
+
+ ))}
@@ -346,250 +398,131 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
width: "100%"
}}
>
+
+
+
+
- {
- openLinkInBrowser(
- "https://github.com/streetwriters/notesnook"
- );
- }}
- activeOpacity={0.9}
- style={{
- padding: 16,
- gap: 12,
- alignItems: "center",
- flexGrow: 1
- }}
- >
+ {strings.testimonials()}
+
+
+ {
+ const value = event.nativeEvent.contentOffset.x;
+ setTestimonialIndex(value > 600 ? 2 : value > 300 ? 1 : 0);
+ }}
+ >
+ {[
+ {
+ user: "Tagby friend",
+ userSource: "Discord",
+ link: "https://discord.com/channels/796015620436787241/828701074465619990/1070172521846026271",
+ userImage:
+ "data:image/webp;base64,UklGRrAFAABXRUJQVlA4WAoAAAAQAAAATwAATwAAQUxQSAoAAAABB9D+iAhERP8DVlA4IIAFAAAQGACdASpQAFAAPm0skkYkIqGhL1K86IANiWdqN1k9SfbwDoK2qhJsXhBwv+m+3ujg5HTtBysrex6esj/qeU5883L4Rbay65pvw7npaa0yc/fmrdXlgwv8WNtJN9J5m8XMkAKD7lrd98bFKn2UcICVz6fIlJpW6gQDx3Y/lQzupEnm4fyWa/VI47NFSGLJjPe4K/NR5nIh1I+JaGqh5h6Zn/9771gyWEnxRaaHU7LdnMvNnAtVXhm3Ijxrv+9TKC7rtKa+oqC2ewAA/v17lyxCQMDU8AW7okR5UCCzmkNNZqVrX1NJ2Mu1LrM2qc+DCezUOb2Y8MzxK5xRgGrcR0/FAx88Y1KeuT5RUbhRcNNnTw1Un3MWtOlBIXpYjntwwdRskDymt47ZvkH+V5QANy6cAr+Lrol9EOVUxXc8G5bTJLcIHELmBulybx2w+O+btTXtlkgn0JSy0pAWMfZunaztVCHoyNnmWxhHAFMMUSycgx76ovzc8+Hwd/rRUY3/P+B4/y3dQZ9FB+vMiyYCEdci0l8arhH6f0IOVijOkAXiuS8KfnOh76NP5jbRF0qvz63DDZSUmpsXJGnI7phYFgJ5Em+3zIebcKqPcn4M5hznAH9mYIPsv8jeOCg7+DRYljkh4AbTxImyoRrPy9GUeUA1QC290cK+877ce6yyNzQK8jaLEAz53ccPZj/cHk17B2SCVknKQhV7bz6yg6fLGR5AT3qAPfdQsVeHrPLQdRZmw1ll62E7lCU7+WCuHk+xAg1JwiyZsdWlcSf1Oazs7qgdnon9lQNVKgzGSR+I811YKPAS5U3go9ANCZwqsmdQ07Y+ZzCuLukH46D0tWk/kBVgXBzMhOf8bAlayYfIGvIdEXjm6Z4j0SIz3juiY35mCjXXwez84ESBpc3z0c2gWgRFzWx/iyYBjPzJ5s3Mub6xzfsWtYqAmhAPzeoK5pJWgiB6tEyI2oZmLuj7sLVHARnaswrfzDlIUMPXRSZFoq+mmsIF1aKThJDQTNdgnkLjfz3rDkVaqVhk3sg8jZLIOMJUKsYvujEmGRbRlO3hwfL0JvoORLh8rOJ0prBA2Tnra+VA/RMfJtKC/AjVXRu/nH0tmGg2/Wkra7C/OWK9E2NqBVVjJvrgqvNN0V8gYZdScIl0jQSLRzA4emm2HfC+L8c4FCxheZFDMP+zGUH5JyXLkBX/hGWE+CWhcPjSJ8hAj8yBeXCyWpM07eiFPxxkqYF+Wka211fUU/HygHPX+Qj+CyoMjz9gstrjNPTX0zc3r55VrpiFUjxfgOoY32Eojwr9mWg/dcleov8wSmKuJZtzjxiXFzemVIP5kzrDIffxS6PR30mOq+d9k/ZgJfzhyuPr6W8kOmQXmLnMwbpcr1KSSgjOLmu6oBtjexL/ukI77ygGzDtdDfRPpj7klVHu34xcWAufMWOMlo70oenOeQGueYXGWPZW175I30dvCT/Ra2R+0MbxvxmdpmmoQmzC4d7l/MI2MhUHUW5N79x0vXB1PEGs+F3o+6dO+N1qqqXxJP/0N5BvADUF55dX2vpBSAXyN30UPO9IBqC0JkFPwXiOncsUir6r50C47HnS2WadAlu2QpHFL8YrTsSdhP19HAc6zWDM2/RaJZxFFQj/tqw0rYVYX//7iKKSiXWWQma12fG+HhJD2tBjEcp8+vU2nzjmd4tR6AurIEns1SsWg2cFcvrZzyzKFB0gdnvVpoCwouvl8UuSAyYc+rHMVGhWln+a+bhRgIERIb5XlrazMxJOqksed7mUs5ArKpOEuHWPYu+U+E2T1OkeusgAKL57F73Fm2xbIunW/IbW2wawYHv8u1AWGGSAB8XYJOW1XxpqIgq+V34pqd3WRpBGd1G4rGAA",
+ review: `I just want to say thank you so much.
+
+After trying all the privacy security oriented note taking apps, for the price and the features afforded to your users, Notesnook is hands down the best.`
+ },
+ {
+ user: "Tagby frien",
+ userSource: "Discord",
+ link: "https://discord.com/channels/796015620436787241/828701074465619990/1070172521846026271",
+ userImage:
+ "data:image/webp;base64,UklGRrAFAABXRUJQVlA4WAoAAAAQAAAATwAATwAAQUxQSAoAAAABB9D+iAhERP8DVlA4IIAFAAAQGACdASpQAFAAPm0skkYkIqGhL1K86IANiWdqN1k9SfbwDoK2qhJsXhBwv+m+3ujg5HTtBysrex6esj/qeU5883L4Rbay65pvw7npaa0yc/fmrdXlgwv8WNtJN9J5m8XMkAKD7lrd98bFKn2UcICVz6fIlJpW6gQDx3Y/lQzupEnm4fyWa/VI47NFSGLJjPe4K/NR5nIh1I+JaGqh5h6Zn/9771gyWEnxRaaHU7LdnMvNnAtVXhm3Ijxrv+9TKC7rtKa+oqC2ewAA/v17lyxCQMDU8AW7okR5UCCzmkNNZqVrX1NJ2Mu1LrM2qc+DCezUOb2Y8MzxK5xRgGrcR0/FAx88Y1KeuT5RUbhRcNNnTw1Un3MWtOlBIXpYjntwwdRskDymt47ZvkH+V5QANy6cAr+Lrol9EOVUxXc8G5bTJLcIHELmBulybx2w+O+btTXtlkgn0JSy0pAWMfZunaztVCHoyNnmWxhHAFMMUSycgx76ovzc8+Hwd/rRUY3/P+B4/y3dQZ9FB+vMiyYCEdci0l8arhH6f0IOVijOkAXiuS8KfnOh76NP5jbRF0qvz63DDZSUmpsXJGnI7phYFgJ5Em+3zIebcKqPcn4M5hznAH9mYIPsv8jeOCg7+DRYljkh4AbTxImyoRrPy9GUeUA1QC290cK+877ce6yyNzQK8jaLEAz53ccPZj/cHk17B2SCVknKQhV7bz6yg6fLGR5AT3qAPfdQsVeHrPLQdRZmw1ll62E7lCU7+WCuHk+xAg1JwiyZsdWlcSf1Oazs7qgdnon9lQNVKgzGSR+I811YKPAS5U3go9ANCZwqsmdQ07Y+ZzCuLukH46D0tWk/kBVgXBzMhOf8bAlayYfIGvIdEXjm6Z4j0SIz3juiY35mCjXXwez84ESBpc3z0c2gWgRFzWx/iyYBjPzJ5s3Mub6xzfsWtYqAmhAPzeoK5pJWgiB6tEyI2oZmLuj7sLVHARnaswrfzDlIUMPXRSZFoq+mmsIF1aKThJDQTNdgnkLjfz3rDkVaqVhk3sg8jZLIOMJUKsYvujEmGRbRlO3hwfL0JvoORLh8rOJ0prBA2Tnra+VA/RMfJtKC/AjVXRu/nH0tmGg2/Wkra7C/OWK9E2NqBVVjJvrgqvNN0V8gYZdScIl0jQSLRzA4emm2HfC+L8c4FCxheZFDMP+zGUH5JyXLkBX/hGWE+CWhcPjSJ8hAj8yBeXCyWpM07eiFPxxkqYF+Wka211fUU/HygHPX+Qj+CyoMjz9gstrjNPTX0zc3r55VrpiFUjxfgOoY32Eojwr9mWg/dcleov8wSmKuJZtzjxiXFzemVIP5kzrDIffxS6PR30mOq+d9k/ZgJfzhyuPr6W8kOmQXmLnMwbpcr1KSSgjOLmu6oBtjexL/ukI77ygGzDtdDfRPpj7klVHu34xcWAufMWOMlo70oenOeQGueYXGWPZW175I30dvCT/Ra2R+0MbxvxmdpmmoQmzC4d7l/MI2MhUHUW5N79x0vXB1PEGs+F3o+6dO+N1qqqXxJP/0N5BvADUF55dX2vpBSAXyN30UPO9IBqC0JkFPwXiOncsUir6r50C47HnS2WadAlu2QpHFL8YrTsSdhP19HAc6zWDM2/RaJZxFFQj/tqw0rYVYX//7iKKSiXWWQma12fG+HhJD2tBjEcp8+vU2nzjmd4tR6AurIEns1SsWg2cFcvrZzyzKFB0gdnvVpoCwouvl8UuSAyYc+rHMVGhWln+a+bhRgIERIb5XlrazMxJOqksed7mUs5ArKpOEuHWPYu+U+E2T1OkeusgAKL57F73Fm2xbIunW/IbW2wawYHv8u1AWGGSAB8XYJOW1XxpqIgq+V34pqd3WRpBGd1G4rGAA",
+ review: `I just want to say thank you so much.
+
+After trying all the privacy security oriented note taking apps, for the price and the features afforded to your users, Notesnook is hands down the best.`
+ },
+ {
+ user: "Tagby frie",
+ userSource: "Discord",
+ link: "https://discord.com/channels/796015620436787241/828701074465619990/1070172521846026271",
+ userImage:
+ "data:image/webp;base64,UklGRrAFAABXRUJQVlA4WAoAAAAQAAAATwAATwAAQUxQSAoAAAABB9D+iAhERP8DVlA4IIAFAAAQGACdASpQAFAAPm0skkYkIqGhL1K86IANiWdqN1k9SfbwDoK2qhJsXhBwv+m+3ujg5HTtBysrex6esj/qeU5883L4Rbay65pvw7npaa0yc/fmrdXlgwv8WNtJN9J5m8XMkAKD7lrd98bFKn2UcICVz6fIlJpW6gQDx3Y/lQzupEnm4fyWa/VI47NFSGLJjPe4K/NR5nIh1I+JaGqh5h6Zn/9771gyWEnxRaaHU7LdnMvNnAtVXhm3Ijxrv+9TKC7rtKa+oqC2ewAA/v17lyxCQMDU8AW7okR5UCCzmkNNZqVrX1NJ2Mu1LrM2qc+DCezUOb2Y8MzxK5xRgGrcR0/FAx88Y1KeuT5RUbhRcNNnTw1Un3MWtOlBIXpYjntwwdRskDymt47ZvkH+V5QANy6cAr+Lrol9EOVUxXc8G5bTJLcIHELmBulybx2w+O+btTXtlkgn0JSy0pAWMfZunaztVCHoyNnmWxhHAFMMUSycgx76ovzc8+Hwd/rRUY3/P+B4/y3dQZ9FB+vMiyYCEdci0l8arhH6f0IOVijOkAXiuS8KfnOh76NP5jbRF0qvz63DDZSUmpsXJGnI7phYFgJ5Em+3zIebcKqPcn4M5hznAH9mYIPsv8jeOCg7+DRYljkh4AbTxImyoRrPy9GUeUA1QC290cK+877ce6yyNzQK8jaLEAz53ccPZj/cHk17B2SCVknKQhV7bz6yg6fLGR5AT3qAPfdQsVeHrPLQdRZmw1ll62E7lCU7+WCuHk+xAg1JwiyZsdWlcSf1Oazs7qgdnon9lQNVKgzGSR+I811YKPAS5U3go9ANCZwqsmdQ07Y+ZzCuLukH46D0tWk/kBVgXBzMhOf8bAlayYfIGvIdEXjm6Z4j0SIz3juiY35mCjXXwez84ESBpc3z0c2gWgRFzWx/iyYBjPzJ5s3Mub6xzfsWtYqAmhAPzeoK5pJWgiB6tEyI2oZmLuj7sLVHARnaswrfzDlIUMPXRSZFoq+mmsIF1aKThJDQTNdgnkLjfz3rDkVaqVhk3sg8jZLIOMJUKsYvujEmGRbRlO3hwfL0JvoORLh8rOJ0prBA2Tnra+VA/RMfJtKC/AjVXRu/nH0tmGg2/Wkra7C/OWK9E2NqBVVjJvrgqvNN0V8gYZdScIl0jQSLRzA4emm2HfC+L8c4FCxheZFDMP+zGUH5JyXLkBX/hGWE+CWhcPjSJ8hAj8yBeXCyWpM07eiFPxxkqYF+Wka211fUU/HygHPX+Qj+CyoMjz9gstrjNPTX0zc3r55VrpiFUjxfgOoY32Eojwr9mWg/dcleov8wSmKuJZtzjxiXFzemVIP5kzrDIffxS6PR30mOq+d9k/ZgJfzhyuPr6W8kOmQXmLnMwbpcr1KSSgjOLmu6oBtjexL/ukI77ygGzDtdDfRPpj7klVHu34xcWAufMWOMlo70oenOeQGueYXGWPZW175I30dvCT/Ra2R+0MbxvxmdpmmoQmzC4d7l/MI2MhUHUW5N79x0vXB1PEGs+F3o+6dO+N1qqqXxJP/0N5BvADUF55dX2vpBSAXyN30UPO9IBqC0JkFPwXiOncsUir6r50C47HnS2WadAlu2QpHFL8YrTsSdhP19HAc6zWDM2/RaJZxFFQj/tqw0rYVYX//7iKKSiXWWQma12fG+HhJD2tBjEcp8+vU2nzjmd4tR6AurIEns1SsWg2cFcvrZzyzKFB0gdnvVpoCwouvl8UuSAyYc+rHMVGhWln+a+bhRgIERIb5XlrazMxJOqksed7mUs5ArKpOEuHWPYu+U+E2T1OkeusgAKL57F73Fm2xbIunW/IbW2wawYHv8u1AWGGSAB8XYJOW1XxpqIgq+V34pqd3WRpBGd1G4rGAA",
+ review: `I just want to say thank you so much.
+
+After trying all the privacy security oriented note taking apps, for the price and the features afforded to your users, Notesnook is hands down the best.`
+ }
+ ].map((item, index) => (
-
-
- Open Source
-
-
-
- {
- openLinkInBrowser(
- "https://github.com/streetwriters/notesnook/stargazers"
- );
- }}
- activeOpacity={0.9}
- style={{
- padding: 16,
- gap: 12,
- alignItems: "center",
- justifyContent: "center",
- flexGrow: 1
- }}
- >
-
-
-
-
- 12.5K stars
-
-
-
- {
- openLinkInBrowser(
- "https://www.privacyguides.org/en/notebooks/#notesnook"
- );
- }}
- activeOpacity={0.9}
- style={{
- justifyContent: "center",
- padding: 16,
- gap: 12,
- alignItems: "center",
- flexGrow: 1
- }}
- >
-
-
- {strings.recommendedByPrivacyGuides()}
-
-
-
-
-
- {strings.featuredOn()}
-
+ ))}
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {[0, 1, 2].map((item) => (
+
+ ))}
-
- {strings.comparePlans()}
-
-
-
-
-
- {strings.faqs()}
+
+ {strings.frequentlyAskedQuestions()}
+
{strings.checkoutFaqs.map((item) => (
@@ -600,6 +533,24 @@ After trying all the privacy security oriented note taking apps, for the price a
/>
))}
+
+
+ {strings.comparePlans()}
+
+
+
+
+
>
) : step === Steps.buy ? (
@@ -664,483 +615,4 @@ After trying all the privacy security oriented note taking apps, for the price a
);
};
-const FAQItem = (props: { question: string; answer: string }) => {
- const [expanded, setExpanded] = useState(false);
- const { colors } = useThemeColors();
- return (
- {
- setExpanded(!expanded);
- }}
- key={props.question}
- >
-
-
- {props.question}
-
-
-
- {expanded ? (
- {props.answer}
- ) : null}
-
- );
-};
-
-const ComparePlans = React.memo(
- (props: {
- pricingPlans?: ReturnType;
- setStep: (step: number) => void;
- }) => {
- const { colors } = useThemeColors();
- const { width } = useWindowDimensions();
- const isTablet = width > 600;
-
- return (
-
-
- {["Features", "Free", "Essential", "Pro", "Believer"].map(
- (plan, index) => (
-
- {plan}
-
- )
- )}
-
-
- {getFeaturesTable().map((item, keyIndex) => {
- return (
-
- {item.map((featureItem, index) => (
-
- {typeof featureItem === "string" ? (
-
- {featureItem as string}
-
- ) : (
- <>
- {typeof featureItem.caption === "string" ||
- typeof featureItem.caption === "number" ? (
-
- {featureItem.caption === "infinity"
- ? "∞"
- : featureItem.caption}
-
- ) : typeof featureItem.caption === "boolean" ? (
- <>
- {featureItem.caption === true ? (
-
- ) : (
-
- )}
- >
- ) : null}
- >
- )}
-
- ))}
-
- );
- })}
-
-
- {["features", "free", "essential", "pro", "believer"].map(
- (plan, index) => (
-
- {plan !== "free" && plan !== "features" ? (
-
- )
- )}
-
-
- );
- },
- () => true
-);
-ComparePlans.displayName = "ComparePlans";
-
-const ReviewItem = (props: {
- review: string;
- user: string;
- link: string;
- userImage?: string;
-}) => {
- const { colors } = useThemeColors();
- return (
-
- {
- openLinkInBrowser(props.link);
- }}
- style={{
- textAlign: "center"
- }}
- size={AppFontSize.md}
- >
- {props.review}
-
-
-
- {props.userImage ? (
-
- ) : null}
- {props.user}
-
-
- );
-};
-const PricingPlanCard = ({
- plan,
- pricingPlans,
- annualBilling,
- setStep
-}: {
- plan: PricingPlan;
- pricingPlans?: ReturnType;
- annualBilling?: boolean;
- setStep: (step: number) => void;
-}) => {
- const { colors } = useThemeColors();
- const regionalDiscount =
- annualBilling && plan.id === "pro"
- ? pricingPlans?.regionalDiscount
- : undefined;
- const { width } = useWindowDimensions();
- const isTablet = width > 600;
-
- const product =
- plan.subscriptions?.[
- regionalDiscount?.sku ||
- `notesnook.${plan.id}.${annualBilling ? "yearly" : "monthly"}`
- ];
-
- const WebPlan = pricingPlans?.getWebPlan(
- plan.id,
- annualBilling ? "yearly" : "monthly"
- );
-
- const price = pricingPlans?.getPrice(
- pricingPlans.isGithubRelease && WebPlan
- ? WebPlan
- : (product as RNIap.Subscription),
- pricingPlans.hasTrialOffer(plan.id, product?.productId) ? 1 : 0,
- annualBilling
- );
-
- const isSubscribed =
- product?.productId &&
- pricingPlans?.user?.subscription?.productId?.includes(plan.id) &&
- pricingPlans.isSubscribed();
-
- const isNotReady =
- pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross);
-
- return (
- {
- if (isNotReady) return;
- const currentPlanSubscribed =
- PremiumService.get() &&
- (pricingPlans?.user?.subscription?.productId ===
- (product as RNIap.Subscription)?.productId ||
- pricingPlans?.user?.subscription?.productId?.startsWith(
- (product as RNIap.Subscription)?.productId
- ));
- pricingPlans?.selectPlan(
- plan.id,
- currentPlanSubscribed
- ? `notesnook.${plan.id}.${
- !(product as RNIap.Subscription)?.productId.includes("yearly")
- ? "yearly"
- : "monthly"
- }`
- : pricingPlans.isGithubRelease
- ? (WebPlan?.period as string)
- : (product?.productId as string)
- );
- setStep(Steps.buy);
- }}
- style={{
- ...getElevationStyle(3),
- backgroundColor: colors.primary.background,
- borderWidth: 1,
- borderColor:
- plan.id === "pro" ? colors.primary.accent : colors.primary.border,
- borderRadius: 10,
- padding: 16,
- width: isTablet ? undefined : "100%",
- flexShrink: isTablet ? 1 : undefined,
- flexDirection: "column",
- justifyContent: "space-between",
- gap: 6
- }}
- >
- {regionalDiscount?.discount || WebPlan?.discount ? (
-
-
- {strings.specialOffer()}{" "}
- {strings.percentOff(
- `${regionalDiscount?.discount || WebPlan?.discount?.amount}`
- )}
-
-
- ) : null}
-
-
-
- {plan.name}{" "}
- {plan.recommended ? (
-
- ({strings.recommended()})
-
- ) : null}
-
- {plan.description}
-
-
-
- {strings.storage()}
-
-
- {PlanOverView[plan.id as keyof typeof PlanOverView].storage}
-
-
-
-
- {strings.fileSize()}
-
-
- {PlanOverView[plan.id as keyof typeof PlanOverView].fileSize}
-
-
-
-
- {strings.hdImages()}
-
-
- {PlanOverView[plan.id as keyof typeof PlanOverView].hdImages
- ? strings.yes()
- : strings.no()}
-
-
-
-
-
- {pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross) ? (
-
- ) : (
-
-
- {price || `${WebPlan?.price?.currency} ${WebPlan?.price?.gross}`}{" "}
- /{strings.month()}
-
-
- {!product && !WebPlan ? null : (
-
- {annualBilling
- ? strings.billedAnnually(
- pricingPlans?.getStandardPrice(
- (product || WebPlan) as any
- ) as string
- )
- : strings.billedMonthly(
- pricingPlans?.getStandardPrice(
- (product || WebPlan) as any
- ) as string
- )}
-
- )}
-
- {isSubscribed ? (
-
-
- {strings.currentPlan()}
-
-
- ) : null}
-
- )}
-
- );
-};
-
export default PayWall;
diff --git a/apps/mobile/app/components/paywall/plan-card.tsx b/apps/mobile/app/components/paywall/plan-card.tsx
new file mode 100644
index 000000000..fff3428ab
--- /dev/null
+++ b/apps/mobile/app/components/paywall/plan-card.tsx
@@ -0,0 +1,332 @@
+/*
+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 .
+*/
+
+import { SKUResponse } from "@notesnook/core";
+import { strings } from "@notesnook/intl";
+import { useThemeColors } from "@notesnook/theme";
+import React, { useEffect, useState } from "react";
+import {
+ ActivityIndicator,
+ Text,
+ useWindowDimensions,
+ View
+} from "react-native";
+import * as RNIap from "react-native-iap";
+//@ts-ignore
+import usePricingPlans, {
+ PlanOverView,
+ PricingPlan
+} from "../../hooks/use-pricing-plans";
+import PremiumService from "../../services/premium";
+import { getElevationStyle } from "../../utils/elevation";
+import { AppFontSize, defaultBorderRadius } from "../../utils/size";
+import Heading from "../ui/typography/heading";
+import Paragraph from "../ui/typography/paragraph";
+import { Steps } from "./common";
+import { Radius, Spacing } from "../../common/design/spacing";
+import AppIcon from "../ui/AppIcon";
+import { Button } from "../ui/button";
+
+export const PricingPlanCard = ({
+ plan,
+ pricingPlans,
+ annualBilling,
+ setStep
+}: {
+ plan: PricingPlan;
+ pricingPlans?: ReturnType;
+ annualBilling?: boolean;
+ setStep: (step: number) => void;
+}) => {
+ const { colors } = useThemeColors();
+ const [regionalDiscount, setRegionaDiscount] = useState();
+ const { width } = useWindowDimensions();
+ const isTablet = width > 600;
+
+ const product =
+ plan.subscriptions?.[
+ regionalDiscount?.sku ||
+ `notesnook.${plan.id}.${annualBilling ? "yearly" : "monthly"}`
+ ];
+
+ const WebPlan = pricingPlans?.getWebPlan(
+ plan.id,
+ annualBilling ? "yearly" : "monthly"
+ );
+
+ const price = pricingPlans?.getPrice(
+ pricingPlans.isGithubRelease && WebPlan
+ ? WebPlan
+ : (product as RNIap.Subscription),
+ pricingPlans.hasTrialOffer(plan.id, product?.productId) ? 1 : 0,
+ annualBilling
+ );
+
+ useEffect(() => {
+ if (pricingPlans?.isGithubRelease || !annualBilling) return;
+ pricingPlans
+ ?.getRegionalDiscount(
+ plan.id,
+ pricingPlans.isGithubRelease
+ ? (WebPlan?.period as string)
+ : `notesnook.${plan.id}.${annualBilling ? "yearly" : "monthly"}`
+ )
+ .then((value) => {
+ setRegionaDiscount(value);
+ });
+ }, [WebPlan?.period, annualBilling, plan.id, pricingPlans]);
+
+ useEffect(() => {
+ if (!annualBilling) {
+ setRegionaDiscount(undefined);
+ }
+ }, [annualBilling]);
+
+ const isSubscribed =
+ product?.productId &&
+ pricingPlans?.user?.subscription?.productId?.includes(plan.id) &&
+ pricingPlans.isSubscribed();
+
+ const isNotReady =
+ pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross);
+
+ return (
+
+
+
+ {plan.name}
+
+
+ {isSubscribed ? (
+
+
+ {strings.currentPlan()}
+
+
+ ) : (
+ <>
+ {regionalDiscount?.discount || WebPlan?.discount ? (
+
+
+ {strings.percentOff(
+ `${regionalDiscount?.discount || WebPlan?.discount?.amount}`
+ )}
+
+
+ ) : null}
+
+ {plan.recommended ? (
+
+
+ {strings.recommended()}
+
+
+ ) : null}
+ >
+ )}
+
+
+
+ {plan.description}
+
+
+ {pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross) ? (
+
+ ) : (
+
+
+ {price ||
+ `${WebPlan?.price?.currency} ${WebPlan?.price?.gross}`}{" "}
+
+ /{strings.month()}
+
+
+
+ {!product && !WebPlan ? null : (
+
+ {annualBilling
+ ? strings.billedAnnually(
+ pricingPlans?.getStandardPrice(
+ (product || WebPlan) as any
+ ) as string
+ )
+ : strings.billedMonthly(
+ pricingPlans?.getStandardPrice(
+ (product || WebPlan) as any
+ ) as string
+ )}
+
+ )}
+
+ )}
+
+
+
+ {Object.keys(PlanOverView[plan.id as keyof typeof PlanOverView]).map(
+ (item) => (
+
+
+
+
+ {strings[item as "storage" | "hdImages" | "fileSize"]()}
+
+
+
+
+ {
+ PlanOverView[plan.id as keyof typeof PlanOverView][
+ item as "storage" | "hdImages" | "fileSize"
+ ]
+ }
+
+
+ )
+ )}
+
+
+
+
+ );
+};
diff --git a/apps/mobile/app/components/paywall/review-item.tsx b/apps/mobile/app/components/paywall/review-item.tsx
new file mode 100644
index 000000000..e5e8a2872
--- /dev/null
+++ b/apps/mobile/app/components/paywall/review-item.tsx
@@ -0,0 +1,84 @@
+/*
+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 .
+*/
+
+import { useThemeColors } from "@notesnook/theme";
+import React from "react";
+import { Image, TouchableOpacity, View } from "react-native";
+//@ts-ignore
+import { openLinkInBrowser } from "../../utils/functions";
+import { AppFontSize } from "../../utils/size";
+import Paragraph from "../ui/typography/paragraph";
+import { Radius, Spacing } from "../../common/design/spacing";
+import Heading from "../ui/typography/heading";
+
+export const ReviewItem = (props: {
+ review: string;
+ user: string;
+ userSource: string;
+ link: string;
+ userImage?: string;
+}) => {
+ const { colors } = useThemeColors();
+ return (
+ {
+ openLinkInBrowser(props.link);
+ }}
+ style={{
+ width: "100%",
+ padding: Spacing.LEVEL_4,
+ borderWidth: 1,
+ backgroundColor: colors.secondary.background,
+ borderRadius: Radius.LG,
+ borderColor: colors.primary.border
+ }}
+ >
+
+ {props.userImage ? (
+
+ ) : null}
+
+ {props.user}
+
+ {props.userSource}
+
+
+
+
+ {props.review}
+
+ );
+};
diff --git a/apps/mobile/app/components/sheets/buy-plan/index.tsx b/apps/mobile/app/components/sheets/buy-plan/index.tsx
index 50eed6e07..cc9526f5f 100644
--- a/apps/mobile/app/components/sheets/buy-plan/index.tsx
+++ b/apps/mobile/app/components/sheets/buy-plan/index.tsx
@@ -23,7 +23,6 @@ import dayjs from "dayjs";
import React, { useState } from "react";
import {
Linking,
- Platform,
ScrollView,
Text,
TouchableOpacity,
@@ -41,12 +40,15 @@ import { DefaultAppStyles } from "../../../utils/styles";
import { Button } from "../../ui/button";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
+import { Radius, Spacing } from "../../../common/design/spacing";
+import useGlobalSafeAreaInsets from "../../../hooks/use-global-safe-area-insets";
const isGithubRelease = Config.GITHUB_RELEASE === "true";
export const BuyPlan = (props: {
planId: string;
canActivateTrial?: boolean;
pricingPlans: ReturnType;
}) => {
+ const insets = useGlobalSafeAreaInsets();
const { colors } = useThemeColors();
const [checkoutUrl, setCheckoutUrl] = useState();
const pricingPlans = props.pricingPlans;
@@ -63,6 +65,18 @@ export const BuyPlan = (props: {
: (pricingPlans.selectedProduct as RNIap.Product)?.productId
)?.includes("5");
+ const isAnnual = isGithubRelease
+ ? (pricingPlans.selectedProduct as Plan)?.period === "yearly"
+ : (pricingPlans.selectedProduct as RNIap.Product)?.productId?.includes(
+ "yearly"
+ );
+
+ const hasTrialOffer = pricingPlans.hasTrialOffer(
+ props.planId,
+ (pricingPlans.selectedProduct as RNIap.Product)?.productId ||
+ (pricingPlans.selectedProduct as Plan)?.period
+ );
+
return checkoutUrl ? (
) : (
-
-
- {[
- Config.GITHUB_RELEASE === "true"
- ? "yearly"
- : `notesnook.${props.planId}.yearly`,
- Config.GITHUB_RELEASE === "true"
- ? "monthly"
- : `notesnook.${props.planId}.monthly`,
- ...(props.planId === "essential" || pricingPlans.isSubscribed()
- ? []
- : [
- Config.GITHUB_RELEASE === "true"
- ? "5-year"
- : `notesnook.${props.planId}.5year`
- ])
- ].map((item) => (
-
- ))}
-
-
- {strings.dueToday()}{" "}
- {pricingPlans.hasTrialOffer(
- props.planId,
- (pricingPlans?.selectedProduct as RNIap.Product)?.productId ||
- (pricingPlans?.selectedProduct as Plan)?.period
- ) ? (
-
- ({strings.daysFree(`${billingDuration?.duration || 0}`)})
-
- ) : null}
-
-
-
- {pricingPlans.hasTrialOffer(
- props.planId,
- (pricingPlans?.selectedProduct as RNIap.Product)?.productId ||
- (pricingPlans?.selectedProduct as Plan)?.period
- )
- ? "FREE"
- : pricingPlans.getStandardPrice(
- pricingPlans.selectedProduct as RNIap.Subscription
- )}
-
-
-
- {pricingPlans.hasTrialOffer(
- props.planId,
- (pricingPlans?.selectedProduct as RNIap.Product)?.productId ||
- (pricingPlans?.selectedProduct as Plan)?.period
- ) ? (
-
- {strings.due(
- dayjs()
- .add(billingDuration?.duration || 0, "day")
- .format("DD MMMM")
- )}
-
-
- {pricingPlans.getStandardPrice(
- pricingPlans.selectedProduct as RNIap.Subscription
- )}
-
-
- ) : null}
-
- {pricingPlans.hasTrialOffer(
- props.planId,
- (pricingPlans.selectedProduct as RNIap.Product)?.productId ||
- (pricingPlans.selectedProduct as Plan)?.period
- ) || is5YearPlanSelected ? (
-
- {(is5YearPlanSelected
- ? strings["5yearPlanConditions"]()
- : [
- strings.trialPlanConditions[0](
- billingDuration?.duration as number as never
- ),
- ...(isGithubRelease
- ? []
- : [strings.trialPlanConditions[1](Platform.OS as never)])
- ]
- ).map((item) => (
- (
+
-
-
- {item}
-
-
+ pricingPlans={pricingPlans}
+ productId={item}
+ />
))}
- ) : null}
+
+ {strings.paymentSummary()}
+
+
+
+
+
+
+ {strings.dueToday()}{" "}
+
+
+ {hasTrialOffer ? (
+
+ {strings.freeTrialIncludes(
+ billingDuration?.duration || 0
+ )}
+
+ ) : is5YearPlanSelected ? (
+ strings.billingType.annual()
+ ) : null}
+
+
+
+
+ {hasTrialOffer
+ ? "Free"
+ : pricingPlans.getStandardPrice(
+ pricingPlans.selectedProduct as RNIap.Subscription
+ )}
+
+
+
+ {hasTrialOffer ? (
+ <>
+
+
+
+
+
+ {strings.nextBillingDate()}
+
+
+ {dayjs()
+ .add(billingDuration?.duration || 0, "day")
+ .format("DD MMMM,YYYY")}{" "}
+ *{" "}
+ {isAnnual
+ ? strings.billingType.annual()
+ : is5YearPlanSelected
+ ? strings.billingType.oneTime()
+ : strings.billingType.monthly()}
+
+
+
+
+ {pricingPlans.getStandardPrice(
+ pricingPlans.selectedProduct as RNIap.Subscription
+ )}
+
+
+ >
+ ) : null}
+
+
+
+ {strings.whatsIncluded()}
+
+
+
+ {[
+ strings.planWhatsIncluded.unlimitedNotes(),
+ strings.planWhatsIncluded.endToEnd(),
+ strings.planWhatsIncluded.allDevices(),
+ hasTrialOffer
+ ? strings.planWhatsIncluded.freeTrial(
+ billingDuration?.duration || 0
+ )
+ : undefined,
+ hasTrialOffer ? strings.planWhatsIncluded.remind() : undefined,
+ ...(is5YearPlanSelected
+ ? strings["5yearPlanConditions"]()
+ : ([] as string[]))
+ ].map((item) =>
+ !item ? null : (
+
+
+
+ {item}
+
+
+ )
+ )}
+
+
+ {strings.note()}:
+ {is5YearPlanSelected
+ ? strings.oneTimePurchase()
+ : strings.cancelAnytimeAlt()}
+
+
+
+
+ {strings.subTerms[0]()}{" "}
+ {
+ openLinkInBrowser("https://notesnook.com/privacy");
+ }}
+ >
+ {strings.subTerms[1]()}
+ {" "}
+ {strings.subTerms[2]()}{" "}
+ {
+ openLinkInBrowser("https://notesnook.com/tos");
+ }}
+ >
+ {strings.subTerms[3]()}
+
+
+
+
+
+
-
-
- {is5YearPlanSelected
- ? strings.oneTimePurchase()
- : strings.cancelAnytimeAlt()}
-
-
- {strings.subTerms[0]()}{" "}
- {
- openLinkInBrowser("https://notesnook.com/privacy");
- }}
- >
- {strings.subTerms[1]()}
- {" "}
- {strings.subTerms[2]()}{" "}
- {
- openLinkInBrowser("https://notesnook.com/tos");
- }}
- >
- {strings.subTerms[3]()}
-
-
-
+
);
};
@@ -389,7 +473,13 @@ const ProductItem = (props: {
style={{
flexDirection: "row",
gap: 10,
- opacity: isSubscribed ? 0.5 : 1
+ opacity: isSubscribed ? 0.5 : 1,
+ backgroundColor: colors.secondary.background,
+ padding: Spacing.LEVEL_2,
+ borderRadius: Radius.S,
+ borderWidth: 1,
+ borderColor: colors.primary.border,
+ justifyContent: "space-between"
}}
activeOpacity={0.9}
onPress={() => {
@@ -408,60 +498,85 @@ const ProductItem = (props: {
);
}}
>
-
-
+
+
-
- {isAnnual
- ? strings.yearly()
- : is5YearProduct
- ? strings.fiveYearPlan()
- : strings.monthly()}
-
+
+
+ {isAnnual
+ ? strings.yearly()
+ : is5YearProduct
+ ? strings.fiveYearPlan()
+ : strings.monthly()}
+
- {discountValue ? (
-
-
- {strings.bestValue()} - {strings.percentOff(`${discountValue}`)}
-
-
- ) : null}
+ {discountValue ? (
+
+
+ {strings.percentOff(`${discountValue}`)}
+
+
+ ) : null}
- {isSubscribed ? (
-
-
- {strings.currentPlan()}
-
-
- ) : null}
+ {isSubscribed ? (
+
+
+ {strings.currentPlan()}
+
+
+ ) : null}
+
+
+
+ {is5YearProduct
+ ? strings.billingType.oneTime()
+ : isAnnual
+ ? strings.billingType.annual()
+ : strings.billingType.monthly()}
+
+
-
+
+
{isAnnual || is5YearProduct
? `${props.pricingPlans.getPrice(
product as RNIap.Subscription,
@@ -472,15 +587,17 @@ const ProductItem = (props: {
? 1
: 0,
isAnnual
- )}/${strings.month()}`
+ )}`
: null}
{!isAnnual && !is5YearProduct
? `${props.pricingPlans.getStandardPrice(
product as RNIap.Subscription
- )}/${strings.month()}`
+ )}`
: null}
-
+
+
+ /month
);
diff --git a/apps/mobile/app/hooks/use-pricing-plans.ts b/apps/mobile/app/hooks/use-pricing-plans.ts
index 5b746a480..beca4d2ac 100644
--- a/apps/mobile/app/hooks/use-pricing-plans.ts
+++ b/apps/mobile/app/hooks/use-pricing-plans.ts
@@ -37,22 +37,22 @@ export const PlanOverView = {
free: {
storage: `50 MB/mo`,
fileSize: `1 MB`,
- hdImages: false
+ hdImages: "No"
},
essential: {
storage: `1 GB`,
fileSize: `100 MB/mo`,
- hdImages: false
+ hdImages: "No"
},
pro: {
storage: `10 GB/mo`,
fileSize: `1 GB`,
- hdImages: true
+ hdImages: "Yes"
},
believer: {
storage: `25 GB/mo`,
fileSize: `5 GB`,
- hdImages: true
+ hdImages: "Yes"
}
};
diff --git a/apps/mobile/app/utils/size/index.js b/apps/mobile/app/utils/size/index.js
index 17eb064ca..cd58367fa 100644
--- a/apps/mobile/app/utils/size/index.js
+++ b/apps/mobile/app/utils/size/index.js
@@ -90,7 +90,7 @@ function getSize() {
return {
xxxs: FontSizes.XXS,
xxs: FontSizes.XXS,
- xs: FontSizes.XX,
+ xs: FontSizes.XS,
sm: FontSizes.SM,
md: FontSizes.MD,
lg: FontSizes.LG,
diff --git a/apps/mobile/fonts/MaterialCommunityIcons.ttf b/apps/mobile/fonts/MaterialCommunityIcons.ttf
index 7bfc48b13..a3aebc48d 100644
Binary files a/apps/mobile/fonts/MaterialCommunityIcons.ttf and b/apps/mobile/fonts/MaterialCommunityIcons.ttf differ
diff --git a/apps/mobile/scripts/optimize-fonts.mjs b/apps/mobile/scripts/optimize-fonts.mjs
index 9bf4890a7..225a37c7d 100644
--- a/apps/mobile/scripts/optimize-fonts.mjs
+++ b/apps/mobile/scripts/optimize-fonts.mjs
@@ -128,7 +128,8 @@ const EXTRA_ICON_NAMES = [
"identifier",
"image-area",
"clock-outline",
- "delete-sweep-outline"
+ "delete-sweep-outline",
+ "image-outline"
];
const __filename = fileURLToPath(import.meta.url);
diff --git a/packages/intl/locale/en.po b/packages/intl/locale/en.po
index 5e6721f62..e2ecfbcad 100644
--- a/packages/intl/locale/en.po
+++ b/packages/intl/locale/en.po
@@ -1,6 +1,6 @@
msgid ""
msgstr ""
-"POT-Creation-Date: 2026-06-16 13:03+0500\n"
+"POT-Creation-Date: 2026-06-16 13:04+0500\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -502,6 +502,10 @@ msgstr "{days, plural, one {1 day} other {# days}}"
msgid "{days} days free"
msgstr "{days} days free"
+#: src/strings.ts:2828
+msgid "{duration} days free trial includes all features"
+msgstr "{duration} days free trial includes all features"
+
#: src/strings.ts:351
msgid "{freq, plural, one {Repeats every day on {selectedDays} at {date}} other {Repeats every # day every {selectedDays} at {date}}}"
msgstr "{freq, plural, one {Repeats every day on {selectedDays} at {date}} other {Repeats every # day every {selectedDays} at {date}}}"
@@ -639,8 +643,8 @@ msgid "2FA code sent via {method}"
msgstr "2FA code sent via {method}"
#: src/strings.ts:2611
-msgid "5 year plan (One time purchase)"
-msgstr "5 year plan (One time purchase)"
+msgid "5 year plan"
+msgstr "5 year plan"
#: src/strings.ts:1861
msgid "6 digit code"
@@ -666,6 +670,10 @@ msgstr "Abc"
msgid "About"
msgstr "About"
+#: src/strings.ts:2822
+msgid "Access on all devices"
+msgstr "Access on all devices"
+
#: src/strings.ts:1040
msgid "Account"
msgstr "Account"
@@ -1292,10 +1300,18 @@ msgstr "Beta"
msgid "Bi-directional note link"
msgstr "Bi-directional note link"
+#: src/strings.ts:2813
+msgid "Billed annually"
+msgstr "Billed annually"
+
#: src/strings.ts:2581
msgid "billed annually at {price}"
msgstr "billed annually at {price}"
+#: src/strings.ts:2814
+msgid "Billed monthly"
+msgstr "Billed monthly"
+
#: src/strings.ts:2582
msgid "billed monthly at {price}"
msgstr "billed monthly at {price}"
@@ -2010,8 +2026,8 @@ msgid "Create a tag to group related notes together."
msgstr "Create a tag to group related notes together."
#: src/strings.ts:1865
-msgid "Create account"
-msgstr "Create account"
+msgid "Create Account"
+msgstr "Create Account"
#: src/strings.ts:2684
msgid "Create API Key"
@@ -2108,8 +2124,8 @@ msgid "Current pin"
msgstr "Current pin"
#: src/strings.ts:1789
-msgid "CURRENT PLAN"
-msgstr "CURRENT PLAN"
+msgid "Current Plan"
+msgstr "Current Plan"
#: src/strings.ts:2026
msgid "Custom"
@@ -2716,6 +2732,10 @@ msgstr "Encryption key"
msgid "End-to-end encrypted."
msgstr "End-to-end encrypted."
+#: src/strings.ts:2821
+msgid "End-to-end encryption (XChaCha20)"
+msgstr "End-to-end encryption (XChaCha20)"
+
#: src/strings.ts:399
msgid "Enter 6 digit code"
msgstr "Enter 6 digit code"
@@ -3249,6 +3269,10 @@ msgstr ""
msgid "Forgot password?"
msgstr "Forgot password?"
+#: src/strings.ts:2823
+msgid "Free {days} days trial, cancel anytime"
+msgstr "Free {days} days trial, cancel anytime"
+
#: src/strings.ts:2591
msgid "Free {duration} day trial, cancel any time"
msgstr "Free {duration} day trial, cancel any time"
@@ -3257,6 +3281,10 @@ msgstr "Free {duration} day trial, cancel any time"
msgid "Free plan"
msgstr "Free plan"
+#: src/strings.ts:2810
+msgid "Frequently Asked Questions"
+msgstr "Frequently Asked Questions"
+
#: src/strings.ts:627
msgid "Fri"
msgstr "Fri"
@@ -3418,8 +3446,8 @@ msgid "Having problems with sync?"
msgstr "Having problems with sync?"
#: src/strings.ts:2580
-msgid "hdImages"
-msgstr "hdImages"
+msgid "HD Images"
+msgstr "HD Images"
#: src/strings.ts:2376
msgid "Heading {level}"
@@ -4414,6 +4442,10 @@ msgstr "Newly created notes will be uncategorized"
msgid "Next"
msgstr "Next"
+#: src/strings.ts:2826
+msgid "Next Billing Date"
+msgstr "Next Billing Date"
+
#: src/strings.ts:2405
msgid "Next match"
msgstr "Next match"
@@ -4719,6 +4751,10 @@ msgstr "Oldest - newest"
msgid "Once your password is changed, please make sure to save the new account recovery key"
msgstr "Once your password is changed, please make sure to save the new account recovery key"
+#: src/strings.ts:2815
+msgid "One time purchase"
+msgstr "One time purchase"
+
#: src/strings.ts:2587
msgid "One time purchase, no auto-renewal"
msgstr "One time purchase, no auto-renewal"
@@ -4904,6 +4940,10 @@ msgstr "Pay once and use for 5 years"
msgid "Payment method"
msgstr "Payment method"
+#: src/strings.ts:2818
+msgid "Payment summary"
+msgstr "Payment summary"
+
#: src/strings.ts:788
msgid "PDF is password protected"
msgstr "PDF is password protected"
@@ -5529,6 +5569,10 @@ msgstr "Relogin to your account"
msgid "Remembered your password?"
msgstr "Remembered your password?"
+#: src/strings.ts:2824
+msgid "Remind before your trial ends"
+msgstr "Remind before your trial ends"
+
#: src/strings.ts:941
msgid "Remind me"
msgstr "Remind me"
@@ -6137,6 +6181,10 @@ msgstr "Select notes to link to \"{title}\""
msgid "Select nth day of the month to repeat the reminder."
msgstr "Select nth day of the month to repeat the reminder."
+#: src/strings.ts:2809
+msgid "Select Plan"
+msgstr "Select Plan"
+
#: src/strings.ts:1833
msgid "Select profile picture"
msgstr "Select profile picture"
@@ -6822,6 +6870,10 @@ msgstr "Test connection"
msgid "Test connection before changing server urls"
msgstr "Test connection before changing server urls"
+#: src/strings.ts:2811
+msgid "Testimonials"
+msgstr "Testimonials"
+
#: src/strings.ts:2309
msgid "Text color"
msgstr "Text color"
@@ -7118,8 +7170,8 @@ msgid "Turns off syncing completely on this device. Any changes made will remain
msgstr "Turns off syncing completely on this device. Any changes made will remain local only and new changes from your other devices won't sync to this device."
#: src/strings.ts:110
-msgid "Two factor authentication"
-msgstr "Two factor authentication"
+msgid "Two Factor Authentication"
+msgstr "Two Factor Authentication"
#: src/strings.ts:494
msgid "Two-factor authentication"
@@ -7165,6 +7217,10 @@ msgstr "Unfavorite"
msgid "Unlimited"
msgstr "Unlimited"
+#: src/strings.ts:2820
+msgid "Unlimited notes and attachments"
+msgstr "Unlimited notes and attachments"
+
#: src/strings.ts:946
msgid "Unlink from all"
msgstr "Unlink from all"
@@ -7664,6 +7720,10 @@ msgstr "What is your refund policy?"
msgid "What went wrong?"
msgstr "What went wrong?"
+#: src/strings.ts:2817
+msgid "What's included"
+msgstr "What's included"
+
#: src/strings.ts:2536
msgid "Why do you need my credit card details for a free trial?"
msgstr "Why do you need my credit card details for a free trial?"
diff --git a/packages/intl/locale/pseudo-LOCALE.po b/packages/intl/locale/pseudo-LOCALE.po
index 402a79c22..1a137772f 100644
--- a/packages/intl/locale/pseudo-LOCALE.po
+++ b/packages/intl/locale/pseudo-LOCALE.po
@@ -1,6 +1,6 @@
msgid ""
msgstr ""
-"POT-Creation-Date: 2026-06-16 13:03+0500\n"
+"POT-Creation-Date: 2026-06-16 13:04+0500\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -502,6 +502,10 @@ msgstr ""
msgid "{days} days free"
msgstr ""
+#: src/strings.ts:2828
+msgid "{duration} days free trial includes all features"
+msgstr ""
+
#: src/strings.ts:351
msgid "{freq, plural, one {Repeats every day on {selectedDays} at {date}} other {Repeats every # day every {selectedDays} at {date}}}"
msgstr ""
@@ -639,7 +643,7 @@ msgid "2FA code sent via {method}"
msgstr ""
#: src/strings.ts:2611
-msgid "5 year plan (One time purchase)"
+msgid "5 year plan"
msgstr ""
#: src/strings.ts:1861
@@ -666,6 +670,10 @@ msgstr ""
msgid "About"
msgstr ""
+#: src/strings.ts:2822
+msgid "Access on all devices"
+msgstr ""
+
#: src/strings.ts:1040
msgid "Account"
msgstr ""
@@ -1292,10 +1300,18 @@ msgstr ""
msgid "Bi-directional note link"
msgstr ""
+#: src/strings.ts:2813
+msgid "Billed annually"
+msgstr ""
+
#: src/strings.ts:2581
msgid "billed annually at {price}"
msgstr ""
+#: src/strings.ts:2814
+msgid "Billed monthly"
+msgstr ""
+
#: src/strings.ts:2582
msgid "billed monthly at {price}"
msgstr ""
@@ -1999,7 +2015,7 @@ msgid "Create a tag to group related notes together."
msgstr ""
#: src/strings.ts:1865
-msgid "Create account"
+msgid "Create Account"
msgstr ""
#: src/strings.ts:2684
@@ -2097,7 +2113,7 @@ msgid "Current pin"
msgstr ""
#: src/strings.ts:1789
-msgid "CURRENT PLAN"
+msgid "Current Plan"
msgstr ""
#: src/strings.ts:2026
@@ -2705,6 +2721,10 @@ msgstr ""
msgid "End-to-end encrypted."
msgstr ""
+#: src/strings.ts:2821
+msgid "End-to-end encryption (XChaCha20)"
+msgstr ""
+
#: src/strings.ts:399
msgid "Enter 6 digit code"
msgstr ""
@@ -3231,6 +3251,10 @@ msgstr ""
msgid "Forgot password?"
msgstr ""
+#: src/strings.ts:2823
+msgid "Free {days} days trial, cancel anytime"
+msgstr ""
+
#: src/strings.ts:2591
msgid "Free {duration} day trial, cancel any time"
msgstr ""
@@ -3239,6 +3263,10 @@ msgstr ""
msgid "Free plan"
msgstr ""
+#: src/strings.ts:2810
+msgid "Frequently Asked Questions"
+msgstr ""
+
#: src/strings.ts:627
msgid "Fri"
msgstr ""
@@ -3400,7 +3428,7 @@ msgid "Having problems with sync?"
msgstr ""
#: src/strings.ts:2580
-msgid "hdImages"
+msgid "HD Images"
msgstr ""
#: src/strings.ts:2376
@@ -4394,6 +4422,10 @@ msgstr ""
msgid "Next"
msgstr ""
+#: src/strings.ts:2826
+msgid "Next Billing Date"
+msgstr ""
+
#: src/strings.ts:2405
msgid "Next match"
msgstr ""
@@ -4693,6 +4725,10 @@ msgstr ""
msgid "Once your password is changed, please make sure to save the new account recovery key"
msgstr ""
+#: src/strings.ts:2815
+msgid "One time purchase"
+msgstr ""
+
#: src/strings.ts:2587
msgid "One time purchase, no auto-renewal"
msgstr ""
@@ -4878,6 +4914,10 @@ msgstr ""
msgid "Payment method"
msgstr ""
+#: src/strings.ts:2818
+msgid "Payment summary"
+msgstr ""
+
#: src/strings.ts:788
msgid "PDF is password protected"
msgstr ""
@@ -5503,6 +5543,10 @@ msgstr ""
msgid "Remembered your password?"
msgstr ""
+#: src/strings.ts:2824
+msgid "Remind before your trial ends"
+msgstr ""
+
#: src/strings.ts:941
msgid "Remind me"
msgstr ""
@@ -6111,6 +6155,10 @@ msgstr ""
msgid "Select nth day of the month to repeat the reminder."
msgstr ""
+#: src/strings.ts:2809
+msgid "Select Plan"
+msgstr ""
+
#: src/strings.ts:1833
msgid "Select profile picture"
msgstr ""
@@ -6781,6 +6829,10 @@ msgstr ""
msgid "Test connection before changing server urls"
msgstr ""
+#: src/strings.ts:2811
+msgid "Testimonials"
+msgstr ""
+
#: src/strings.ts:2309
msgid "Text color"
msgstr ""
@@ -7077,7 +7129,7 @@ msgid "Turns off syncing completely on this device. Any changes made will remain
msgstr ""
#: src/strings.ts:110
-msgid "Two factor authentication"
+msgid "Two Factor Authentication"
msgstr ""
#: src/strings.ts:494
@@ -7124,6 +7176,10 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+#: src/strings.ts:2820
+msgid "Unlimited notes and attachments"
+msgstr ""
+
#: src/strings.ts:946
msgid "Unlink from all"
msgstr ""
@@ -7614,6 +7670,10 @@ msgstr ""
msgid "What went wrong?"
msgstr ""
+#: src/strings.ts:2817
+msgid "What's included"
+msgstr ""
+
#: src/strings.ts:2536
msgid "Why do you need my credit card details for a free trial?"
msgstr ""
diff --git a/packages/intl/src/strings.ts b/packages/intl/src/strings.ts
index 8a0133323..5eea7c97e 100644
--- a/packages/intl/src/strings.ts
+++ b/packages/intl/src/strings.ts
@@ -107,7 +107,7 @@ export const strings = {
},
alreadyHaveAccount: () => t`Already have an account?`,
login: () => t`Login`,
- "2fa": () => t`Two factor authentication`,
+ "2fa": () => t`Two Factor Authentication`,
select2faMethod: () => t`Select method for two-factor authentication`,
select2faCodeHelpText: () => t`Select how you would like to recieve the code`,
"2faCodeHelpText": {
@@ -1786,7 +1786,7 @@ For example:
dragAndDropFiles: () => t`Drag & drop files here, or click to select files`,
onlyZipSupported: () => t`Only .zip files are supported.`,
clickToRemove: () => t`Click to remove`,
- currentPlan: () => t`CURRENT PLAN`,
+ currentPlan: () => t`Current Plan`,
appWillReloadIn: (sec: number) => t`App will reload in ${sec} seconds`,
changesReflectOnStart: () =>
t`Your changes have been saved and will be reflected after the app has refreshed.`,
@@ -1862,7 +1862,7 @@ For example:
newEmail: () => t`New Email`,
accountPassword: () => t`Account password`,
phoneNumber: () => t`Phone number`,
- createAccount: () => t`Create account`,
+ createAccount: () => t`Create Account`,
accountRecoverHelpText: () =>
t`You will receive instructions on how to recover your account on this email`,
enterRecoveryKey: () => t`Enter account recovery key`,
@@ -2577,7 +2577,7 @@ Use this if changes from other devices are not appearing on this device. This wi
thankYouForSubscribing: () => t`Thank you for subscribing`,
settingUpPlan: () =>
t`We’re setting up your plan right now. We’ll notify you as soon as everything is ready.`,
- hdImages: () => t`hdImages`,
+ hdImages: () => t`HD Images`,
billedAnnually: (price: string) => t`billed annually at ${price}`,
billedMonthly: (price: string) => t`billed monthly at ${price}`,
dueToday: () => t`Due today`,
@@ -2608,7 +2608,7 @@ Use this if changes from other devices are not appearing on this device. This wi
bestValue: () => t`Best value`,
planLimits: () => t`Plan limits`,
unlimited: () => t`Unlimited`,
- fiveYearPlan: () => t`5 year plan (One time purchase)`,
+ fiveYearPlan: () => t`5 year plan`,
educationPlan: () => t`Education plan`,
welcomeToPlan: (plan: string) => t`Welcome to Notesnook ${plan}`,
thankYouForPurchase: () => t`Thank you for the purchase`,
@@ -2805,5 +2805,25 @@ Continue without attachments?`,
setupInboxKeys: () => t`Setup inbox keys`,
enterPgpPublicKey: () => t`Enter your PGP public key`,
enterPgpPrivateKey: () => t`Enter your PGP private key`,
- expiryDateRemoved: () => t`Expiry date removed`
+ expiryDateRemoved: () => t`Expiry date removed`,
+ selectPlan: () => t`Select Plan`,
+ frequentlyAskedQuestions: () => t`Frequently Asked Questions`,
+ testimonials: () => t`Testimonials`,
+ billingType: {
+ annual: () => t`Billed annually`,
+ monthly: () => t`Billed monthly`,
+ oneTime: () => t`One time purchase`
+ },
+ whatsIncluded: () => t`What's included`,
+ paymentSummary: () => t`Payment summary`,
+ planWhatsIncluded: {
+ unlimitedNotes: () => t`Unlimited notes and attachments`,
+ endToEnd: () => t`End-to-end encryption (XChaCha20)`,
+ allDevices: () => t`Access on all devices`,
+ freeTrial: (days: number) => t`Free ${days} days trial, cancel anytime`,
+ remind: () => t`Remind before your trial ends`
+ },
+ nextBillingDate: () => t`Next Billing Date`,
+ freeTrialIncludes: (duration: number) =>
+ t`${duration} days free trial includes all features`
};