| @@ -5,8 +5,9 @@ | ||
| 5 | 5 | deleteEmailSequence, |
| 6 | 6 | fetchEmailLogs, |
| 7 | 7 | fetchEmailSequences, |
| 8 | 8 | updateEmailSequenceStatus, |
| 9 | + fetchEmailTemplates, | |
| 9 | 10 | } from "../api/email-automation-api"; |
| 10 | 11 | import { useToast } from "../components/ui/toast"; |
| 11 | 12 | import { |
| 12 | 13 | Card, |
| @@ -93,11 +94,9 @@ | ||
| 93 | 94 | enabled: isEmailAutomationModuleEnabled(), |
| 94 | 95 | }); |
| 95 | 96 | |
| 96 | 97 | // Shared dialog rather than the browser's native confirm(). |
| 97 | - const [sequenceToDelete, setSequenceToDelete] = useState<number | null>( | |
| 98 | - null, | |
| 99 | - ); | |
| 98 | + const [sequenceToDelete, setSequenceToDelete] = useState<number | null>(null); | |
| 100 | 99 | |
| 101 | 100 | const deleteMutation = useMutation({ |
| 102 | 101 | mutationFn: async (id: number) => { |
| 103 | 102 | return await deleteEmailSequence(id); |
| @@ -362,8 +361,40 @@ | ||
| 362 | 361 | queryKey: ["email-logs", page, perPage], |
| 363 | 362 | queryFn: () => fetchEmailLogs({ page, per_page: perPage }), |
| 364 | 363 | enabled: isEmailAutomationModuleEnabled(), |
| 365 | 364 | }); |
| 365 | + // Template names for the log rows: an override's key is machine-generated | |
| 366 | + // ("booking_confirmation__ov_…"), so show "Global name · Override name". | |
| 367 | + const { data: templatesForNames } = useQuery({ | |
| 368 | + queryKey: ["email-templates"], | |
| 369 | + queryFn: () => fetchEmailTemplates(), | |
| 370 | + enabled: isEmailAutomationModuleEnabled(), | |
| 371 | + }); | |
| 372 | + const templateLabel = useCallback( | |
| 373 | + (key: string | null | undefined): string => { | |
| 374 | + if (!key) return "—"; | |
| 375 | + const list = Array.isArray(templatesForNames) | |
| 376 | + ? (templatesForNames as any[]) | |
| 377 | + : []; | |
| 378 | + const row = list.find((t) => t.template_key === key); | |
| 379 | + if (!row) { | |
| 380 | + // A deleted override: derive its global template from the key | |
| 381 | + // ("booking_confirmation__ov_1a2b3c4d") so the log stays readable. | |
| 382 | + const m = key.match(/^(.+)__ov_[a-z0-9]+$/); | |
| 383 | + if (m) { | |
| 384 | + const parent = list.find((t) => t.template_key === m[1]); | |
| 385 | + return `${parent?.name || m[1]} · ${__("Override (deleted)", "yatra")}`; | |
| 386 | + } | |
| 387 | + return key; | |
| 388 | + } | |
| 389 | + if (row.overrides) { | |
| 390 | + const parent = list.find((t) => t.template_key === row.overrides); | |
| 391 | + return `${parent?.name || row.overrides} · ${__("Override", "yatra")}: ${row.name}`; | |
| 392 | + } | |
| 393 | + return row.name || key; | |
| 394 | + }, | |
| 395 | + [templatesForNames], | |
| 396 | + ); | |
| 366 | 397 | |
| 367 | 398 | const logs = (logsData?.items ?? []) as EmailLog[]; |
| 368 | 399 | const totalItems = logsData?.total ?? 0; |
| 369 | 400 | const totalPages = Math.max(1, Math.ceil(totalItems / perPage)); |
| @@ -458,10 +489,13 @@ | ||
| 458 | 489 | </td> |
| 459 | 490 | <td className="px-4 py-3 text-sm text-gray-900 dark:text-white max-w-xs truncate"> |
| 460 | 491 | {log.subject} |
| 461 | 492 | </td> |
| 462 | - <td className="px-4 py-3 text-sm text-gray-500 dark:text-gray-400"> | |
| 463 | - {log.template_key} | |
| 493 | + <td | |
| 494 | + className="px-4 py-3 text-sm text-gray-500 dark:text-gray-400" | |
| 495 | + title={log.template_key} | |
| 496 | + > | |
| 497 | + {templateLabel(log.template_key)} | |
| 464 | 498 | </td> |
| 465 | 499 | <td className="px-4 py-3"> |
| 466 | 500 | <Badge |
| 467 | 501 | className={ |
| @@ -925,9 +959,9 @@ | ||
| 925 | 959 | <> |
| 926 | 960 | {automationReady && ( |
| 927 | 961 | <p className="mb-6 text-sm text-gray-600 dark:text-gray-400"> |
| 928 | 962 | {__( |
| 929 | - "Customer booking, payment, cancellation, and trip-reminder emails use the matching template when its body is filled; otherwise the free plugin defaults or settings HTML apply. Admin: New Booking sends when that template has a body (plain-text admin notices from checkout and notifications are skipped to avoid duplicates). Other booking.created templates send in addition to the customer email. Booking Confirmed uses the “Booking Confirmed” row when a booking moves to confirmed; Trip Completed uses its template instead of the generic completed email when the body is filled.", | |
| 963 | + "Customer booking, payment, cancellation, and trip-reminder emails use the matching template when its body is filled; otherwise the free plugin defaults or settings HTML apply. Admin: New Booking sends when that template has a body (plain-text admin notices from checkout and notifications are skipped to avoid duplicates). Other booking.created templates send in addition to the customer email. Booking Confirmed uses the “Booking Confirmed” row when a booking moves to confirmed; Trip Completed uses its template instead of the generic completed email when the body is filled. Override templates replace their global template for the trips they target and are never sent in addition to it.", | |
| 930 | 964 | "yatra", |
| 931 | 965 | )} |
| 932 | 966 | </p> |
| 933 | 967 | )} |