/** * Enquiry Form Page * Create or edit enquiry in a clean, minimal SaaS-style design */ import React, { useMemo, useEffect, useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { ArrowLeft, Save, Loader2 } from "lucide-react"; import { __ } from "../lib/i18n"; import { apiService } from "../lib/api-client"; import { usePermissions } from "../hooks/usePermissions"; import { Button } from "../components/ui/button"; import { Input } from "../components/ui/input"; import { DatePicker } from "../components/ui/date-picker"; import { Select } from "../components/ui/select"; import { useToast } from "../components/ui/toast"; import { PageHeader } from "../components/common/PageHeader"; import { Card, CardContent, CardHeader, CardTitle, } from "../components/ui/card"; import { ConditionalRender } from "../components/ui/conditional-render"; import { useNavigate } from "../hooks/useNavigate"; import { Skeleton } from "../components/ui/skeleton"; import { EnquiryReplyAffordance } from "../components/ai/EnquiryReplyAffordance"; import { Sparkles } from "lucide-react"; interface Enquiry { id: number; name: string; email: string; phone?: string; trip_id?: number; trip_title?: string; message: string; travelers_count?: number; travel_date?: string; status: | "new" | "pending" | "responded" | "closed" | "converted" | "read" | "archived" | "spam" | "trash"; response_notes?: string; created_at: string; responded_at?: string; } interface Trip { id: number; title: string; } const EnquiryForm: React.FC = () => { const { can } = usePermissions(); const { navigate } = useNavigate(); const queryClient = useQueryClient(); const { showToast } = useToast(); // Form state const [formData, setFormData] = useState>({ name: "", email: "", phone: "", trip_id: undefined, message: "", travelers_count: 1, travel_date: "", status: "new", response_notes: "", }); // Tracks whether the AI is currently drafting a reply so the banner // above the textarea can show / hide. Lives in EnquiryForm (not in // EnquiryReplyAffordance) so the textarea + banner can render side by // side without the affordance owning the layout. const [aiDrafting, setAiDrafting] = useState(false); // Get enquiry id from URL (null for create, number for edit) const enquiryId = useMemo(() => { const params = new URLSearchParams(window.location.search); const id = params.get("id"); return id ? parseInt(id) : null; }, []); const isEdit = !!enquiryId; // Fetch enquiry data for editing const { data: enquiry, isLoading: isLoadingEnquiry } = useQuery({ queryKey: ["enquiry", enquiryId], queryFn: async () => { if (!enquiryId) return null; const response = await apiService.getEnquiry(enquiryId!); // Some endpoints return { success, data }, others return the object directly return (response as any)?.data ?? response; }, enabled: !!enquiryId && can("yatra_respond_to_enquiries"), }); // Fetch trips for dropdown const { data: tripsData } = useQuery({ queryKey: ["trips-select"], queryFn: async () => { return await apiService.getTrips({ per_page: 100 }); }, enabled: can("yatra_respond_to_enquiries"), }); // Normalize trips response to array const trips: Trip[] = Array.isArray((tripsData as any)?.data) ? (tripsData as any).data : Array.isArray(tripsData) ? (tripsData as Trip[]) : []; // Update form when enquiry data loads useEffect(() => { if (enquiry) { setFormData({ name: enquiry.name || "", email: enquiry.email || "", phone: enquiry.phone || "", trip_id: enquiry.trip_id, message: enquiry.message || "", travelers_count: enquiry.travelers_count || 1, travel_date: enquiry.travel_date || "", status: enquiry.status || "new", response_notes: enquiry.response_notes || "", }); } }, [enquiry]); // Save mutation const saveMutation = useMutation({ mutationFn: async (data: Partial) => { return isEdit ? await apiService.updateEnquiry(enquiryId!, data) : await apiService.createEnquiry(data); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["enquiries"] }); queryClient.invalidateQueries({ queryKey: ["enquiry", enquiryId] }); showToast(__("Enquiry saved successfully.", "yatra"), "success"); navigate({ subpage: "enquiries" }); }, }); const handleBack = () => { navigate({ subpage: "enquiries" }); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); saveMutation.mutate(formData); }; const handleChange = (field: keyof Enquiry, value: any) => { setFormData((prev) => ({ ...prev, [field]: value })); }; if (isEdit && isLoadingEnquiry) { return (
} />
); } return (
} />
{saveMutation.isError && (
{saveMutation.error?.message || __("Failed to save enquiry. Please try again.", "yatra")}
)}
{/* Main Content */}
{/* Customer Information */} {__("Customer Information", "yatra")}
handleChange("name", e.target.value)} placeholder={__("Customer name", "yatra")} required />
handleChange("email", e.target.value)} placeholder={__("customer@example.com", "yatra")} required />
handleChange("phone", e.target.value)} placeholder={__("Phone number", "yatra")} />
{/* Enquiry Details */} {__("Enquiry Details", "yatra")}