submit form contactus and start api projects

This commit is contained in:
zahravaziri
2025-06-09 17:14:44 +03:30
parent 11446b98e4
commit 3e9143f32c
18 changed files with 515 additions and 35 deletions
+125 -9
View File
@@ -1,32 +1,148 @@
'use client';
import { useState } from 'react';
import Button from '@/components/uikit/button';
import FormField from '@/components/uikit/inputs';
import { useTranslations } from 'next-intl';
import api from '@/lib/axios';
import { setContact } from '@/services/contact';
const ContactForm = () => {
const t = useTranslations();
const [formData, setFormData] = useState({
first_name: '',
last_name: '',
email: '',
phone: '',
message: '',
});
const [errors, setErrors] = useState<Record<string, string>>({});
const [loading, setLoading] = useState(false);
const validate = () => {
const newErrors: Record<string, string> = {};
if (!formData.first_name.trim())
newErrors.first_name = t('com_contact_first_name_required');
if (!formData.last_name.trim())
newErrors.last_name = t('com_contact_last_name_required');
if (!formData.email) {
newErrors.email = t('com_contact_email_required');
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = t('com_contact_email_error');
}
if (!formData.phone) {
newErrors.phone = t('com_contact_phone_required');
} else if (!/^09\d{9}$/.test(formData.phone)) {
newErrors.phone = t('com_contact_phone_error');
}
if (!formData.message.trim()) {
newErrors.message = t('com_contact_textarea_required');
} else if (formData.message.trim().length < 10) {
newErrors.message = t('com_contact_textarea_error');
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleChange = (field: string, value: string) => {
setFormData({ ...formData, [field]: value });
setErrors({ ...errors, [field]: '' });
};
const handleSubmit = (e: React.FormEvent) => {
console.log(e);
e.preventDefault();
setLoading(true);
setContact(formData).finally(() => {
setLoading(false);
});
};
return (
<div className="w-full rounded-4xl bg-white p-4 md:w-1/2">
<form
onSubmit={handleSubmit}
className="z-10 w-full rounded-4xl bg-white p-4 md:w-1/2"
>
<h2 className="mt-8 mb-10 text-5xl text-gray-800">
{t('com_contact_title')}{' '}
<span className="text-5xl font-bold">
{t('com_contact_title_bold')}
</span>
</h2>
<div className="space-y-6">
<div className="flex flex-col gap-6 md:flex-row md:gap-8">
<FormField type="text" placeholder={t('com_contact_first_name')} />
<FormField type="text" placeholder={t('com_contact_last_name')} />
</div>
<FormField type="email" placeholder={t('com_contact_email')} />
<FormField type="tel" placeholder={t('com_contact_phone')} />
<FormField type="textarea" placeholder={t('com_contact_textarea')} />
<div className="w-full">
<FormField
type="text"
placeholder={t('com_contact_first_name')}
value={formData.first_name}
onChange={(e: any) => handleChange('first_name', e.target.value)}
/>
{errors.first_name && (
<p className="text-primary mt-1 text-sm">{errors.first_name}</p>
)}
</div>
<Button>Submit Message</Button>
<div className="w-full">
<FormField
type="text"
placeholder={t('com_contact_last_name')}
value={formData.last_name}
onChange={(e: any) => handleChange('last_name', e.target.value)}
/>
{errors.last_name && (
<p className="text-primary mt-1 text-sm">{errors.last_name}</p>
)}
</div>
</div>
<div>
<FormField
type="email"
placeholder={t('com_contact_email')}
value={formData.email}
onChange={(e: any) => handleChange('email', e.target.value)}
/>
{errors.email && (
<p className="text-primary mt-1 text-sm">{errors.email}</p>
)}
</div>
<div>
<FormField
type="tel"
placeholder={t('com_contact_phone')}
value={formData.phone}
onChange={(e: any) => handleChange('phone', e.target.value)}
/>
{errors.phone && (
<p className="text-primary mt-1 text-sm">{errors.phone}</p>
)}
</div>
<div>
<FormField
type="textarea"
placeholder={t('com_contact_textarea')}
value={formData.message}
onChange={(e: any) => handleChange('message', e.target.value)}
/>
{errors.message && (
<p className="text-primary mt-1 text-sm">{errors.message}</p>
)}
</div>
<Button disabled={loading}>{t('com_contact_button_submit')}</Button>
</div>
</div>
</form>
);
};
+10 -14
View File
@@ -1,5 +1,6 @@
'use client';
import SectionTitle from '@/components/layout/sectionTitle';
import { Icon } from '@/components/uikit/icons';
import { useTranslations } from 'next-intl';
@@ -8,23 +9,18 @@ const TouchUs = () => {
return (
<div className="w-full p-8 md:w-1/2">
<div className="mb-3.5 flex items-center gap-0.5 text-base">
<Icon name="setting" className="text-primary h-4 w-4" />
<p>{t('pages_contact_title')}</p>
</div>
<h1 className="mb-5 text-3xl font-light text-gray-800 md:text-5xl">
{t('com_contact_touch_title')}{' '}
<span className="text-3xl font-light md:text-5xl md:font-bold">
{t('com_contact_touch_title_bold')}
</span>
</h1>
<p className="mb-10 text-base font-normal text-gray-600">
<SectionTitle
title={t('pages_contact_title')}
description={t('com_contact_touch_title')}
description_bold={t('com_contact_touch_title_bold')}
/>
<p className="mt-4 mb-10 text-base font-normal text-gray-600">
{t('com_contact_touch_description')}
</p>
<div className="flex flex-col justify-between gap-10">
<div className="flex items-center">
<div className="mr-4 flex h-10 w-10 items-center justify-center rounded-full bg-red-500">
<div className="me-4 flex h-10 w-10 items-center justify-center rounded-full bg-red-500">
<Icon name="phone" className="text-white" />
</div>
<div>
@@ -36,7 +32,7 @@ const TouchUs = () => {
</div>
<div className="flex items-center">
<div className="mr-4 flex h-10 w-10 items-center justify-center rounded-full bg-red-500">
<div className="me-4 flex h-10 w-10 items-center justify-center rounded-full bg-red-500">
<Icon name="email" className="text-white" />
</div>
<div>
@@ -48,7 +44,7 @@ const TouchUs = () => {
</div>
<div className="flex items-center">
<div className="mr-4 flex h-10 w-10 items-center justify-center rounded-full bg-red-500">
<div className="me-4 flex h-10 w-10 items-center justify-center rounded-full bg-red-500">
<Icon name="location" className="text-white" />
</div>
<div>
+66
View File
@@ -0,0 +1,66 @@
import images from '@/assets/images/images';
import SectionTitle from '@/components/layout/sectionTitle';
import { getProductCategories } from '@/services/products';
import Link from 'next/link';
import routeFactory from '@/assets/constants/routeFactory';
import { getTranslations } from 'next-intl/server';
import { TLocales } from '@/models/layout';
import { getProjectCategories } from '@/services/projects';
import { IProjectCardProps } from '../project/project';
interface Props {
locale: TLocales;
}
export default async function HomePageProjects({ locale }: Props) {
const t = await getTranslations({ locale });
// const projectCategories: IProjectCardProps[] = await getProjectCategories();
const routes = routeFactory(t, locale);
return (
<div className="w-full">
<div
className={`relative w-full bg-white bg-cover bg-fixed bg-center bg-no-repeat pt-28 pb-48`}
// style={{ backgroundImage: `url(${images.homeProductBack.src})` }}
>
<div className="absolute inset-0 z-10 bg-black opacity-50" />
<div className="relative z-20 container mx-auto grid grid-cols-2 gap-28">
<SectionTitle
title={t('pages_product_categories_title')}
description={t('com_home_products_title')}
reverseColor
/>
<h4 className="pt-10 text-base font-extralight tracking-normal text-white">
{t('com_home_products_description')}
</h4>
</div>
</div>
<div className="relative top-[-100px] z-20 container mx-auto w-full">
{/* <div className="grid grid-cols-1 gap-8 rounded-4xl bg-gray-50 py-10 shadow-2xl md:grid-cols-2 lg:grid-cols-4">
{projectCategories.map((category, index) => (
<Link
href={'#'}
key={index}
// href={routes.products.route(index)}
>
<div
className={`flex flex-col items-center justify-center gap-4 p-6 text-center ${index ? 'border-s-[1px] border-gray-100' : ''}`}
>
<h3 className="text-xl font-bold text-gray-500">
{category.title}
</h3>
{/* <p className="text-lg font-light text-gray-400">
{t('com_products_category_types_count', {
count: category.typesCount,
})}
</p>
</div>
</Link>
))}
</div>*/}
</div>
</div>
);
}
+9 -8
View File
@@ -1,39 +1,40 @@
import images from '@/assets/images/images';
import Image from 'next/image';
import Link from 'next/link';
import { IProjectCardProps } from './project';
const projects = [
{
title: 'Sustainable Practices Reducing Waste in Industrial Production',
image: images.projectImg_1.src,
imageSrc: images.projectImg_1.src,
link: '#',
},
{
title: 'Advanced Robotics Revolutionizing Industrial Workflows',
image: images.projectImg_1.src,
imageSrc: images.projectImg_1.src,
link: '#',
},
{
title: 'Top Benefits of the Robotics in Manufacturing',
image: images.projectImg_1.src,
imageSrc: images.projectImg_1.src,
link: '#',
},
{
title: 'Leveraging Data Analytics for Smarter Production',
image: images.projectImg_1.src,
imageSrc: images.projectImg_1.src,
link: '#',
},
{
title: 'Reducing Operational Costs Through Automation',
image: '/images/post5.jpg',
imageSrc: '/images/post5.jpg',
link: '#',
},
{
title: 'The Advantages of Customized Manufacturing Solutions',
image: '/images/post6.jpg',
imageSrc: '/images/post6.jpg',
link: '#',
},
];
] as IProjectCardProps[];
export default function ProjectsGrid() {
return (
@@ -46,7 +47,7 @@ export default function ProjectsGrid() {
>
<div className="relative aspect-[1.09] w-full overflow-hidden rounded-4xl">
<Image
src={project.image}
src={project.imageSrc}
alt={project.title}
fill
className="h-auto w-full object-cover"
+5
View File
@@ -0,0 +1,5 @@
export interface IProjectCardProps {
imageSrc: string;
title: string;
link: string;
}
+1 -1
View File
@@ -20,7 +20,7 @@ const FormField: React.FC<FormFieldProps> = ({
name,
}) => {
const commonClass =
'w-full rounded-lg border border-gray-300 p-3 focus:ring-2 focus:ring-red-500 focus:outline-none';
'w-full rounded-lg border border-gray-100 p-3 focus:outline-none';
if (type === 'textarea') {
return (