import React, { useState, useEffect, useMemo } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { __ } from "../lib/i18n"; import { createEmailSequence, fetchEmailSequence, fetchEmailTemplates, updateEmailSequence, } from "../api/email-automation-api"; import { useToast } from "../components/ui/toast"; import { Card, CardContent, CardHeader, CardTitle, } from "../components/ui/card"; import { Button } from "../components/ui/button"; import { Input } from "../components/ui/input"; import { Badge } from "../components/ui/badge"; import { Select } from "../components/ui/select"; import { Switch } from "../components/ui/switch"; import { GitBranch, ArrowLeft, Save, Loader2, Plus, Trash2, Zap, GripVertical, Info, ChevronDown, Mail, Check, } from "lucide-react"; interface EmailTemplate { id: number; name: string; template_key: string; category: string; description?: string; event_key?: string; recipient_type?: string; } interface SequenceStep { id?: number; step_order: number; delay_value: number; delay_unit: "minutes" | "hours" | "days" | "weeks"; template_id: number | null; template_name?: string; custom_subject: string; custom_body: string; conditions: any[]; is_active: boolean; } interface SequenceData { id?: number; name: string; description: string; trigger_type: string; trigger_config: any; status: "active" | "paused" | "draft"; applicable_to: string; trip_ids: number[]; steps?: SequenceStep[]; } const delayUnits = [ { value: "minutes", label: __("Minutes") }, { value: "hours", label: __("Hours") }, { value: "days", label: __("Days") }, { value: "weeks", label: __("Weeks") }, ]; const EmailSequenceForm: React.FC = () => { const id = useMemo(() => { const params = new URLSearchParams(window.location.search); return params.get("id"); }, []); const isEditing = !!id; const goBack = () => { window.location.href = `admin.php?page=yatra&subpage=email-automation&tab=sequences`; }; const queryClient = useQueryClient(); const { showToast } = useToast(); const [formData, setFormData] = useState({ name: "", description: "", trigger_type: "booking.created", trigger_config: {}, status: "draft", applicable_to: "all", trip_ids: [], }); const [steps, setSteps] = useState([ { step_order: 0, delay_value: 0, delay_unit: "minutes", template_id: null, custom_subject: "", custom_body: "", conditions: [], is_active: true, }, ]); // State for template dropdown per step const [openTemplateDropdown, setOpenTemplateDropdown] = useState< number | null >(null); // Get events from window.yatraAdmin (passed from PHP) // eslint-disable-next-line react-hooks/exhaustive-deps const events = (window as any).yatraAdmin?.emailEvents || []; // Fetch sequence data if editing const { data: sequenceData, isLoading: isLoadingSequence } = useQuery({ queryKey: ["email-sequence", id], queryFn: () => fetchEmailSequence(id as string), enabled: isEditing, }); // Fetch templates for step selection const { data: templatesData } = useQuery({ queryKey: ["email-templates"], queryFn: () => fetchEmailTemplates(), }); // eslint-disable-next-line react-hooks/exhaustive-deps const templates: EmailTemplate[] = Array.isArray(templatesData) ? (templatesData as EmailTemplate[]) : []; // Get all trigger events from Schema (passed via window.yatraAdmin.emailEvents) const allTriggerEvents = useMemo(() => { return events.map((e: any) => ({ key: e.key, name: e.name, description: e.description, category: e.category, })); }, [events]); // State for trigger dropdown const [openTriggerDropdown, setOpenTriggerDropdown] = useState(false); // Sequences send to the customer; exclude admin-only templates. Event-bound templates may still be reused as step content. const sequenceTemplates = useMemo(() => { return templates.filter((t) => t.recipient_type !== "admin"); }, [templates]); // Populate form when editing useEffect(() => { if (!sequenceData || typeof sequenceData !== "object") { return; } const loaded = sequenceData as SequenceData; setFormData({ name: loaded.name || "", description: loaded.description || "", trigger_type: loaded.trigger_type || "booking.created", trigger_config: loaded.trigger_config || {}, status: loaded.status || "draft", applicable_to: loaded.applicable_to || "all", trip_ids: loaded.trip_ids || [], }); if (loaded.steps && loaded.steps.length > 0) { setSteps(loaded.steps); } }, [sequenceData]); // Create mutation const createMutation = useMutation({ mutationFn: async (data: any) => { return await createEmailSequence(data); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["email-sequences"] }); showToast(__("Sequence created successfully"), "success"); goBack(); }, onError: () => { showToast(__("Failed to create sequence"), "error"); }, }); // Update mutation const updateMutation = useMutation({ mutationFn: async (data: any) => { return await updateEmailSequence(id as string, data); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["email-sequences"] }); queryClient.invalidateQueries({ queryKey: ["email-sequence", id] }); showToast(__("Sequence updated successfully"), "success"); }, onError: () => { showToast(__("Failed to update sequence"), "error"); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const payload = { ...formData, steps: steps.map((step, index) => ({ ...step, step_order: index, })), }; if (isEditing) { updateMutation.mutate(payload); } else { createMutation.mutate(payload); } }; const addStep = () => { setSteps([ ...steps, { step_order: steps.length, delay_value: 1, delay_unit: "days", template_id: null, custom_subject: "", custom_body: "", conditions: [], is_active: true, }, ]); }; const removeStep = (index: number) => { if (steps.length > 1) { setSteps(steps.filter((_, i) => i !== index)); } }; const updateStep = (index: number, field: string, value: any) => { const newSteps = [...steps]; (newSteps[index] as any)[field] = value; setSteps(newSteps); }; const selectedTrigger = allTriggerEvents.find( (t: any) => t.key === formData.trigger_type, ); const isPending = createMutation.isPending || updateMutation.isPending; if (isEditing && isLoadingSequence) { return (
{/* Header Skeleton */}
{/* Main Form Skeleton */}
{/* Basic Info Card */}
{/* Trigger Card */}
{[1, 2, 3, 4, 5, 6].map((i) => (
))}
{/* Steps Card */}
{[1, 2].map((i) => (
))}
{/* Sidebar Skeleton */}
{[1, 2, 3].map((i) => (
))}
); } return (
{/* Header */}

{isEditing ? __("Edit Sequence") : __("Create Sequence")}

{isEditing && formData.name && (

{formData.name}

)}
{/* Main Form */}
{/* Basic Info */} {__("Sequence Details")}
setFormData({ ...formData, name: e.target.value }) } placeholder={__("e.g., Post-Booking Welcome Series")} required />
setFormData({ ...formData, description: e.target.value }) } placeholder={__( "Brief description of what this sequence does", )} />
{/* Trigger */} {__("Trigger")}
{/* Dropdown Trigger Button */} {/* Dropdown List - Same style as Email Template form */} {openTriggerDropdown && (

{__("Select an event to trigger this sequence")}

{allTriggerEvents.map((trigger: any) => { const isSelected = formData.trigger_type === trigger.key; return ( ); })}
)} {/* Click outside to close */} {openTriggerDropdown && (
setOpenTriggerDropdown(false)} /> )}
{/* Days input for schedule events */} {(formData.trigger_type === "schedule.days_before_trip" || formData.trigger_type === "schedule.days_after_trip") && (
setFormData({ ...formData, trigger_config: { ...formData.trigger_config, days: parseInt(e.target.value), }, }) } className="w-32" />
)} {/* Steps */}
{__("Sequence Steps")}
{steps.map((step, index) => (
{/* Step Header */}
{__("Step")} {index + 1} {index === 0 && ( {__("First Email")} )}
updateStep(index, "is_active", checked) } /> {steps.length > 1 && ( )}
{/* Step Content */}
{/* Delay */}
updateStep( index, "delay_value", parseInt(e.target.value) || 0, ) } className="w-24" /> {index === 0 && step.delay_value === 0 && ( ({__("Immediately")}) )}
{/* Template Selection - Card Style Dropdown */}
{/* Dropdown Trigger */} {/* Dropdown List */} {openTemplateDropdown === index && (
{sequenceTemplates.length === 0 ? (

{__("No templates available")}

{__( "Add customer email templates under Email → Templates first.", )}

) : ( sequenceTemplates.map((template) => { const isSelected = step.template_id === template.id; return ( ); }) )}
)} {/* Click outside to close */} {openTemplateDropdown === index && (
setOpenTemplateDropdown(null)} /> )} {!step.template_id && (

{__("Please select a template for this step")}

)}
))}
{steps.length === 0 && (

{__("No steps added yet")}

)}
{/* Sidebar */}
{/* Info Card */} {__("How Sequences Work")}

{__( "Email sequences are automated workflows that send emails based on triggers and timing.", )}

  1. {__("Choose a trigger event (e.g., booking created)")}
  2. {__("Add steps with delays and email templates")}
  3. {__("Set the sequence to Active")}
  4. {__("Emails will be sent automatically!")}
{/* Status Info */} {__("Status")}
{__("Current Status")} {formData.status === "active" ? __("Active") : formData.status === "paused" ? __("Paused") : __("Draft")}
{__("Steps")} {steps.length}
{__("Trigger")} {selectedTrigger?.label}
); }; export default EmailSequenceForm;