From acf2f53dafa20ea53227f2185374c0e44884d13c Mon Sep 17 00:00:00 2001 From: Kartik Labhshetwar Date: Fri, 12 Dec 2025 02:34:13 +0530 Subject: [PATCH] fix: hide insights submenu for free users (#25754) * fix: hide insights submenu for free users * fix: allow navigation access while plan pending * refactor: update upgrade link to insights in navigation * fix: addressed all the issues * fix: prevent flash of premium features for free users during loading Change from optimistic to pessimistic loading so free users don't briefly see the Insights submenu while plan status is being fetched. --------- Co-authored-by: Dhairyashil --- .../features/shell/navigation/Navigation.tsx | 71 ++++++++++++------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/packages/features/shell/navigation/Navigation.tsx b/packages/features/shell/navigation/Navigation.tsx index 6e8db68dbf..20091813c8 100644 --- a/packages/features/shell/navigation/Navigation.tsx +++ b/packages/features/shell/navigation/Navigation.tsx @@ -3,6 +3,7 @@ import { useMemo } from "react"; import { useIsEmbed } from "@calcom/embed-core/embed-iframe"; import UnconfirmedBookingBadge from "@calcom/features/bookings/UnconfirmedBookingBadge"; +import { useHasPaidPlan } from "@calcom/features/billing/hooks/useHasPaidPlan"; import { useOrgBranding, type OrganizationBranding, @@ -16,7 +17,19 @@ import { NavigationItem, MobileNavigationItem, MobileNavigationMoreItem } from " export const MORE_SEPARATOR_NAME = "more"; -const getNavigationItems = (orgBranding: OrganizationBranding): NavigationItemType[] => [ +const preserveBookingsQueryParams = ({ + prevPathname, + nextPathname, +}: { + prevPathname: string | null; + nextPathname: string; +}) => Boolean(prevPathname?.startsWith("/bookings/")) && nextPathname.startsWith("/bookings/"); + +const getNavigationItems = ( + orgBranding: OrganizationBranding, + hasInsightsAccess: boolean +): NavigationItemType[] => [ + { name: "event_types_page_title", href: "/event-types", @@ -106,29 +119,31 @@ const getNavigationItems = (orgBranding: OrganizationBranding): NavigationItemTy icon: "chart-bar", isCurrent: ({ pathname: path, item }) => path?.startsWith(item.href) ?? false, moreOnMobile: true, - child: [ - { - name: "bookings", - href: "/insights", - isCurrent: ({ pathname: path }) => path === "/insights", - }, - { - name: "routing", - href: "/insights/routing", - isCurrent: ({ pathname: path }) => path?.startsWith("/insights/routing") ?? false, - }, - { - name: "router_position", - href: "/insights/router-position", - isCurrent: ({ pathname: path }) => path?.startsWith("/insights/router-position") ?? false, - }, - { - name: "call_history", - href: "/insights/call-history", - // icon: "phone", - isCurrent: ({ pathname: path }) => path?.startsWith("/insights/call-history") ?? false, - }, - ], + child: hasInsightsAccess + ? [ + { + name: "bookings", + href: "/insights", + isCurrent: ({ pathname: path }) => path === "/insights", + }, + { + name: "routing", + href: "/insights/routing", + isCurrent: ({ pathname: path }) => path?.startsWith("/insights/routing") ?? false, + }, + { + name: "router_position", + href: "/insights/router-position", + isCurrent: ({ pathname: path }) => path?.startsWith("/insights/router-position") ?? false, + }, + { + name: "call_history", + href: "/insights/call-history", + // icon: "phone", + isCurrent: ({ pathname: path }) => path?.startsWith("/insights/call-history") ?? false, + }, + ] + : undefined, }, ]; @@ -184,8 +199,12 @@ const platformNavigationItems: NavigationItemType[] = [ const useNavigationItems = (isPlatformNavigation = false) => { const orgBranding = useOrgBranding(); + const { hasPaidPlan, isPending } = useHasPaidPlan(); return useMemo(() => { - const items = !isPlatformNavigation ? getNavigationItems(orgBranding) : platformNavigationItems; + const hasInsightsAccess = !isPending && !!hasPaidPlan; + const items = !isPlatformNavigation + ? getNavigationItems(orgBranding, hasInsightsAccess) + : platformNavigationItems; const desktopNavigationItems = items.filter((item) => item.name !== MORE_SEPARATOR_NAME); const mobileNavigationBottomItems = items.filter( @@ -196,7 +215,7 @@ const useNavigationItems = (isPlatformNavigation = false) => { ); return { desktopNavigationItems, mobileNavigationBottomItems, mobileNavigationMoreItems }; - }, [isPlatformNavigation, orgBranding]); + }, [hasPaidPlan, isPending, isPlatformNavigation, orgBranding]); }; export const Navigation = ({ isPlatformNavigation = false }: { isPlatformNavigation?: boolean }) => {