feat: add Fight and Exhibition registration forms with input validation and file upload functionality
This commit is contained in:
@@ -1,15 +1,25 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||
import Button from "./Button";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
interface EventCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
image: string;
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
function EventCard(props: EventCardProps) {
|
||||
const router = useRouter();
|
||||
|
||||
const handleClick = () => {
|
||||
if (!props.disabled) {
|
||||
router.push(props.link);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
id={props.id}
|
||||
@@ -35,7 +45,12 @@ function EventCard(props: EventCardProps) {
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-center md:justify-end w-full md:w-1/3">
|
||||
<Button variant="blue" shadowEnabled={false}>
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
disabled={props.disabled}
|
||||
variant="blue"
|
||||
shadowEnabled={false}
|
||||
>
|
||||
регистрация
|
||||
</Button>
|
||||
</div>
|
||||
@@ -77,6 +92,7 @@ function Events() {
|
||||
|
||||
<div className="flex flex-col space-y-4 md:space-y-7 mt-16 md:mt-36">
|
||||
<EventCard
|
||||
disabled={true}
|
||||
id="yuka"
|
||||
image="/events/yuka.png"
|
||||
title="YUKA Drive Fest Джимхана"
|
||||
@@ -84,13 +100,15 @@ function Events() {
|
||||
link="#"
|
||||
/>
|
||||
<EventCard
|
||||
disabled={false}
|
||||
id="moscow_fight"
|
||||
image="/events/moscow_fight.png"
|
||||
title="Дрифт«Битва за Москву»"
|
||||
description="Любительский турнир по дрифту, который вырос из проекта «Дорога в дрифт», созданного в 2021 году для поиска новых талантов. За три года он превратился в полноценные соревнования с привлекательным призовым фондом. Во второй день фестиваля, 8 сентября, пройдет дрифт-гонка, где главным призом станет электромобиль «Москвич». Соревнования проводятся по традиционной олимпийской системе. Чтобы принять участие, необходимо подать заявку на сайте и дождаться приглашения от организаторов."
|
||||
link="#"
|
||||
link="/forms/fight"
|
||||
/>
|
||||
<EventCard
|
||||
disabled={true}
|
||||
id="moto"
|
||||
image="/events/moto.png"
|
||||
title="КуБок ШОС по Мотокроссу"
|
||||
@@ -98,6 +116,7 @@ function Events() {
|
||||
link="#"
|
||||
/>
|
||||
<EventCard
|
||||
disabled={true}
|
||||
image="/events/cart.png"
|
||||
title="Кубок по Фиджитал картингу"
|
||||
description="На Фестивале технических видов спорта 2025 впервые состоится Кубок по Фиджитал Картингу! Это уникальное состязание, где виртуальная реальность встречается с реальной трассой. Участники будут сражаться на симуляторах, а затем переносить свои навыки на настоящий картинг, демонстрируя невероятную адаптивность и мастерство."
|
||||
|
||||
@@ -272,7 +272,7 @@ function Fileupload({
|
||||
className="ml-2 p-1 text-gray-400 hover:text-gray-600"
|
||||
>
|
||||
<svg
|
||||
className="w-3 h-3"
|
||||
className="w-4 h-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -281,7 +281,7 @@ function Fileupload({
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { gothampro } from "@/utils/fonts";
|
||||
interface InputProps {
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
type?: "text" | "email" | "password" | "number" | "tel";
|
||||
type?: "text" | "email" | "password" | "number" | "tel" | "date" | "datetime-local" | "time";
|
||||
value?: string;
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
|
||||
@@ -15,6 +15,8 @@ interface InputProps {
|
||||
className?: string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
min?: string;
|
||||
max?: string;
|
||||
}
|
||||
|
||||
function Input({
|
||||
@@ -30,6 +32,8 @@ function Input({
|
||||
className = "",
|
||||
id,
|
||||
name,
|
||||
min,
|
||||
max,
|
||||
}: InputProps) {
|
||||
return (
|
||||
<div className={`flex flex-col gap-2 w-full ${className}`}>
|
||||
@@ -52,6 +56,8 @@ function Input({
|
||||
placeholder={placeholder}
|
||||
disabled={disabled}
|
||||
required={required}
|
||||
min={min}
|
||||
max={max}
|
||||
className={`
|
||||
w-full px-4 py-3
|
||||
border border-gray-300
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
|
||||
export const usePhoneMask = (initialValue: string = '') => {
|
||||
const [value, setValue] = useState(initialValue);
|
||||
|
||||
const formatPhoneNumber = useCallback((input: string) => {
|
||||
// Remove all non-digit characters
|
||||
const digits = input.replace(/\D/g, '');
|
||||
|
||||
// Format as +7 (XXX) XXX-XX-XX
|
||||
if (digits.length === 0) return '';
|
||||
if (digits.length <= 1) return '+7';
|
||||
if (digits.length <= 4) return `+7 (${digits.slice(1)}`;
|
||||
if (digits.length <= 7) return `+7 (${digits.slice(1, 4)}) ${digits.slice(4)}`;
|
||||
if (digits.length <= 9) return `+7 (${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7)}`;
|
||||
return `+7 (${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7, 9)}-${digits.slice(9, 11)}`;
|
||||
}, []);
|
||||
|
||||
const handleChange = useCallback((input: string) => {
|
||||
const formatted = formatPhoneNumber(input);
|
||||
setValue(formatted);
|
||||
return formatted;
|
||||
}, [formatPhoneNumber]);
|
||||
|
||||
return { value, handleChange, setValue };
|
||||
};
|
||||
@@ -2,25 +2,120 @@ import Checkbox from "@/components/form/Checkbox";
|
||||
import Fileupload from "@/components/form/Fileupload";
|
||||
import Input from "@/components/form/Input";
|
||||
import Textarea from "@/components/form/Textarea";
|
||||
import { usePhoneMask } from "@/hooks/usePhoneMask";
|
||||
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||
import { useState } from "react";
|
||||
|
||||
import PocketBase from "pocketbase";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const pb = new PocketBase(
|
||||
"http://pocketbase-nkg4scskc4okw4w0cw4w88gk.176.114.67.63.sslip.io"
|
||||
);
|
||||
|
||||
function ExhibtionFormPage() {
|
||||
const [checkboxValues, setCheckboxValues] = useState<string[]>([]);
|
||||
const router = useRouter();
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
carBrand: "",
|
||||
carModel: "",
|
||||
description: "",
|
||||
});
|
||||
const [carPhotos, setCarPhotos] = useState<File[]>([]);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
// Add a key to force re-render of Fileupload component
|
||||
const [fileUploadKey, setFileUploadKey] = useState(0);
|
||||
|
||||
const { value: phoneValue, handleChange: handlePhoneChange } = usePhoneMask();
|
||||
|
||||
const handleInputChange = (field: string, value: string) => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[field]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!checkboxValues.includes("terms")) {
|
||||
alert("Необходимо согласие на обработку персональных данных");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const formDataObject = {
|
||||
name: formData.name,
|
||||
phone: phoneValue,
|
||||
email: formData.email,
|
||||
carBrand: formData.carBrand,
|
||||
carModel: formData.carModel,
|
||||
description: formData.description,
|
||||
};
|
||||
|
||||
const data = new FormData();
|
||||
|
||||
// Store all form data as JSON in the data field
|
||||
data.append("data", JSON.stringify(formDataObject));
|
||||
data.append("type", "exhibition");
|
||||
|
||||
// Add car photos to the images field (PocketBase will handle multiple files)
|
||||
carPhotos.forEach((file) => {
|
||||
data.append("images", file);
|
||||
});
|
||||
|
||||
const record = await pb.collection("forms").create(data);
|
||||
|
||||
console.log("Form submitted successfully:", record);
|
||||
console.log("Uploaded images:", record.images);
|
||||
alert("Форма успешно отправлена!");
|
||||
|
||||
// Reset form
|
||||
setFormData({
|
||||
name: "",
|
||||
email: "",
|
||||
carBrand: "",
|
||||
carModel: "",
|
||||
description: "",
|
||||
});
|
||||
setCheckboxValues([]);
|
||||
setCarPhotos([]);
|
||||
// Force re-render of Fileupload component
|
||||
setFileUploadKey((prev) => prev + 1);
|
||||
handlePhoneChange(""); // Reset phone value
|
||||
|
||||
router.push("/thankyou");
|
||||
} catch (error) {
|
||||
console.error("Error submitting form:", error);
|
||||
alert("Ошибка при отправке формы. Попробуйте еще раз.");
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-[#ffffff] relative p-6 md:p-8 lg:p-12 flex flex-col items-center justify-center md:h-full">
|
||||
<div className="relative p-6 md:p-8 lg:p-12 flex flex-col items-center">
|
||||
<Head>
|
||||
<title>Фестиваль технических видов спорта</title>
|
||||
</Head>
|
||||
<h1
|
||||
className={`${fluxgore.className} text-4xl md:text-7xl text-[#060606] relative mb-8 md:mb-12`}
|
||||
>
|
||||
Регистрация на выставку
|
||||
</h1>
|
||||
|
||||
<div className="space-y-6 max-w-2xl w-full">
|
||||
<form onSubmit={handleSubmit} className="space-y-6 max-w-2xl w-full">
|
||||
<Input
|
||||
label="Имя"
|
||||
placeholder="Введите ваше имя"
|
||||
type="text"
|
||||
value={formData.name}
|
||||
onChange={(e) => handleInputChange("name", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -28,6 +123,8 @@ function ExhibtionFormPage() {
|
||||
label="Телефон"
|
||||
placeholder="+7 (___) ___-__-__"
|
||||
type="tel"
|
||||
value={phoneValue}
|
||||
onChange={(e) => handlePhoneChange(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -35,6 +132,8 @@ function ExhibtionFormPage() {
|
||||
label="Почта"
|
||||
placeholder="example@email.com"
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) => handleInputChange("email", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -42,6 +141,8 @@ function ExhibtionFormPage() {
|
||||
label="Марка автомобиля"
|
||||
placeholder="Введите марку автомобиля"
|
||||
type="text"
|
||||
value={formData.carBrand}
|
||||
onChange={(e) => handleInputChange("carBrand", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -49,12 +150,15 @@ function ExhibtionFormPage() {
|
||||
label="Модель"
|
||||
placeholder="Введите модель автомобиля"
|
||||
type="text"
|
||||
value={formData.carModel}
|
||||
onChange={(e) => handleInputChange("carModel", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<Fileupload
|
||||
key={fileUploadKey} // Force component re-render on reset
|
||||
label="Фото автомобиля (до 3 файлов)"
|
||||
onFileSelect={(files) => console.log("Selected files:", files)}
|
||||
onFileSelect={(files) => setCarPhotos(files)}
|
||||
acceptedTypes={["image/*"]}
|
||||
maxFileSize={5}
|
||||
multiple={true}
|
||||
@@ -64,6 +168,8 @@ function ExhibtionFormPage() {
|
||||
<Textarea
|
||||
label="Интересное об автомобиле"
|
||||
placeholder="Расскажите что-то интересное о вашем автомобиле"
|
||||
value={formData.description}
|
||||
onChange={(e) => handleInputChange("description", e.target.value)}
|
||||
rows={4}
|
||||
cols={50}
|
||||
/>
|
||||
@@ -90,11 +196,12 @@ function ExhibtionFormPage() {
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className={`${fluxgore.className} bg-[#1068B0] hover:bg-[#0d5a96] text-white px-9 py-4 text-base font-medium uppercase tracking-wide disabled:opacity-50 w-full`}
|
||||
>
|
||||
Отправить
|
||||
{isSubmitting ? "Отправка..." : "Отправить"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+142
-6
@@ -2,25 +2,137 @@ import Checkbox from "@/components/form/Checkbox";
|
||||
import Fileupload from "@/components/form/Fileupload";
|
||||
import Input from "@/components/form/Input";
|
||||
import Textarea from "@/components/form/Textarea";
|
||||
import { usePhoneMask } from "@/hooks/usePhoneMask";
|
||||
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||
import Head from "next/head";
|
||||
import { useState } from "react";
|
||||
|
||||
import PocketBase from "pocketbase";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const pb = new PocketBase(
|
||||
"http://pocketbase-nkg4scskc4okw4w0cw4w88gk.176.114.67.63.sslip.io"
|
||||
);
|
||||
|
||||
function FightFormPage() {
|
||||
const router = useRouter();
|
||||
const [checkboxValues, setCheckboxValues] = useState<string[]>([]);
|
||||
const [formData, setFormData] = useState({
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
middleName: "",
|
||||
birthDate: "",
|
||||
citizenship: "",
|
||||
email: "",
|
||||
carBrand: "",
|
||||
carModel: "",
|
||||
engine: "",
|
||||
power: "",
|
||||
additionalInfo: "",
|
||||
});
|
||||
const [carPhotos, setCarPhotos] = useState<File[]>([]);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
// Add a key to force re-render of Fileupload component
|
||||
const [fileUploadKey, setFileUploadKey] = useState(0);
|
||||
|
||||
const { value: phoneValue, handleChange: handlePhoneChange } = usePhoneMask();
|
||||
|
||||
const handleInputChange = (field: string, value: string) => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[field]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!checkboxValues.includes("terms")) {
|
||||
alert("Необходимо согласие на обработку персональных данных");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const formDataObject = {
|
||||
lastName: formData.lastName,
|
||||
firstName: formData.firstName,
|
||||
middleName: formData.middleName,
|
||||
birthDate: formData.birthDate,
|
||||
citizenship: formData.citizenship,
|
||||
phone: phoneValue,
|
||||
email: formData.email,
|
||||
carBrand: formData.carBrand,
|
||||
carModel: formData.carModel,
|
||||
engine: formData.engine,
|
||||
power: formData.power,
|
||||
additionalInfo: formData.additionalInfo,
|
||||
};
|
||||
|
||||
const data = new FormData();
|
||||
|
||||
// Store all form data as JSON in the data field
|
||||
data.append("data", JSON.stringify(formDataObject));
|
||||
data.append("type", "fight");
|
||||
|
||||
// Add car photos to the images field (PocketBase will handle multiple files)
|
||||
carPhotos.forEach((file) => {
|
||||
data.append("images", file);
|
||||
});
|
||||
|
||||
const record = await pb.collection("forms").create(data);
|
||||
|
||||
console.log("Form submitted successfully:", record);
|
||||
console.log("Uploaded images:", record.images);
|
||||
alert("Форма успешно отправлена!");
|
||||
|
||||
// Reset form
|
||||
setFormData({
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
middleName: "",
|
||||
birthDate: "",
|
||||
citizenship: "",
|
||||
email: "",
|
||||
carBrand: "",
|
||||
carModel: "",
|
||||
engine: "",
|
||||
power: "",
|
||||
additionalInfo: "",
|
||||
});
|
||||
setCheckboxValues([]);
|
||||
setCarPhotos([]);
|
||||
// Force re-render of Fileupload component
|
||||
setFileUploadKey((prev) => prev + 1);
|
||||
handlePhoneChange(""); // Reset phone value
|
||||
router.push("/thankyou");
|
||||
} catch (error) {
|
||||
console.error("Error submitting form:", error);
|
||||
alert("Ошибка при отправке формы. Попробуйте еще раз.");
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-[#ffffff] relative p-6 md:p-8 lg:p-12 flex flex-col items-center justify-center">
|
||||
<div className="relative p-6 md:p-8 lg:p-12 flex flex-col items-center justify-center">
|
||||
<Head>
|
||||
<title>Фестиваль технических видов спорта</title>
|
||||
</Head>
|
||||
<h1
|
||||
className={`${fluxgore.className} text-4xl md:text-7xl text-[#060606] relative mb-8 md:mb-12`}
|
||||
>
|
||||
Регистрация на Битву за Москву
|
||||
</h1>
|
||||
|
||||
<div className="space-y-6 max-w-2xl w-full">
|
||||
<form onSubmit={handleSubmit} className="space-y-6 max-w-2xl w-full">
|
||||
<Input
|
||||
label="Фамилия"
|
||||
placeholder="Введите вашу фамилию"
|
||||
type="text"
|
||||
value={formData.lastName}
|
||||
onChange={(e) => handleInputChange("lastName", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -28,6 +140,8 @@ function FightFormPage() {
|
||||
label="Имя"
|
||||
placeholder="Введите ваше имя"
|
||||
type="text"
|
||||
value={formData.firstName}
|
||||
onChange={(e) => handleInputChange("firstName", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -35,13 +149,17 @@ function FightFormPage() {
|
||||
label="Отчество"
|
||||
placeholder="Введите ваше отчество"
|
||||
type="text"
|
||||
value={formData.middleName}
|
||||
onChange={(e) => handleInputChange("middleName", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Дата рождения"
|
||||
placeholder="дд.мм.гггг"
|
||||
type="text"
|
||||
type="date"
|
||||
value={formData.birthDate}
|
||||
onChange={(e) => handleInputChange("birthDate", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -49,6 +167,8 @@ function FightFormPage() {
|
||||
label="Гражданство"
|
||||
placeholder="Введите ваше гражданство"
|
||||
type="text"
|
||||
value={formData.citizenship}
|
||||
onChange={(e) => handleInputChange("citizenship", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -56,6 +176,8 @@ function FightFormPage() {
|
||||
label="Телефон"
|
||||
placeholder="+7 (___) ___-__-__"
|
||||
type="tel"
|
||||
value={phoneValue}
|
||||
onChange={(e) => handlePhoneChange(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -63,6 +185,8 @@ function FightFormPage() {
|
||||
label="Почта"
|
||||
placeholder="example@email.com"
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) => handleInputChange("email", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -70,6 +194,8 @@ function FightFormPage() {
|
||||
label="Марка автомобиля"
|
||||
placeholder="Введите марку автомобиля"
|
||||
type="text"
|
||||
value={formData.carBrand}
|
||||
onChange={(e) => handleInputChange("carBrand", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -77,6 +203,8 @@ function FightFormPage() {
|
||||
label="Модель"
|
||||
placeholder="Введите модель автомобиля"
|
||||
type="text"
|
||||
value={formData.carModel}
|
||||
onChange={(e) => handleInputChange("carModel", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -84,6 +212,8 @@ function FightFormPage() {
|
||||
label="Двигатель"
|
||||
placeholder="Введите тип двигателя"
|
||||
type="text"
|
||||
value={formData.engine}
|
||||
onChange={(e) => handleInputChange("engine", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -91,12 +221,15 @@ function FightFormPage() {
|
||||
label="Мощность"
|
||||
placeholder="Введите мощность (л.с.)"
|
||||
type="text"
|
||||
value={formData.power}
|
||||
onChange={(e) => handleInputChange("power", e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<Fileupload
|
||||
key={fileUploadKey} // Force component re-render on reset
|
||||
label="Фото автомобиля (до 3 файлов)"
|
||||
onFileSelect={(files) => console.log("Selected files:", files)}
|
||||
onFileSelect={(files) => setCarPhotos(files)}
|
||||
acceptedTypes={["image/*"]}
|
||||
maxFileSize={5}
|
||||
multiple={true}
|
||||
@@ -106,6 +239,8 @@ function FightFormPage() {
|
||||
<Textarea
|
||||
label="Дополнительная информация"
|
||||
placeholder="Дополнительная информация об автомобиле"
|
||||
value={formData.additionalInfo}
|
||||
onChange={(e) => handleInputChange("additionalInfo", e.target.value)}
|
||||
rows={4}
|
||||
cols={50}
|
||||
/>
|
||||
@@ -132,11 +267,12 @@ function FightFormPage() {
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className={`${fluxgore.className} bg-[#1068B0] hover:bg-[#0d5a96] text-white px-9 py-4 text-base font-medium uppercase tracking-wide disabled:opacity-50 w-full`}
|
||||
>
|
||||
Отправить
|
||||
{isSubmitting ? "Отправка..." : "Отправить"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+24
-2
@@ -1,4 +1,15 @@
|
||||
import { CoverSoon } from "@/components/Cover";
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import Activities from "@/components/Activities";
|
||||
import Cover from "@/components/Cover";
|
||||
import Events from "@/components/Events";
|
||||
import Footer from "@/components/Footer";
|
||||
import Info from "@/components/Info";
|
||||
import Map from "@/components/Map";
|
||||
import Navbar from "@/components/Navbar";
|
||||
import Partners from "@/components/Partners";
|
||||
import Scheme from "@/components/Scheme";
|
||||
import Video from "@/components/Video";
|
||||
|
||||
import Head from "next/head";
|
||||
|
||||
export default function Home() {
|
||||
@@ -7,7 +18,18 @@ export default function Home() {
|
||||
<Head>
|
||||
<title>Фестиваль технических видов спорта</title>
|
||||
</Head>
|
||||
<CoverSoon />
|
||||
<Navbar />
|
||||
<main className="flex-col min-h-full">
|
||||
<Cover />
|
||||
<Info />
|
||||
<Video />
|
||||
{/* <Scheme /> */}
|
||||
<Events />
|
||||
<Activities />
|
||||
<Partners />
|
||||
<Map />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import Head from "next/head";
|
||||
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||
|
||||
function ThankYouPage() {
|
||||
return (
|
||||
<div className="relative p-6 md:p-8 lg:p-12 flex flex-col items-center justify-center h-full">
|
||||
<Head>
|
||||
<title>Фестиваль технических видов спорта</title>
|
||||
</Head>
|
||||
|
||||
<h1
|
||||
className={`${fluxgore.className} text-4xl md:text-7xl text-[#060606] relative mb-8 md:mb-12`}
|
||||
>
|
||||
СПАСИБО!
|
||||
</h1>
|
||||
|
||||
<p
|
||||
className={`${gothampro.className} text-lg md:text-2xl text-center text-[#060606]`}
|
||||
>
|
||||
Ваша заявка отправлена. вам придет письмо на почту
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ThankYouPage;
|
||||
@@ -13,5 +13,4 @@
|
||||
body {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
background-color: #0d0d0d;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user