added en lang

This commit is contained in:
Batyr 2025-02-04 15:05:30 +05:00
parent 78e95cab9c
commit 620ca2438d
30 changed files with 499 additions and 112 deletions

View File

@ -13,7 +13,7 @@
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-dialog": "^1.1.5",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-popover": "^1.1.5",
"@radix-ui/react-radio-group": "^1.2.2",
"@radix-ui/react-slot": "^1.1.1",
"axios": "^1.7.9",

View File

@ -18,7 +18,7 @@ importers:
specifier: ^2.1.1
version: 2.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-popover':
specifier: ^1.1.4
specifier: ^1.1.5
version: 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-radio-group':
specifier: ^1.2.2

24
public/en.svg Normal file
View File

@ -0,0 +1,24 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_70_686)">
<path d="M18 2.475C16.2375 1.3875 14.2125 0.75 12 0.75V2.475H18Z" fill="#ED4C5C"/>
<path d="M12 4.20004H20.1C19.4625 3.56254 18.75 2.96254 18 2.47504H12V4.20004Z" fill="white"/>
<path d="M12 5.92507H21.4875C21.075 5.28757 20.625 4.72507 20.1375 4.20007H12V5.92507Z" fill="#ED4C5C"/>
<path d="M12 7.64993H22.3875C22.125 7.04993 21.825 6.44993 21.4875 5.92493H12V7.64993Z" fill="white"/>
<path d="M12 9.37496H22.95C22.8 8.77496 22.6125 8.21246 22.3875 7.64996H12V9.37496Z" fill="#ED4C5C"/>
<path d="M12 11.1375H23.2125C23.175 10.5375 23.0625 9.97504 22.95 9.41254H12V11.1375Z" fill="white"/>
<path d="M23.2125 11.1376H12V12.0001H0.75C0.75 12.3001 0.75 12.5626 0.7875 12.8626H23.2125C23.25 12.5626 23.25 12.3001 23.25 12.0001C23.25 11.7001 23.25 11.4001 23.2125 11.1376Z" fill="#ED4C5C"/>
<path d="M1.04961 14.5874H22.9496C23.0996 14.0249 23.1746 13.4624 23.2121 12.8624H0.787109C0.824609 13.4249 0.899609 14.0249 1.04961 14.5874Z" fill="white"/>
<path d="M1.6123 16.3125H22.3873C22.6123 15.75 22.7998 15.1875 22.9498 14.5875H1.0498C1.1998 15.1875 1.3873 15.75 1.6123 16.3125Z" fill="#ED4C5C"/>
<path d="M2.5123 18.0375H21.4873C21.8248 17.475 22.1248 16.9125 22.3873 16.3125H1.6123C1.8748 16.9125 2.1748 17.475 2.5123 18.0375Z" fill="white"/>
<path d="M3.8627 19.7625H20.1377C20.6252 19.2375 21.1127 18.6375 21.4877 18.0375H2.5127C2.8877 18.675 3.3752 19.2375 3.8627 19.7625Z" fill="#ED4C5C"/>
<path d="M5.9623 21.4876H18.0373C18.8248 21.0001 19.4998 20.4001 20.1373 19.7626H3.8623C4.4998 20.4376 5.2123 21.0001 5.9623 21.4876Z" fill="white"/>
<path d="M12.0004 23.2499C14.2129 23.2499 16.2754 22.6124 18.0379 21.4874H5.96289C7.72539 22.6124 9.78789 23.2499 12.0004 23.2499Z" fill="#ED4C5C"/>
<path d="M6 2.475C5.2125 2.9625 4.5 3.5625 3.8625 4.2C3.3375 4.725 2.8875 5.325 2.5125 5.925C2.175 6.4875 1.8375 7.05 1.6125 7.65C1.3875 8.2125 1.2 8.775 1.05 9.375C0.9 9.9375 0.825 10.5 0.7875 11.1C0.75 11.4 0.75 11.7 0.75 12H12V0.75C9.7875 0.75 7.7625 1.3875 6 2.475Z" fill="#428BC1"/>
<path d="M9.37539 1.125L9.56289 1.6875H10.1254L9.67539 2.0625L9.82539 2.625L9.37539 2.2875L8.92539 2.625L9.07539 2.0625L8.62539 1.6875H9.18789L9.37539 1.125ZM10.8754 3.375L11.0629 3.9375H11.6254L11.1754 4.3125L11.3254 4.875L10.8754 4.5375L10.4254 4.875L10.5754 4.3125L10.1254 3.9375H10.6879L10.8754 3.375ZM7.87539 3.375L8.06289 3.9375H8.62539L8.17539 4.3125L8.32539 4.875L7.87539 4.5375L7.42539 4.875L7.57539 4.3125L7.12539 3.9375H7.68789L7.87539 3.375ZM9.37539 5.625L9.56289 6.1875H10.1254L9.67539 6.5625L9.82539 7.125L9.37539 6.7875L8.92539 7.125L9.07539 6.5625L8.62539 6.1875H9.18789L9.37539 5.625ZM6.37539 5.625L6.56289 6.1875H7.12539L6.67539 6.5625L6.82539 7.125L6.37539 6.7875L5.92539 7.125L6.07539 6.5625L5.62539 6.1875H6.18789L6.37539 5.625ZM3.37539 5.625L3.56289 6.1875H4.12539L3.67539 6.5625L3.82539 7.125L3.37539 6.7875L2.92539 7.125L3.07539 6.5625L2.62539 6.1875H3.18789L3.37539 5.625ZM10.8754 7.875L11.0629 8.4375H11.6254L11.1754 8.8125L11.3254 9.375L10.8754 9.0375L10.4254 9.375L10.5754 8.8125L10.1254 8.4375H10.6879L10.8754 7.875ZM7.87539 7.875L8.06289 8.4375H8.62539L8.17539 8.8125L8.32539 9.375L7.87539 9.0375L7.42539 9.375L7.57539 8.8125L7.12539 8.4375H7.68789L7.87539 7.875ZM4.87539 7.875L5.06289 8.4375H5.62539L5.17539 8.8125L5.32539 9.375L4.87539 9.0375L4.42539 9.375L4.57539 8.8125L4.12539 8.4375H4.68789L4.87539 7.875ZM9.37539 10.125L9.56289 10.6875H10.1254L9.67539 11.0625L9.82539 11.625L9.37539 11.2875L8.92539 11.625L9.07539 11.0625L8.62539 10.6875H9.18789L9.37539 10.125ZM6.37539 10.125L6.56289 10.6875H7.12539L6.67539 11.0625L6.82539 11.625L6.37539 11.2875L5.92539 11.625L6.07539 11.0625L5.62539 10.6875H6.18789L6.37539 10.125ZM3.37539 10.125L3.56289 10.6875H4.12539L3.67539 11.0625L3.82539 11.625L3.37539 11.2875L2.92539 11.625L3.07539 11.0625L2.62539 10.6875H3.18789L3.37539 10.125ZM4.42539 4.875L4.87539 4.5375L5.32539 4.875L5.13789 4.3125L5.58789 3.9375H5.02539L4.87539 3.375L4.68789 3.9375H4.16289L4.61289 4.275L4.42539 4.875ZM1.42539 9.375L1.87539 9.0375L2.32539 9.375L2.13789 8.8125L2.58789 8.4375H2.06289L1.87539 7.875L1.68789 8.4375H1.31289C1.31289 8.475 1.27539 8.5125 1.27539 8.55L1.57539 8.775L1.42539 9.375Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_70_686">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

12
public/ru.svg Normal file
View File

@ -0,0 +1,12 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_70_688)">
<path d="M11.9627 0.75C7.08769 0.75 2.9252 3.9 1.3877 8.25H22.6127C21.0377 3.9 16.8752 0.75 11.9627 0.75Z" fill="#F9F9F9"/>
<path d="M11.9627 23.25C16.8752 23.25 21.0377 20.1 22.5752 15.75H1.3877C2.9252 20.1375 7.0877 23.25 11.9627 23.25Z" fill="#ED4C5C"/>
<path d="M1.3875 8.25C0.975 9.4125 0.75 10.6875 0.75 12C0.75 13.3125 0.975 14.5875 1.3875 15.75H22.6125C23.025 14.5875 23.25 13.3125 23.25 12C23.25 10.6875 23.025 9.4125 22.6125 8.25H1.3875Z" fill="#428BC1"/>
</g>
<defs>
<clipPath id="clip0_70_688">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 709 B

View File

@ -3,7 +3,7 @@ import { Container, Burger } from "./";
import { MapPin, Smartphone } from "lucide-react";
import { Link } from "react-router-dom";
import { Button } from "../ui/button";
import { Logo } from "../shared";
import { LangMenu, Logo } from "../shared";
import { useLangStore } from "@/store/lang";
import { navData } from "@/data/header.data";
import { useTranslate } from "@/hooks/use-translate";
@ -42,7 +42,7 @@ export const Header: FC = () => {
<h4 className="text-sm ">+99371871812</h4>
</div>
{/* <LangMenu /> */}
<LangMenu />
</div>
</Container>
</div>

View File

@ -4,7 +4,7 @@ import { Container } from "@/components/layout";
import { TimeCard } from "../";
import { useTranslate } from "@/hooks/use-translate";
import { useLangStore } from "@/store/lang";
import { times } from "@/data/home-time.data";
import { times } from "@/data/home/home-time.data";
interface Props {
className?: string;

View File

@ -11,6 +11,9 @@ import {
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { Field } from "../field";
import { b2bStage1 } from "@/data/b2b.data";
import { useTranslate } from "@/hooks/use-translate";
import { Language, useLangStore } from "@/store/lang";
interface Props {
className?: string;
@ -19,6 +22,7 @@ interface Props {
export const Stage1: FC<Props> = ({ handleNext }) => {
const { control, formState } = useFormContext();
const lang = useLangStore((state) => state.lang);
return (
<motion.div
@ -27,7 +31,7 @@ export const Stage1: FC<Props> = ({ handleNext }) => {
exit={{ opacity: 0, y: "100%", transition: { duration: 0.2 } }}
className="w-full"
>
<h3 className="h2 mb-8">Информация об экспоненте:</h3>
<h2 className="h2 mb-8">{b2bStage1[useTranslate(lang)].h2}</h2>
<div className="flex flex-col gap-8">
<FormField
@ -36,7 +40,9 @@ export const Stage1: FC<Props> = ({ handleNext }) => {
name="type"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel className="text-xl">Тип:</FormLabel>
<FormLabel className="text-xl">
{lang === Language.RU ? "Тип:" : "Type:"}
</FormLabel>
<FormControl>
<RadioGroup
@ -74,55 +80,55 @@ export const Stage1: FC<Props> = ({ handleNext }) => {
name={"company_name"}
error={formState.errors.company_name as FieldError}
placeholder=""
label="Название компании/организации"
label={b2bStage1[useTranslate(lang)].data[0].label}
/>
<Field
control={control}
name={"representative_name"}
error={formState.errors.representative_name as FieldError}
placeholder=""
label="Имя представителя"
label={b2bStage1[useTranslate(lang)].data[1].label}
/>
<Field
control={control}
name={"job_title"}
error={formState.errors.job_title as FieldError}
placeholder=""
label="Название должности/позиция"
label={b2bStage1[useTranslate(lang)].data[2].label}
/>
<Field
control={control}
name={"participants_number"}
error={formState.errors.participants_number as FieldError}
placeholder=""
label="Количество участников"
label={b2bStage1[useTranslate(lang)].data[3].label}
/>
<Field
control={control}
name={"country"}
error={formState.errors.country as FieldError}
placeholder=""
label="Страна"
label={b2bStage1[useTranslate(lang)].data[4].label}
/>
<Field
control={control}
name={"email_address"}
error={formState.errors.email_address as FieldError}
placeholder=""
label="E-mail адрес"
label={b2bStage1[useTranslate(lang)].data[5].label}
/>
<Field
control={control}
name={"phone_number"}
error={formState.errors.phone_number as FieldError}
placeholder=""
label="Номер телефона"
label={b2bStage1[useTranslate(lang)].data[6].label}
/>
<Field
control={control}
name={"website"}
placeholder=""
label="Вебсайт"
label={b2bStage1[useTranslate(lang)].data[7].label}
/>
</div>
@ -132,7 +138,7 @@ export const Stage1: FC<Props> = ({ handleNext }) => {
onClick={handleNext}
className="w-full mt-10"
>
Далее
{lang === Language.RU ? "Далее" : "Next"}
</Button>
</motion.div>
);

View File

@ -3,6 +3,9 @@ import { FieldError, useFormContext } from "react-hook-form";
import { Field } from "../";
import { motion } from "motion/react";
import { Button } from "@/components/ui/button";
import { Language, useLangStore } from "@/store/lang";
import { useTranslate } from "@/hooks/use-translate";
import { b2bStage2 } from "@/data/b2b.data";
interface Props {
className?: string;
@ -11,6 +14,7 @@ interface Props {
}
export const Stage2: FC<Props> = ({ handleNext, handlePrev }) => {
const lang = useLangStore((state) => state.lang);
const { control, formState } = useFormContext();
return (
@ -19,7 +23,7 @@ export const Stage2: FC<Props> = ({ handleNext, handlePrev }) => {
animate={{ opacity: 1, y: 0, transition: { delay: 0.5, duration: 0.3 } }}
exit={{ opacity: 0, y: 100 }}
>
<h3 className="h2 mb-8">Цели встречи:</h3>
<h2 className="h2 mb-8">{b2bStage2[useTranslate(lang)].h2}</h2>
<div className="flex flex-col gap-8">
<Field
@ -27,51 +31,45 @@ export const Stage2: FC<Props> = ({ handleNext, handlePrev }) => {
name={"meeting_objective"}
error={formState.errors.meeting_objective as FieldError}
placeholder=""
label="Основная цель встречи"
label={b2bStage2[useTranslate(lang)].data[0].label}
/>
<Field
control={control}
name={"proposal_description"}
error={formState.errors.proposal_description as FieldError}
placeholder=""
label="Краткое описание вашего предложения/проекта/запроса"
label={b2bStage2[useTranslate(lang)].data[1].label}
/>
<Field
control={control}
name={"government_agency"}
error={formState.errors.government_agency as FieldError}
placeholder=""
label="Соответствующее государственное учреждение/департамент"
label={b2bStage2[useTranslate(lang)].data[2].label}
/>
<h3 className="h2 mt-4">
Информация о компании/организации:
{/* Company/Organization Profile: */}
</h3>
<h2 className="h2 mt-4">{b2bStage2[useTranslate(lang)].secondH2}</h2>
<Field
control={control}
name={"sector_industry"}
error={formState.errors.sector_industry as FieldError}
placeholder=""
// label="Sector sector_industry"
label="Отраслевая промышленность"
label={b2bStage2[useTranslate(lang)].data[3].label}
/>
<Field
control={control}
name={"key_services"}
error={formState.errors.key_services as FieldError}
placeholder=""
label="Ключевые услуги/продукты"
// label="Key Services/Products"
label={b2bStage2[useTranslate(lang)].data[4].label}
/>
<Field
control={control}
name={"government_experience"}
error={formState.errors.government_experience as FieldError}
placeholder=""
label="Предыдущий опыт работы с правительствами (если применимо)"
// label="Previous Experience working with Governments (if applicable)"
label={b2bStage2[useTranslate(lang)].data[5].label}
/>
</div>
@ -82,7 +80,7 @@ export const Stage2: FC<Props> = ({ handleNext, handlePrev }) => {
variant={"outline"}
className="text-on_surface"
>
Вернуться назад
{lang === Language.RU ? "Вернуться назад" : "Back"}
</Button>
<Button
@ -91,7 +89,7 @@ export const Stage2: FC<Props> = ({ handleNext, handlePrev }) => {
onClick={handleNext}
className="w-full"
>
Далее
{lang === Language.RU ? "Далее" : "Next"}
</Button>
</div>
</motion.div>

View File

@ -4,6 +4,9 @@ import { FieldError, useFormContext } from "react-hook-form";
import { Field } from "../field";
import { Button } from "@/components/ui/button";
import { Loader } from "lucide-react";
import { b2bStage3 } from "@/data/b2b.data";
import { useTranslate } from "@/hooks/use-translate";
import { Language, useLangStore } from "@/store/lang";
interface Props {
className?: string;
@ -12,6 +15,7 @@ interface Props {
export const Stage3: FC<Props> = ({ handlePrev }) => {
const { control, formState } = useFormContext();
const lang = useLangStore((state) => state.lang);
return (
<motion.div
@ -19,10 +23,7 @@ export const Stage3: FC<Props> = ({ handlePrev }) => {
animate={{ opacity: 1, y: 0, transition: { delay: 0.5, duration: 0.3 } }}
transition={{ duration: 1 }}
>
<h3 className="h2 mb-8">
Логистика встречи:
{/* Meeting Logistics */}
</h3>
<h2 className="h2 mb-8">{b2bStage3[useTranslate(lang)].h2}</h2>
<div className="flex flex-col gap-6">
<Field
@ -30,24 +31,21 @@ export const Stage3: FC<Props> = ({ handlePrev }) => {
name={"preferred_meeting_datetime"}
error={formState.errors.preferred_meeting_datetime as FieldError}
placeholder=""
label="Предпочтительная дата и время "
// label="Preferred date and time for the meeting"
label={b2bStage3[useTranslate(lang)].data[0].label}
/>
<Field
control={control}
name={"preferred_mode"}
error={formState.errors.preferred_mode as FieldError}
placeholder=""
label="Предпочтительный способ проведения встречи (лично, виртуально (через zoom/ teams/другое), гибридный)"
// label="Preferred mode of meeting (in-person, virtual (via zoom/teams/other), hybrid)"
label={b2bStage3[useTranslate(lang)].data[1].label}
/>
<Field
control={control}
name={"language_preference"}
error={formState.errors.language_preference as FieldError}
placeholder=""
label="Предпочитаемый язык (английский, туркменский, русский, другой)"
// label="Additional technical or logistical requirements (e.g. AV equipment, interpreters, etc)"
label={b2bStage3[useTranslate(lang)].data[2].label}
/>
<Field
@ -55,37 +53,36 @@ export const Stage3: FC<Props> = ({ handlePrev }) => {
name={"additional_technical"}
error={formState.errors.additional_technical as FieldError}
placeholder=""
label="Дополнительные технические или логистические требования (например, аудио-видео оборудование, переводчики и т.д.)"
// label="Additional technical or logistical requirements (e.g. AV equipment, interpreters, etc)"
label={b2bStage3[useTranslate(lang)].data[3].label}
/>
</div>
<div className="flex flex-col gap-8">
<div className="">
<h3 className="h2 mt-10">Приложения:</h3>
<div>
<h3 className="h2 mt-10">{b2bStage3[useTranslate(lang)].secondH2}</h3>
<h5 className="text-on_surface_v">
(Пожалуйста приложите следующие документы, если это необходимо)
{b2bStage3[useTranslate(lang)].subtitle}
</h5>
</div>
<Field
control={control}
name="company_profile"
label="Название компании/организации"
label={b2bStage3[useTranslate(lang)].data[4].label}
type="file"
textDark
/>
<Field
control={control}
name="proposal_presentation"
label="Предложение/презентация"
label={b2bStage3[useTranslate(lang)].data[5].label}
type="file"
textDark
/>
<Field
control={control}
name="relevant_certification"
label="Соответствующие сертификаты/лицензии"
label={b2bStage3[useTranslate(lang)].data[6].label}
type="file"
textDark
/>
@ -98,7 +95,7 @@ export const Stage3: FC<Props> = ({ handlePrev }) => {
variant={"outline"}
className="text-on_surface"
>
Вернуться назад
{lang === Language.RU ? "Вернуться назад" : "Back"}
</Button>
<Button
@ -109,7 +106,7 @@ export const Stage3: FC<Props> = ({ handlePrev }) => {
{formState.isSubmitting ? (
<Loader className="animate-spin" />
) : (
"Отправить"
b2bStage3[useTranslate(lang)].button
)}
</Button>
</div>

View File

@ -85,18 +85,16 @@ export const B2bForm: FC<Props> = ({
try {
const formData = new FormData();
// Перебираем все поля
Object.entries(values).forEach(([key, value]) => {
if (value instanceof File) {
console.log(`Добавляем файл: ${key}`, value); // Отладочный вывод
console.log(`Добавляем файл: ${key}`, value);
formData.append(key, value);
} else if (value !== undefined) {
console.log(`Добавляем поле: ${key}`, value); // Отладочный вывод
console.log(`Добавляем поле: ${key}`, value);
formData.append(key, value as string);
}
});
// Отправляем запрос
const res = await axios.post(
"https://turkmentextile.turkmenexpo.com/app/api/v1/form",
formData,
@ -108,7 +106,6 @@ export const B2bForm: FC<Props> = ({
);
if (res.status === 201) {
console.log("Форма успешно отправлена!");
setSuccess(true);
}
} catch (error) {

View File

@ -4,29 +4,10 @@ import { Link } from "react-router-dom";
import useEmblaCarousel from "embla-carousel-react";
import { Container } from "@/components/layout";
import { AboutCard } from "../about-card";
import { aboutData } from "@/data/home-about.data";
import { aboutData } from "@/data/home/home-about.data";
import { useTranslate } from "@/hooks/use-translate";
import { Language, useLangStore } from "@/store/lang";
const data = [
{
nums: "8,400 m²",
text: "выставочной площади",
},
{
nums: "10000+",
text: "Посетители посетят выставку",
},
{
nums: "100+",
text: "Экспоненты из более чем 30 стран",
},
{
nums: "80%",
text: "Участники принимают участие в принятии решений о закупках",
},
];
export const HomeAbout: FC = () => {
const [ebmblaRef] = useEmblaCarousel();
const lang = useLangStore((state) => state.lang);

View File

@ -4,7 +4,7 @@ import { Link } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Container } from "@/components/layout";
import { useMediaQuery } from "usehooks-ts";
import { btns } from "@/data/home-hero.data";
import { btns } from "@/data/home/home-hero.data";
import { useTranslate } from "@/hooks/use-translate";
import { useLangStore } from "@/store/lang";

View File

@ -2,7 +2,7 @@ import { FC, useCallback, useEffect, useState } from "react";
import useEmblaCarousel from "embla-carousel-react";
import { Container } from "@/components/layout";
import { EmblaDots, OfferCard } from "../";
import { offersData } from "@/data/home-offers.data";
import { offersData } from "@/data/home/home-offers.data";
import { useTranslate } from "@/hooks/use-translate";
import { useLangStore } from "@/store/lang";

View File

@ -2,7 +2,7 @@ import { FC } from "react";
import { ThemeCard } from "../theme-card";
import { Container } from "@/components/layout";
import { useLangStore } from "@/store/lang";
import { homeTheme } from "@/data/home-theme.data";
import { homeTheme } from "@/data/home/home-theme.data";
import { useTranslate } from "@/hooks/use-translate";
export const themes = [

View File

@ -6,7 +6,7 @@ import { Container } from "@/components/layout";
import { ContactCard, TimeCard } from "../";
import { useTranslate } from "@/hooks/use-translate";
import { Language, useLangStore } from "@/store/lang";
import { times } from "@/data/home-time.data";
import { times } from "@/data/home/home-time.data";
import { contacts } from "@/data/contacts.data";
interface Props {

View File

@ -8,5 +8,7 @@ export { B2bFormProgress } from "./b2b-form-progress";
export { Field } from "./field";
export { FormSuccesStatus } from "./form-succes-status";
export { EmblaDots } from "./embla-dots";
export { LangMenu } from "./lang-menu";
export * from "./about";
export * from "./home";

View File

@ -0,0 +1,70 @@
import { FC, useState } from "react";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { cn } from "@/lib/utils";
import { Language, useLangStore } from "@/store/lang";
interface Props {
className?: string;
}
export const langs = [
{
lang: Language.RU,
},
{
lang: Language.EN,
},
];
export const LangMenu: FC<Props> = ({ className }) => {
const lang = useLangStore((state) => state.lang);
const setLang = useLangStore((state) => state.setLang);
const [isOpen, setIsOpen] = useState(false);
console.log(langs.filter((item) => item.lang === lang));
return (
<Popover open={isOpen} onOpenChange={() => setIsOpen(!isOpen)}>
<PopoverTrigger className={cn("flex items-center gap-2", className)}>
<img src={lang === Language.RU ? "/ru.svg" : "/en.svg"} alt="" />
{lang === Language.RU ? "Ру" : "En"}
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M4.23021 8.01443C4.35919 7.70304 4.66305 7.5 5.00011 7.5H15.0001C15.3372 7.5 15.641 7.70304 15.77 8.01443C15.899 8.32583 15.8277 8.68426 15.5894 8.92259L10.5894 13.9226C10.2639 14.248 9.73629 14.248 9.41085 13.9226L4.41085 8.92259C4.17252 8.68426 4.10122 8.32583 4.23021 8.01443ZM7.01195 9.16667L10.0001 12.1548L12.9883 9.16667H7.01195Z"
fill="#2C2828"
/>
</svg>
</PopoverTrigger>
<PopoverContent className="flex flex-col gap-6">
{langs
.filter((item) => item.lang !== lang)
.map((item, i) => (
<div
onClick={() => {
setLang(item.lang);
setIsOpen(false);
}}
key={i}
className="flex gap-3 py-1 items-center cursor-pointer"
>
<img
src={item.lang === Language.RU ? "/ru.svg" : "/en.svg"}
alt="flag"
/>
<h5>{item.lang === Language.RU ? "Русский" : "English"}</h5>
</div>
))}
</PopoverContent>
</Popover>
);
};

View File

@ -0,0 +1,31 @@
import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import { cn } from "@/lib/utils";
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverAnchor = PopoverPrimitive.Anchor;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-32 rounded-[2px] s bg-white p-4 text-popover-foreground drop-shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };

189
src/data/b2b.data.ts Normal file
View File

@ -0,0 +1,189 @@
export const b2bStage1 = [
{
h2: "Информация об экспоненте:",
data: [
{
label: "Название компании/организации",
},
{
label: "Имя представителя",
},
{
label: "Название должности/позиция",
},
{
label: "Количество участников",
},
{
label: "Страна",
},
{
label: "E-mail адрес",
},
{
label: "Номер телефона",
},
{
label: "Вебсайт",
},
],
},
{
h2: "Applicant Information:",
data: [
{
label: "Company/Organization Name",
},
{
label: "Name of Representative",
},
{
label: "Job title/Position",
},
{
label: "Number of the participants",
},
{
label: "Country",
},
{
label: "E-mail address",
},
{
label: "Phone number",
},
{
label: "Website",
},
],
},
];
export const b2bStage2 = [
{
h2: "Цели встречи:",
secondH2: "Информация о компании/организации:",
data: [
{
label: "Основная цель встречи",
},
{
label: "Краткое описание вашего предложения/проекта/запроса",
},
{
label: "Соответствующее государственное учреждение/департамент",
},
{
label: "Отраслевая промышленность",
},
{
label: "Ключевые услуги/продукты",
},
{
label: "Предыдущий опыт работы с правительствами (если применимо)",
},
],
},
{
h2: "Meeting Purpose: ",
secondH2: "Company/Organization Profile:",
data: [
{
label: "Primary objective of the meeting",
},
{
label: "Brief description of your proposal/project/request",
},
{
label: "Relevant government agency/department",
},
{
label: "Sector Industry ",
},
{
label: "Key Services/Products",
},
{
label: "Previous Experience working with Governments (if applicable)",
},
],
},
];
export const b2bStage3 = [
{
h2: "Логистика встречи:",
secondH2: "Логистика встречи:",
subtitle: "(Пожалуйста приложите следующие документы, если это необходимо)",
data: [
{
label: "Предпочтительная дата и время",
},
{
label:
"Предпочтительный способ проведения встречи (лично, виртуально (через zoom/ teams/другое), гибридный)",
},
{
label: "Предпочитаемый язык (английский, туркменский, русский, другой)",
},
{
label:
"Дополнительные технические или логистические требования (например, аудио-видео оборудование, переводчики и т.д.)",
},
{
label: "Название компании/организации",
},
{
label: "Предложение/презентация",
},
{
label: "Соответствующие сертификаты/лицензии",
},
],
button: "Отправить",
},
{
h2: "Meeting Logistics:",
secondH2: "Attachments",
subtitle: "(Please attach the following documents as applicable)",
data: [
{
label: "Preferred date and time for the meeting",
},
{
label:
"Preferred mode of meeting (in-person, virtual (via zoom/teams/other), hybrid)",
},
{
label: "Language preference (English, turkmen, Russian, other)",
},
{
label:
"Additional technical or logistical requirements (e.g. AV equipment, interpreters, etc)",
},
{
label: "Company/organization profile",
},
{
label: "Proposal presentation",
},
{
label: "Relevant certification/licenses",
},
],
button: "Send",
},
];

View File

@ -27,7 +27,7 @@ export const contacts = [
img: "/contacts/home/mail.svg",
},
{
title: "здание ТПП Туркменистана",
title: "Building of the CCI of Turkmenistan",
subtitle: "Exhibition address",
img: "/contacts/home/location.svg",
},

47
src/data/stend.data.ts Normal file
View File

@ -0,0 +1,47 @@
export const stendData = [
{
cover: "Забронировать стенд",
h2: "Выберите один из вариантов:",
radio: "Только стенд",
radio_2: "Комплексное предложение",
label_1: "Название компании/организации",
label_2: "Имя представителя",
label_3: "Название должности/позиция",
number_of_participants: "Количество участников",
label_4: "Страна",
label_5: "E-mail адрес",
label_6: "Номер телефона",
label_7: "Вебсайт",
visa: "Визовая поддержка:",
visa_radio: "Да",
visa_radio_2: "Нет",
button: "Отправить",
},
{
cover: "Book your stand",
h2: "Select one of the options:",
radio: "Space Only",
radio_2: "Stand Package",
label_1: "Company/Organization Name",
label_2: "Name of Representative",
label_3: "Job title/Position",
number_of_participants: "Number of the participants",
label_4: "Country",
label_5: "E-mail address",
label_6: "Phone number",
label_7: "Website",
visa: "Visa support:",
visa_radio: "Yes",
visa_radio_2: "No",
button: "Send",
},
];

View File

@ -2,17 +2,23 @@ import { Cover } from "@/components/layout";
import { B2bFormProgress } from "@/components/shared";
import { B2bForm } from "@/components/shared/forms/b2b-form";
import { useScrollTop } from "@/hooks/use-scroll-top";
import { Language, useLangStore } from "@/store/lang";
import { useState } from "react";
export default function B2b() {
useScrollTop();
const lang = useLangStore((state) => state.lang);
const [stage, setStage] = useState(1);
const [success, setSuccess] = useState(false);
return (
<div className={"pb-[120px]"}>
<Cover title="B2B | B2G встречи" />
<Cover
title={
lang === Language.RU ? "B2B | B2G встречи" : "B2B | B2G meetings"
}
/>
{!success && stage !== 0 && <B2bFormProgress stage={stage} />}

View File

@ -22,10 +22,14 @@ import { Loader } from "lucide-react";
import { postSponsor } from "@/services/service";
import { useScrollTop } from "@/hooks/use-scroll-top";
import { Cover } from "@/components/layout";
import { Language, useLangStore } from "@/store/lang";
import { stendData } from "@/data/stend.data";
import { useTranslate } from "@/hooks/use-translate";
export default function BecomeSponsor() {
useScrollTop();
const lang = useLangStore((state) => state.lang);
const [success, setSuccess] = useState(false);
const form = useForm<SponsorFormType>({
resolver: zodResolver(sponsorFormSchema),
@ -46,7 +50,9 @@ export default function BecomeSponsor() {
return (
<div>
<Cover title="Стать спонсором" />
<Cover
title={lang === Language.RU ? "Стать спонсором" : "Become a sponsor"}
/>
<AnimatePresence>
{!success && (
@ -59,42 +65,46 @@ export default function BecomeSponsor() {
onSubmit={form.handleSubmit(onSubmit)}
>
<Field
label="Название компании/организации"
label={stendData[useTranslate(lang)].label_1}
name="company_name"
control={form.control}
error={errors.company_name}
/>
<Field
label="Имя представителя"
label={stendData[useTranslate(lang)].label_2}
name="rep_name"
control={form.control}
error={errors.rep_name}
/>
<Field
label="Название должности/позиция"
label={stendData[useTranslate(lang)].label_3}
name="job_title"
control={form.control}
error={errors.job_title}
/>
<Field
label="Страна"
label={stendData[useTranslate(lang)].label_4}
name="country"
control={form.control}
error={errors.country}
/>
<Field
label="E-mail адрес"
label={stendData[useTranslate(lang)].label_5}
name="email"
control={form.control}
error={errors.email}
/>
<Field
label="Номер телефона"
label={stendData[useTranslate(lang)].label_6}
name="phone"
control={form.control}
error={errors.phone}
/>
<Field label="Вебсайт" name="website" control={form.control} />
<Field
label={stendData[useTranslate(lang)].label_7}
name="website"
control={form.control}
/>
<FormField
control={form.control}
@ -102,7 +112,7 @@ export default function BecomeSponsor() {
render={({ field }) => (
<FormItem className="space-y-5">
<FormLabel className="text-xl">
Визовая поддержка:
{stendData[useTranslate(lang)].visa}
</FormLabel>
<FormControl>
@ -118,7 +128,9 @@ export default function BecomeSponsor() {
checked={field.value === "yes"}
/>
</FormControl>
<FormLabel className="text-base">Да</FormLabel>
<FormLabel className="text-base">
{stendData[useTranslate(lang)].visa_radio}
</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-5 space-y-0 ">
@ -128,7 +140,9 @@ export default function BecomeSponsor() {
checked={field.value === "no"}
/>
</FormControl>
<FormLabel className="text-base">Нет</FormLabel>
<FormLabel className="text-base">
{stendData[useTranslate(lang)].visa_radio_2}
</FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
@ -140,7 +154,7 @@ export default function BecomeSponsor() {
{form.formState.isSubmitting ? (
<Loader className="animate-spin" />
) : (
"Отправить"
stendData[useTranslate(lang)].button
)}
</Button>
</motion.form>

View File

@ -20,8 +20,12 @@ import { useForm } from "react-hook-form";
import { Loader } from "lucide-react";
import { Cover } from "@/components/layout";
import { postStend } from "@/services/service";
import { stendData } from "@/data/stend.data";
import { useTranslate } from "@/hooks/use-translate";
import { useLangStore } from "@/store/lang";
export default function StendForm() {
const lang = useLangStore((state) => state.lang);
const [success, setSuccess] = useState(false);
const form = useForm<StandFormType>({
resolver: zodResolver(standFormSchema),
@ -42,7 +46,7 @@ export default function StendForm() {
return (
<div>
<Cover title="Забронировать стенд" />
<Cover title={stendData[useTranslate(lang)].cover} />
<AnimatePresence>
{!success && (
@ -60,7 +64,7 @@ export default function StendForm() {
render={({ field }) => (
<FormItem className="space-y-5">
<FormLabel className="text-xl">
Выберите один из вариантов:
{stendData[useTranslate(lang)].h2}
</FormLabel>
<FormControl>
@ -77,7 +81,7 @@ export default function StendForm() {
/>
</FormControl>
<FormLabel className="text-base">
Только стенд
{stendData[useTranslate(lang)].radio}
</FormLabel>
</FormItem>
@ -89,7 +93,7 @@ export default function StendForm() {
/>
</FormControl>
<FormLabel className="text-base">
Комплексное предложение
{stendData[useTranslate(lang)].radio_2}
</FormLabel>
</FormItem>
</RadioGroup>
@ -99,49 +103,54 @@ export default function StendForm() {
/>
<Field
label="Название компании/организации"
label={stendData[useTranslate(lang)].label_1}
name="company_name"
control={form.control}
error={errors.company_name}
/>
<Field
label="Имя представителя"
label={stendData[useTranslate(lang)].label_2}
name="rep_name"
control={form.control}
error={errors.rep_name}
/>
<Field
label="Название должности/позиция"
label={stendData[useTranslate(lang)].label_3}
name="job_title"
control={form.control}
error={errors.job_title}
/>
<Field
label="Количество участников"
label={stendData[useTranslate(lang)].number_of_participants}
type="number"
name="participants_number"
control={form.control}
error={errors.participants_number}
/>
<Field
label="Страна"
label={stendData[useTranslate(lang)].label_4}
name="country"
control={form.control}
error={errors.country}
/>
<Field
label="E-mail адрес"
label={stendData[useTranslate(lang)].label_5}
name="email"
control={form.control}
error={errors.email}
/>
<Field
label="Номер телефона"
label={stendData[useTranslate(lang)].label_6}
name="phone"
control={form.control}
error={errors.phone}
/>
<Field label="Вебсайт" name="website" control={form.control} />
<Field
label={stendData[useTranslate(lang)].label_7}
name="website"
control={form.control}
/>
<FormField
control={form.control}
@ -149,7 +158,7 @@ export default function StendForm() {
render={({ field }) => (
<FormItem className="space-y-5">
<FormLabel className="text-xl">
Визовая поддержка:
{stendData[useTranslate(lang)].visa}
</FormLabel>
<FormControl>
@ -165,7 +174,9 @@ export default function StendForm() {
checked={field.value === "yes"}
/>
</FormControl>
<FormLabel className="text-base">Да</FormLabel>
<FormLabel className="text-base">
{stendData[useTranslate(lang)].visa_radio}
</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-5 space-y-0 ">
@ -175,7 +186,9 @@ export default function StendForm() {
checked={field.value === "no"}
/>
</FormControl>
<FormLabel className="text-base">Нет</FormLabel>
<FormLabel className="text-base">
{stendData[useTranslate(lang)].visa_radio_2}
</FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
@ -187,7 +200,7 @@ export default function StendForm() {
{form.formState.isSubmitting ? (
<Loader className="animate-spin" />
) : (
"Отправить"
stendData[useTranslate(lang)].button
)}
</Button>
</motion.form>

View File

@ -11,6 +11,6 @@ export interface LangState {
}
export const useLangStore = create<LangState>()((set) => ({
lang: Language.EN,
lang: Language.RU,
setLang: (lang) => set({ lang }),
}));