web: replace usage of subscription.type to subscription.plan

This commit is contained in:
Abdullah Atta
2025-09-10 11:59:56 +05:00
parent 1377ac38db
commit cfa9f11f44
16 changed files with 61 additions and 124 deletions

View File

@@ -426,7 +426,7 @@ export async function logout() {
const result = await showLogoutConfirmation();
if (!result) return;
if (result.backup) {
if (result.checks?.backup) {
try {
await createBackup({ mode: "partial" });
} catch (e) {

View File

@@ -129,7 +129,7 @@ async function pickFile(
options?: AddAttachmentOptions
): Promise<Attachment | undefined> {
try {
if (!(await checkFeature("fileSize", file.size))) return;
if (!(await checkFeature("fileSize", { value: file.size }))) return;
const hash = await addAttachment(file, options);
return {
@@ -154,7 +154,7 @@ async function pickImage(
options?: AddAttachmentOptions
): Promise<Attachment | undefined> {
try {
if (!(await checkFeature("fileSize", file.size))) return;
if (!(await checkFeature("fileSize", { value: file.size }))) return;
const hash = await addAttachment(file, options);
const dimensions = await getImageDimensions(file);

View File

@@ -241,7 +241,7 @@ function NavigationMenu({ onExpand }: { onExpand?: () => void }) {
}, [isNavPaneCollapsed]);
useEffect(() => {
function onNavigate(_, location: string) {
function onNavigate() {
// collapse navigation menu on navigate e.g. when navigating to a notebook
// or a tag
if (!useAppStore.getState().isNavPaneCollapsed) return;

View File

@@ -23,11 +23,10 @@ import { Loading, Coupon } from "../../components/icons";
import { useStore as useUserStore } from "../../stores/user-store";
import { useStore as useThemeStore } from "../../stores/theme-store";
import Rocket from "../../assets/rocket.svg?url";
import { hardNavigate } from "../../navigation";
import { Features } from "./features";
import { PaddleCheckout } from "./paddle";
import { Plan, PricingInfo } from "./types";
import { getPlans, PERIOD_METADATA, PLAN_METADATA, usePlans } from "./plans";
import { getPlans, PERIOD_METADATA, PLAN_METADATA } from "./plans";
import {
ComparePlans,
Footer,
@@ -38,7 +37,6 @@ import {
import { useCheckoutStore } from "./store";
import { getCurrencySymbol, toPricingInfo } from "./helpers";
import { isUserSubscribed } from "../../hooks/use-is-user-premium";
import { SUBSCRIPTION_STATUS } from "../../common/constants";
import BaseDialog from "../../components/dialog";
import { ScopedThemeProvider } from "../../components/theme-provider";
import { Period, SubscriptionPlan, User } from "@notesnook/core";
@@ -186,14 +184,7 @@ export function CheckoutSideBar(props: SideBarProps) {
);
if (user && isUserSubscribed(user)) {
return (
<AlreadyPremium
isCanceled={
user?.subscription?.type === SUBSCRIPTION_STATUS.PREMIUM_CANCELED
}
onShowPlans={onShowPlans}
/>
);
return <AlreadyPremium />;
}
return null;
@@ -232,39 +223,17 @@ export function CheckoutDetails({
return <Features />;
}
type AlreadyPremiumProps = {
isCanceled?: boolean;
onShowPlans: () => void;
};
function AlreadyPremium(props: AlreadyPremiumProps) {
const { isCanceled, onShowPlans } = props;
function AlreadyPremium() {
return (
<>
<Image src={Rocket} style={{ flexShrink: 0, width: 200, height: 200 }} />
<Text variant="heading" mt={4} sx={{ textAlign: "center" }}>
Notesnook Pro
Notesnook
</Text>
<Text variant="body" mt={1} sx={{ textAlign: "center" }}>
You already have a Notesnook subscription. You can change your plan from
Settings {">"} Subscription.
</Text>
{isCanceled ? (
<>
<Text variant="body" mt={1} sx={{ textAlign: "center" }}>
Resubscribing to Notesnook Pro will replace your existing
subscription.
</Text>
<Button
variant="accent"
mt={2}
sx={{ borderRadius: 100, px: 6 }}
onClick={onShowPlans}
data-test-id="see-all-plans"
>
Continue
</Button>
</>
) : (
<Text variant="body" mt={1} sx={{ textAlign: "center" }}>
You are already subscribed to Notesnook Pro.
</Text>
)}
</>
);
}

View File

@@ -44,6 +44,10 @@ export const PLAN_METADATA: PlanMetadata = {
[SubscriptionPlan.EDUCATION]: {
title: "Education",
subtitle: ""
},
[SubscriptionPlan.LEGACY_PRO]: {
title: "Pro (legacy)",
subtitle: ""
}
};

View File

@@ -357,7 +357,7 @@ async function getActiveNotebookCommands() {
const commands: Command[] = [];
const parentId = await db.notebooks.parentId(notebook.id);
const menuItems = notebookMenuItems(notebook, [notebook.id], {
const menuItems = await notebookMenuItems(notebook, [notebook.id], {
isRoot: !parentId
});
for (const menuItem of menuItems) {
@@ -375,7 +375,7 @@ async function getActiveTagCommands() {
const group = strings.actionsForTag(tag.title);
const commands: Command[] = [];
const menuItems = tagMenuItems(tag, [tag.id]);
const menuItems = await tagMenuItems(tag, [tag.id]);
for (const menuItem of menuItems) {
commands.push(...menuItemToCommands(menuItem, group, "active-tag"));
}

View File

@@ -55,7 +55,7 @@ export type ConfirmDialogProps = BaseDialogProps<
inputs?: Record<string, Input>;
};
export const ConfirmDialog = DialogManager.register(function ConfirmDialog<>(
export const ConfirmDialog = DialogManager.register(function ConfirmDialog(
props: ConfirmDialogProps
) {
const {

View File

@@ -40,7 +40,7 @@ import { BaseDialogProps, DialogManager } from "../common/dialog-manager";
import { strings } from "@notesnook/intl";
import { Virtuoso } from "react-virtuoso";
import { CustomScrollbarsVirtualList } from "../components/list-container";
import { BuyDialog } from "./buy-dialog";
import { UpgradeDialog } from "./buy-dialog/upgrade-dialog";
export type NoteLinkingDialogProps = BaseDialogProps<LinkAttributes | false> & {
attributes?: LinkAttributes;
@@ -203,9 +203,11 @@ export const NoteLinkingDialog = DialogManager.register(
{blockLinkingAvailability?.error}{" "}
<Button
onClick={() =>
BuyDialog.show({
plan: blockLinkingAvailability?.availableOn
})
blockLinkingAvailability
? UpgradeDialog.show({
feature: blockLinkingAvailability
})
: null
}
variant="anchor"
>

View File

@@ -86,10 +86,10 @@ export const BackupExportSettings: SettingsGroup[] = [
{
type: "dropdown",
options: [
{ value: "0", title: strings.never(), premium: true },
{ value: "1", title: strings.daily(), premium: true },
{ value: "2", title: strings.weekly(), premium: true },
{ value: "3", title: strings.monthly(), premium: true }
{ value: "0", title: strings.never() },
{ value: "1", title: strings.daily() },
{ value: "2", title: strings.weekly() },
{ value: "3", title: strings.monthly() }
],
selectedOption: () =>
useSettingStore.getState().backupReminderOffset.toString(),
@@ -118,9 +118,9 @@ export const BackupExportSettings: SettingsGroup[] = [
{
type: "dropdown",
options: [
{ value: "0", title: strings.never(), premium: true },
{ value: "1", title: strings.weekly(), premium: true },
{ value: "2", title: strings.monthly(), premium: true }
{ value: "0", title: strings.never() },
{ value: "1", title: strings.weekly() },
{ value: "2", title: strings.monthly() }
],
selectedOption: () =>
useSettingStore.getState().fullBackupReminderOffset.toString(),
@@ -212,13 +212,12 @@ export const BackupExportSettings: SettingsGroup[] = [
options: [
{ value: "-", title: strings.exportAs() },
{ value: "txt", title: "Text" },
{ value: "md", title: "Markdown", premium: true },
{ value: "md", title: "Markdown" },
{
value: "md-frontmatter",
title: "Markdown + Frontmatter",
premium: true
title: "Markdown + Frontmatter"
},
{ value: "html", title: "HTML", premium: true }
{ value: "html", title: "HTML" }
],
selectedOption: () => "-",
onSelectionChanged: async (value) => {

View File

@@ -37,7 +37,7 @@ export function SubscriptionStatus() {
const user = useUserStore((store) => store.user);
const featuresUsage = usePromise(() => getFeaturesUsage(), [user]);
const { title, autoRenew, expiryDate, trialExpiryDate, trial, legacy } =
const { title, autoRenew, expiryDate, trialExpiryDate, trial } =
getSubscriptionInfo(user);
const subtitle =
title === "Free"
@@ -76,10 +76,7 @@ export function SubscriptionStatus() {
>
{strings.currentPlan()}
</Text>
<Text variant="heading">
{title}
{legacy ? " (legacy)" : ""}
</Text>
<Text variant="heading">{title}</Text>
{subtitle ? <Text variant="body">{subtitle}</Text> : null}
{featuresUsage.status === "fulfilled" ? (
<Grid

View File

@@ -32,7 +32,6 @@ import {
SubscriptionPlan,
SubscriptionProvider,
SubscriptionStatus,
SubscriptionType,
User
} from "@notesnook/core";
@@ -41,30 +40,27 @@ export function getSubscriptionInfo(user?: User): {
trial?: boolean;
paused?: boolean;
canceled?: boolean;
legacy?: boolean;
expiryDate?: string;
startDate?: string;
autoRenew?: boolean;
trialExpiryDate?: string;
} {
user = user || useUserStore.getState().user;
const { type, expiry, plan, status, provider } = user?.subscription || {};
const { expiry, plan, status, provider } = user?.subscription || {};
if (!expiry) return { title: "Free" };
const legacy = !!type;
const trial =
status === SubscriptionStatus.TRIAL || type === SubscriptionType.TRIAL;
const trial = status === SubscriptionStatus.TRIAL;
const title =
plan === SubscriptionPlan.BELIEVER
? "Believer"
: plan === SubscriptionPlan.PRO ||
type === SubscriptionType.PREMIUM ||
type === SubscriptionType.PREMIUM_CANCELED
: plan === SubscriptionPlan.PRO
? "Pro"
: plan === SubscriptionPlan.ESSENTIAL
? "Essential"
: plan === SubscriptionPlan.EDUCATION
? "Education"
: plan === SubscriptionPlan.LEGACY_PRO
? "Pro (legacy)"
: "Free";
const autoRenew =
(status === SubscriptionStatus.ACTIVE ||
@@ -88,7 +84,6 @@ export function getSubscriptionInfo(user?: User): {
return {
title,
legacy,
trial,
expiryDate,
startDate,
@@ -107,7 +102,7 @@ export function UserProfile({ minimal }: Props) {
const user = useUserStore((store) => store.user);
const profile = useSettingStore((store) => store.profile);
const { title, legacy, trial } = getSubscriptionInfo(user);
const { title, trial } = getSubscriptionInfo(user);
if (!user || !user.id)
return (
@@ -206,7 +201,7 @@ export function UserProfile({ minimal }: Props) {
color: "accent"
}}
>
{`${title}${trial ? " (trial)" : ""}${legacy ? " (legacy)" : ""}`}
{`${title}${trial ? " (trial)" : ""}`}
</Text>
<Text variant={minimal ? "body" : "subtitle"}>

View File

@@ -90,7 +90,7 @@ export const SubscriptionSettings: SettingsGroup[] = [
const user = useUserStore.getState().user;
const status = user?.subscription.status;
return (
getSubscriptionInfo(user).legacy ||
user?.subscription.plan === SubscriptionPlan.LEGACY_PRO ||
user?.subscription.provider !== SubscriptionProvider.PADDLE ||
!isUserSubscribed(user) ||
status === SubscriptionStatusEnum.CANCELED ||
@@ -162,7 +162,7 @@ export const SubscriptionSettings: SettingsGroup[] = [
const user = useUserStore.getState().user;
const status = user?.subscription.status;
return (
getSubscriptionInfo(user).legacy ||
user?.subscription.plan === SubscriptionPlan.LEGACY_PRO ||
user?.subscription.provider !== SubscriptionProvider.PADDLE ||
!isUserSubscribed(user) ||
status !== SubscriptionStatusEnum.TRIAL

View File

@@ -21,9 +21,7 @@ import { SettingsGroup } from "./types";
import { useStore as useAppStore } from "../../stores/app-store";
import { useStore as useSettingStore } from "../../stores/setting-store";
import { ConfirmDialog } from "../confirm";
import { strings } from "@notesnook/intl";
import { withFeatureCheck } from "../../common";
export const SyncSettings: SettingsGroup[] = [
{
@@ -115,7 +113,7 @@ export const SyncSettings: SettingsGroup[] = [
positiveButtonText: strings.continue(),
negativeButtonText: strings.cancel()
}).then((result) => {
if (!result || !result.accept) return;
if (!result || !result.checks?.accept) return;
return useAppStore
.getState()
.sync({ force: true, type: "send" });
@@ -135,7 +133,7 @@ export const SyncSettings: SettingsGroup[] = [
positiveButtonText: strings.continue(),
negativeButtonText: strings.cancel()
}).then((result) => {
if (!result || !result.accept) return;
if (!result || !result.checks?.accept) return;
return useAppStore
.getState()
.sync({ force: true, type: "fetch" });

View File

@@ -34,10 +34,6 @@ declare global {
var IS_THEME_BUILDER: boolean;
var hasNativeTitlebar: boolean;
interface Window {
ApplePaySession?: PaymentRequest;
}
interface AuthenticationExtensionsClientInputs {
prf?: {
eval: {

View File

@@ -17,12 +17,7 @@ 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,
SubscriptionStatus,
SubscriptionType,
User
} from "@notesnook/core";
import { SubscriptionPlan, SubscriptionStatus, User } from "@notesnook/core";
import { useStore as useUserStore } from "../stores/user-store";
export function isActiveSubscription(user?: User) {
@@ -39,30 +34,10 @@ export function isUserSubscribed(user?: User) {
user = user || useUserStore.getState().user;
if (!user) return false;
const { type, expiry, plan, status } = user?.subscription || {};
const { expiry, plan, status } = user?.subscription || {};
if (!expiry) return false;
const isLegacyPro =
type !== undefined &&
(type === SubscriptionType.BETA ||
type === SubscriptionType.PREMIUM ||
type === SubscriptionType.PREMIUM_CANCELED ||
type === SubscriptionType.TRIAL);
if (isLegacyPro) {
return (
type === SubscriptionType.PREMIUM ||
type === SubscriptionType.PREMIUM_CANCELED
);
}
return (
plan !== SubscriptionPlan.FREE && status !== SubscriptionStatus.EXPIRED
);
// const { type, plan } = user.subscription || {};
// return (
// (type === SubscriptionType.TRIAL || type === SubscriptionType.PREMIUM ||
// type === SubscriptionType.PREMIUM_CANCELED) &&
// plan !== SubscriptionPlan.FREE
// );
}

View File

@@ -85,13 +85,6 @@ function Checkout() {
const [currentStep, setCurrentStep] = useState(0);
const [error, setError] = useState<string>();
const [customer, setCustomer] = useState<{ id: string; email: string }>();
const isCheckoutCompleted = useCheckoutStore((store) => store.isCompleted);
useEffect(() => {
if (isCheckoutCompleted) {
setCurrentStep(2);
}
}, [isCheckoutCompleted]);
useEffect(() => {
useUserStore.getState().init();
@@ -106,7 +99,11 @@ function Checkout() {
return;
}
useCheckoutStore.getState().selectPlan(pricingInfo.data);
useCheckoutStore.getState().updatePrice(toPricingInfo(pricingInfo.data));
useCheckoutStore
.getState()
.updatePrice(
toPricingInfo(pricingInfo.data, useUserStore.getState().user)
);
useCheckoutStore.getState().applyCoupon(pricingInfo.data.discount?.code);
if (pricingInfo.data.customer) {
setCustomer(pricingInfo.data.customer);
@@ -263,7 +260,12 @@ function Checkout() {
You are one step away from unlocking the full potential of
Notesnook.
</Text>
<CheckoutDetails user={customer} />
<CheckoutDetails
user={customer}
onComplete={() => {
setCurrentStep(2);
}}
/>
</Flex>
) : currentStep === 2 ? (
<Flex