912 lines
35 KiB
TypeScript
912 lines
35 KiB
TypeScript
"use client";
|
||
|
||
import { useState, ChangeEvent, FormEvent, useEffect } from "react";
|
||
import { usePortfolioData } from "@/lib/usePortfolioData";
|
||
import { buildWhatsAppUrl } from "@/lib/whatsapp";
|
||
import { motion } from "motion/react";
|
||
|
||
interface ContactFormProps {
|
||
formType: "simple" | "advanced";
|
||
setFormType: (type: "simple" | "advanced") => void;
|
||
}
|
||
|
||
export function ContactForm({ formType, setFormType }: ContactFormProps) {
|
||
const { data } = usePortfolioData();
|
||
const [contactMethod, setContactMethod] = useState<"whatsapp" | "email">(
|
||
"whatsapp",
|
||
);
|
||
|
||
// MENTORIA: Agrupamento de estado para reduzir complexidade e re-renders
|
||
const [formData, setFormData] = useState({
|
||
userName: "",
|
||
userEmail: "",
|
||
userPhone: "",
|
||
userCompany: "",
|
||
howFound: "",
|
||
projectType: "",
|
||
otherProjectType: "",
|
||
desiredDeadline: "",
|
||
budgetValue: "",
|
||
technicalComplexity: "",
|
||
hasInternalTeam: "",
|
||
customMessage: "",
|
||
});
|
||
|
||
const [isDecisor, setIsDecisor] = useState<string>("");
|
||
const [projectApproved, setProjectApproved] = useState<string>("");
|
||
const [urgency, setUrgency] = useState<string>("");
|
||
const [preferredModality, setPreferredModality] = useState<string>("");
|
||
const [isExpanded, setIsExpanded] = useState<boolean>(false); // Novo estado para controlar a expansão do formulário avançado
|
||
const [nameError, setNameError] = useState<string | null>(null);
|
||
const [emailError, setEmailError] = useState<string | null>(null);
|
||
const [phoneError, setPhoneError] = useState<string | null>(null);
|
||
const [otherProjectTypeError, setOtherProjectTypeError] = useState<
|
||
string | null
|
||
>(null); // Novo estado de erro
|
||
const [honeypot, setHoneypot] = useState<string>(""); // Estado para o campo honeypot
|
||
const [startTime, setStartTime] = useState<number>(0); // Estado para o tempo de início do formulário
|
||
const [nameFocused, setNameFocused] = useState<boolean>(false);
|
||
const [emailFocused, setEmailFocused] = useState<boolean>(false);
|
||
const [phoneFocused, setPhoneFocused] = useState<boolean>(false);
|
||
|
||
useEffect(() => {
|
||
setStartTime(Date.now()); // Registra o tempo de carregamento do componente
|
||
}, []);
|
||
|
||
if (!data) {
|
||
return null; // Ou um componente de carregamento/erro
|
||
}
|
||
|
||
const getGreetingMessageWithUserName = () => {
|
||
const hour = new Date().getHours();
|
||
const dayPart =
|
||
hour >= 8 && hour < 12
|
||
? "manhã"
|
||
: hour >= 12 && hour < 18
|
||
? "tarde"
|
||
: "noite";
|
||
|
||
return `Olá Evandro, espero que esta ${dayPart} esteja sendo produtiva.
|
||
|
||
Meu nome é ${formData.userName} e entrei em contato pois vi seu portfólio e identifiquei que suas habilidades como Desenvolvedor Full-Stack podem agregar muito ao projeto que tenho em mente.
|
||
|
||
Gostaria de agendar uma conversa para discutirmos detalhes e entender como podemos trabalhar juntos de forma eficiente e produtiva.
|
||
|
||
Fico no aguardo do seu contato para marcarmos um horário que seja conveniente para ambos.
|
||
|
||
Atenciosamente,
|
||
${formData.userName}`;
|
||
};
|
||
|
||
const generateAdvancedMessage = () => {
|
||
if (formData.customMessage) return formData.customMessage;
|
||
|
||
// Saudação profissional
|
||
let message = `Prezado Evandro,\n\n`;
|
||
|
||
// Informações do contato
|
||
message += `Meu nome é ${formData.userName}`;
|
||
if (formData.userCompany) {
|
||
message += `, represento a empresa ${formData.userCompany}`;
|
||
}
|
||
message += `.\n`;
|
||
|
||
if (formData.howFound) {
|
||
message += `Conheci seu trabalho através de ${formData.howFound}.\n`;
|
||
}
|
||
|
||
message += `\n`;
|
||
|
||
// Detalhes do projeto
|
||
message += `=== DETALHES DO PROJETO ===\n`;
|
||
message += `Tipo de projeto: `;
|
||
if (formData.projectType === "outro" && formData.otherProjectType) {
|
||
message += `${formData.otherProjectType}\n`;
|
||
} else if (formData.projectType) {
|
||
message += `${formData.projectType}\n`;
|
||
} else {
|
||
message += `Não especificado\n`;
|
||
}
|
||
|
||
if (formData.desiredDeadline) {
|
||
message += `Prazo desejado: ${formData.desiredDeadline}\n`;
|
||
}
|
||
|
||
if (formData.budgetValue) {
|
||
message += `Orçamento disponível: ${formData.budgetValue}\n`;
|
||
}
|
||
|
||
if (formData.technicalComplexity) {
|
||
message += `Complexidade técnica estimada: ${formData.technicalComplexity}\n`;
|
||
}
|
||
|
||
if (formData.hasInternalTeam) {
|
||
message += `Equipe técnica interna: ${
|
||
formData.hasInternalTeam === "sim"
|
||
? "Sim"
|
||
: formData.hasInternalTeam === "nao"
|
||
? "Não"
|
||
: "Parcialmente"
|
||
}\n`;
|
||
}
|
||
|
||
message += `\n`;
|
||
|
||
// Contatos
|
||
message += `=== INFORMAÇÕES PARA CONTATO ===\n`;
|
||
if (formData.userEmail) {
|
||
message += `📧 Email: ${formData.userEmail}\n`;
|
||
}
|
||
if (formData.userPhone) {
|
||
message += `📱 Telefone/WhatsApp: ${formData.userPhone}\n`;
|
||
}
|
||
|
||
message += `\n`;
|
||
|
||
// Mensagem final
|
||
message += `Estou entrando em contato pois acredito que seus conhecimentos como Desenvolvedor Full-Stack podem agregar muito ao projeto que tenho em mente.\n\n`;
|
||
message += `Fico no aguardo do seu contato para discutirmos detalhes e definirmos os próximos passos.\n\n`;
|
||
message += `Atenciosamente,\n`;
|
||
message += `${formData.userName}`;
|
||
|
||
return message;
|
||
};
|
||
|
||
const handleInputChange =
|
||
(field: keyof typeof formData) =>
|
||
(
|
||
e: ChangeEvent<
|
||
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
|
||
>,
|
||
) => {
|
||
setFormData((prev) => ({ ...prev, [field]: e.target.value }));
|
||
|
||
// Clear specific errors if the user starts typing
|
||
if (e.target.value.trim() !== "") {
|
||
if (field === "userName") setNameError(null);
|
||
if (field === "userEmail") setEmailError(null);
|
||
if (field === "userPhone") setPhoneError(null);
|
||
if (field === "otherProjectType") setOtherProjectTypeError(null);
|
||
}
|
||
};
|
||
|
||
const handleNameFocus = () => setNameFocused(true);
|
||
const handleEmailFocus = () => setEmailFocused(true);
|
||
const handlePhoneFocus = () => setPhoneFocused(true);
|
||
|
||
const generateWhatsAppUrl = () =>
|
||
buildWhatsAppUrl(
|
||
formType === "advanced"
|
||
? generateAdvancedMessage()
|
||
: formData.customMessage || getGreetingMessageWithUserName(),
|
||
);
|
||
|
||
const generateEmailUrl = () => {
|
||
const subject = encodeURIComponent("Proposta de Projeto - Portfólio");
|
||
const body = encodeURIComponent(
|
||
formType === "advanced"
|
||
? generateAdvancedMessage()
|
||
: `Nome: ${formData.userName}\nEmail: ${formData.userEmail}\nTelefone: ${formData.userPhone}\nEmpresa/Posição: ${formData.userCompany}\nComo conheceu: ${formData.howFound}\n\nTipo de Projeto: ${formData.projectType}\nPrazo Desejado: ${formData.desiredDeadline}\nOrçamento Disponível: ${formData.budgetValue}\nComplexidade Técnica: ${formData.technicalComplexity}\nTem equipe interna: ${formData.hasInternalTeam}\n\nMensagem: ${
|
||
formData.customMessage || getGreetingMessageWithUserName()
|
||
}`,
|
||
);
|
||
return `mailto:${data.contact.email}?subject=${subject}&body=${body}`;
|
||
};
|
||
|
||
const handleSubmit = (e: FormEvent) => {
|
||
e.preventDefault();
|
||
|
||
let hasError = false;
|
||
if (formData.userName.trim() === "") {
|
||
setNameError("Por favor, insira seu nome.");
|
||
hasError = true;
|
||
} else {
|
||
setNameError(null);
|
||
}
|
||
|
||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
if (!emailRegex.test(formData.userEmail)) {
|
||
setEmailError("Por favor, insira um email válido.");
|
||
hasError = true;
|
||
} else {
|
||
setEmailError(null);
|
||
}
|
||
|
||
if (formData.userPhone.trim() === "") {
|
||
setPhoneError("Por favor, insira seu telefone.");
|
||
hasError = true;
|
||
} else {
|
||
setPhoneError(null);
|
||
}
|
||
|
||
if (
|
||
formData.projectType === "outro" &&
|
||
formData.otherProjectType.trim() === ""
|
||
) {
|
||
setOtherProjectTypeError("Por favor, especifique o tipo de projeto.");
|
||
hasError = true;
|
||
} else {
|
||
setOtherProjectTypeError(null);
|
||
}
|
||
|
||
// Validação Honeypot
|
||
if (honeypot) {
|
||
console.log("Honeypot preenchido, provável bot.");
|
||
return; // Ignora a submissão
|
||
}
|
||
|
||
// UX FIX: Validação de tempo com feedback ou limite menor
|
||
const timeElapsed = Date.now() - startTime;
|
||
// Reduzido para 1000ms para evitar falsos positivos com autofill
|
||
if (timeElapsed < 1000) {
|
||
console.log("Formulário preenchido muito rápido, provável bot.");
|
||
// Opcional: Mostrar erro para humano real que digita muito rápido
|
||
// alert("Por favor, verifique os dados antes de enviar.");
|
||
return; // Ignora a submissão
|
||
}
|
||
|
||
if (hasError) return;
|
||
|
||
// Verificação de interação mínima
|
||
if (!nameFocused || !emailFocused || !phoneFocused) {
|
||
// MENTORIA: Isso pode bloquear usuários de Screen Readers ou Autofill agressivo.
|
||
// Considere remover ou tornar apenas um aviso no console.
|
||
console.warn(
|
||
"Campos principais não foram focados, verificando integridade.",
|
||
);
|
||
}
|
||
|
||
if (contactMethod === "whatsapp") {
|
||
window.open(generateWhatsAppUrl(), "_blank");
|
||
} else {
|
||
window.open(generateEmailUrl(), "_blank");
|
||
}
|
||
};
|
||
|
||
const getCtaMessage = () => {
|
||
if (formData.projectType === "consultoria") {
|
||
return "Agendar Consultoria Gratuita";
|
||
}
|
||
if (
|
||
formData.budgetValue &&
|
||
parseFloat(formData.budgetValue.replace(/\D/g, "")) < 2000
|
||
) {
|
||
return "Discutir Soluções de Baixo Custo";
|
||
}
|
||
if (
|
||
formData.projectType &&
|
||
formData.desiredDeadline &&
|
||
formData.budgetValue
|
||
) {
|
||
return "Receber Proposta Personalizada";
|
||
}
|
||
return "Enviar Formulário";
|
||
};
|
||
|
||
const getEstimatedValue = () => {
|
||
let hours = 0;
|
||
let hourlyRate = 55; // Taxa base R$ 55/h
|
||
|
||
// Estimativa de horas baseada no tipo de projeto
|
||
switch (formData.projectType) {
|
||
case "web-app":
|
||
hours += 80; // Aplicação web completa
|
||
break;
|
||
case "landing-page":
|
||
hours += 16; // Landing page simples
|
||
break;
|
||
case "mvp":
|
||
hours += 40; // MVP básico
|
||
break;
|
||
case "iot-app":
|
||
hours += 120; // Aplicação IoT complexa
|
||
break;
|
||
case "integracao":
|
||
hours += 32; // Integração de sistemas
|
||
break;
|
||
case "manutencao":
|
||
hours += 8; // Manutenção pontual
|
||
break;
|
||
case "consultoria":
|
||
hours += 4; // Consultoria inicial
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// Ajuste de horas baseado no prazo
|
||
switch (formData.desiredDeadline) {
|
||
case "1-3-weeks":
|
||
hours *= 1.3; // Urgência aumenta horas
|
||
break;
|
||
case "1-2-months":
|
||
hours *= 1.1;
|
||
break;
|
||
case "6-plus-months":
|
||
hours *= 0.9; // Prazo longo pode reduzir horas
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// Ajuste de horas baseado na complexidade
|
||
switch (formData.technicalComplexity) {
|
||
case "alta":
|
||
hours *= 1.4;
|
||
hourlyRate = 65; // Taxa maior para alta complexidade
|
||
break;
|
||
case "muito-alta":
|
||
hours *= 1.7;
|
||
hourlyRate = 70; // Taxa máxima para muito alta complexidade
|
||
break;
|
||
case "media":
|
||
hourlyRate = 50; // Taxa média
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (formData.hasInternalTeam === "nao") {
|
||
hours *= 1.2; // Sem equipe interna = mais horas necessárias
|
||
}
|
||
|
||
const totalValue = hours * hourlyRate;
|
||
|
||
if (totalValue > 0) {
|
||
return `Estimativa: ${Math.round(
|
||
hours,
|
||
)}h × R$ ${hourlyRate}/h = R$ ${totalValue.toFixed(0)}`;
|
||
}
|
||
|
||
return "Estimativa: Solicite orçamento personalizado";
|
||
};
|
||
|
||
return (
|
||
<motion.div
|
||
initial={{ opacity: 0, x: 30 }}
|
||
whileInView={{ opacity: 1, x: 0 }}
|
||
transition={{ duration: 0.8, delay: 0.4 }}
|
||
viewport={{ once: true }}
|
||
className="space-y-4"
|
||
>
|
||
<h3 className="text-2xl font-semibold mb-6 bg-gradient-to-r from-cyan-400 to-blue-500 bg-clip-text text-transparent">
|
||
Preencha o Formulário
|
||
</h3>
|
||
|
||
<div className="flex justify-center gap-4 mb-8">
|
||
<button
|
||
type="button"
|
||
onClick={() => setFormType("simple")}
|
||
className={`py-2 px-4 rounded-lg font-semibold transition-all duration-300 ${
|
||
formType === "simple"
|
||
? "bg-gradient-to-r from-cyan-500 to-blue-600 text-white shadow-lg shadow-cyan-500/25 border-2 border-cyan-500"
|
||
: "bg-gray-700 text-gray-300 hover:bg-gray-600 cursor-pointer"
|
||
}`}
|
||
>
|
||
Formulário Simples
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => setFormType("advanced")}
|
||
className={`py-2 px-4 rounded-lg font-semibold transition-all duration-300 ${
|
||
formType === "advanced"
|
||
? "bg-gradient-to-r from-cyan-500 to-blue-600 text-white shadow-lg shadow-cyan-500/25 border-2 border-cyan-500"
|
||
: "bg-gray-700 text-gray-300 hover:bg-gray-600 cursor-pointer"
|
||
}`}
|
||
>
|
||
Formulário Avançado
|
||
</button>
|
||
</div>
|
||
|
||
{formType === "simple" ? (
|
||
<form onSubmit={handleSubmit} className="space-y-6">
|
||
{/* Campo Honeypot */}
|
||
<div style={{ display: "none" }}>
|
||
<label htmlFor="honeypot">Não preencha este campo</label>
|
||
<input
|
||
type="text"
|
||
id="honeypot"
|
||
name="honeypot"
|
||
value={honeypot}
|
||
onChange={(e) => setHoneypot(e.target.value)}
|
||
/>
|
||
</div>
|
||
|
||
{/* Formulário Simples: Apenas Nome */}
|
||
<div>
|
||
<label
|
||
htmlFor="simple-user-name"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Seu Nome:
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="simple-user-name"
|
||
className={`w-full p-3 rounded-lg bg-white/5 border ${
|
||
nameError ? "border-red-500" : "border-white/10"
|
||
} text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent`}
|
||
placeholder="Seu nome"
|
||
value={formData.userName}
|
||
onChange={handleInputChange("userName")}
|
||
onFocus={handleNameFocus}
|
||
required
|
||
/>
|
||
{nameError && (
|
||
<p className="text-red-400 text-xs mt-1">{nameError}</p>
|
||
)}
|
||
</div>
|
||
|
||
{/* Botão de Contato para o formulário simples */}
|
||
<motion.div whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }}>
|
||
<button
|
||
type="submit"
|
||
className="w-full py-4 px-6 rounded-lg font-semibold text-lg transition-all duration-300 bg-green-600 hover:bg-green-700 text-white shadow-lg shadow-green-600/25"
|
||
onClick={() => window.open(generateWhatsAppUrl(), "_blank")}
|
||
>
|
||
Enviar Mensagem via WhatsApp
|
||
</button>
|
||
</motion.div>
|
||
</form>
|
||
) : (
|
||
<form onSubmit={handleSubmit} className="space-y-6">
|
||
{/* Campo Honeypot */}
|
||
<div style={{ display: "none" }}>
|
||
<label htmlFor="honeypot">Não preencha este campo</label>
|
||
<input
|
||
type="text"
|
||
id="honeypot"
|
||
name="honeypot"
|
||
value={honeypot}
|
||
onChange={(e) => setHoneypot(e.target.value)}
|
||
/>
|
||
</div>
|
||
|
||
{/* Dados Básicos */}
|
||
<div>
|
||
<h4 className="text-xl font-semibold mb-4 text-gray-200">
|
||
Dados Básicos
|
||
</h4>
|
||
<div className="space-y-4">
|
||
<div>
|
||
<label
|
||
htmlFor="user-name"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Nome Completo:
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="user-name"
|
||
className={`w-full p-3 rounded-lg bg-white/5 border ${
|
||
nameError ? "border-red-500" : "border-white/10"
|
||
} text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent`}
|
||
placeholder="Seu nome completo"
|
||
value={formData.userName}
|
||
onChange={handleInputChange("userName")}
|
||
onFocus={handleNameFocus}
|
||
required
|
||
/>
|
||
{nameError && (
|
||
<p className="text-red-400 text-xs mt-1">{nameError}</p>
|
||
)}
|
||
</div>
|
||
<div>
|
||
<label
|
||
htmlFor="user-email"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Email Corporativo:
|
||
</label>
|
||
<input
|
||
type="email"
|
||
id="user-email"
|
||
className={`w-full p-3 rounded-lg bg-white/5 border ${
|
||
emailError ? "border-red-500" : "border-white/10"
|
||
} text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent`}
|
||
placeholder="[email protected]"
|
||
value={formData.userEmail}
|
||
onChange={handleInputChange("userEmail")}
|
||
onFocus={handleEmailFocus}
|
||
required
|
||
/>
|
||
{emailError && (
|
||
<p className="text-red-400 text-xs mt-1">{emailError}</p>
|
||
)}
|
||
</div>
|
||
<div>
|
||
<label
|
||
htmlFor="user-phone"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
WhatsApp/Telefone:
|
||
</label>
|
||
<input
|
||
type="tel"
|
||
id="user-phone"
|
||
className={`w-full p-3 rounded-lg bg-white/5 border ${
|
||
phoneError ? "border-red-500" : "border-white/10"
|
||
} text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent`}
|
||
placeholder="(XX) XXXXX-XXXX"
|
||
value={formData.userPhone}
|
||
onChange={handleInputChange("userPhone")}
|
||
onFocus={handlePhoneFocus}
|
||
required
|
||
/>
|
||
{phoneError && (
|
||
<p className="text-red-400 text-xs mt-1">{phoneError}</p>
|
||
)}
|
||
</div>
|
||
<div>
|
||
<label
|
||
htmlFor="user-company"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Empresa/Posição:
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="user-company"
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent"
|
||
placeholder="Nome da empresa, sua posição"
|
||
value={formData.userCompany}
|
||
onChange={handleInputChange("userCompany")}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label
|
||
htmlFor="how-found"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Como conheceu meu trabalho?
|
||
</label>
|
||
<select
|
||
id="how-found"
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white focus:ring-2 focus:ring-cyan-500 focus:border-transparent appearance-none"
|
||
style={{
|
||
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e")`,
|
||
backgroundPosition: "right 12px center",
|
||
backgroundRepeat: "no-repeat",
|
||
backgroundSize: "16px",
|
||
}}
|
||
value={formData.howFound}
|
||
onChange={handleInputChange("howFound")}
|
||
>
|
||
{" "}
|
||
<option value="" className="bg-gray-800 text-white">
|
||
Selecione uma opção
|
||
</option>
|
||
<option value="linkedin" className="bg-gray-800 text-white">
|
||
LinkedIn
|
||
</option>
|
||
<option value="github" className="bg-gray-800 text-white">
|
||
GitHub
|
||
</option>
|
||
<option value="indicacao" className="bg-gray-800 text-white">
|
||
Indicação
|
||
</option>
|
||
<option value="pesquisa" className="bg-gray-800 text-white">
|
||
Pesquisa Online
|
||
</option>
|
||
<option value="outro" className="bg-gray-800 text-white">
|
||
Outro
|
||
</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Tile de Expandir/Recolher */}
|
||
<div
|
||
onClick={() => setIsExpanded(!isExpanded)}
|
||
className="p-4 rounded-lg bg-white/5 border border-white/10 text-white cursor-pointer hover:bg-white/10 transition-colors duration-300 mb-6 flex justify-between items-center"
|
||
>
|
||
<h4 className="text-xl font-semibold text-gray-200">
|
||
{isExpanded
|
||
? "Detalhes do Projeto (Recolher)"
|
||
: "Detalhes do Projeto (Expandir)"}
|
||
</h4>
|
||
<svg
|
||
className={`w-6 h-6 transition-transform duration-300 ${
|
||
isExpanded ? "rotate-180" : ""
|
||
}`}
|
||
fill="none"
|
||
stroke="currentColor"
|
||
viewBox="0 0 24 24"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
strokeWidth="2"
|
||
d="M19 9l-7 7-7-7"
|
||
></path>
|
||
</svg>
|
||
</div>
|
||
|
||
<div
|
||
className={`overflow-hidden transition-all duration-500 ease-in-out ${
|
||
isExpanded ? "max-h-[1000px] opacity-100" : "max-h-0 opacity-0"
|
||
} space-y-6`}
|
||
>
|
||
{/* Conteúdo do Formulário Avançado */}
|
||
{/* Sobre o Projeto */}
|
||
<div>
|
||
<h4 className="text-xl font-semibold mb-4 text-gray-200">
|
||
Sobre o Projeto
|
||
</h4>
|
||
<div className="space-y-4">
|
||
<div>
|
||
<label
|
||
htmlFor="project-type"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Tipo de Projeto:
|
||
</label>
|
||
<select
|
||
id="project-type"
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white focus:ring-2 focus:ring-cyan-500 focus:border-transparent appearance-none"
|
||
style={{
|
||
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e")`,
|
||
backgroundPosition: "right 12px center",
|
||
backgroundRepeat: "no-repeat",
|
||
backgroundSize: "16px",
|
||
}}
|
||
value={formData.projectType}
|
||
onChange={handleInputChange("projectType")}
|
||
>
|
||
<option value="" className="bg-gray-800 text-white">
|
||
Selecione o tipo
|
||
</option>
|
||
<option value="web-app" className="bg-gray-800 text-white">
|
||
Aplicação Web Completa
|
||
</option>
|
||
<option
|
||
value="landing-page"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
Landing Page
|
||
</option>
|
||
<option value="mvp" className="bg-gray-800 text-white">
|
||
MVP (Produto Mínimo Viável)
|
||
</option>
|
||
<option value="iot-app" className="bg-gray-800 text-white">
|
||
Aplicação IoT
|
||
</option>
|
||
<option
|
||
value="integracao"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
Integração de Sistemas
|
||
</option>
|
||
<option
|
||
value="manutencao"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
Manutenção/Ajustes
|
||
</option>
|
||
<option
|
||
value="consultoria"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
Consultoria/Mentoria
|
||
</option>
|
||
<option value="outro" className="bg-gray-800 text-white">
|
||
Outro
|
||
</option>
|
||
</select>
|
||
</div>
|
||
{formData.projectType === "outro" && (
|
||
<div>
|
||
<label
|
||
htmlFor="other-project-type"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Qual outro tipo de projeto?
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="other-project-type"
|
||
className={`w-full p-3 rounded-lg bg-white/5 border ${
|
||
otherProjectTypeError
|
||
? "border-red-500"
|
||
: "border-white/10"
|
||
} text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent`}
|
||
placeholder="Ex: Desenvolvimento de Plugin, Automação de Processos"
|
||
value={formData.otherProjectType}
|
||
onChange={handleInputChange("otherProjectType")}
|
||
required
|
||
/>
|
||
{otherProjectTypeError && (
|
||
<p className="text-red-400 text-xs mt-1">
|
||
{otherProjectTypeError}
|
||
</p>
|
||
)}
|
||
</div>
|
||
)}
|
||
<div>
|
||
<label
|
||
htmlFor="desired-deadline"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Prazo Desejado:
|
||
</label>
|
||
<select
|
||
id="desired-deadline"
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white focus:ring-2 focus:ring-cyan-500 focus:border-transparent appearance-none"
|
||
style={{
|
||
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e")`,
|
||
backgroundPosition: "right 12px center",
|
||
backgroundRepeat: "no-repeat",
|
||
backgroundSize: "16px",
|
||
}}
|
||
value={formData.desiredDeadline}
|
||
onChange={handleInputChange("desiredDeadline")}
|
||
>
|
||
<option value="" className="bg-gray-800 text-white">
|
||
Selecione o prazo
|
||
</option>
|
||
<option
|
||
value="1-3-weeks"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
1-3 Semanas
|
||
</option>
|
||
<option
|
||
value="1-2-months"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
1-2 Meses
|
||
</option>
|
||
<option
|
||
value="2-4-months"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
2-4 Meses
|
||
</option>
|
||
<option
|
||
value="4-6-months"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
4-6 Meses
|
||
</option>
|
||
<option
|
||
value="6-plus-months"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
Mais de 6 Meses
|
||
</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label
|
||
htmlFor="budget-value"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Orçamento Disponível (R$):
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="budget-value"
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent"
|
||
placeholder="Ex: 5000, 10000, A Combinar"
|
||
value={formData.budgetValue}
|
||
onChange={handleInputChange("budgetValue")}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label
|
||
htmlFor="technical-complexity"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Complexidade Técnica Estimada:
|
||
</label>
|
||
<select
|
||
id="technical-complexity"
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white focus:ring-2 focus:ring-cyan-500 focus:border-transparent appearance-none"
|
||
style={{
|
||
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e")`,
|
||
backgroundPosition: "right 12px center",
|
||
backgroundRepeat: "no-repeat",
|
||
backgroundSize: "16px",
|
||
}}
|
||
value={formData.technicalComplexity}
|
||
onChange={handleInputChange("technicalComplexity")}
|
||
>
|
||
<option value="" className="bg-gray-800 text-white">
|
||
Selecione a complexidade
|
||
</option>
|
||
<option value="baixa" className="bg-gray-800 text-white">
|
||
Baixa
|
||
</option>
|
||
<option value="media" className="bg-gray-800 text-white">
|
||
Média
|
||
</option>
|
||
<option value="alta" className="bg-gray-800 text-white">
|
||
Alta
|
||
</option>
|
||
<option
|
||
value="muito-alta"
|
||
className="bg-gray-800 text-white"
|
||
>
|
||
Muito Alta
|
||
</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label
|
||
htmlFor="has-internal-team"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Já tem equipe técnica interna?
|
||
</label>
|
||
<select
|
||
id="has-internal-team"
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white focus:ring-2 focus:ring-cyan-500 focus:border-transparent appearance-none"
|
||
style={{
|
||
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e")`,
|
||
backgroundPosition: "right 12px center",
|
||
backgroundRepeat: "no-repeat",
|
||
backgroundSize: "16px",
|
||
}}
|
||
value={formData.hasInternalTeam}
|
||
onChange={handleInputChange("hasInternalTeam")}
|
||
>
|
||
<option value="" className="bg-gray-800 text-white">
|
||
Selecione
|
||
</option>
|
||
<option value="sim" className="bg-gray-800 text-white">
|
||
Sim
|
||
</option>
|
||
<option value="nao" className="bg-gray-800 text-white">
|
||
Não
|
||
</option>
|
||
<option value="parcial" className="bg-gray-800 text-white">
|
||
Parcialmente
|
||
</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Custom Message Input */}
|
||
<div className="mb-6">
|
||
<label
|
||
htmlFor="custom-message"
|
||
className="block text-sm font-medium text-gray-300 mb-2"
|
||
>
|
||
Mensagem Adicional (Opcional):
|
||
</label>
|
||
<textarea
|
||
id="custom-message"
|
||
rows={4}
|
||
className="w-full p-3 rounded-lg bg-white/5 border border-white/10 text-white placeholder-gray-500 focus:ring-2 focus:ring-cyan-500 focus:border-transparent"
|
||
placeholder="Descreva seu projeto ou suas necessidades aqui..."
|
||
value={formData.customMessage}
|
||
onChange={handleInputChange("customMessage")}
|
||
></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Contact Button */}
|
||
<motion.div whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }}>
|
||
<button
|
||
type="submit"
|
||
className="w-full py-4 px-6 rounded-lg font-semibold text-lg transition-all duration-300 bg-gradient-to-r from-cyan-500 to-blue-600 hover:from-cyan-600 hover:to-blue-700 text-white shadow-lg shadow-cyan-500/25 border-2 border-cyan-500"
|
||
>
|
||
{getCtaMessage()}
|
||
</button>
|
||
</motion.div>
|
||
{formData.projectType &&
|
||
formData.desiredDeadline &&
|
||
formData.budgetValue && (
|
||
<p className="text-center text-lg font-semibold text-cyan-400 mt-4">
|
||
{getEstimatedValue()}
|
||
</p>
|
||
)}
|
||
</form>
|
||
)}
|
||
</motion.div>
|
||
);
|
||
}
|