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/components/modules/PremiumUpgradeDialog.tsx +159 -34 3.0.2.8 → 3.0.16 View file →
@@ -22,21 +22,140 @@
22 22 interface PremiumUpgradeDialogProps {
23 23 open: boolean;
24 24 onClose: () => void;
25 25 moduleName?: string;
26 + /** Module slug — used to pick module-specific bullet copy. */
27 + moduleSlug?: string;
26 28 purchaseUrl?: string;
27 29 moduleDescription?: string;
30 + /**
31 + * Required plan tier for this feature — drives the badge in the
32 + * header AND the CTA copy. When unset, the dialog falls back to
33 + * the generic "Yatra Pro" messaging.
34 + */
35 + requiredPlan?: "personal" | "growth" | "agency";
28 36 }
29 37
38 +/**
39 + * Module-specific bullets shown in the "Key Features" list. Without
40 + * these we'd be stuck with the generic four-item placeholder
41 + * ("Advanced analytics and reporting", etc.) regardless of which
42 + * module the operator is looking at — confusing because the dialog
43 + * title already says "White Label" but the bullets say nothing about
44 + * branding.
45 + */
46 +const MODULE_FEATURES: Record<string, string[]> = {
47 + white_label: [
48 + "Rebrand the plugin: name, logo, author, support URL",
49 + "Replace Yatra/MantraBrain references on plugin list + PDFs",
50 + "Custom admin menu labels, icons, ordering",
51 + "Custom brand color applied across the admin UI",
52 + ],
53 + "white-label": [
54 + "Rebrand the plugin: name, logo, author, support URL",
55 + "Replace Yatra/MantraBrain references on plugin list + PDFs",
56 + "Custom admin menu labels, icons, ordering",
57 + "Custom brand color applied across the admin UI",
58 + ],
59 + ai_assistant: [
60 + "Inline AI generation on trip descriptions, FAQs, SEO meta",
61 + "Multi-step agents for full trip + itinerary creation",
62 + "AI public chat widget on every single-trip page",
63 + "Bring your own OpenAI / Anthropic key — no per-call markup",
64 + ],
65 + "ai-assistant": [
66 + "Inline AI generation on trip descriptions, FAQs, SEO meta",
67 + "Multi-step agents for full trip + itinerary creation",
68 + "AI public chat widget on every single-trip page",
69 + "Bring your own OpenAI / Anthropic key — no per-call markup",
70 + ],
71 +};
72 +
73 +/**
74 + * Fallback bullets per plan tier when the module isn't in
75 + * MODULE_FEATURES yet. Tier-appropriate so a "Growth" module's
76 + * generic bullets don't accidentally mention Agency-only perks.
77 + */
78 +const TIER_DEFAULT_FEATURES: Record<string, string[]> = {
79 + agency: [
80 + "Unlocks every premium module — Scale-tier and below",
81 + "Full white-label rebranding capability",
82 + "Priority support with faster response times",
83 + "All future Scale-tier features included",
84 + ],
85 + growth: [
86 + "Advanced operator-productivity features",
87 + "AI assistant for content + itinerary generation",
88 + "Priority support included",
89 + "All future Growth-tier features included",
90 + ],
91 + personal: [
92 + "Premium booking-system extensions",
93 + "Email automation + abandoned-recovery workflows",
94 + "Dynamic pricing + advanced discount tools",
95 + "All future Starter-tier features included",
96 + ],
97 +};
98 +
30 99 export const PremiumUpgradeDialog: React.FC<PremiumUpgradeDialogProps> = ({
31 100 open,
32 101 onClose,
33 102 moduleName,
103 + moduleSlug,
34 104 purchaseUrl,
35 105 moduleDescription,
106 + requiredPlan,
36 107 }) => {
37 108 if (!open) return null;
38 109
110 + // Resolve the customer-facing plan name from the tier slug. The
111 + // header badge + footer CTA both consume this so the operator
112 + // sees one consistent answer to "which plan do I need?".
113 + const planLabel =
114 + requiredPlan === "agency"
115 + ? __("Scale plan", "yatra")
116 + : requiredPlan === "growth"
117 + ? __("Growth plan", "yatra")
118 + : requiredPlan === "personal"
119 + ? __("Starter plan", "yatra")
120 + : null;
121 + const planCtaLabel =
122 + requiredPlan === "agency"
123 + ? __("Upgrade to Scale", "yatra")
124 + : requiredPlan === "growth"
125 + ? __("Upgrade to Growth", "yatra")
126 + : requiredPlan === "personal"
127 + ? __("Upgrade to Starter", "yatra")
128 + : __("Upgrade to Pro", "yatra");
129 + const planFooterCopy =
130 + requiredPlan === "agency"
131 + ? __(
132 + "This feature is exclusive to the Scale plan. Upgrade to unlock it.",
133 + "yatra",
134 + )
135 + : requiredPlan === "growth"
136 + ? __(
137 + "This feature unlocks on the Growth plan (or Scale). Upgrade to enable it.",
138 + "yatra",
139 + )
140 + : requiredPlan === "personal"
141 + ? __(
142 + "This feature is included on every Pro plan. Upgrade to unlock it.",
143 + "yatra",
144 + )
145 + : __("Upgrade to Yatra Pro and unlock this feature today", "yatra");
146 +
147 + // Module-specific bullets first; fall back to tier-appropriate
148 + // defaults; finally fall back to the very generic Pro bullets so
149 + // the section never renders empty.
150 + const features: string[] = (moduleSlug && MODULE_FEATURES[moduleSlug]) ||
151 + (requiredPlan && TIER_DEFAULT_FEATURES[requiredPlan]) || [
152 + __("Advanced analytics and reporting", "yatra"),
153 + __("Automated workflows and notifications", "yatra"),
154 + __("Enhanced customer management tools", "yatra"),
155 + __("Priority support and updates", "yatra"),
156 + ];
157 +
39 158 return createPortal(
40 159 <div
41 160 className="fixed top-0 left-0 right-0 bottom-0 m-0 bg-black/60 backdrop-blur-sm flex items-center justify-center px-4 pb-4"
42 161 style={{
@@ -61,17 +180,39 @@
61 180 <div className="flex items-start gap-4">
62 181 <div className="w-12 h-12 rounded-full bg-gradient-to-br from-orange-500 to-orange-600 flex items-center justify-center flex-shrink-0">
63 182 <Crown className="w-6 h-6 text-white" />
64 183 </div>
65 - <div>
66 - <CardTitle className="text-xl font-bold text-gray-900 dark:text-white">
67 - {moduleName
68 - ? `${moduleName} - Premium Feature`
69 - : "Premium Feature"}
70 - </CardTitle>
184 + <div className="flex-1">
185 + <div className="flex flex-wrap items-center gap-2">
186 + <CardTitle className="text-xl font-bold text-gray-900 dark:text-white">
187 + {moduleName || __("Premium Feature", "yatra")}
188 + </CardTitle>
189 + {/* Plan-tier badge so the operator immediately
190 + knows which license unlocks this. Without it the
191 + generic "Premium Feature" copy was ambiguous —
192 + Growth and Scale are both premium but cost
193 + different amounts. */}
194 + {planLabel && (
195 + <span
196 + className={
197 + "inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium text-white shadow-sm " +
198 + (requiredPlan === "agency"
199 + ? "bg-gradient-to-r from-purple-600 to-indigo-500"
200 + : requiredPlan === "growth"
201 + ? "bg-gradient-to-r from-emerald-500 to-teal-500"
202 + : "bg-gradient-to-r from-blue-500 to-blue-600")
203 + }
204 + >
205 + {planLabel}
206 + </span>
207 + )}
208 + </div>
71 209 <CardDescription className="text-gray-600 dark:text-gray-400 mt-1">
72 210 {moduleDescription ||
73 - "This feature requires Yatra Pro to unlock powerful premium capabilities."}
211 + __(
212 + "This feature requires Yatra Pro to unlock powerful premium capabilities.",
213 + "yatra",
214 + )}
74 215 </CardDescription>
75 216 </div>
76 217 </div>
77 218 <Button
@@ -103,9 +244,11 @@
103 244 )}
104 245 </p>
105 246 </div>
106 247
107 - {/* Feature List */}
248 + {/* Feature List — module-specific bullets so the
249 + operator sees exactly what they're getting, not
250 + a generic placeholder list. */}
108 251 <div>
109 252 <h4 className="font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
110 253 <Sparkles className="w-4 h-4 text-orange-500" />
111 254 {__("Key Features", "yatra")}
@@ -110,32 +253,14 @@
110 253 <Sparkles className="w-4 h-4 text-orange-500" />
111 254 {__("Key Features", "yatra")}
112 255 </h4>
113 256 <ul className="space-y-2 text-sm text-gray-600 dark:text-gray-400">
114 - <li className="flex items-start gap-2">
115 - <CheckCircle2 className="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5" />
116 - <span>
117 - {__("Advanced analytics and reporting", "yatra")}
118 - </span>
119 - </li>
120 - <li className="flex items-start gap-2">
121 - <CheckCircle2 className="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5" />
122 - <span>
123 - {__("Automated workflows and notifications", "yatra")}
124 - </span>
125 - </li>
126 - <li className="flex items-start gap-2">
127 - <CheckCircle2 className="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5" />
128 - <span>
129 - {__("Enhanced customer management tools", "yatra")}
130 - </span>
131 - </li>
132 - <li className="flex items-start gap-2">
133 - <CheckCircle2 className="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5" />
134 - <span>
135 - {__("Priority support and updates", "yatra")}
136 - </span>
137 - </li>
257 + {features.map((line, i) => (
258 + <li key={i} className="flex items-start gap-2">
259 + <CheckCircle2 className="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5" />
260 + <span>{line}</span>
261 + </li>
262 + ))}
138 263 </ul>
139 264 </div>
140 265 </div>
141 266 </div>
@@ -163,9 +288,9 @@
163 288 <div className="border-t border-gray-200 dark:border-gray-800 p-6 bg-gray-50 dark:bg-gray-900/50">
164 289 <div className="flex flex-col sm:flex-row items-center justify-between gap-4">
165 290 <div className="text-center sm:text-left">
166 291 <p className="text-sm text-gray-600 dark:text-gray-400">
167 - Upgrade to Yatra Pro and unlock this feature today
292 + {planFooterCopy}
168 293 </p>
169 294 </div>
170 295 <Button
171 296 className="bg-gradient-to-r from-orange-600 to-orange-500 hover:from-orange-700 hover:to-orange-600 text-white px-6 py-2 font-medium shadow-lg hover:shadow-xl transition-all duration-200 group"
@@ -176,9 +301,9 @@
176 301 )
177 302 }
178 303 >
179 304 <Sparkles className="w-4 h-4 mr-2 group-hover:rotate-12 transition-transform" />
180 - {__("Upgrade to Pro", "yatra")}
305 + {planCtaLabel}
181 306 <ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
182 307 </Button>
183 308 </div>
184 309 </div>