mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 15:09:33 +01:00
mobile: pricing fixes
This commit is contained in:
committed by
Abdullah Atta
parent
dc1498d672
commit
7dddebef2e
@@ -132,7 +132,8 @@ function ReorderableList<T extends { id: string }>({
|
||||
);
|
||||
|
||||
function getOrderedItems() {
|
||||
const items: T[] = customizableSidebarFeature?.isAllowed ? data : [];
|
||||
if (!customizableSidebarFeature?.isAllowed) return data;
|
||||
const items: T[] = [];
|
||||
itemOrderState.forEach((id) => {
|
||||
const item = data.find((i) => i.id === id);
|
||||
if (!item) return;
|
||||
@@ -183,7 +184,6 @@ function ReorderableList<T extends { id: string }>({
|
||||
dragging: true
|
||||
});
|
||||
}}
|
||||
disableVirtualization
|
||||
itemsDraggable={disableDefaultDrag ? dragging : true}
|
||||
lockItemDragsToMainAxis
|
||||
onItemReorder={async ({ fromIndex, fromItem, toIndex, toItem }) => {
|
||||
|
||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { getFeaturesTable } from "@notesnook/common";
|
||||
import { EV, EVENTS, Plan, SubscriptionPlan, User } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect, useState } from "react";
|
||||
@@ -37,6 +38,15 @@ import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { WebView } from "react-native-webview";
|
||||
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 { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import usePricingPlans, { PricingPlan } from "../../hooks/use-pricing-plans";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
@@ -44,28 +54,16 @@ import { getElevationStyle } from "../../utils/elevation";
|
||||
import { openLinkInBrowser } from "../../utils/functions";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { AuthMode } from "../auth/common";
|
||||
import { Header } from "../header";
|
||||
import { BuyPlan } from "../sheets/buy-plan";
|
||||
import { Toast } from "../toast";
|
||||
import AppIcon from "../ui/AppIcon";
|
||||
import { Button } from "../ui/button";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import { SvgView } from "../ui/svg";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { db } from "../../common/database";
|
||||
import { SvgView } from "../ui/svg";
|
||||
import {
|
||||
ANDROID_POLICE_SVG,
|
||||
APPLE_INSIDER_PNG,
|
||||
FREEDOM_PRESS_SVG,
|
||||
ITS_FOSS_NEWS_PNG,
|
||||
NESS_LABS_PNG,
|
||||
PRIVACY_GUIDES_SVG,
|
||||
TECHLORE_SVG,
|
||||
XDA_SVG
|
||||
} from "../../assets/images/assets";
|
||||
import { EV, EVENTS, Plan, SubscriptionPlan, User } from "@notesnook/core";
|
||||
import { AuthMode } from "../auth/common";
|
||||
|
||||
const Steps = {
|
||||
select: 1,
|
||||
@@ -944,7 +942,7 @@ const PricingPlanCard = ({
|
||||
|
||||
const price = pricingPlans?.getPrice(
|
||||
product as RNIap.Subscription,
|
||||
1,
|
||||
pricingPlans.hasTrialOffer(plan.id, product?.productId) ? 1 : 0,
|
||||
annualBilling
|
||||
);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ 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/>.
|
||||
*/
|
||||
import { SubscriptionPlan } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
@@ -27,7 +28,6 @@ import { useMenuStore } from "../../stores/use-menu-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { SUBSCRIPTION_STATUS } from "../../utils/constants";
|
||||
import { MenuItemsList } from "../../utils/menu-items";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import ReorderableList from "../list/reorderable-list";
|
||||
import { MenuItemProperties } from "../sheets/menu-item-properties";
|
||||
@@ -36,6 +36,7 @@ import { ColorSection } from "./color-section";
|
||||
import { MenuItem } from "./menu-item";
|
||||
import { PinnedSection } from "./pinned-section";
|
||||
import { SideMenuHeader } from "./side-menu-header";
|
||||
import { MenuItemsList } from "../../utils/menu-items";
|
||||
|
||||
const pro = {
|
||||
title: strings.upgradePlan(),
|
||||
@@ -59,7 +60,7 @@ export function SideMenuHome() {
|
||||
state.hiddenItems["routes"]
|
||||
]);
|
||||
const subscriptionType = useUserStore(
|
||||
(state) => state.user?.subscription?.type
|
||||
(state) => state.user?.subscription?.plan
|
||||
);
|
||||
const user = useUserStore.getState().user;
|
||||
|
||||
@@ -139,8 +140,9 @@ export function SideMenuHome() {
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
{subscriptionType === SUBSCRIPTION_STATUS.TRIAL ||
|
||||
subscriptionType === SUBSCRIPTION_STATUS.BASIC ||
|
||||
{((subscriptionType === SUBSCRIPTION_STATUS.TRIAL ||
|
||||
subscriptionType === SUBSCRIPTION_STATUS.BASIC) &&
|
||||
subscriptionType === SubscriptionPlan.FREE) ||
|
||||
!user ? (
|
||||
<Button
|
||||
title={pro.title}
|
||||
|
||||
@@ -53,12 +53,21 @@ export const Walkthrough = ({
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
padding: DefaultAppStyles.GAP,
|
||||
paddingBottom: 0
|
||||
paddingBottom: DefaultAppStyles.GAP * 2,
|
||||
gap: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
{step.walkthroughItem(colors)}
|
||||
|
||||
{step.title ? <Heading>{step.title}</Heading> : null}
|
||||
{step.title ? (
|
||||
<Heading
|
||||
style={{
|
||||
textAlign: "center"
|
||||
}}
|
||||
>
|
||||
Notesnook Free plan activated
|
||||
</Heading>
|
||||
) : null}
|
||||
{step.text ? (
|
||||
<Paragraph
|
||||
style={{
|
||||
@@ -74,8 +83,7 @@ export const Walkthrough = ({
|
||||
{step.actionButton && (
|
||||
<Button
|
||||
style={{
|
||||
height: 30,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
height: 30
|
||||
}}
|
||||
textStyle={{
|
||||
textDecorationLine: "underline"
|
||||
@@ -89,11 +97,6 @@ export const Walkthrough = ({
|
||||
)}
|
||||
|
||||
<Button
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
height: 40,
|
||||
marginTop: DefaultAppStyles.GAP
|
||||
}}
|
||||
onPress={async () => {
|
||||
switch (step.button?.type) {
|
||||
case "next":
|
||||
|
||||
@@ -40,6 +40,10 @@ import { SvgView } from "../ui/svg";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { planToId, SubscriptionPlan } from "@notesnook/core";
|
||||
import { planToDisplayName } from "../../utils/constants";
|
||||
import AppIcon from "../ui/AppIcon";
|
||||
|
||||
export type TStep = {
|
||||
text?: string;
|
||||
@@ -356,7 +360,6 @@ const Support = () => {
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<SvgView src={SUPPORT_SVG()} />
|
||||
<Heading>{strings.prioritySupport()}</Heading>
|
||||
<Paragraph
|
||||
style={{
|
||||
@@ -384,21 +387,6 @@ const Support = () => {
|
||||
title={strings.joinDiscord()}
|
||||
/>
|
||||
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
width: "90%"
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL("https://t.me/notesnook").catch(() => {
|
||||
/* empty */
|
||||
});
|
||||
}}
|
||||
icon="telegram"
|
||||
type="secondary"
|
||||
title={strings.joinTelegram()}
|
||||
/>
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
@@ -415,7 +403,7 @@ const Support = () => {
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
width: "90%"
|
||||
}}
|
||||
icon="mail"
|
||||
icon="email"
|
||||
type="secondary"
|
||||
title={strings.emailSupport()}
|
||||
/>
|
||||
@@ -427,18 +415,15 @@ const prouser: { id: string; steps: TStep[] } = {
|
||||
id: "prouser",
|
||||
steps: [
|
||||
{
|
||||
title: strings.welcomeToNotesnookPro(),
|
||||
title: strings.welcomeToPlan(
|
||||
planToDisplayName(
|
||||
useUserStore.getState().user?.subscription?.plan as SubscriptionPlan
|
||||
)
|
||||
),
|
||||
text: strings.thankYouPrivacy(),
|
||||
walkthroughItem: (colors) => (
|
||||
<SvgView src={LAUNCH_ROCKET(colors.primary.paragraph)} />
|
||||
<AppIcon name="check" color={colors.primary.accent} size={50} />
|
||||
),
|
||||
button: {
|
||||
type: "next",
|
||||
title: strings.next()
|
||||
}
|
||||
},
|
||||
{
|
||||
walkthroughItem: () => <Support />,
|
||||
button: {
|
||||
type: "done",
|
||||
title: strings.continue()
|
||||
|
||||
@@ -22,6 +22,8 @@ import {
|
||||
EVENTS,
|
||||
EventManagerSubscription,
|
||||
SYNC_CHECK_IDS,
|
||||
SubscriptionPlan,
|
||||
SubscriptionType,
|
||||
SyncStatusEvent,
|
||||
User
|
||||
} from "@notesnook/core";
|
||||
@@ -224,7 +226,11 @@ const onUserEmailVerified = async () => {
|
||||
const onUserSubscriptionStatusChanged = async (
|
||||
subscription: User["subscription"]
|
||||
) => {
|
||||
if (!PremiumService.get() && subscription.type === 5) {
|
||||
if (
|
||||
!PremiumService.get() &&
|
||||
(subscription.type === SubscriptionType.PREMIUM ||
|
||||
subscription.plan != SubscriptionPlan.FREE)
|
||||
) {
|
||||
PremiumService.subscriptions.clear();
|
||||
Walkthrough.present("prouser", false, true);
|
||||
}
|
||||
|
||||
@@ -86,9 +86,7 @@ const pricingPlans: PricingPlan[] = [
|
||||
subscriptionSkuList: [
|
||||
"notesnook.pro.monthly",
|
||||
"notesnook.pro.yearly",
|
||||
"notesnook.pro.monthly.tier2",
|
||||
"notesnook.pro.yearly.tier2",
|
||||
"notesnook.pro.monthly.tier3",
|
||||
"notesnook.pro.yearly.tier3",
|
||||
// no trial
|
||||
"notesnook.pro.monthly.nt",
|
||||
@@ -281,8 +279,11 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
: (product as Plan).price.gross
|
||||
}`;
|
||||
|
||||
const pricingPhaseListItem = (product as RNIap.SubscriptionAndroid)
|
||||
?.subscriptionOfferDetails?.[0]?.pricingPhases?.pricingPhaseList?.[1];
|
||||
const pricingPhaseListItem =
|
||||
(product as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
|
||||
?.pricingPhases?.pricingPhaseList?.[1] ||
|
||||
(product as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
|
||||
?.pricingPhases?.pricingPhaseList?.[0];
|
||||
|
||||
return (
|
||||
pricingPhaseListItem?.formattedPrice ||
|
||||
@@ -534,10 +535,18 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
if (!p1 || !p2) return 0;
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
const androidPricingPhase1 = (p1 as RNIap.SubscriptionAndroid)
|
||||
?.subscriptionOfferDetails?.[0].pricingPhases?.pricingPhaseList?.[1];
|
||||
const androidPricingPhase2 = (p2 as RNIap.SubscriptionAndroid)
|
||||
?.subscriptionOfferDetails?.[0].pricingPhases?.pricingPhaseList?.[1];
|
||||
const androidPricingPhase1 =
|
||||
(p1 as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
|
||||
.pricingPhases?.pricingPhaseList?.[1] ||
|
||||
(p1 as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
|
||||
.pricingPhases?.pricingPhaseList?.[0];
|
||||
const androidPricingPhase2 =
|
||||
(p2 as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
|
||||
.pricingPhases?.pricingPhaseList?.[1] ||
|
||||
(p2 as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
|
||||
.pricingPhases?.pricingPhaseList?.[0];
|
||||
|
||||
if (!androidPricingPhase1 || !androidPricingPhase2) return 0;
|
||||
|
||||
return getDiscountValue(
|
||||
androidPricingPhase1.priceAmountMicros,
|
||||
|
||||
@@ -40,6 +40,8 @@ import { SyncStatus, useUserStore } from "../../stores/use-user-store";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { SectionItem } from "./section-item";
|
||||
import { planToDisplayName } from "../../utils/constants";
|
||||
import { SubscriptionType } from "@notesnook/core";
|
||||
|
||||
export const getTimeLeft = (t2) => {
|
||||
let daysRemaining = dayjs(t2).diff(dayjs(), "days");
|
||||
@@ -118,6 +120,8 @@ const onChangePicture = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const LONG_MAX = 9223372036854776000;
|
||||
|
||||
const SettingsUserSection = ({ item }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [user] = useUserStore((state) => [state.user]);
|
||||
@@ -276,7 +280,10 @@ const SettingsUserSection = ({ item }) => {
|
||||
{strings.storage()}
|
||||
</Paragraph>
|
||||
<Paragraph size={AppFontSize.xxs}>
|
||||
{formatBytes(used)}/{formatBytes(total)} {strings.used()}
|
||||
{formatBytes(used)}/
|
||||
{total === LONG_MAX
|
||||
? "Unlimited"
|
||||
: formatBytes(total) + " " + strings.used()}
|
||||
</Paragraph>
|
||||
</View>
|
||||
<View
|
||||
@@ -317,7 +324,10 @@ const SettingsUserSection = ({ item }) => {
|
||||
}}
|
||||
>
|
||||
<Paragraph size={AppFontSize.sm}>
|
||||
{strings.freePlan()}
|
||||
{user.subscription.plan === 0 &&
|
||||
user.subscription.type === SubscriptionType.PREMIUM
|
||||
? strings.proPlan()
|
||||
: planToDisplayName(user.subscription.plan)}
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
|
||||
@@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SubscriptionPlan } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { Platform } from "react-native";
|
||||
import { getVersion } from "react-native-device-info";
|
||||
|
||||
@@ -63,6 +65,23 @@ export const itemSkus = [
|
||||
"notesnook.believer.5year"
|
||||
];
|
||||
|
||||
export function planToDisplayName(plan: SubscriptionPlan): string {
|
||||
switch (plan) {
|
||||
case SubscriptionPlan.FREE:
|
||||
return strings.freePlan();
|
||||
case SubscriptionPlan.ESSENTIAL:
|
||||
return strings.essentialPlan();
|
||||
case SubscriptionPlan.PRO:
|
||||
return strings.proPlan();
|
||||
case SubscriptionPlan.BELIEVER:
|
||||
return strings.believerPlan();
|
||||
case SubscriptionPlan.EDUCATION:
|
||||
return strings.educationPlan();
|
||||
default:
|
||||
return strings.freePlan();
|
||||
}
|
||||
}
|
||||
|
||||
export const SUBSCRIPTION_STATUS = {
|
||||
BASIC: 0,
|
||||
TRIAL: 1,
|
||||
|
||||
@@ -2372,6 +2372,10 @@ msgstr "Edit your full name"
|
||||
msgid "Editor"
|
||||
msgstr "Editor"
|
||||
|
||||
#: src/strings.ts:2573
|
||||
msgid "Education plan"
|
||||
msgstr "Education plan"
|
||||
|
||||
#: src/strings.ts:1480
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
@@ -7055,6 +7059,10 @@ msgstr "Welcome back, {email}"
|
||||
msgid "Welcome back!"
|
||||
msgstr "Welcome back!"
|
||||
|
||||
#: src/strings.ts:2574
|
||||
msgid "Welcome to Notesnook {plan} plan"
|
||||
msgstr "Welcome to Notesnook {plan} plan"
|
||||
|
||||
#: src/strings.ts:2072
|
||||
msgid "Welcome to Notesnook Pro"
|
||||
msgstr "Welcome to Notesnook Pro"
|
||||
|
||||
@@ -2361,6 +2361,10 @@ msgstr ""
|
||||
msgid "Editor"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2573
|
||||
msgid "Education plan"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:1480
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
@@ -7006,6 +7010,10 @@ msgstr ""
|
||||
msgid "Welcome back!"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2574
|
||||
msgid "Welcome to Notesnook {plan} plan"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2072
|
||||
msgid "Welcome to Notesnook Pro"
|
||||
msgstr ""
|
||||
|
||||
@@ -2577,5 +2577,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 (One time purchase)`,
|
||||
educationPlan: () => t`Education plan`,
|
||||
welcomeToPlan: (plan: string) => t`Welcome to Notesnook ${plan}`
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user