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/availability/RecurringRules.tsx +43 -17 3.0.8 → 3.0.16 View file →
@@ -18,8 +18,9 @@
18 18 Search,
19 19 X,
20 20 } from "lucide-react";
21 21 import { __ } from "../../lib/i18n";
22 +import { toDateValue } from "../../lib/dateFormat";
22 23 import { Button } from "../ui/button";
23 24 import { Input } from "../ui/input";
24 25 import { Select } from "../ui/select";
25 26 import { Card, CardContent } from "../ui/card";
@@ -116,8 +117,9 @@
116 117 status: true,
117 118 });
118 119
119 120 // Confirmation dialogs
121 + const [bulkDeleteConfirm, setBulkDeleteConfirm] = useState(false);
120 122 const [deleteConfirm, setDeleteConfirm] = useState<{
121 123 isOpen: boolean;
122 124 rule: RecurringRule | null;
123 125 }>({
@@ -285,25 +287,27 @@
285 287 });
286 288
287 289 // Handle bulk actions
288 290 const handleBulkApply = () => {
289 - if (!bulkAction || selectedIds.length === 0) {
290 - showToast(__("Please select rules and an action", "yatra"), "warning");
291 + // Report the input that is actually missing. The Apply button is disabled
292 + // whenever nothing is selected, so this can only be reached with a non-empty
293 + // selection — the combined message blamed the selection and left operators
294 + // re-selecting rows that were already ticked.
295 + if (selectedIds.length === 0) {
296 + showToast(__("Please select at least one rule.", "yatra"), "warning");
291 297 return;
292 298 }
293 299
300 + if (!bulkAction) {
301 + showToast(__("Please choose an action to apply.", "yatra"), "warning");
302 + return;
303 + }
304 +
294 305 switch (bulkAction) {
295 306 case "delete":
296 - if (
297 - confirm(
298 - __(
299 - "Are you sure you want to delete {count} rule(s)?",
300 - "yatra",
301 - ).replace("{count}", selectedIds.length.toString()),
302 - )
303 - ) {
304 - bulkDeleteMutation.mutate(selectedIds.map((id) => id.toString()));
305 - }
307 + // Confirmed through the shared dialog, matching the single-rule delete
308 + // and duplicate actions in this same component.
309 + setBulkDeleteConfirm(true);
306 310 break;
307 311 }
308 312
309 313 setBulkAction("");
@@ -320,9 +324,9 @@
320 324 // Format date
321 325 const formatDate = (dateString: string | null | undefined): string => {
322 326 if (!dateString) return "--";
323 327 try {
324 - const date = new Date(dateString);
328 + const date = toDateValue(dateString);
325 329 return date.toLocaleDateString("en-US", {
326 330 year: "numeric",
327 331 month: "short",
328 332 day: "numeric",
@@ -499,11 +503,15 @@
499 503 // Use Number(...) > 0 (not truthiness) so a "0.00" string from the
500 504 // DB doesn't mask a real original_price.
501 505 const sale = Number(rule.sale_price) || 0;
502 506 const original = Number(rule.original_price) || 0;
503 - display = formatYatraMoney(sale > 0 ? sale : original, adminCurrency, {
504 - zeroAsUnknown: false,
505 - });
507 + display = formatYatraMoney(
508 + sale > 0 ? sale : original,
509 + adminCurrency,
510 + {
511 + zeroAsUnknown: false,
512 + },
513 + );
506 514 }
507 515
508 516 return (
509 517 <div className="text-sm font-semibold text-gray-900 dark:text-white">
@@ -523,9 +531,9 @@
523 531 });
524 532 }
525 533
526 534 return cols;
527 - // eslint-disable-next-line react-hooks/exhaustive-deps
535 + // eslint-disable-next-line react-hooks/exhaustive-deps
528 536 }, [
529 537 visibleColumns,
530 538 formatRulePattern,
531 539 formatDate,
@@ -933,8 +941,26 @@
933 941 </div>
934 942 </div>
935 943 </CardContent>
936 944 </Card>
945 +
946 + <ConfirmationDialog
947 + isOpen={bulkDeleteConfirm}
948 + onClose={() => setBulkDeleteConfirm(false)}
949 + onConfirm={() => {
950 + bulkDeleteMutation.mutate(selectedIds.map((id) => id.toString()));
951 + setBulkDeleteConfirm(false);
952 + }}
953 + title={__("Delete Rules", "yatra")}
954 + message={__(
955 + "Are you sure you want to delete {count} rule(s)? This action cannot be undone.",
956 + "yatra",
957 + ).replace("{count}", selectedIds.length.toString())}
958 + confirmText={__("Delete", "yatra")}
959 + cancelText={__("Cancel", "yatra")}
960 + variant="danger"
961 + isLoading={bulkDeleteMutation.isPending}
962 + />
937 963 </div>
938 964 );
939 965 };
940 966