PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.17
Yatra – Travel Booking & Tour Operator Software v3.0.17
3.0.17 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 All 85 releases
← All changes | resources/js/pages/License.tsx +62 -1 3.0.3 → 3.0.17 View file →
@@ -1,7 +1,8 @@
1 1 import React, { useState, useEffect } from "react";
2 2 import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3 3 import { apiClient } from "../lib/api-client";
4 +import { toDateValue } from "../lib/dateFormat";
4 5 import { __ } from "../lib/i18n";
5 6 import { useToast } from "../components/ui/toast";
6 7 import {
7 8 Key,
@@ -12,8 +13,9 @@
12 13 EyeOff,
13 14 RefreshCw,
14 15 Bug,
15 16 ChevronDown,
17 + Crown,
16 18 } from "lucide-react";
17 19
18 20 interface LicenseInfo {
19 21 key: string;
@@ -25,9 +27,21 @@
25 27 customer_email?: string;
26 28 license_limit?: number;
27 29 site_count?: number;
28 30 activations_left?: number;
31 + price_id?: string | number;
29 32 };
33 + plan?: {
34 + name: string;
35 + tier: string;
36 + is_agency: boolean;
37 + is_growth?: boolean;
38 + is_personal?: boolean;
39 + is_lifetime?: boolean;
40 + price_id: number | string | null;
41 + matched_by?: "price_id" | "label" | "fallback" | "inactive" | "";
42 + detected_label?: string;
43 + };
30 44 }
31 45
32 46 interface LicenseData {
33 47 is_pro: boolean;
@@ -568,8 +582,53 @@
568 582 </div>
569 583
570 584 {/* License Details */}
571 585 <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
586 + {licenseInfo.plan?.name && (
587 + <div className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4">
588 + <div className="text-sm text-gray-600 dark:text-gray-400 mb-1">
589 + {__("Plan", "yatra")}
590 + </div>
591 + <div className="flex flex-wrap items-center gap-2">
592 + <span className="font-medium text-gray-900 dark:text-white">
593 + {licenseInfo.plan.name}
594 + </span>
595 + {licenseInfo.plan.is_agency && (
596 + <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[11px] font-semibold bg-gradient-to-r from-purple-600 to-indigo-500 text-white">
597 + <Crown className="w-3 h-3" />
598 + {__("Scale", "yatra")}
599 + </span>
600 + )}
601 + {licenseInfo.plan.is_growth && (
602 + <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[11px] font-semibold bg-blue-600 text-white">
603 + {__("Growth", "yatra")}
604 + </span>
605 + )}
606 + {licenseInfo.plan.is_lifetime && (
607 + <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[11px] font-semibold bg-gradient-to-r from-amber-500 to-orange-500 text-white">
608 + {__("Lifetime", "yatra")}
609 + </span>
610 + )}
611 + </div>
612 + {licenseInfo.plan.matched_by === "label" && (
613 + <p className="mt-2 text-[11px] text-gray-500 dark:text-gray-400">
614 + {__(
615 + "Detected from plan label (the original price ID was re-numbered on the store).",
616 + "yatra",
617 + )}
618 + </p>
619 + )}
620 + {licenseInfo.plan.matched_by === "fallback" && (
621 + <p className="mt-2 text-[11px] text-amber-600 dark:text-amber-400">
622 + {__(
623 + "Could not match price ID or label — defaulted to Starter. Contact support if your subscription is Growth or Scale.",
624 + "yatra",
625 + )}
626 + </p>
627 + )}
628 + </div>
629 + )}
630 +
572 631 {licenseInfo.server_response?.customer_name && (
573 632 <div className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4">
574 633 <div className="text-sm text-gray-600 dark:text-gray-400 mb-1">
575 634 {__("Licensed To", "yatra")}
@@ -599,9 +658,11 @@
599 658 </div>
600 659 <div className="font-medium text-gray-900 dark:text-white">
601 660 {(() => {
602 661 try {
603 - const date = new Date(
662 + // toDateValue: a date-only "expires" must not roll back a
663 + // day in behind-UTC zones (datetime values pass through).
664 + const date = toDateValue(
604 665 licenseInfo.server_response.expires,
605 666 );
606 667 return isNaN(date.getTime())
607 668 ? licenseInfo.server_response.expires