feat: add animated components for enhanced UI/UX
- Introduced DrawLine component for drawing animations. - Added LazyRevealImage component for lazy loading images with reveal animations. - Implemented TextDiffuseReveal for animated text reveals with staggered effects. - Created TopProgressBar for a dynamic loading indicator. - Added PointCloud mock for testing animations. - Developed useReducedMotion hook to handle user preferences for reduced motion. - Centralized animation configurations in config.ts for easier management. - Defined animation variants in variants.ts for consistent animation effects. - Established AnimationProvider to supply global animation settings. - Created tests for AnimationProvider and useReducedMotion hook. - Added SVG assets for branding and UI elements. - Documented frontend review plan and hero circuit board animation plan.
This commit is contained in:
1 parent
0ab6930f92
commit
08dd046887
76 files changed
+21682
-1197
No files matched your search
+128
-140
@@ -14,18 +14,23 @@ export function ContactForm({ formType, setFormType }: ContactFormProps) {
|
||||
const [contactMethod, setContactMethod] = useState<"whatsapp" | "email">(
|
||||
"whatsapp",
|
||||
);
|
||||
const [userName, setUserName] = useState<string>("");
|
||||
const [userEmail, setUserEmail] = useState<string>("");
|
||||
const [userPhone, setUserPhone] = useState<string>("");
|
||||
const [userCompany, setUserCompany] = useState<string>("");
|
||||
const [howFound, setHowFound] = useState<string>("");
|
||||
const [projectType, setProjectType] = useState<string>("");
|
||||
const [otherProjectType, setOtherProjectType] = useState<string>(""); // Novo estado para "Outro" tipo de projeto
|
||||
const [desiredDeadline, setDesiredDeadline] = useState<string>("");
|
||||
const [budgetValue, setBudgetValue] = useState<string>(""); // Novo estado para o valor do orçamento
|
||||
const [technicalComplexity, setTechnicalComplexity] = useState<string>("");
|
||||
const [hasInternalTeam, setHasInternalTeam] = useState<string>("");
|
||||
const [customMessage, setCustomMessage] = useState<string>("");
|
||||
|
||||
// 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>("");
|
||||
@@ -62,31 +67,31 @@ export function ContactForm({ formType, setFormType }: ContactFormProps) {
|
||||
|
||||
return `Olá Evandro, espero que esta ${dayPart} esteja sendo produtiva.
|
||||
|
||||
Meu nome é ${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.
|
||||
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,
|
||||
${userName}`;
|
||||
${formData.userName}`;
|
||||
};
|
||||
|
||||
const generateAdvancedMessage = () => {
|
||||
if (customMessage) return customMessage;
|
||||
if (formData.customMessage) return formData.customMessage;
|
||||
|
||||
// Saudação profissional
|
||||
let message = `Prezado Evandro,\n\n`;
|
||||
|
||||
// Informações do contato
|
||||
message += `Meu nome é ${userName}`;
|
||||
if (userCompany) {
|
||||
message += `, represento a empresa ${userCompany}`;
|
||||
message += `Meu nome é ${formData.userName}`;
|
||||
if (formData.userCompany) {
|
||||
message += `, represento a empresa ${formData.userCompany}`;
|
||||
}
|
||||
message += `.\n`;
|
||||
|
||||
if (howFound) {
|
||||
message += `Conheci seu trabalho através de ${howFound}.\n`;
|
||||
if (formData.howFound) {
|
||||
message += `Conheci seu trabalho através de ${formData.howFound}.\n`;
|
||||
}
|
||||
|
||||
message += `\n`;
|
||||
@@ -94,31 +99,31 @@ ${userName}`;
|
||||
// Detalhes do projeto
|
||||
message += `=== DETALHES DO PROJETO ===\n`;
|
||||
message += `Tipo de projeto: `;
|
||||
if (projectType === "outro" && otherProjectType) {
|
||||
message += `${otherProjectType}\n`;
|
||||
} else if (projectType) {
|
||||
message += `${projectType}\n`;
|
||||
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 (desiredDeadline) {
|
||||
message += `Prazo desejado: ${desiredDeadline}\n`;
|
||||
if (formData.desiredDeadline) {
|
||||
message += `Prazo desejado: ${formData.desiredDeadline}\n`;
|
||||
}
|
||||
|
||||
if (budgetValue) {
|
||||
message += `Orçamento disponível: ${budgetValue}\n`;
|
||||
if (formData.budgetValue) {
|
||||
message += `Orçamento disponível: ${formData.budgetValue}\n`;
|
||||
}
|
||||
|
||||
if (technicalComplexity) {
|
||||
message += `Complexidade técnica estimada: ${technicalComplexity}\n`;
|
||||
if (formData.technicalComplexity) {
|
||||
message += `Complexidade técnica estimada: ${formData.technicalComplexity}\n`;
|
||||
}
|
||||
|
||||
if (hasInternalTeam) {
|
||||
if (formData.hasInternalTeam) {
|
||||
message += `Equipe técnica interna: ${
|
||||
hasInternalTeam === "sim"
|
||||
formData.hasInternalTeam === "sim"
|
||||
? "Sim"
|
||||
: hasInternalTeam === "nao"
|
||||
: formData.hasInternalTeam === "nao"
|
||||
? "Não"
|
||||
: "Parcialmente"
|
||||
}\n`;
|
||||
@@ -128,11 +133,11 @@ ${userName}`;
|
||||
|
||||
// Contatos
|
||||
message += `=== INFORMAÇÕES PARA CONTATO ===\n`;
|
||||
if (userEmail) {
|
||||
message += `📧 Email: ${userEmail}\n`;
|
||||
if (formData.userEmail) {
|
||||
message += `📧 Email: ${formData.userEmail}\n`;
|
||||
}
|
||||
if (userPhone) {
|
||||
message += `📱 Telefone/WhatsApp: ${userPhone}\n`;
|
||||
if (formData.userPhone) {
|
||||
message += `📱 Telefone/WhatsApp: ${formData.userPhone}\n`;
|
||||
}
|
||||
|
||||
message += `\n`;
|
||||
@@ -141,69 +146,38 @@ ${userName}`;
|
||||
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 += `${userName}`;
|
||||
message += `${formData.userName}`;
|
||||
|
||||
return message;
|
||||
};
|
||||
|
||||
const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setUserName(e.target.value);
|
||||
if (e.target.value.trim() !== "") setNameError(null);
|
||||
};
|
||||
const handleInputChange =
|
||||
(field: keyof typeof formData) =>
|
||||
(
|
||||
e: ChangeEvent<
|
||||
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
|
||||
>,
|
||||
) => {
|
||||
setFormData((prev) => ({ ...prev, [field]: e.target.value }));
|
||||
|
||||
const handleEmailChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setUserEmail(e.target.value);
|
||||
if (e.target.value.trim() !== "") setEmailError(null);
|
||||
};
|
||||
|
||||
const handlePhoneChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setUserPhone(e.target.value);
|
||||
if (e.target.value.trim() !== "") setPhoneError(null);
|
||||
};
|
||||
// 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 handleCompanyChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setUserCompany(e.target.value);
|
||||
};
|
||||
|
||||
const handleHowFoundChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
setHowFound(e.target.value);
|
||||
};
|
||||
|
||||
const handleProjectTypeChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
setProjectType(e.target.value);
|
||||
};
|
||||
|
||||
const handleDesiredDeadlineChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
setDesiredDeadline(e.target.value);
|
||||
};
|
||||
|
||||
const handleBudgetValueChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setBudgetValue(e.target.value);
|
||||
};
|
||||
|
||||
const handleTechnicalComplexityChange = (
|
||||
e: ChangeEvent<HTMLSelectElement>,
|
||||
) => {
|
||||
setTechnicalComplexity(e.target.value);
|
||||
};
|
||||
|
||||
const handleHasInternalTeamChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
setHasInternalTeam(e.target.value);
|
||||
};
|
||||
|
||||
const handleMessageChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setCustomMessage(e.target.value);
|
||||
};
|
||||
|
||||
const generateWhatsAppUrl = () => {
|
||||
const message = encodeURIComponent(
|
||||
formType === "advanced"
|
||||
? generateAdvancedMessage()
|
||||
: customMessage || getGreetingMessageWithUserName(),
|
||||
: formData.customMessage || getGreetingMessageWithUserName(),
|
||||
);
|
||||
const phone = data.contact.whatsapp.replace(/\D/g, ""); // Remove caracteres não numéricos
|
||||
return `https://wa.me/${phone}?text=${message}`;
|
||||
@@ -214,8 +188,8 @@ ${userName}`;
|
||||
const body = encodeURIComponent(
|
||||
formType === "advanced"
|
||||
? generateAdvancedMessage()
|
||||
: `Nome: ${userName}\nEmail: ${userEmail}\nTelefone: ${userPhone}\nEmpresa/Posição: ${userCompany}\nComo conheceu: ${howFound}\n\nTipo de Projeto: ${projectType}\nPrazo Desejado: ${desiredDeadline}\nOrçamento Disponível: ${budgetValue}\nComplexidade Técnica: ${technicalComplexity}\nTem equipe interna: ${hasInternalTeam}\n\nMensagem: ${
|
||||
customMessage || getGreetingMessageWithUserName()
|
||||
: `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}`;
|
||||
@@ -225,7 +199,7 @@ ${userName}`;
|
||||
e.preventDefault();
|
||||
|
||||
let hasError = false;
|
||||
if (userName.trim() === "") {
|
||||
if (formData.userName.trim() === "") {
|
||||
setNameError("Por favor, insira seu nome.");
|
||||
hasError = true;
|
||||
} else {
|
||||
@@ -233,21 +207,24 @@ ${userName}`;
|
||||
}
|
||||
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(userEmail)) {
|
||||
if (!emailRegex.test(formData.userEmail)) {
|
||||
setEmailError("Por favor, insira um email válido.");
|
||||
hasError = true;
|
||||
} else {
|
||||
setEmailError(null);
|
||||
}
|
||||
|
||||
if (userPhone.trim() === "") {
|
||||
if (formData.userPhone.trim() === "") {
|
||||
setPhoneError("Por favor, insira seu telefone.");
|
||||
hasError = true;
|
||||
} else {
|
||||
setPhoneError(null);
|
||||
}
|
||||
|
||||
if (projectType === "outro" && otherProjectType.trim() === "") {
|
||||
if (
|
||||
formData.projectType === "outro" &&
|
||||
formData.otherProjectType.trim() === ""
|
||||
) {
|
||||
setOtherProjectTypeError("Por favor, especifique o tipo de projeto.");
|
||||
hasError = true;
|
||||
} else {
|
||||
@@ -260,10 +237,13 @@ ${userName}`;
|
||||
return; // Ignora a submissão
|
||||
}
|
||||
|
||||
// Validação de tempo de preenchimento (mínimo de 3 segundos)
|
||||
// UX FIX: Validação de tempo com feedback ou limite menor
|
||||
const timeElapsed = Date.now() - startTime;
|
||||
if (timeElapsed < 3000) {
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -271,9 +251,11 @@ ${userName}`;
|
||||
|
||||
// Verificação de interação mínima
|
||||
if (!nameFocused || !emailFocused || !phoneFocused) {
|
||||
console.log("Campos principais não foram focados, provável bot.");
|
||||
// Opcional: exibir uma mensagem de erro para o usuário
|
||||
return;
|
||||
// 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") {
|
||||
@@ -284,13 +266,20 @@ ${userName}`;
|
||||
};
|
||||
|
||||
const getCtaMessage = () => {
|
||||
if (projectType === "consultoria") {
|
||||
if (formData.projectType === "consultoria") {
|
||||
return "Agendar Consultoria Gratuita";
|
||||
}
|
||||
if (budgetValue && parseFloat(budgetValue.replace(/\D/g, "")) < 2000) {
|
||||
if (
|
||||
formData.budgetValue &&
|
||||
parseFloat(formData.budgetValue.replace(/\D/g, "")) < 2000
|
||||
) {
|
||||
return "Discutir Soluções de Baixo Custo";
|
||||
}
|
||||
if (projectType && desiredDeadline && budgetValue) {
|
||||
if (
|
||||
formData.projectType &&
|
||||
formData.desiredDeadline &&
|
||||
formData.budgetValue
|
||||
) {
|
||||
return "Receber Proposta Personalizada";
|
||||
}
|
||||
return "Enviar Formulário";
|
||||
@@ -301,7 +290,7 @@ ${userName}`;
|
||||
let hourlyRate = 55; // Taxa base R$ 55/h
|
||||
|
||||
// Estimativa de horas baseada no tipo de projeto
|
||||
switch (projectType) {
|
||||
switch (formData.projectType) {
|
||||
case "web-app":
|
||||
hours += 80; // Aplicação web completa
|
||||
break;
|
||||
@@ -328,7 +317,7 @@ ${userName}`;
|
||||
}
|
||||
|
||||
// Ajuste de horas baseado no prazo
|
||||
switch (desiredDeadline) {
|
||||
switch (formData.desiredDeadline) {
|
||||
case "1-3-weeks":
|
||||
hours *= 1.3; // Urgência aumenta horas
|
||||
break;
|
||||
@@ -343,7 +332,7 @@ ${userName}`;
|
||||
}
|
||||
|
||||
// Ajuste de horas baseado na complexidade
|
||||
switch (technicalComplexity) {
|
||||
switch (formData.technicalComplexity) {
|
||||
case "alta":
|
||||
hours *= 1.4;
|
||||
hourlyRate = 65; // Taxa maior para alta complexidade
|
||||
@@ -359,7 +348,7 @@ ${userName}`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasInternalTeam === "nao") {
|
||||
if (formData.hasInternalTeam === "nao") {
|
||||
hours *= 1.2; // Sem equipe interna = mais horas necessárias
|
||||
}
|
||||
|
||||
@@ -440,8 +429,8 @@ ${userName}`;
|
||||
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={userName}
|
||||
onChange={handleNameChange}
|
||||
value={formData.userName}
|
||||
onChange={handleInputChange("userName")}
|
||||
onFocus={handleNameFocus}
|
||||
required
|
||||
/>
|
||||
@@ -495,8 +484,8 @@ ${userName}`;
|
||||
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={userName}
|
||||
onChange={handleNameChange}
|
||||
value={formData.userName}
|
||||
onChange={handleInputChange("userName")}
|
||||
onFocus={handleNameFocus}
|
||||
required
|
||||
/>
|
||||
@@ -518,8 +507,8 @@ ${userName}`;
|
||||
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={userEmail}
|
||||
onChange={handleEmailChange}
|
||||
value={formData.userEmail}
|
||||
onChange={handleInputChange("userEmail")}
|
||||
onFocus={handleEmailFocus}
|
||||
required
|
||||
/>
|
||||
@@ -541,8 +530,8 @@ ${userName}`;
|
||||
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={userPhone}
|
||||
onChange={handlePhoneChange}
|
||||
value={formData.userPhone}
|
||||
onChange={handleInputChange("userPhone")}
|
||||
onFocus={handlePhoneFocus}
|
||||
required
|
||||
/>
|
||||
@@ -562,8 +551,8 @@ ${userName}`;
|
||||
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={userCompany}
|
||||
onChange={handleCompanyChange}
|
||||
value={formData.userCompany}
|
||||
onChange={handleInputChange("userCompany")}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -582,9 +571,10 @@ ${userName}`;
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "16px",
|
||||
}}
|
||||
value={howFound}
|
||||
onChange={handleHowFoundChange}
|
||||
value={formData.howFound}
|
||||
onChange={handleInputChange("howFound")}
|
||||
>
|
||||
{" "}
|
||||
<option value="" className="bg-gray-800 text-white">
|
||||
Selecione uma opção
|
||||
</option>
|
||||
@@ -664,8 +654,8 @@ ${userName}`;
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "16px",
|
||||
}}
|
||||
value={projectType}
|
||||
onChange={handleProjectTypeChange}
|
||||
value={formData.projectType}
|
||||
onChange={handleInputChange("projectType")}
|
||||
>
|
||||
<option value="" className="bg-gray-800 text-white">
|
||||
Selecione o tipo
|
||||
@@ -708,7 +698,7 @@ ${userName}`;
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
{projectType === "outro" && (
|
||||
{formData.projectType === "outro" && (
|
||||
<div>
|
||||
<label
|
||||
htmlFor="other-project-type"
|
||||
@@ -725,12 +715,8 @@ ${userName}`;
|
||||
: "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={otherProjectType}
|
||||
onChange={(e) => {
|
||||
setOtherProjectType(e.target.value);
|
||||
if (e.target.value.trim() !== "")
|
||||
setOtherProjectTypeError(null);
|
||||
}}
|
||||
value={formData.otherProjectType}
|
||||
onChange={handleInputChange("otherProjectType")}
|
||||
required
|
||||
/>
|
||||
{otherProjectTypeError && (
|
||||
@@ -756,8 +742,8 @@ ${userName}`;
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "16px",
|
||||
}}
|
||||
value={desiredDeadline}
|
||||
onChange={handleDesiredDeadlineChange}
|
||||
value={formData.desiredDeadline}
|
||||
onChange={handleInputChange("desiredDeadline")}
|
||||
>
|
||||
<option value="" className="bg-gray-800 text-white">
|
||||
Selecione o prazo
|
||||
@@ -806,8 +792,8 @@ ${userName}`;
|
||||
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={budgetValue}
|
||||
onChange={handleBudgetValueChange}
|
||||
value={formData.budgetValue}
|
||||
onChange={handleInputChange("budgetValue")}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -826,8 +812,8 @@ ${userName}`;
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "16px",
|
||||
}}
|
||||
value={technicalComplexity}
|
||||
onChange={handleTechnicalComplexityChange}
|
||||
value={formData.technicalComplexity}
|
||||
onChange={handleInputChange("technicalComplexity")}
|
||||
>
|
||||
<option value="" className="bg-gray-800 text-white">
|
||||
Selecione a complexidade
|
||||
@@ -865,8 +851,8 @@ ${userName}`;
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "16px",
|
||||
}}
|
||||
value={hasInternalTeam}
|
||||
onChange={handleHasInternalTeamChange}
|
||||
value={formData.hasInternalTeam}
|
||||
onChange={handleInputChange("hasInternalTeam")}
|
||||
>
|
||||
<option value="" className="bg-gray-800 text-white">
|
||||
Selecione
|
||||
@@ -898,8 +884,8 @@ ${userName}`;
|
||||
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={customMessage}
|
||||
onChange={handleMessageChange}
|
||||
value={formData.customMessage}
|
||||
onChange={handleInputChange("customMessage")}
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
@@ -913,11 +899,13 @@ ${userName}`;
|
||||
{getCtaMessage()}
|
||||
</button>
|
||||
</motion.div>
|
||||
{projectType && desiredDeadline && budgetValue && (
|
||||
<p className="text-center text-lg font-semibold text-cyan-400 mt-4">
|
||||
{getEstimatedValue()}
|
||||
</p>
|
||||
)}
|
||||
{formData.projectType &&
|
||||
formData.desiredDeadline &&
|
||||
formData.budgetValue && (
|
||||
<p className="text-center text-lg font-semibold text-cyan-400 mt-4">
|
||||
{getEstimatedValue()}
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
Reference in new issue
Block a user