mobile: hide pricing flows on self hosted clients

This commit is contained in:
Ammar Ahmed
2025-10-06 10:58:39 +05:00
parent c77050eccc
commit dae8b5c542
9 changed files with 74 additions and 63 deletions

View File

@@ -19,14 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { strings } from "@notesnook/intl"; import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme"; import { useThemeColors } from "@notesnook/theme";
import { useRoute } from "@react-navigation/native";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { import { TouchableOpacity, View, useWindowDimensions } from "react-native";
ScrollView,
TouchableOpacity,
View,
useWindowDimensions
} from "react-native";
import { SheetManager } from "react-native-actions-sheet"; import { SheetManager } from "react-native-actions-sheet";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { DDS } from "../../services/device-detection"; import { DDS } from "../../services/device-detection";
import { eSendEvent } from "../../services/event-manager"; import { eSendEvent } from "../../services/event-manager";
import Navigation from "../../services/navigation"; import Navigation from "../../services/navigation";
@@ -47,8 +44,7 @@ import { hideAuth } from "./common";
import { ForgotPassword } from "./forgot-password"; import { ForgotPassword } from "./forgot-password";
import { AuthHeader } from "./header"; import { AuthHeader } from "./header";
import { useLogin } from "./use-login"; import { useLogin } from "./use-login";
import { useRoute } from "@react-navigation/native"; import SettingsService from "../../services/settings";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
const LoginSteps = { const LoginSteps = {
emailAuth: 1, emailAuth: 1,
@@ -81,7 +77,7 @@ export const Login = ({ changeMode }) => {
} }
}, 5000); }, 5000);
if (!PremiumService.get()) { if (!PremiumService.get() && !SettingsService.getProperty("serverUrls")) {
Navigation.navigate("PayWall", { Navigation.navigate("PayWall", {
context: "signup", context: "signup",
state: route.params.state, state: route.params.state,

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { strings } from "@notesnook/intl"; import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme"; import { useThemeColors } from "@notesnook/theme";
import { useRoute } from "@react-navigation/native";
import React, { useRef, useState } from "react"; import React, { useRef, useState } from "react";
import { TouchableOpacity, View, useWindowDimensions } from "react-native"; import { TouchableOpacity, View, useWindowDimensions } from "react-native";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view"; import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
@@ -38,7 +39,6 @@ import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph"; import Paragraph from "../ui/typography/paragraph";
import { AuthHeader } from "./header"; import { AuthHeader } from "./header";
import { SignupContext } from "./signup-context"; import { SignupContext } from "./signup-context";
import { useRoute } from "@react-navigation/native";
const SignupSteps = { const SignupSteps = {
signup: 0, signup: 0,
@@ -91,11 +91,13 @@ export const Signup = ({ changeMode, welcome }) => {
setLastSynced(await db.lastSynced()); setLastSynced(await db.lastSynced());
clearMessage(); clearMessage();
setEmailVerifyMessage(); setEmailVerifyMessage();
Navigation.navigate("PayWall", { if (!SettingsService.getProperty("serverUrls")) {
canGoBack: false, Navigation.navigate("PayWall", {
state: route.params.state, canGoBack: false,
context: "signup" state: route.params.state,
}); context: "signup"
});
}
return true; return true;
} catch (e) { } catch (e) {
setCurrentStep(SignupSteps.signup); setCurrentStep(SignupSteps.signup);

View File

@@ -60,6 +60,7 @@ import usePricingPlans, {
PricingPlan PricingPlan
} from "../../hooks/use-pricing-plans"; } from "../../hooks/use-pricing-plans";
import Navigation, { NavigationProps } from "../../services/navigation"; import Navigation, { NavigationProps } from "../../services/navigation";
import PremiumService from "../../services/premium";
import { getElevationStyle } from "../../utils/elevation"; import { getElevationStyle } from "../../utils/elevation";
import { openLinkInBrowser } from "../../utils/functions"; import { openLinkInBrowser } from "../../utils/functions";
import { AppFontSize, defaultBorderRadius } from "../../utils/size"; import { AppFontSize, defaultBorderRadius } from "../../utils/size";
@@ -74,7 +75,6 @@ import { IconButton } from "../ui/icon-button";
import { SvgView } from "../ui/svg"; import { SvgView } from "../ui/svg";
import Heading from "../ui/typography/heading"; import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph"; import Paragraph from "../ui/typography/paragraph";
import PremiumService from "../../services/premium";
const Steps = { const Steps = {
select: 1, select: 1,
@@ -114,15 +114,8 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
routeParams.state?.planId, routeParams.state?.planId,
routeParams.state?.productId routeParams.state?.productId
); );
console.log(
"selectPlan",
routeParams.state?.planId,
routeParams.state?.productId,
(pricingPlans.selectedProduct as any).productId
);
} }
setStep(Steps.buy); setStep(Steps.buy);
console.log("Buy step");
} }
}, [routeParams.state]); }, [routeParams.state]);
@@ -949,7 +942,6 @@ const PricingPlanCard = ({
regionalDiscount?.sku || regionalDiscount?.sku ||
`notesnook.${plan.id}.${annualBilling ? "yearly" : "monthly"}` `notesnook.${plan.id}.${annualBilling ? "yearly" : "monthly"}`
]; ];
console.log(regionalDiscount?.sku);
const price = pricingPlans?.getPrice( const price = pricingPlans?.getPrice(
product as RNIap.Subscription, product as RNIap.Subscription,
pricingPlans.hasTrialOffer(plan.id, product?.productId) ? 1 : 0, pricingPlans.hasTrialOffer(plan.id, product?.productId) ? 1 : 0,
@@ -962,6 +954,7 @@ const PricingPlanCard = ({
); );
useEffect(() => { useEffect(() => {
if (pricingPlans?.isGithubRelease) return;
pricingPlans pricingPlans
?.getRegionalDiscount( ?.getRegionalDiscount(
plan.id, plan.id,
@@ -980,7 +973,7 @@ const PricingPlanCard = ({
pricingPlans.isSubscribed(); pricingPlans.isSubscribed();
const isNotReady = const isNotReady =
pricingPlans?.loadingPlans || (!price && !WebPlan?.price.gross); pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross);
return ( return (
<TouchableOpacity <TouchableOpacity
@@ -1112,7 +1105,7 @@ const PricingPlanCard = ({
</View> </View>
</View> </View>
{pricingPlans?.loadingPlans || (!price && !WebPlan?.price.gross) ? ( {pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross) ? (
<ActivityIndicator size="small" color={colors.primary.accent} /> <ActivityIndicator size="small" color={colors.primary.accent} />
) : ( ) : (
<View> <View>
@@ -1120,7 +1113,7 @@ const PricingPlanCard = ({
{isFreePlan {isFreePlan
? "0.00" ? "0.00"
: price || : price ||
`${WebPlan?.price.currency} ${WebPlan?.price.gross}`}{" "} `${WebPlan?.price?.currency} ${WebPlan?.price?.gross}`}{" "}
<Paragraph>/{strings.month()}</Paragraph> <Paragraph>/{strings.month()}</Paragraph>
</Paragraph> </Paragraph>

View File

@@ -24,6 +24,7 @@ import AppIcon from "../../ui/AppIcon";
import { Button } from "../../ui/button"; import { Button } from "../../ui/button";
import Heading from "../../ui/typography/heading"; import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph"; import Paragraph from "../../ui/typography/paragraph";
import SettingsService from "../../../services/settings";
const isGithubRelease = Config.GITHUB_RELEASE === "true"; const isGithubRelease = Config.GITHUB_RELEASE === "true";
const INDEX_TO_PLAN = { const INDEX_TO_PLAN = {
1: "essential", 1: "essential",
@@ -55,11 +56,11 @@ export default function PaywallSheet<Tid extends FeatureId>(props: {
}, []); }, []);
const isSubscribedOnWeb = const isSubscribedOnWeb =
(PremiumService.get() && PremiumService.get() &&
(pricingPlans.user?.subscription?.provider ===
SubscriptionProvider.PADDLE ||
pricingPlans.user?.subscription?.provider === pricingPlans.user?.subscription?.provider ===
SubscriptionProvider.PADDLE) || SubscriptionProvider.STREETWRITERS);
pricingPlans.user?.subscription?.provider ===
SubscriptionProvider.STREETWRITERS;
const isCurrentPlatform = const isCurrentPlatform =
(pricingPlans.user?.subscription?.provider === SubscriptionProvider.APPLE && (pricingPlans.user?.subscription?.provider === SubscriptionProvider.APPLE &&
@@ -194,25 +195,28 @@ export default function PaywallSheet<Tid extends FeatureId>(props: {
width: "100%" width: "100%"
}} }}
onPress={() => { onPress={() => {
if ( if (PremiumService.get()) {
pricingPlans.user?.subscription.plan === if (
SubscriptionPlan.LEGACY_PRO || pricingPlans.user?.subscription.plan ===
!isCurrentPlatform SubscriptionPlan.LEGACY_PRO ||
) { !isCurrentPlatform
ToastManager.show({ ) {
message: strings.cannotChangePlan(), ToastManager.show({
context: "local" message: strings.cannotChangePlan(),
}); context: "local"
return; });
return;
}
if (isSubscribedOnWeb) {
ToastManager.show({
message: strings.changePlanOnWeb(),
context: "local"
});
return;
}
} }
if (isSubscribedOnWeb) {
ToastManager.show({
message: strings.changePlanOnWeb(),
context: "local"
});
return;
}
eSendEvent(eCloseSheet); eSendEvent(eCloseSheet);
if (!useUserStore.getState().user) { if (!useUserStore.getState().user) {
Navigation.navigate("Auth", { Navigation.navigate("Auth", {
@@ -256,6 +260,7 @@ export default function PaywallSheet<Tid extends FeatureId>(props: {
} }
PaywallSheet.present = <Tid extends FeatureId>(feature: FeatureResult<Tid>) => { PaywallSheet.present = <Tid extends FeatureId>(feature: FeatureResult<Tid>) => {
if (SettingsService.getProperty("serverUrls")) return;
presentSheet({ presentSheet({
component: <PaywallSheet feature={feature} /> component: <PaywallSheet feature={feature} />
}); });

View File

@@ -20,6 +20,7 @@ import Paragraph from "../../ui/typography/paragraph";
import { SubscriptionPlan, SubscriptionProvider } from "@notesnook/core"; import { SubscriptionPlan, SubscriptionProvider } from "@notesnook/core";
import { useUserStore } from "../../../stores/use-user-store"; import { useUserStore } from "../../../stores/use-user-store";
import PremiumService from "../../../services/premium"; import PremiumService from "../../../services/premium";
import SettingsService from "../../../services/settings";
export function PlanLimits() { export function PlanLimits() {
const { colors } = useThemeColors(); const { colors } = useThemeColors();
@@ -84,10 +85,11 @@ export function PlanLimits() {
</View> </View>
))} ))}
{(user?.subscription?.provider === SubscriptionProvider.PADDLE || {((user?.subscription?.provider === SubscriptionProvider.PADDLE ||
user?.subscription?.provider === SubscriptionProvider.STREETWRITERS || user?.subscription?.provider === SubscriptionProvider.STREETWRITERS ||
!isCurrentPlatform) && !isCurrentPlatform) &&
PremiumService.get() ? null : ( PremiumService.get()) ||
SettingsService.getProperty("serverUrls") ? null : (
<Button <Button
title={strings.changePlan()} title={strings.changePlan()}
onPress={() => { onPress={() => {

View File

@@ -24,10 +24,11 @@ import { FlatList, View } from "react-native";
import { DraxProvider, DraxScrollView } from "react-native-drax"; import { DraxProvider, DraxScrollView } from "react-native-drax";
import { db } from "../../common/database"; import { db } from "../../common/database";
import Navigation from "../../services/navigation"; import Navigation from "../../services/navigation";
import SettingsService from "../../services/settings";
import { useMenuStore } from "../../stores/use-menu-store"; import { useMenuStore } from "../../stores/use-menu-store";
import { useSettingStore } from "../../stores/use-setting-store"; import { useSettingStore } from "../../stores/use-setting-store";
import { useUserStore } from "../../stores/use-user-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 { DefaultAppStyles } from "../../utils/styles";
import ReorderableList from "../list/reorderable-list"; import ReorderableList from "../list/reorderable-list";
import { MenuItemProperties } from "../sheets/menu-item-properties"; import { MenuItemProperties } from "../sheets/menu-item-properties";
@@ -36,7 +37,6 @@ import { ColorSection } from "./color-section";
import { MenuItem } from "./menu-item"; import { MenuItem } from "./menu-item";
import { PinnedSection } from "./pinned-section"; import { PinnedSection } from "./pinned-section";
import { SideMenuHeader } from "./side-menu-header"; import { SideMenuHeader } from "./side-menu-header";
import { MenuItemsList } from "../../utils/menu-items";
const pro = { const pro = {
title: strings.upgradePlan(), title: strings.upgradePlan(),
@@ -140,9 +140,10 @@ export function SideMenuHome() {
paddingVertical: DefaultAppStyles.GAP_VERTICAL paddingVertical: DefaultAppStyles.GAP_VERTICAL
}} }}
> >
{subscriptionType === SubscriptionPlan.FREE || {(subscriptionType === SubscriptionPlan.FREE ||
!subscriptionType || !subscriptionType ||
!user ? ( !user) &&
!SettingsService.getProperty("serverUrls") ? (
<Button <Button
title={pro.title} title={pro.title}
style={{ style={{

View File

@@ -85,6 +85,7 @@ export default function useFeatureManager() {
negativeText: strings.cancel(), negativeText: strings.cancel(),
positivePress: async () => { positivePress: async () => {
eSendEvent(eCloseSimpleDialog); eSendEvent(eCloseSimpleDialog);
if (SettingsService.getProperty("serverUrls")) return;
Navigation.navigate("PayWall", { Navigation.navigate("PayWall", {
context: "logged-in" context: "logged-in"
}); });

View File

@@ -25,6 +25,7 @@ import { DatabaseLogger, db } from "../common/database";
import PremiumService from "../services/premium"; import PremiumService from "../services/premium";
import { useSettingStore } from "../stores/use-setting-store"; import { useSettingStore } from "../stores/use-setting-store";
import { useUserStore } from "../stores/use-user-store"; import { useUserStore } from "../stores/use-user-store";
import SettingsService from "../services/settings";
function numberWithCommas(x: string) { function numberWithCommas(x: string) {
const parts = x.toString().split("."); const parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
@@ -201,7 +202,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
if (productId?.includes("5year")) return false; if (productId?.includes("5year")) return false;
if (isGithubRelease) { if (isGithubRelease) {
if ( if (
user?.subscription.trialsAvailed?.some( user?.subscription?.trialsAvailed?.some(
(plan) => plan === planIdToIndex(planId || currentPlan) (plan) => plan === planIdToIndex(planId || currentPlan)
) )
) { ) {
@@ -246,7 +247,10 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
}); });
setPlans([...pricingPlans]); setPlans([...pricingPlans]);
setUserCanRequestTrial(hasTrialOffer()); setUserCanRequestTrial(hasTrialOffer());
if (Config.GITHUB_RELEASE === "true") { if (
Config.GITHUB_RELEASE === "true" &&
!SettingsService.getProperty("serverUrls")
) {
try { try {
const products = WebPlanCache || (await db.pricing.products()); const products = WebPlanCache || (await db.pricing.products());
WebPlanCache = products; WebPlanCache = products;
@@ -264,7 +268,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
if (!product) return; if (!product) return;
if (Platform.OS === "android") { if (Platform.OS === "android") {
if (isGithubRelease) if (isGithubRelease) {
if (!(product as Plan)?.price) return null;
return `${(product as Plan).price.currency} ${ return `${(product as Plan).price.currency} ${
(product as Plan).period === "yearly" (product as Plan).period === "yearly"
? ((product as Plan).price.gross / 12).toFixed(2) ? ((product as Plan).price.gross / 12).toFixed(2)
@@ -272,6 +277,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
? ((product as Plan).price.gross / (12 * 5)).toFixed(2) ? ((product as Plan).price.gross / (12 * 5)).toFixed(2)
: (product as Plan).price.gross : (product as Plan).price.gross
}`; }`;
}
const pricingPhaseListItem = const pricingPhaseListItem =
(product as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0] (product as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
@@ -414,7 +420,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
offerIndex: number offerIndex: number
) => { ) => {
if (isGithubRelease) { if (isGithubRelease) {
return (product as Plan).period; return (product as Plan)?.period;
} }
if (Platform.OS === "android") { if (Platform.OS === "android") {
@@ -444,7 +450,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
if (isGithubRelease) { if (isGithubRelease) {
return { return {
duration: 1, duration: 1,
type: (product as Plan).period type: (product as Plan)?.period
}; };
} }
@@ -591,7 +597,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
) => { ) => {
if (!product) return null; if (!product) return null;
if (isGithubRelease) if (isGithubRelease) {
if (!(product as Plan)?.price) return null;
return `${(product as Plan).price.currency} ${ return `${(product as Plan).price.currency} ${
(product as Plan).period === "yearly" (product as Plan).period === "yearly"
? ((product as Plan).price.gross / 12).toFixed(2) ? ((product as Plan).price.gross / 12).toFixed(2)
@@ -599,6 +606,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
? ((product as Plan).price.gross / (12 * 5)).toFixed(2) ? ((product as Plan).price.gross / (12 * 5)).toFixed(2)
: (product as Plan).price.gross : (product as Plan).price.gross
}`; }`;
}
const androidPricingPhase = (product as RNIap.SubscriptionAndroid) const androidPricingPhase = (product as RNIap.SubscriptionAndroid)
?.subscriptionOfferDetails?.[0].pricingPhases?.pricingPhaseList?.[ ?.subscriptionOfferDetails?.[0].pricingPhases?.pricingPhaseList?.[

View File

@@ -43,6 +43,7 @@ import { planToDisplayName } from "../../utils/constants";
import { AppFontSize } from "../../utils/size"; import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles"; import { DefaultAppStyles } from "../../utils/styles";
import { SectionItem } from "./section-item"; import { SectionItem } from "./section-item";
import SettingsService from "../../services/settings";
export const getTimeLeft = (t2) => { export const getTimeLeft = (t2) => {
let daysRemaining = dayjs(t2).diff(dayjs(), "days"); let daysRemaining = dayjs(t2).diff(dayjs(), "days");
@@ -339,11 +340,13 @@ const SettingsUserSection = ({ item }) => {
</Paragraph> </Paragraph>
</TouchableOpacity> </TouchableOpacity>
{(user.subscription?.provider === SubscriptionProvider.PADDLE || {((user.subscription?.provider ===
SubscriptionProvider.PADDLE ||
user.subscription?.provider === user.subscription?.provider ===
SubscriptionProvider.STREETWRITERS || SubscriptionProvider.STREETWRITERS ||
!isCurrentPlatform) && !isCurrentPlatform) &&
PremiumService.get() ? null : ( PremiumService.get()) ||
SettingsService.getProperty("serverUrls") ? null : (
<Button <Button
title={ title={
user.subscription?.plan !== SubscriptionPlan.FREE user.subscription?.plan !== SubscriptionPlan.FREE