/** * Settings Page * Comprehensive settings page for trip booking software * Left sidebar navigation + Right side form fields with detailed configurations */ import React, { useState, useEffect, useMemo } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Settings as SettingsIcon, Save, Loader2, Building2, Calendar, DollarSign, Mail, MapPin, SlidersHorizontal, Users, Star, Receipt, Globe, Plug, Shield, Info, ChevronDown, GripVertical, ArrowUp, ArrowDown, ClipboardList, Plus, Trash2, Eye, EyeOff, Edit2, Lock, CheckCircle, XCircle, AlertCircle, RefreshCw, ExternalLink, ChevronRight, Check, Image, X, TrendingUp, BarChart3, Palette, Percent, } from "lucide-react"; import { __ } from "../lib/i18n"; import { prepareWordPressMediaFrameOpen } from "../lib/wp-media-open"; import { usePermissions } from "../hooks/usePermissions"; import { useToast } from "../components/ui/toast"; import { navigateMenu } from "../hooks/useNavigate"; import { apiClient, apiService } from "../lib/api-client"; import { fetchBookingPageShortcodeStatus, fetchPaymentGatewayDefinitions, fetchSettings, fetchWordPressPages, postFlushRewriteRules, postInsertBookingShortcode, saveSettings, } from "../api/settings-api"; import { fetchUsageTrackingStatus, postUsageTrackingSettings, postUsageTrackingSend, type UsageTrackingStatus, } from "../api/usage-tracking-api"; import { Button } from "../components/ui/button"; import { ProFeature, ProBadge } from "../components/ProFeature"; import { PremiumUpgradeDialog } from "../components/modules/PremiumUpgradeDialog"; import { Input } from "../components/ui/input"; import { Select } from "../components/ui/select"; import { Label } from "../components/ui/label"; import { PageHeader } from "../components/common/PageHeader"; import { Card, CardContent, CardHeader, CardTitle, CardFooter, } from "../components/ui/card"; import { ConditionalRender } from "../components/ui/conditional-render"; import { ConfirmationDialog } from "../components/ui/confirmation-dialog"; import { buildYatraAccountViewUrl, buildYatraListingPublicUrl, isWordPressPlainPermalink, } from "../lib/frontend-permalink-urls"; import { getCurrencyOptions } from "../data/currencies"; import { SearchableSelect } from "../components/ui/searchable-select"; import { MultiSelect, MultiSelectOption } from "../components/ui/multi-select"; // Multiple Taxes Editor Component const MultipleTaxesEditor = React.memo( ({ taxes, onChange, }: { taxes: Array<{ name: string; rate: number }>; onChange: (taxes: Array<{ name: string; rate: number }>) => void; }) => { const removeTax = (index: number) => { onChange(taxes.filter((_, i) => i !== index)); }; const updateTax = ( index: number, field: "name" | "rate", value: string | number, ) => { const updated = [...taxes]; if (field === "rate") { updated[index].rate = parseFloat(value as string) || 0; } else { updated[index].name = value as string; } onChange(updated); }; return (
{__( "Connect your Google Calendar to automatically sync bookings and departures. Events will be created for each booking with trip details, traveler information, and departure dates.", "yatra", )}
123...apps.googleusercontent.com
>
}
>
setClientId(e.target.value)}
placeholder="123456789-xxxxx.apps.googleusercontent.com"
/>
https://www.googleapis.com/auth/calendar
https://www.googleapis.com/auth/calendar.events
{lastSync ? ( <> {__("Last sync:", "yatra")}{" "} {new Date(lastSync).toLocaleString()} > ) : ( __("Never synced", "yatra") )}
{__("Lowercase, no spaces", "yatra")}
{__( 'Click "Add Option" to add dropdown choices.', "yatra", )}
)}{__( 'No fields configured. Click "Add Field" to get started.', "yatra", )}
{__( 'No options. Click "Add Option" to add dropdown choices.', "yatra", )}
)}
{field.id}
)}
{fieldTypes.find((t) => t.value === field.type)
?.label || field.type}
{widthOptions.find((w) => w.value === field.width)
?.label || "Full"}
{field.type === "text_block" && field.content && (
"
{field.content
.replace(/<[^>]*>/g, "")
.slice(0, 60)}
"
)}
{field.type === "select" &&
field.options &&
field.options.length > 0 && (
({field.options.length}{" "}
{field.options.length === 1
? "option"
: "options"}
)
)}
{field.required && (
{__("Required", "yatra")}
)}
{activeFormTab === "traveler_form" &&
field.applies_to === "lead" && (
{__("Lead only", "yatra")}
)}
{field.locked && (
{currentConfig.description}
{__( "Control how Yatra looks on the public site (trip pages, booking, listings, and shortcodes). These options complement your WordPress theme.", "yatra", )}
{__( "Enable deposit and partial payment options for bookings. Allow customers to pay a percentage upfront and the rest later.", "yatra", )}
{__( "Allow customers to pay a portion now and the rest later", "yatra", )}
{__("Require a deposit to confirm bookings", "yatra")}
{__( "After a deposit or partial payment, automatically schedule the remaining balance with your gateway (Stripe invoices or subscription schedules). Requires a gateway customer and payment method from checkout.", "yatra", )}
{__( "When a booking still has an amount due after checkout, create gateway-side schedules using the rules below.", "yatra", )}
{__( 'Automatically confirm bookings when "Book Now, Pay Later" is selected. If disabled, bookings will remain pending until payment is received.', "yatra", )}
{__( "Enable test/sandbox mode for all payment gateways. Use test API keys for development and testing. Disable this for live payments.", "yatra", )}
{gateway.description}
{gateway.id === "pay_later" ? __( "Allow customers to book now and pay later. Payment must be completed before the trip date.", "yatra", ) : __( "This is an offline payment method. Customers will be shown these details after booking.", "yatra", )}
{field.description}
)} {stripeSetupUrl && ( {field.help_text || __( "Open Stripe → Webhooks", "yatra", )}{" "} → )}{__( "Apple Pay requires domain verification inside your Stripe Dashboard.", "yatra", )} {(field.help_url || field.help_url_test || field.help_url_live) && ( {__("Learn more →", "yatra")} )}
{field.help_text}
)}{field.help_text}
)}{field.help_text}
)}{field.help_text} {(field.help_url || field.help_url_test || field.help_url_live) && ( {__("Learn more →", "yatra")} )}
)}{__("Loading payment gateways...", "yatra")}
{__( "Choose which fields appear in the trip search bar. Turn off the ones you don't need for a cleaner search.", "yatra", )}
{row.description}
{__( "Controls the filter sidebar on the trip listing page on mobile devices.", "yatra", )}
{__( "On mobile, show filter sections collapsed so trip listings are visible right away. Visitors tap a section to expand it. Desktop is unaffected.", "yatra", )}
{__( "Send a confirmation email to the customer immediately after a successful booking. The post-checkout page is always shown; this toggle only controls the email.", "yatra", )}
{__( "Automatically confirm bookings without manual approval", "yatra", )}
{__( "Customers must create an account to make bookings", "yatra", )}
{__( "Allow customers to book without creating an account", "yatra", )}
{__( "Hold guest bookings until the customer clicks a magic link sent to their email. Stops typo'd addresses and form-spam bots. Only applies when guest checkout is allowed and login isn't required — logged-in customers are already verified.", "yatra", )}
{__( "Keep sold-out dates on the calendar marked \"Sold out\" — needed for the waitlist below. Turn this off to hide them entirely, the way blocked dates are hidden.", "yatra", )}
{__( "Customers can join a waitlist instead of being blocked when seats are gone (per-trip caps still apply).", "yatra", )}
{__( "When a spot opens, move the next waitlisted booking to confirmed; otherwise it becomes pending for staff review.", "yatra", )}
{__( "Replace the calendar date picker with a dropdown listing every available departure date on the single-trip sidebar and the mobile sticky bar. Best for trips with a small set of fixed departures.", "yatra", )}
{__( "Allow customers to create accounts on your website", "yatra", )}
{__( "Shows the heart control on trip cards and single trips, and the Saved Trips area in the customer account. Requires Yatra Pro.", "yatra", )}
{__( "Customers must verify their email before account activation", "yatra", )}
{__( "Allow customers to leave reviews and ratings", "yatra", )}
{__( "Only customers who have booked can leave reviews", "yatra", )}
{__( "Automatically publish reviews without moderation", "yatra", )}
{__( "Manually approve reviews before they are published", "yatra", )}
{__("Add tax to booking prices", "yatra")}
{__("Tax is included in displayed prices", "yatra")}
{__( "Automatically sync customers to Mailchimp lists when they book. Add tags based on trips booked and build targeted email campaigns.", "yatra", )}
{__( "Automatically add customers to Mailchimp when they make a booking", "yatra", )}
{__( "Require email confirmation before adding to list (recommended for GDPR)", "yatra", )}
{__( "Map Yatra customer fields to Mailchimp merge fields. This controls what data is synced when a customer is added to your list.", "yatra", )}
{__( "Automatically tag subscribers with the trip name they booked", "yatra", )}
{__( "Track booking conversions with Facebook Pixel. Retarget visitors who viewed trips and optimize ad campaigns with accurate conversion data.", "yatra", )}
{__( "Your Facebook Pixel ID (e.g., 123456789012345).", "yatra", )}
{__( "Required for Conversions API. Enables server-side tracking for better accuracy.", "yatra", )}
{__("💡 Tip:", "yatra")}{" "} {__( "If you have multiple Pixels, look for the one that matches the Pixel ID you entered above. The Pixel ID is displayed next to each Pixel name in the list.", "yatra", )}
{__( "⚠️ Keep your access token secure and never share it publicly.", "yatra", )}
{__( "Connect GA4 for ecommerce events (view item, add to cart, checkout, purchase). Optional Measurement Protocol sends verified server-side events for more reliable attribution.", "yatra", )}
{__( "Use your GA4 web data stream Measurement ID (format G-XXXXXXXXXX). Find it under Admin → Data streams → your stream.", "yatra", )}
{__( "Your GA4 web data stream Measurement ID (format G-XXXXXXXXXX). The Validate button checks the format only — confirm the stream is live in your GA4 Admin.", "yatra", )}
{__( "Choose which standard ecommerce events Yatra should emit to GA4 on the storefront and booking flow.", "yatra", )}
{__( "Trip detail pages (recommended for remarketing).", "yatra", )}
{__( "When a trip is added to the booking session / checkout.", "yatra", )}
{__( "When a booking is created (checkout started).", "yatra", )}
{__( "When payment completes (and on confirmation page).", "yatra", )}
{__( "Send duplicate events from your server with an API secret—useful when ad blockers affect the browser tag or for reconciliation.", "yatra", )}
{__( "Requires an API secret from the same GA4 data stream.", "yatra", )}
{__( "Send Measurement Protocol hits to Google’s validation URL for troubleshooting. Events won’t appear in standard reports.", "yatra", )}
{__( "Treat this like a password — anyone with it can send fake events to your GA4 property. Restrict who can view Yatra settings.", "yatra", )}
{__("Reports & event log", "yatra")}
{__( "Review connection status and recent Measurement Protocol activity under", "yatra", )}{" "} {__("Reports", "yatra")} {" → "} {__("Google Analytics 4.", "yatra")}
{__( "Maps are powered by OpenStreetMap - a free, open-source mapping service. No API key required! Maps will automatically display trip starting locations with custom markers.", "yatra", )}
{__("Protect forms from spam and bots", "yatra")}
{__( "Uses reCAPTCHA v3 (invisible, score-based). Create v3 keys at google.com/recaptcha and paste them above.", "yatra", )}
{__( "Choose which forms reCAPTCHA should verify. Booking protection is off by default to avoid blocking a legitimate payment on a low score.", "yatra", )}
{__( "Configure URL slugs for your Yatra content types. These settings control how your trips, destinations, and activities appear in URLs.", "yatra", )}
{listingHref(formData.trip_base || "trip")}
{listingHref(
formData.destination_base || "destination",
)}
{listingHref(formData.activity_base || "activity")}
{listingHref(
formData.trip_category_base || "trip-category",
)}
{__( "Configure the booking page URL. By default, bookings use /book/{trip-slug}. You can customize the URL base or use a custom WordPress page.", "yatra", )}
{listingHref(formData.booking_base || "book")}
{bookingConfirmationPreviewUrl(
formData.booking_base || "book",
)}
{__(
"append booking reference after checkout",
"yatra",
)}
{__("Booking URL:", "yatra")}{" "}
{pagesData.find(
(p) => p.id === formData.booking_page_id,
)?.url || ""}
{__("The page", "yatra")}{" "}
"{selectedPageForShortcode.title}"{" "}
{__("doesn't have the", "doesn't have the")}{" "}
[yatra_booking]
{" "}
{__("shortcode.", "yatra")}
{__( "Would you like to add it automatically, or edit the page manually to place it where you want?", "yatra", )}
{__("Important:", "yatra")}
{__( "After changing permalink settings, you must flush rewrite rules for the changes to take effect.", "yatra", )}
{__( "Configure SEO meta tags for the trip archive page (/trip/). These meta tags will be used for the main trip listing page.", "yatra", )}
{__( "Recommended size: 1200x630 pixels for optimal social media display.", "yatra", )}
{__( "Upload an image that will appear when your trip archive page is shared on social media. Recommended size: 1200x630 pixels.", "yatra", )}
{__( "Yatra publishes one sitemap of all trips, destinations, activities and categories so search engines can find them. It is advertised in robots.txt and linked into Yoast, Rank Math, AIOSEO and WordPress core sitemaps automatically.", "yatra", )}
{__( "Generate /yatra-sitemap.xml and advertise it to search engines.", "yatra", )}
{__( "Optional: submit this URL in Google Search Console or Bing Webmaster Tools. It is already listed in robots.txt, so search engines find it automatically.", "yatra", )}
{__( "Log system events and errors for troubleshooting", "yatra", )}
{__( "Extra plugin-side diagnostics. When on, Yatra object cache is bypassed (same as when WP_DEBUG is true in wp-config).", "yatra", )}
{__( "Stores frequently used data for faster loads. Stays off while WP_DEBUG or Debug mode (above) is on.", "yatra", )}
{__( "Select the pages that will be linked from the booking Terms and Privacy consent checkboxes.", "yatra", )}
{__( "If not set here, WordPress Settings → Privacy will be used when available.", "yatra", )}
{__(
"Share non-sensitive technical details so we can make Yatra better. You can turn this off anytime. See what we collect on our site:",
"yatra",
)}{" "}
{__("What we collect", "yatra")}
{__( "Could not load this section. You may need permission to manage Yatra.", "yatra", )}
{usageError && ({usageError}
)}
{__(
"Sent periodically while enabled. Learn more: ",
"yatra",
)}
{__("What we collect", "yatra")}