first commit
This commit is contained in:
158
frontend/src/app/(public)/contact/page.tsx
Normal file
158
frontend/src/app/(public)/contact/page.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useLanguage } from '@/context/LanguageContext';
|
||||
import { contactsApi } from '@/lib/api';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Input from '@/components/ui/Input';
|
||||
import { ChatBubbleLeftRightIcon } from '@heroicons/react/24/outline';
|
||||
import { getSocialLinks, socialIcons, socialConfig } from '@/lib/socialLinks';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
export default function ContactPage() {
|
||||
const { t } = useLanguage();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
message: '',
|
||||
});
|
||||
|
||||
const socialLinks = getSocialLinks();
|
||||
const emailLink = socialLinks.find(l => l.type === 'email');
|
||||
const otherLinks = socialLinks.filter(l => l.type !== 'email');
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
await contactsApi.submit(formData);
|
||||
toast.success(t('contact.success'));
|
||||
setFormData({ name: '', email: '', message: '' });
|
||||
} catch (error) {
|
||||
toast.error(t('contact.error'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="section-padding">
|
||||
<div className="container-page">
|
||||
<div className="text-center max-w-2xl mx-auto">
|
||||
<h1 className="section-title">{t('contact.title')}</h1>
|
||||
<p className="section-subtitle">{t('contact.subtitle')}</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-16 grid grid-cols-1 lg:grid-cols-2 gap-12 max-w-5xl mx-auto">
|
||||
{/* Contact Form */}
|
||||
<Card className="p-8">
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<Input
|
||||
id="name"
|
||||
label={t('contact.form.name')}
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
id="email"
|
||||
label={t('contact.form.email')}
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="message"
|
||||
className="block text-sm font-medium text-primary-dark mb-1.5"
|
||||
>
|
||||
{t('contact.form.message')}
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
rows={5}
|
||||
value={formData.message}
|
||||
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||||
className="w-full px-4 py-3 rounded-btn border border-secondary-light-gray transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-primary-yellow focus:border-transparent placeholder:text-gray-400 resize-none"
|
||||
required
|
||||
minLength={10}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button type="submit" className="w-full" size="lg" isLoading={loading}>
|
||||
{t('contact.form.submit')}
|
||||
</Button>
|
||||
</form>
|
||||
</Card>
|
||||
|
||||
{/* Contact Info */}
|
||||
<div className="space-y-6">
|
||||
{/* Email Card */}
|
||||
{emailLink && (
|
||||
<Card className="p-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 bg-primary-yellow/20 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
{socialIcons.email}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-lg">{t('contact.info.email')}</h3>
|
||||
<a
|
||||
href={emailLink.url}
|
||||
className="text-secondary-blue hover:underline"
|
||||
>
|
||||
{emailLink.handle}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Social Links Card */}
|
||||
{otherLinks.length > 0 && (
|
||||
<Card className="p-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 bg-primary-yellow/20 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<ChatBubbleLeftRightIcon className="w-6 h-6 text-primary-dark" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-semibold text-lg">{t('contact.info.social')}</h3>
|
||||
<div className="mt-3 space-y-3">
|
||||
{otherLinks.map((link) => (
|
||||
<a
|
||||
key={link.type}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-3 text-secondary-blue hover:text-primary-dark transition-colors group"
|
||||
>
|
||||
<span className="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100 group-hover:bg-primary-yellow/20 transition-colors">
|
||||
{socialIcons[link.type]}
|
||||
</span>
|
||||
<span className="hover:underline">{link.handle || link.label}</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Map placeholder */}
|
||||
<Card className="h-64 bg-gradient-to-br from-secondary-gray to-secondary-light-gray flex items-center justify-center">
|
||||
<div className="text-center text-gray-400">
|
||||
<div className="text-4xl mb-2">📍</div>
|
||||
<p>Asunción, Paraguay</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user