# yatra/3.0.8/resources/js/lib/sidebar-menu-defaults.ts

Yatra – Travel Booking &amp; Tour Operator Software, version 3.0.8. 320 lines.

- Page: https://pluginprobe.com/plugins/yatra/3.0.8/code/resources/js/lib/sidebar-menu-defaults.ts
- Raw: https://pluginprobe.com/plugins/yatra/3.0.8/raw/resources/js/lib/sidebar-menu-defaults.ts
- Modified: 2026-05-25T04:28:24+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/yatra/3.0.8/code/resources/js/lib/sidebar-menu-defaults.ts#L10-L20`.

```typescript
/**
 * Shared sidebar menu definitions for the Yatra React admin.
 *
 * The single source of truth for menu slugs, default labels, and default
 * icon names. Layout.tsx renders from this list (plus per-item overrides
 * from window.yatraAdmin.brandMenuOverrides); the White Label settings
 * page reads the same list to generate the customization form.
 *
 * Icons are referenced by Lucide name as strings so they can round-trip
 * through saved settings; the runtime icon map lives in ./icon-map.ts.
 */

export interface SubmenuItemDefault {
  /** Combined "parent.tab" key — unique across the whole menu tree. */
  key: string;
  /** Owning top-level slug. */
  parentSlug: string;
  /** Tab segment used by Layout.tsx for URL routing. */
  tab: string;
  label: string;
  iconName: string;
}

export interface MenuItemDefault {
  slug: string;
  label: string;
  iconName: string;
  submenu?: SubmenuItemDefault[];
}

/**
 * Icon override may be either:
 *   - a Lucide name string (legacy / curated Lucide dropdown)
 *   - an IconPickerValue (Yatra-library icon, FontAwesome, or image upload)
 *
 * The sidebar renderer (MenuIcon) handles all three shapes; existing
 * stored data keeps working without migration.
 */
import type { IconPickerValue } from "./icon-picker-types";

export type MenuIconValue = string | IconPickerValue;

/**
 * Per-item override. `parent` reparents the item under a different
 * top-level slug ("" / undefined = keep at top-level). Cross-parent
 * moves preserve the original click URL — the sidebar tree is purely
 * visual; routes still resolve via the original subpage/tab pair.
 */
export interface MenuItemOverride {
  label?: string;
  icon?: MenuIconValue;
  hidden?: boolean;
  parent?: string;
}

/**
 * Ordered children list per parent. The empty-string key holds the
 * top-level order; each top-level slug key holds that parent's ordered
 * children. Anything not listed falls back to its default position.
 */
export type MenuOrderMap = Record<string, string[]>;

/**
 * Submenu overrides are keyed by `{parentSlug}.{tab}` and currently
 * support label/icon/hidden — cross-parent moves are not supported yet
 * because the React App.tsx routing pins each submenu to its parent.
 */
export type MenuOverrides = Record<string, MenuItemOverride>;

/**
 * All known top-level sidebar items. Includes Pro-gated entries (their
 * visibility is still gated by isProPluginActive/isModuleActive at render
 * time) so customers can pre-configure them before enabling those modules.
 */
export const DEFAULT_MENU_ITEMS: MenuItemDefault[] = [
  { slug: "dashboard", label: "Dashboard", iconName: "LayoutDashboard" },
  {
    slug: "trips",
    label: "Trips",
    iconName: "MapPin",
    submenu: [
      {
        key: "trips.all",
        parentSlug: "trips",
        tab: "all",
        label: "All Trips",
        iconName: "List",
      },
      {
        key: "trips.activities",
        parentSlug: "trips",
        tab: "activities",
        label: "Activities",
        iconName: "Activity",
      },
      {
        key: "trips.destinations",
        parentSlug: "trips",
        tab: "destinations",
        label: "Destinations",
        iconName: "Route",
      },
      {
        key: "trips.categories",
        parentSlug: "trips",
        tab: "categories",
        label: "Categories",
        iconName: "FolderTree",
      },
      {
        key: "trips.difficulty-levels",
        parentSlug: "trips",
        tab: "difficulty-levels",
        label: "Difficulty Levels",
        iconName: "TrendingUp",
      },
      {
        key: "trips.availability",
        parentSlug: "trips",
        tab: "availability",
        label: "Availability",
        iconName: "CalendarDays",
      },
      {
        key: "trips.attributes",
        parentSlug: "trips",
        tab: "attributes",
        label: "Attributes",
        iconName: "Tag",
      },
      {
        key: "trips.additional-services",
        parentSlug: "trips",
        tab: "additional-services",
        label: "Additional Services",
        iconName: "Package",
      },
      {
        key: "trips.trip-consent",
        parentSlug: "trips",
        tab: "trip-consent",
        label: "Trip Consent",
        iconName: "FileSignature",
      },
    ],
  },
  {
    slug: "traveler-categories",
    label: "Traveler Categories",
    iconName: "Users",
  },
  {
    slug: "itinerary",
    label: "Itinerary",
    iconName: "Route",
    submenu: [
      {
        key: "itinerary.item-types",
        parentSlug: "itinerary",
        tab: "item-types",
        label: "Item Types",
        iconName: "Tag",
      },
      {
        key: "itinerary.items",
        parentSlug: "itinerary",
        tab: "items",
        label: "Items",
        iconName: "Route",
      },
      {
        key: "itinerary.itinerary",
        parentSlug: "itinerary",
        tab: "itinerary",
        label: "Itinerary",
        iconName: "FileText",
      },
    ],
  },
  { slug: "departures", label: "Departures", iconName: "Calendar" },
  { slug: "discounts", label: "Discounts", iconName: "BadgePercent" },
  { slug: "payments", label: "Payments", iconName: "CreditCard" },
  { slug: "bookings", label: "Bookings", iconName: "Calendar" },
  { slug: "customers", label: "Customers", iconName: "UserCircle" },
  { slug: "travelers", label: "Travelers", iconName: "Plane" },
  { slug: "enquiries", label: "Enquiries", iconName: "MessageSquare" },
  { slug: "reviews", label: "Reviews", iconName: "Star" },
  { slug: "reports", label: "Reports", iconName: "BarChart3" },
  { slug: "email-automation", label: "Email", iconName: "Mail" },
  {
    slug: "abandoned-recovery",
    label: "Abandoned Recovery",
    iconName: "RotateCcw",
  },
  { slug: "dynamic-pricing", label: "Dynamic Pricing", iconName: "TrendingUp" },
  { slug: "modules", label: "Modules", iconName: "Puzzle" },
  { slug: "white-label", label: "White Label", iconName: "Crown" },
  { slug: "ai-assistant", label: "AI Assistant", iconName: "Sparkles" },
  { slug: "whatsapp", label: "WhatsApp", iconName: "MessageCircle" },
  { slug: "channel-manager", label: "Channel Manager", iconName: "Network" },
  { slug: "webhooks", label: "Webhooks", iconName: "Webhook" },
  { slug: "team", label: "Team & Access", iconName: "Users" },
  { slug: "license", label: "License", iconName: "Key" },
  { slug: "settings", label: "Settings", iconName: "Settings" },
];

export function getDefaultTopLevelSlugs(): string[] {
  return DEFAULT_MENU_ITEMS.map((item) => item.slug);
}

/**
 * Read the saved menu order. Supports two stored shapes for backwards
 * compatibility:
 *   - flat array of slugs → wrapped into { "": [...] } (top-level only)
 *   - object map keyed by parent → returned as-is
 */
export function readMenuOrder(): MenuOrderMap {
  const raw = (window as any).yatraAdmin?.brandMenuOrder;
  if (Array.isArray(raw)) {
    return { "": raw.filter((s): s is string => typeof s === "string") };
  }
  if (raw && typeof raw === "object") {
    const out: MenuOrderMap = {};
    for (const [key, list] of Object.entries(raw)) {
      if (typeof key === "string" && Array.isArray(list)) {
        out[key] = list.filter((s): s is string => typeof s === "string");
      }
    }
    return out;
  }
  return {};
}

export interface UiChromeFlags {
  hideVersion?: boolean;
  hideBackToWp?: boolean;
  hideJoinCommunity?: boolean;
}

export function readUiChrome(): UiChromeFlags {
  const raw = (window as any).yatraAdmin?.brandUiChrome;
  if (!raw || typeof raw !== "object") return {};
  return raw as UiChromeFlags;
}

/**
 * Icons offered in the White Label menu-customization dropdown. Curated
 * to match icons we already import in Layout.tsx — keeps the runtime
 * map small and predictable.
 */
export const SELECTABLE_ICON_NAMES = [
  "LayoutDashboard",
  "MapPin",
  "Calendar",
  "CalendarDays",
  "Star",
  "BarChart3",
  "Settings",
  "Wrench",
  "FileText",
  "CreditCard",
  "Package",
  "UserCircle",
  "Users",
  "FolderTree",
  "Tag",
  "TrendingUp",
  "List",
  "Activity",
  "Crown",
  "Mail",
  "Key",
  "FileSignature",
  "Route",
  "BadgePercent",
  "Plane",
  "MessageSquare",
  "Puzzle",
  "RotateCcw",
  "Tools",
  "Sparkles",
  "MessageCircle",
  "Network",
];

export function readMenuOverrides(): MenuOverrides {
  const raw = (window as any).yatraAdmin?.brandMenuOverrides;
  if (!raw || typeof raw !== "object") return {};
  return raw as MenuOverrides;
}

export function effectiveLabel(
  item: MenuItemDefault,
  overrides: MenuOverrides,
): string {
  const override = overrides[item.slug]?.label;
  return override && override.trim() !== "" ? override : item.label;
}

export function effectiveIconName(
  item: MenuItemDefault,
  overrides: MenuOverrides,
): string {
  // MenuIconValue is `string | IconPickerValue` — only treat the
  // string variant as a candidate override. IconPickerValue (object
  // form) is the picker payload, not the legacy lucide-string name
  // we resolve from a `<MenuIcon name="…" />` mapping table — the
  // picker form is handled elsewhere via toPickerValue() and isn't
  // a substitute for the iconName here.
  const override = overrides[item.slug]?.icon;
  if (typeof override === "string" && override.trim() !== "") {
    return override;
  }
  return item.iconName;
}

export function isHidden(slug: string, overrides: MenuOverrides): boolean {
  return Boolean(overrides[slug]?.hidden);
}

```
