diff --git a/index.html b/index.html index 3f9190f..0e7950b 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,9 @@ - + - Vite + React + TS + Arte na Pele
diff --git a/public/gallery/gallery1.jpg b/public/gallery/gallery1.jpg new file mode 100644 index 0000000..74de97b Binary files /dev/null and b/public/gallery/gallery1.jpg differ diff --git a/public/gallery/gallery2.jpg b/public/gallery/gallery2.jpg new file mode 100644 index 0000000..a352bfe Binary files /dev/null and b/public/gallery/gallery2.jpg differ diff --git a/public/gallery/gallery3.jpg b/public/gallery/gallery3.jpg new file mode 100644 index 0000000..5e1d1e7 Binary files /dev/null and b/public/gallery/gallery3.jpg differ diff --git a/public/gallery/gallery4.jpg b/public/gallery/gallery4.jpg new file mode 100644 index 0000000..4b3a4e2 Binary files /dev/null and b/public/gallery/gallery4.jpg differ diff --git a/public/gallery/gallery5.jpg b/public/gallery/gallery5.jpg new file mode 100644 index 0000000..ac0a325 Binary files /dev/null and b/public/gallery/gallery5.jpg differ diff --git a/public/gallery/gallery6.jpg b/public/gallery/gallery6.jpg new file mode 100644 index 0000000..913a847 Binary files /dev/null and b/public/gallery/gallery6.jpg differ diff --git a/public/gallery/gallery7.jpg b/public/gallery/gallery7.jpg new file mode 100644 index 0000000..d077aa2 Binary files /dev/null and b/public/gallery/gallery7.jpg differ diff --git a/public/gallery/gallery8.jpg b/public/gallery/gallery8.jpg new file mode 100644 index 0000000..6731fe3 Binary files /dev/null and b/public/gallery/gallery8.jpg differ diff --git a/public/hero/hero.jpg b/public/hero/hero.jpg new file mode 100644 index 0000000..3e7f554 Binary files /dev/null and b/public/hero/hero.jpg differ diff --git a/public/hero/hero1.jpg b/public/hero/hero1.jpg new file mode 100644 index 0000000..59a303b Binary files /dev/null and b/public/hero/hero1.jpg differ diff --git a/public/hero/hero2.jpg b/public/hero/hero2.jpg new file mode 100644 index 0000000..819aa3b Binary files /dev/null and b/public/hero/hero2.jpg differ diff --git a/public/hero/hero3.jpg b/public/hero/hero3.jpg new file mode 100644 index 0000000..ee32bdf Binary files /dev/null and b/public/hero/hero3.jpg differ diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..0ceaa45 --- /dev/null +++ b/public/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/tatto/Ana Oliveira-artista.jpg b/public/tatto/Ana Oliveira-artista.jpg new file mode 100644 index 0000000..d70440e Binary files /dev/null and b/public/tatto/Ana Oliveira-artista.jpg differ diff --git a/public/tatto/Carlos Mendes-artista.jpg b/public/tatto/Carlos Mendes-artista.jpg new file mode 100644 index 0000000..73417f4 Binary files /dev/null and b/public/tatto/Carlos Mendes-artista.jpg differ diff --git a/public/tatto/Maria Silva-artista.jpg b/public/tatto/Maria Silva-artista.jpg new file mode 100644 index 0000000..ace006e Binary files /dev/null and b/public/tatto/Maria Silva-artista.jpg differ diff --git a/public/tatto/Rafael Costa-artista.jpeg b/public/tatto/Rafael Costa-artista.jpeg new file mode 100644 index 0000000..f000c2d Binary files /dev/null and b/public/tatto/Rafael Costa-artista.jpeg differ diff --git a/public/tatto/arte.jpg b/public/tatto/arte.jpg new file mode 100644 index 0000000..c1b1ce6 Binary files /dev/null and b/public/tatto/arte.jpg differ diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/AppointmentSection.tsx b/src/components/AppointmentSection.tsx index 67c1d50..224118e 100644 --- a/src/components/AppointmentSection.tsx +++ b/src/components/AppointmentSection.tsx @@ -1,57 +1,52 @@ -import React from "react"; -import { useForm } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; -import * as z from "zod"; -import { CalendarIcon, Send, Clock, MapPin } from "lucide-react"; - -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "./ui/form"; -import { Input } from "./ui/input"; -import { Textarea } from "./ui/textarea"; -import { Button } from "./ui/button"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "./ui/select"; -import { Checkbox } from "./ui/checkbox"; +import React, { useState } from 'react'; +import { CalendarIcon, Send, Clock, MapPin } from 'lucide-react'; +import { z } from 'zod'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +// Form Schema with more robust validation const formSchema = z.object({ - name: z.string().min(2, { message: "Nome deve ter pelo menos 2 caracteres" }), - email: z.string().email({ message: "Email inválido" }), - phone: z.string().min(10, { message: "Telefone inválido" }), - serviceType: z.string({ - required_error: "Selecione um tipo de serviço", + name: z.string().trim().min(2, { message: "Nome deve ter pelo menos 2 caracteres" }), + email: z.string().trim().email({ message: "Email inválido" }), + phone: z.string() + .trim() + .regex(/^\(\d{2}\)\s*\d{4,5}-\d{4}$/, { message: "Telefone inválido. Use (00) 00000-0000" }), + serviceType: z.enum([ + 'consultation', + 'small', + 'medium', + 'large', + 'coverup', + 'custom' + ], { + errorMap: () => ({ message: "Selecione um tipo de serviço" }) }), preferredDate: z.string().optional(), preferredTime: z.string().optional(), - acceptTerms: z.boolean().refine((val) => val === true, { - message: "Você precisa aceitar os termos para continuar", - }), - message: z.string().optional(), + message: z.string().max(500, { message: "Mensagem muito longa" }).optional(), + acceptTerms: z.boolean().refine(val => val, { + message: "Você precisa aceitar os termos para continuar" + }) }); -interface AppointmentSectionProps { - title?: string; - subtitle?: string; - backgroundImage?: string; -} +// Centralized service type options +const SERVICE_TYPES = [ + { value: 'consultation', label: 'Consulta Inicial' }, + { value: 'small', label: 'Tatuagem Pequena' }, + { value: 'medium', label: 'Tatuagem Média' }, + { value: 'large', label: 'Tatuagem Grande' }, + { value: 'coverup', label: 'Cobertura' }, + { value: 'custom', label: 'Projeto Personalizado' } +]; const AppointmentSection = ({ title = "Agende sua Consulta", subtitle = "Dê o primeiro passo para transformar sua ideia em arte. Nossa equipe entrará em contato em até 24 horas.", - backgroundImage = "https://images.unsplash.com/photo-1585681614545-cd8c7b9d92b3?q=80&w=2070&auto=format&fit=crop", -}: AppointmentSectionProps) => { - const form = useForm>({ + backgroundImage = "/hero/hero.jpg" +}) => { + const [isSubmitting, setIsSubmitting] = useState(false); + + const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { name: "", @@ -60,275 +55,210 @@ const AppointmentSection = ({ serviceType: "", preferredDate: "", preferredTime: "", - acceptTerms: false, message: "", - }, + acceptTerms: false + } }); - function onSubmit(values: z.infer) { - // In a real implementation, this would send the form data to a server - console.log(values); - alert("Formulário enviado com sucesso! Entraremos em contato em breve."); - form.reset(); - } + const onSubmit = async (values) => { + setIsSubmitting(true); + try { + // Simulated async submission + await new Promise(resolve => setTimeout(resolve, 1500)); + console.log(values); + form.reset(); + alert("Formulário enviado com sucesso! Entraremos em contato em breve."); + } catch (error) { + alert("Erro ao enviar formulário. Tente novamente."); + } finally { + setIsSubmitting(false); + } + }; + + // Reusable feature item component + const FeatureItem = ({ icon: Icon, title, description }) => ( +
+
+ +
+
+

{title}

+

{description}

+
+
+ ); + + const FormInput = ({ id, label, type = "text", error, ...props }) => ( +
+ + + {error && ( +

{error.message}

+ )} +
+ ); return ( -
- {/* Background Image with Overlay */} +
+ {/* Background with Overlay */}
-
+
Tattoo studio background
{/* Content Container */} -
+
{/* Text Content */} -
-

{title}

-

{subtitle}

-
-
-
- -
-
-

Horário Flexível

-

- Atendemos de segunda a sábado, das 10h às 20h -

-
-
-
-
- -
-
-

Consulta Gratuita

-

- Primeira consulta sem compromisso para discutir seu projeto -

-
-
-
-
- -
-
-

Localização Central

-

- Estúdio localizado no centro da cidade, fácil acesso -

-
-
+
+
+ Estúdio de Arte Corporal +
+

{title}

+

{subtitle}

+
+ + +
{/* Form */} -
-
- - ( - - Nome - - - - - - )} +
+ + + +
+ -
- ( - - Email - - - - - - )} - /> - ( - - Telefone - - - - - - )} - /> -
- ( - - - Tipo de Serviço - - - - - )} + + -
- ( - - - Data Preferida - - - - - - - )} - /> - ( - - - Horário Preferido - - - - - )} - /> -
- ( - - - Mensagem (opcional) - - -