/** * Departure Recurring Rule Form * Create and edit recurring rules for departures */ import React, { useState, useEffect } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { ArrowLeft, Save, Loader2 } from "lucide-react"; import { __ } from "../lib/i18n"; import { Button } from "../components/ui/button"; import { Input } from "../components/ui/input"; import { Select } from "../components/ui/select"; import { PageHeader } from "../components/common/PageHeader"; import { Card, CardContent } from "../components/ui/card"; import { HelpText } from "../components/ui/help-text"; import { DatePicker } from "../components/ui/date-picker"; import { apiClient } from "../lib/api-client"; import { useToast } from "../components/ui/toast"; interface RecurringRuleFormData { recurrence_type: "daily" | "weekly" | "monthly" | "custom_days"; weekdays: number[]; start_date?: string; end_date?: string; max_capacity: string; base_price?: string; is_active: boolean; } const dayOptions = [ { value: 0, label: __("Sunday", "yatra") }, { value: 1, label: __("Monday", "yatra") }, { value: 2, label: __("Tuesday", "yatra") }, { value: 3, label: __("Wednesday", "yatra") }, { value: 4, label: __("Thursday", "yatra") }, { value: 5, label: __("Friday", "yatra") }, { value: 6, label: __("Saturday", "yatra") }, ]; const DepartureRecurringRuleForm: React.FC = () => { const queryClient = useQueryClient(); const { showToast } = useToast(); // Get trip_id and id from URL const urlParams = new URLSearchParams(window.location.search); const tripId = urlParams.get("trip_id") ? parseInt(urlParams.get("trip_id")!) : null; const ruleId = urlParams.get("id") || null; const isEditMode = !!ruleId; const [formData, setFormData] = useState({ recurrence_type: "weekly", weekdays: [], start_date: "", end_date: "", max_capacity: "", base_price: "", is_active: true, }); const [errors, setErrors] = useState< Partial> >({}); // Fetch existing rule data if editing const { data: ruleData, isLoading: isLoadingRule } = useQuery({ queryKey: ["recurring-rule", ruleId], queryFn: async () => { if (!ruleId || !tripId) return null; const response = await apiClient.get( `/trips/${tripId}/recurring-rules/${ruleId}`, ); return response?.data || response; }, enabled: isEditMode && !!ruleId && !!tripId, }); // Load form data when rule data is available useEffect(() => { if (ruleData) { setFormData({ recurrence_type: ruleData.recurrence_type || "weekly", weekdays: ruleData.weekdays || [], start_date: ruleData.start_date || "", end_date: ruleData.end_date || "", max_capacity: ruleData.max_capacity?.toString() || "", base_price: ruleData.base_price?.toString() || "", is_active: ruleData.is_active !== false, }); } }, [ruleData]); // Create/Update mutation const saveMutation = useMutation({ mutationFn: async (data: RecurringRuleFormData) => { if (!tripId) throw new Error("Trip ID is required"); const payload: any = { trip_id: tripId, recurrence_type: data.recurrence_type, max_capacity: parseInt(data.max_capacity), is_active: data.is_active, }; if ( data.recurrence_type === "weekly" || data.recurrence_type === "custom_days" ) { payload.weekdays = data.weekdays; } if (data.start_date) payload.start_date = data.start_date; if (data.end_date) payload.end_date = data.end_date; if (data.base_price) payload.base_price = parseFloat(data.base_price); if (isEditMode && ruleId) { return await apiClient.put( `/trips/${tripId}/recurring-rules/${ruleId}`, payload, ); } else { return await apiClient.post( `/trips/${tripId}/recurring-rules`, payload, ); } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["recurring-rules", tripId] }); showToast( isEditMode ? __("Recurring rule updated successfully", "yatra") : __("Recurring rule created successfully", "yatra"), "success", ); window.location.href = `?page=yatra&subpage=trips&tab=departures&action=rules&trip_id=${tripId}`; }, onError: (error: any) => { showToast(error?.message || __("Failed to save rule", "yatra"), "error"); }, }); const validateForm = (): boolean => { const newErrors: Partial> = {}; if (!formData.max_capacity) { newErrors.max_capacity = __("Max capacity is required", "yatra"); } else if (parseInt(formData.max_capacity) < 1) { newErrors.max_capacity = __("Max capacity must be at least 1", "yatra"); } if ( (formData.recurrence_type === "weekly" || formData.recurrence_type === "custom_days") && formData.weekdays.length === 0 ) { newErrors.weekdays = __("At least one weekday must be selected", "yatra"); } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (validateForm()) { saveMutation.mutate(formData); } }; const handleBack = () => { window.location.href = `?page=yatra&subpage=trips&tab=departures&action=rules${tripId ? `&trip_id=${tripId}` : ""}`; }; const toggleWeekday = (day: number) => { setFormData({ ...formData, weekdays: formData.weekdays.includes(day) ? formData.weekdays.filter((d) => d !== day) : [...formData.weekdays, day].sort(), }); }; if (isLoadingRule) { return (
); } return (
{__("Back", "yatra")} } />
{/* Recurrence Type */}
{/* Weekdays (for weekly/custom_days) */} {(formData.recurrence_type === "weekly" || formData.recurrence_type === "custom_days") && (
{dayOptions.map((day) => ( ))}
{errors.weekdays && (

{errors.weekdays}

)}
)} {/* Start Date */}
setFormData({ ...formData, start_date: value }) } />
{/* End Date */}
setFormData({ ...formData, end_date: value }) } minDate={ formData.start_date ? new Date(formData.start_date) : undefined } />
{/* Max Capacity */}
setFormData({ ...formData, max_capacity: e.target.value }) } placeholder={__("e.g., 20", "yatra")} /> {errors.max_capacity && (

{errors.max_capacity}

)}
{/* Base Price (Optional) */}
setFormData({ ...formData, base_price: e.target.value }) } placeholder={__("e.g., 150.00", "yatra")} />
{/* Active Status */}
{/* Submit Button */}
); }; export default DepartureRecurringRuleForm;