PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
← All changes | resources/js/hooks/useModules.ts +113 -3 3.0.2.7 → 3.0.16 View file →
@@ -7,8 +7,22 @@
7 7 import { apiClient } from "../lib/api-client";
8 8 import { __ } from "../lib/i18n";
9 9 import { useToast } from "../components/ui/toast";
10 10
11 +/**
12 + * Plan tier a module belongs to.
13 + *
14 + * - `free` — bundled with the free Yatra plugin, no license required.
15 + * - `personal` — unlocked by the entry-level Pro license.
16 + * - `growth` — middle tier (AI Assistant + the same-band modules).
17 + * - `agency` — top tier (white-label + agency-only modules).
18 + *
19 + * `growth` was previously missing from this union even though
20 + * `Modules.tsx` already renders a `module.plan === "growth"` badge, which
21 + * surfaced a `TS2367` "no overlap" warning on every type-check.
22 + */
23 +export type ModulePlan = "free" | "personal" | "growth" | "agency";
24 +
11 25 export interface ModuleDefinition {
12 26 slug: string;
13 27 name: string;
14 28 description?: string;
@@ -18,8 +32,10 @@
18 32 is_core?: boolean;
19 33 is_premium?: boolean;
20 34 is_available?: boolean;
21 35 requires_pro?: boolean;
36 + requires_agency?: boolean;
37 + plan?: ModulePlan;
22 38 purchase_url?: string;
23 39 video_url?: string;
24 40 enabled: boolean;
25 41 tags?: string[];
@@ -111,8 +127,11 @@
111 127 );
112 128 window.yatraAdmin.dynamicFormFieldEnabled = enabledModules.some(
113 129 (m) => m.slug === "dynamic_form_field",
114 130 );
131 + window.yatraAdmin.customLandingPagesModuleEnabled = enabledModules.some(
132 + (m) => m.slug === "custom_landing_pages",
133 + );
115 134 window.yatraAdmin.showGoogleCalendarSettingsUI = enabledModules.some(
116 135 (m) => m.slug === "google_calendar" || m.slug === "google-calendar",
117 136 );
118 137 window.yatraAdmin.advancedDiscountEnabled = enabledModules.some(
@@ -118,8 +137,48 @@
118 137 window.yatraAdmin.advancedDiscountEnabled = enabledModules.some(
119 138 (m) =>
120 139 m.slug === "advanced_discount" || m.slug === "advanced-discount",
121 140 );
141 + // AI Assistant + White Label + WhatsApp control top-level
142 + // sidebar menus. Updating these flags here means the menu
143 + // appears / disappears instantly when the operator toggles
144 + // any of them — Layout.tsx re-evaluates its memoized menuItems
145 + // on the `yatra-modules-updated` event dispatched below.
146 + window.yatraAdmin.aiAssistantEnabled = enabledModules.some(
147 + (m) => m.slug === "ai_assistant" || m.slug === "ai-assistant",
148 + );
149 + window.yatraAdmin.whiteLabelEnabled = enabledModules.some(
150 + (m) => m.slug === "white_label" || m.slug === "white-label",
151 + );
152 + window.yatraAdmin.whatsappEnabled = enabledModules.some(
153 + (m) => m.slug === "whatsapp",
154 + );
155 + // Channel Manager controls a top-level Agency-only sidebar menu.
156 + // Updating this flag here means the menu appears / disappears
157 + // instantly when the operator toggles the module — Layout.tsx
158 + // re-evaluates its memoized menuItems on the
159 + // `yatra-modules-updated` event dispatched below.
160 + window.yatraAdmin.channelManagerEnabled = enabledModules.some(
161 + (m) => m.slug === "channel_manager" || m.slug === "channel-manager",
162 + );
163 + // Webhooks — Agency-only sidebar menu, same instant-toggle pattern.
164 + window.yatraAdmin.webhooksEnabled = enabledModules.some(
165 + (m) => m.slug === "webhooks",
166 + );
167 + // Scheduled Payments — decides whether Payments is a plain menu item
168 + // or a parent with All Payments / Scheduled beneath it. Same
169 + // instant-toggle pattern, so the submenu appears and disappears as the
170 + // module is switched, without reloading the admin.
171 + window.yatraAdmin.scheduledPaymentsEnabled = enabledModules.some(
172 + (m) =>
173 + m.slug === "scheduled_payments" || m.slug === "scheduled-payments",
174 + );
175 + // Team & Access — Agency-only sidebar menu. Also drives the
176 + // teamEnabled flag that <Can/> reads to decide whether the
177 + // capability gates apply (vs admin fallback).
178 + window.yatraAdmin.teamEnabled = enabledModules.some(
179 + (m) => m.slug === "team",
180 + );
122 181 // Add flags for Pro feature modules
123 182 window.yatraAdmin.showMailchimpSettingsUI = enabledModules.some(
124 183 (m) => m.slug === "mailchimp",
125 184 );
@@ -181,11 +240,18 @@
181 240 { items },
182 241 );
183 242 return Array.isArray(response?.data) ? response.data : [];
184 243 },
185 - onSuccess: (data, variables = []) => {
244 + onSuccess: (data, variables = [], context) => {
186 245 queryClient.setQueryData(["modules"], data);
187 246
247 + // Check if there's a partial success message (some modules blocked)
248 + const response = context as any;
249 + if (response?.message) {
250 + // Show partial success message with warning
251 + showToast(response.message, "warning");
252 + }
253 +
188 254 // Update global admin variables for navigation
189 255 if (window.yatraAdmin && data) {
190 256 // Update module-specific flags based on the enabled modules
191 257 const enabledModules = data.filter((m) => m.enabled);
@@ -215,8 +281,11 @@
215 281 );
216 282 window.yatraAdmin.dynamicFormFieldEnabled = enabledModules.some(
217 283 (m) => m.slug === "dynamic_form_field",
218 284 );
285 + window.yatraAdmin.customLandingPagesModuleEnabled = enabledModules.some(
286 + (m) => m.slug === "custom_landing_pages",
287 + );
219 288 window.yatraAdmin.showGoogleCalendarSettingsUI = enabledModules.some(
220 289 (m) => m.slug === "google_calendar" || m.slug === "google-calendar",
221 290 );
222 291 window.yatraAdmin.advancedDiscountEnabled = enabledModules.some(
@@ -222,8 +291,48 @@
222 291 window.yatraAdmin.advancedDiscountEnabled = enabledModules.some(
223 292 (m) =>
224 293 m.slug === "advanced_discount" || m.slug === "advanced-discount",
225 294 );
295 + // AI Assistant + White Label + WhatsApp control top-level
296 + // sidebar menus. Updating these flags here means the menu
297 + // appears / disappears instantly when the operator toggles
298 + // any of them — Layout.tsx re-evaluates its memoized menuItems
299 + // on the `yatra-modules-updated` event dispatched below.
300 + window.yatraAdmin.aiAssistantEnabled = enabledModules.some(
301 + (m) => m.slug === "ai_assistant" || m.slug === "ai-assistant",
302 + );
303 + window.yatraAdmin.whiteLabelEnabled = enabledModules.some(
304 + (m) => m.slug === "white_label" || m.slug === "white-label",
305 + );
306 + window.yatraAdmin.whatsappEnabled = enabledModules.some(
307 + (m) => m.slug === "whatsapp",
308 + );
309 + // Channel Manager controls a top-level Agency-only sidebar menu.
310 + // Updating this flag here means the menu appears / disappears
311 + // instantly when the operator toggles the module — Layout.tsx
312 + // re-evaluates its memoized menuItems on the
313 + // `yatra-modules-updated` event dispatched below.
314 + window.yatraAdmin.channelManagerEnabled = enabledModules.some(
315 + (m) => m.slug === "channel_manager" || m.slug === "channel-manager",
316 + );
317 + // Webhooks — Agency-only sidebar menu, same instant-toggle pattern.
318 + window.yatraAdmin.webhooksEnabled = enabledModules.some(
319 + (m) => m.slug === "webhooks",
320 + );
321 + // Scheduled Payments — decides whether Payments is a plain menu item
322 + // or a parent with All Payments / Scheduled beneath it. Same
323 + // instant-toggle pattern, so the submenu appears and disappears as the
324 + // module is switched, without reloading the admin.
325 + window.yatraAdmin.scheduledPaymentsEnabled = enabledModules.some(
326 + (m) =>
327 + m.slug === "scheduled_payments" || m.slug === "scheduled-payments",
328 + );
329 + // Team & Access — Agency-only sidebar menu. Also drives the
330 + // teamEnabled flag that <Can/> reads to decide whether the
331 + // capability gates apply (vs admin fallback).
332 + window.yatraAdmin.teamEnabled = enabledModules.some(
333 + (m) => m.slug === "team",
334 + );
226 335 // Add flags for Pro feature modules
227 336 window.yatraAdmin.showMailchimpSettingsUI = enabledModules.some(
228 337 (m) => m.slug === "mailchimp",
229 338 );
@@ -250,9 +359,10 @@
250 359 (window as any).__yatraUrlKey = urlKey + 1;
251 360 window.dispatchEvent(new CustomEvent("yatra-force-nav-refresh"));
252 361 }
253 362
254 - if (variables.length > 0) {
363 + // Only show success message if there wasn't a partial success message
364 + if (!response?.message && variables.length > 0) {
255 365 const names = variables.map((item) => item.name || item.slug);
256 366 const summary = formatNamesList(names);
257 367 const message = variables[0].enabled
258 368 ? __("Enabled: {modules}", "yatra").replace("{modules}", summary)
@@ -257,9 +367,9 @@
257 367 const message = variables[0].enabled
258 368 ? __("Enabled: {modules}", "yatra").replace("{modules}", summary)
259 369 : __("Disabled: {modules}", "yatra").replace("{modules}", summary);
260 370 showToast(message, "success");
261 - } else {
371 + } else if (!response?.message) {
262 372 showToast(__("Modules updated successfully.", "yatra"), "success");
263 373 }
264 374 },
265 375 onError: (error: Error) => {