表单 onSubmit 未触发

问题描述 投票:0回答:1
"use client";

import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { api } from "@/trpc/react";
import { DatePickerWithRange } from "@/components/DatePickerWithRange";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormDescription,
  FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Country, State, City } from "country-state-city";
import type { ICity, ICountry, IState } from "country-state-city";

// Zod Schema for Form Validation
const tripFormSchema = z.object({
  name: z.string().min(1, { message: "Name is required." }),
  destination: z.string().min(1, { message: "Destination is required." }),
  country: z.string().min(1, { message: "Country is required." }),
  state: z.string().min(1, { message: "State is required." }),
  city: z.string().min(1, { message: "City is required." }),
  hotelDetails: z.string().optional(),
  dateRange: z.object({
    from: z.date({
      required_error: "Start date is required.",
    }),
    to: z
      .date({
        required_error: "End date is required.",
      })
      .refine((val) => val > new Date(), {
        message: "End date must be after start date.",
      }),
  }),
  flightNumber: z.string().optional(),
});

export function CreateTripForm() {
  const [selectedCountry, setSelectedCountry] = useState<ICountry | null>(null);
  const [selectedState, setSelectedState] = useState<IState | null>(null);
  const [selectedCity, setSelectedCity] = useState<ICity | null>(null);

  const router = useRouter();

  const form = useForm<z.infer<typeof tripFormSchema>>({
    resolver: zodResolver(tripFormSchema),
    defaultValues: {
      name: "",
      destination: "",
      country: "",
      state: "",
      city: "",
      hotelDetails: "",
      dateRange: {
        from: new Date(),
        to: new Date(),
      },
      flightNumber: "",
    },
  });

  const createTrip = api.post.create.useMutation({
    onSuccess: () => {
      router.refresh(); // Refresh the page or navigate if necessary
    },
    onError: (error: unknown) => {
      console.error("Error creating trip:", error);
    },
  });

  function onSubmit(data: z.infer<typeof tripFormSchema>) {
    console.log("Form submitted with data:", data); // Debugging statement

    const { dateRange, ...rest } = data;
    const updatedData = {
      ...rest,
      destination: selectedCity?.name ?? "",
      durationOfStay: Math.ceil(
        (dateRange.to.getTime() - dateRange.from.getTime()) /
          (1000 * 60 * 60 * 24),
      ),
    };
    console.log("Updated data:", updatedData); // Debugging statement
    createTrip.mutate(updatedData);
  }

  const handleCountryChange = (value: string) => {
    const country = Country.getAllCountries().find((c) => c.isoCode === value);
    setSelectedCountry(country ?? null);
    setSelectedState(null); // Reset state and city
    setSelectedCity(null);
    form.setValue("country", value); // Update form state
  };

  const handleStateChange = (value: string) => {
    const state = State.getStatesOfCountry(selectedCountry?.isoCode ?? "").find(
      (s) => s.isoCode === value,
    );
    setSelectedState(state ?? null);
    setSelectedCity(null); // Reset city
    form.setValue("state", value); // Update form state
  };

  const handleCityChange = (value: string) => {
    const city = City.getCitiesOfState(
      selectedState?.countryCode ?? "",
      selectedState?.isoCode ?? "",
    ).find((c) => c.name === value);
    setSelectedCity(city ?? null);
    form.setValue("city", value); // Update form state
  };

  const countries = Country.getAllCountries();
  const states = selectedCountry
    ? State.getStatesOfCountry(selectedCountry.isoCode)
    : [];
  const cities = selectedState
    ? City.getCitiesOfState(selectedState.countryCode, selectedState.isoCode)
    : [];

  return (
    <Form {...form}>
      <form
        onSubmit={form.handleSubmit(onSubmit)}
        className="my-10 flex w-full flex-col items-start justify-center gap-y-5 px-10"
      >
        <h1 className="mb-5 text-center text-2xl font-bold">Create a Trip</h1>

        {/* Name Field */}
        <FormField
          control={form.control}
          name="name"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Name</FormLabel>
              <FormControl>
                <Input
                  {...field}
                  placeholder="Enter trip name"
                  className="w-full"
                />
              </FormControl>
              <FormMessage>{form.formState.errors.name?.message}</FormMessage>
            </FormItem>
          )}
        />

        {/* Country Selector */}
        <FormField
          control={form.control}
          name="country"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Country</FormLabel>
              <FormControl>
                <Select value={field.value} onValueChange={handleCountryChange}>
                  <SelectTrigger className="w-[280px]">
                    <SelectValue placeholder="Select a country" />
                  </SelectTrigger>
                  <SelectContent>
                    {countries.map((country) => (
                      <SelectItem key={country.isoCode} value={country.isoCode}>
                        {country.name}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </FormControl>
              <FormMessage>
                {form.formState.errors.country?.message}
              </FormMessage>
            </FormItem>
          )}
        />

        {/* State Selector */}
        <FormField
          control={form.control}
          name="state"
          render={({ field }) => (
            <FormItem>
              <FormLabel>State</FormLabel>
              <FormControl>
                <Select
                  value={field.value}
                  onValueChange={handleStateChange}
                  disabled={!selectedCountry}
                >
                  <SelectTrigger className="w-[280px]">
                    <SelectValue placeholder="Select a state" />
                  </SelectTrigger>
                  <SelectContent>
                    {states.map((state) => (
                      <SelectItem key={state.isoCode} value={state.isoCode}>
                        {state.name}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </FormControl>
              <FormMessage>{form.formState.errors.state?.message}</FormMessage>
            </FormItem>
          )}
        />

        {/* City Selector */}
        <FormField
          control={form.control}
          name="city"
          render={({ field }) => (
            <FormItem>
              <FormLabel>City</FormLabel>
              <FormControl>
                <Select
                  value={field.value}
                  onValueChange={handleCityChange}
                  disabled={!selectedState}
                >
                  <SelectTrigger className="w-[280px]">
                    <SelectValue placeholder="Select a city" />
                  </SelectTrigger>
                  <SelectContent>
                    {cities.map((city) => (
                      <SelectItem key={city.name} value={city.name}>
                        {city.name}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </FormControl>
              <FormMessage>{form.formState.errors.city?.message}</FormMessage>
            </FormItem>
          )}
        />

        {/* Date Range Field */}
        <FormField
          control={form.control}
          name="dateRange"
          render={({ field }) => (
            <FormItem className="flex flex-col">
              <FormLabel>Date Range</FormLabel>
              <DatePickerWithRange
                className="w-[300px]"
                onChange={(dateRange) => field.onChange(dateRange)}
                value={field.value}
              />
              <FormDescription>
                Choose the date range for your trip.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />

        {/* Hotel Details Field */}
        <FormField
          control={form.control}
          name="hotelDetails"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Hotel Details</FormLabel>
              <FormControl>
                <Input
                  {...field}
                  placeholder="Enter hotel details"
                  className="w-full"
                />
              </FormControl>
              <FormMessage>
                {form.formState.errors.hotelDetails?.message}
              </FormMessage>
            </FormItem>
          )}
        />

        {/* Flight Number Field */}
        <FormField
          control={form.control}
          name="flightNumber"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Flight Number</FormLabel>
              <FormControl>
                <Input
                  {...field}
                  placeholder="Enter flight number"
                  className="w-full"
                />
              </FormControl>
              <FormMessage>
                {form.formState.errors.flightNumber?.message}
              </FormMessage>
            </FormItem>
          )}
        />

        {/* Submit Button */}
        <Button type="submit" className="mt-4">
          Create Trip
        </Button>
      </form>
    </Form>
  );
}

export default CreateTripForm;

我的控制台中没有任何内容,甚至没有一个错误。 请帮助我面对这个问题,这是黑客马拉松的代码,我需要快速帮助。 我使用 shadcn 表单,我的 onsubmit 没有被触发,我在单击按钮时尝试了 console.log,它可以工作,在提交时在表单上也可以工作,但 onSubmit 永远不会获取表单值

reactjs forms next.js submit shadcnui
1个回答
0
投票

“每个表单都必须包含在 FORM 元素内。单个文档中可以有多个表单,但 FORM 元素不能嵌套”
(参见:https://www.w3.org/MarkUp/html3/forms.html#:~:text=Every%20form%20must%20be%20enheld,element%20can%27t%20be%20nested。)

© www.soinside.com 2019 - 2024. All rights reserved.