feat(contact): enhance form submission and improve user experience
- Updated the Contact component to include a WhatsApp integration for project requests, streamlining communication. - Improved form handling with clearer placeholder text and refined emoji-based message templates for better user engagement. - Adjusted submission delay for a more responsive user experience and enhanced button labeling for clarity.
This commit is contained in:
1 parent
b58c5dabbc
commit
dfae6bae2f
1 file changed
+50
-48
+50
-48
@@ -1,12 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { motion } from "framer-motion"; // Ajustado para o padrão mais estável
|
import { motion } from "framer-motion";
|
||||||
import { Send, User, Mail, MessageSquare, Sparkles } from "lucide-react";
|
import { Send, User, Mail, MessageSquare, Sparkles } from "lucide-react";
|
||||||
// Importamos o componente original.
|
|
||||||
// Nota: Se o erro de tipo persistir, corrigiremos a interface aqui no wrapper.
|
|
||||||
import { ShimmerButton as MagicShimmerButton } from "@/components/magicui/shimmer-button";
|
import { ShimmerButton as MagicShimmerButton } from "@/components/magicui/shimmer-button";
|
||||||
|
|
||||||
|
// --- CONFIGURAÇÃO DE ENGENHARIA ---
|
||||||
|
// Substitua pelo seu número real: CódigoPaís + DDD + Número (sem espaços ou símbolos)
|
||||||
|
const WHATSAPP_NUMBER = "5547992742365";
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -15,15 +17,12 @@ interface FormData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper Component para corrigir o erro de tipagem TS2322
|
* Wrapper Component: Resolve o erro de tipagem TS2322 (IntrinsicAttributes)
|
||||||
* Aqui garantimos que o componente aceite as cores e tamanhos
|
* Estendemos a interface para aceitar propriedades de estilo customizadas.
|
||||||
*/
|
*/
|
||||||
interface ExtendedShimmerProps {
|
interface ExtendedShimmerProps extends React.ComponentProps<typeof MagicShimmerButton> {
|
||||||
children: React.ReactNode;
|
|
||||||
className?: string;
|
|
||||||
shimmerColor?: string;
|
shimmerColor?: string;
|
||||||
shimmerSize?: string;
|
shimmerSize?: string;
|
||||||
onClick?: () => void;
|
|
||||||
type?: "button" | "submit" | "reset";
|
type?: "button" | "submit" | "reset";
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
@@ -39,9 +38,7 @@ const CustomShimmerButton = ({
|
|||||||
<MagicShimmerButton
|
<MagicShimmerButton
|
||||||
{...props}
|
{...props}
|
||||||
className={className}
|
className={className}
|
||||||
// Passamos como variáveis CSS se o componente original suportar,
|
// @ts-ignore - Ignora restrição de tipos da lib original se necessário
|
||||||
// ou apenas omitimos se o componente da MagicUI for estático.
|
|
||||||
// @ts-ignore - Ignoramos se a lib original tiver tipos restritos
|
|
||||||
shimmerColor={shimmerColor}
|
shimmerColor={shimmerColor}
|
||||||
shimmerSize={shimmerSize}
|
shimmerSize={shimmerSize}
|
||||||
>
|
>
|
||||||
@@ -63,10 +60,36 @@ export default function Contact() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
|
|
||||||
// Simulação de latência de rede (Princípio de UX Feedback)
|
await new Promise((resolve) => setTimeout(resolve, 800));
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
||||||
|
|
||||||
console.log("Payload de Engenharia enviado:", formData);
|
// Definimos os emojis via Unicode Escape para máxima compatibilidade
|
||||||
|
const icons = {
|
||||||
|
rocket: "\u{1F680}",
|
||||||
|
person: "\u{1F464}",
|
||||||
|
email: "\u{1F4E7}",
|
||||||
|
tools: "\u{1F6E0}",
|
||||||
|
chat: "\u{1F4AC}"
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageTemplate = `${icons.rocket} *NOVA REQUISICAO DE PROJETO*
|
||||||
|
|
||||||
|
*Origem:* Portfolio Profissional
|
||||||
|
*Prioridade:* Alta (Lead Qualificado)
|
||||||
|
|
||||||
|
---
|
||||||
|
${icons.person} *CLIENTE:* ${formData.name}
|
||||||
|
${icons.email} *EMAIL:* ${formData.email}
|
||||||
|
${icons.tools} *AREA:* ${formData.subject.toUpperCase()}
|
||||||
|
|
||||||
|
${icons.chat} *DESCRICAO:*
|
||||||
|
"${formData.message}"
|
||||||
|
---
|
||||||
|
_Mensagem gerada via Evandro.dev | Garuva, SC_`;
|
||||||
|
|
||||||
|
const encodedMessage = encodeURIComponent(messageTemplate);
|
||||||
|
const whatsappUrl = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodedMessage}`;
|
||||||
|
|
||||||
|
window.open(whatsappUrl, "_blank", "noopener,noreferrer");
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,7 +102,6 @@ export default function Contact() {
|
|||||||
<section id="contact" className="w-full max-w-2xl mx-auto p-6">
|
<section id="contact" className="w-full max-w-2xl mx-auto p-6">
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
<div className="grid md:grid-cols-2 gap-6">
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
{/* Nome */}
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className={labelStyles}>
|
<label className={labelStyles}>
|
||||||
<User className="w-3 h-3" /> Nome_Completo
|
<User className="w-3 h-3" /> Nome_Completo
|
||||||
@@ -87,16 +109,13 @@ export default function Contact() {
|
|||||||
<input
|
<input
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Digite seu nome"
|
placeholder="Ex: Alan Turing"
|
||||||
className={inputStyles}
|
className={inputStyles}
|
||||||
value={formData.name}
|
value={formData.name}
|
||||||
onChange={(e) =>
|
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||||
setFormData({ ...formData, name: e.target.value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Email */}
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className={labelStyles}>
|
<label className={labelStyles}>
|
||||||
<Mail className="w-3 h-3" /> Endpoint_Email
|
<Mail className="w-3 h-3" /> Endpoint_Email
|
||||||
@@ -104,17 +123,14 @@ export default function Contact() {
|
|||||||
<input
|
<input
|
||||||
required
|
required
|
||||||
type="email"
|
type="email"
|
||||||
placeholder="seuemail@gmail.com"
|
placeholder="contato@empresa.com"
|
||||||
className={inputStyles}
|
className={inputStyles}
|
||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={(e) =>
|
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||||
setFormData({ ...formData, email: e.target.value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tipo de Requisição */}
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className={labelStyles}>
|
<label className={labelStyles}>
|
||||||
<Sparkles className="w-3 h-3" /> Tipo_de_Requisicao
|
<Sparkles className="w-3 h-3" /> Tipo_de_Requisicao
|
||||||
@@ -122,18 +138,15 @@ export default function Contact() {
|
|||||||
<select
|
<select
|
||||||
className={inputStyles}
|
className={inputStyles}
|
||||||
value={formData.subject}
|
value={formData.subject}
|
||||||
onChange={(e) =>
|
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
|
||||||
setFormData({ ...formData, subject: e.target.value })
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<option value="full-stack">Desenvolvimento Full-Stack</option>
|
<option value="full-stack">Desenvolvimento Full-Stack</option>
|
||||||
<option value="cloud">Cloud & Infrastructure</option>
|
<option value="cloud">Cloud & Infrastructure</option>
|
||||||
<option value="iot">Internet of Things (IoT)</option>
|
<option value="iot">Internet of Things (IoT)</option>
|
||||||
<option value="consultancy">Consultoria Técnica</option>
|
<option value="consultancy">Consultoria Técnica Sênior</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Mensagem */}
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className={labelStyles}>
|
<label className={labelStyles}>
|
||||||
<MessageSquare className="w-3 h-3" /> Descricao_do_Projeto
|
<MessageSquare className="w-3 h-3" /> Descricao_do_Projeto
|
||||||
@@ -141,21 +154,14 @@ export default function Contact() {
|
|||||||
<textarea
|
<textarea
|
||||||
required
|
required
|
||||||
rows={5}
|
rows={5}
|
||||||
placeholder="Descreva os requisitos técnicos e objetivos do seu sistema..."
|
placeholder="Descreva os requisitos técnicos e objetivos do sistema..."
|
||||||
className={`${inputStyles} resize-none`}
|
className={`${inputStyles} resize-none`}
|
||||||
value={formData.message}
|
value={formData.message}
|
||||||
onChange={(e) =>
|
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||||||
setFormData({ ...formData, message: e.target.value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Botão de Submissão */}
|
<motion.div whileHover={{ scale: 1.01 }} whileTap={{ scale: 0.99 }} className="pt-4">
|
||||||
<motion.div
|
|
||||||
whileHover={{ scale: 1.01 }}
|
|
||||||
whileTap={{ scale: 0.99 }}
|
|
||||||
className="pt-4"
|
|
||||||
>
|
|
||||||
<CustomShimmerButton
|
<CustomShimmerButton
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full h-14 rounded-xl shadow-2xl"
|
className="w-full h-14 rounded-xl shadow-2xl"
|
||||||
@@ -163,17 +169,13 @@ export default function Contact() {
|
|||||||
shimmerSize="0.2em"
|
shimmerSize="0.2em"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
>
|
>
|
||||||
{/* CONTAINER INTERNO (FAIL-SAFE):
|
|
||||||
Forçamos um novo contexto flex-row aqui.
|
|
||||||
O 'w-full' e 'h-full' garantem que ele ocupe todo o botão.
|
|
||||||
*/}
|
|
||||||
<div className="flex flex-row items-center justify-center gap-3 w-full h-full">
|
<div className="flex flex-row items-center justify-center gap-3 w-full h-full">
|
||||||
{isSubmitting ? (
|
{isSubmitting ? (
|
||||||
<div className="w-6 h-6 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
<div className="w-6 h-6 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span className="text-white font-bold tracking-widest uppercase text-sm leading-none">
|
<span className="text-white font-bold tracking-widest uppercase text-sm leading-none">
|
||||||
Enviar request
|
Executar Request
|
||||||
</span>
|
</span>
|
||||||
<Send className="w-4 h-4 text-white" />
|
<Send className="w-4 h-4 text-white" />
|
||||||
</>
|
</>
|
||||||
@@ -184,10 +186,10 @@ export default function Contact() {
|
|||||||
|
|
||||||
<footer className="pt-4">
|
<footer className="pt-4">
|
||||||
<p className="text-[10px] text-center text-slate-600 font-mono uppercase tracking-tighter">
|
<p className="text-[10px] text-center text-slate-600 font-mono uppercase tracking-tighter">
|
||||||
Qualidade ponta-ponta garantida | Garuva, SC
|
Engenharia de Software de Alta Performance | Garuva, SC
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user