feat(main): cria página de contato com formulário

This commit is contained in:
Andrea Matsunaga 2023-01-05 16:16:15 -03:00
parent 2146b9edc6
commit 14db077644
9 changed files with 448 additions and 7 deletions

View File

@ -8,7 +8,7 @@
font-weight: 700;
font-size: 24px;
line-height: 28px;
color: #292929;
color: #292929; // #000000 ??
margin: 0 0 12px;
@media screen and (width >= 2500px) {

View File

@ -3,7 +3,6 @@
padding: 0;
list-style: none;
text-decoration: none;
border-right: 1px solid #000000;
li {
padding: 10px 16px;
@ -24,8 +23,17 @@
}
}
// &.active {
// background: #000000;
// a {
// font-weight: 700;
// color: #ffffff;
// }
// }
&:hover {
background: #000000;
background: #292929;
a {
font-weight: 700;

View File

@ -0,0 +1,19 @@
.section-container {
margin-left: 30px;
padding: 10px 0;
.section-title {
font-family: "Roboto";
font-style: normal;
font-weight: 700;
font-size: 24px;
line-height: 28px;
color: #000000; // #292929 ??
margin: 0 0 12px;
@media screen and (width >= 2500px) {
font-size: 48px;
line-height: 56px;
}
}
}

View File

@ -0,0 +1,18 @@
import React from "react";
import { ContactForm } from "../ContactForm/ContactForm";
// import { Formik, Form, Field, ErrorMessage, FormikHelpers } from "formik";
// import FormSchema from "../../schema/FormSchema";
import styles from "./Contact.module.scss";
const Contact = () => {
return (
<section className={styles["section-container"]}>
<h2 className={styles["section-title"]}>Preencha o formulário </h2>
{/* <div className={styles["section-description"]}></div> */}
<ContactForm />
</section>
);
};
export { Contact };

View File

@ -0,0 +1,181 @@
.form-wrapper {
width: 100%;
padding-bottom: 26.56px;
position: relative;
// max-width: 720px;
// min-height: 100vh;
// margin: 0 auto;
// padding: 0 12px;
// display: flex;
// justify-content: center;
// align-items: center;
@media screen and (width >= 2500px) {
padding-bottom: 40px;
}
form {
width: 100%;
}
.form-col {
position: relative;
display: flex;
flex-direction: column;
margin-bottom: 12px;
label {
font-family: "Roboto";
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 16px;
color: #100d0e;
padding: 0 15px 12px;
@media screen and (width >= 2500px) {
font-size: 28px;
line-height: 33px;
}
}
input {
background: #ffffff;
border: 1px solid #100d0e;
border-radius: 25px;
padding: 15px 20px;
font-family: "Roboto";
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 16px;
color: #000000;
outline: 0;
@media screen and (width >= 2500px) {
font-size: 28px;
line-height: 33px;
}
&::placeholder {
color: #b9b7b7;
}
}
}
.invalid-form-feedback {
font-family: "Roboto";
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: #ff0000;
position: absolute;
top: 15px;
right: 20px;
@media screen and (width >= 2500px) {
font-size: 24px;
line-height: 28px;
top: 17px;
}
}
.terms-col {
margin: 1.58px 0 12.6px;
text-align: center;
font-family: "Roboto";
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 16px;
display: flex;
align-items: center;
justify-content: center;
@media screen and (width >= 2500px) {
font-size: 28px;
line-height: 33px;
margin: 0 0 12.85px;
}
span {
// font-family: "Proxima Nova"; Adobe Fonts
color: #ff0000;
}
label {
color: #100d0e;
text-decoration: underline;
}
// .custom-checkbox {
// border: 1px solid #000000;
// border-radius: 3px;
// width: 34.4px;
// height: 33.15px;
// margin: 0 0 0 4.28px;
// // display: inline-block;
// // position: absolute;
// // bottom: 2.2px;
// }
input {
// talvez tenha que substituir o checkbox original - não pegando as bordas direito e o alinhamento está errado, tem que ser no underline. considerar as bordas na medida do input original ou do custom?
width: 18.64px;
height: 18px;
margin: 0 0 0 4.28px;
// opacity: 0;
@media screen and (width >= 2500px) {
width: 36.4px;
height: 35.15px;
}
}
}
.submit-button {
background: #000000;
border-radius: 25px;
font-family: "Roboto";
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 19px;
width: 100%;
padding: 17px 0;
letter-spacing: 0.05em;
color: #ffffff;
text-transform: uppercase;
border: none;
cursor: pointer;
transition: all 0.2s ease-in-out;
@media screen and (width >= 2500px) {
font-size: 32px;
line-height: 38px;
}
&:hover {
background: #292929;
}
}
.success-message {
font-family: "Roboto";
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: #008000;
position: absolute;
bottom: 0;
left: 0;
@media screen and (width >= 2500px) {
font-size: 24px;
line-height: 28px;
}
}
}

View File

@ -0,0 +1,194 @@
import React, { useCallback, useState } from "react";
import {
Formik,
Form,
Field,
ErrorMessage,
// FormikHelpers,
// FormikBag,
// FormikState,
} from "formik";
import FormSchema from "../../schema/FormSchema";
import "./ContactForm.module.scss";
import styles from "./ContactForm.module.scss";
interface IFormikValues {
name: string;
email: string;
cpf: string;
dateOfBirth: string;
phoneNumber: string;
instagram: string;
acceptTerms: boolean;
}
const initialValues = {
name: "",
email: "",
cpf: "",
dateOfBirth: "",
phoneNumber: "",
instagram: "",
acceptTerms: false,
};
const ContactForm = () => {
const [hasSubmitBegun, setHasSubmitBegun] = useState(false);
const [hasSubmitCompleted, setHasSubmitCompleted] = useState(false);
const doSubmit = async (values: IFormikValues) =>
console.log("submitted", values);
const handleSubmit = useCallback(
async (values: IFormikValues, { resetForm }: any) => {
setHasSubmitBegun(true);
await doSubmit(values);
setHasSubmitCompleted(true);
resetForm({ ...initialValues });
},
[doSubmit]
);
// const handleSubmit = (values: IFormikValues) => {
// console.log(values);
// };
return (
<div className={styles["form-wrapper"]}>
<Formik
onSubmit={handleSubmit}
initialValues={initialValues}
validationSchema={FormSchema}
>
{({ errors, touched, resetForm }) => (
<Form>
<div className={styles["form-col"]}>
<label htmlFor="name">Nome</label>
<Field
id="name"
name="name"
placeholder="Seu nome completo"
// className={errors.name && touched.name && "invalid"}
/>
<ErrorMessage
component="span"
name="name"
className={styles["invalid-form-feedback"]}
/>
</div>
<div className={styles["form-col"]}>
<label htmlFor="email">E-mail</label>
<Field
id="email"
name="email"
placeholder="Seu e-mail"
// className={errors.email && touched.email && `${styles["invalid"]}`}
// className={errors.email && touched.email && "invalid"}
/>
<ErrorMessage
component="span"
name="email"
className={styles["invalid-form-feedback"]}
/>
</div>
<div className={styles["form-col"]}>
<label htmlFor="subject">CPF</label>
<Field
id="cpf"
name="cpf"
placeholder="000.000.000-00"
// className={errors.cpf && touched.cpf && "invalid"}
/>
<ErrorMessage
component="span"
name="cpf"
className={styles["invalid-form-feedback"]}
/>
</div>
<div className={styles["form-col"]}>
<label htmlFor="dateOfBirth">Data de Nascimento:</label>
{/* tem : só nesses campos? */}
<Field
// as="textarea"
id="dateOfBirth"
name="dateOfBirth"
placeholder="00.00.0000"
// className={errors.dateOfBirth && touched.dateOfBirth && "invalid"}
/>
<ErrorMessage
component="span"
name="dateOfBirth"
className={styles["invalid-form-feedback"]}
/>
</div>
<div className={styles["form-col"]}>
<label htmlFor="message">Telefone:</label>
{/* tem : só nesses campos? */}
<Field
// as="textarea"
id="phoneNumber"
name="phoneNumber"
placeholder="(00) 00000-0000"
// className={
// errors.phoneNumber && touched.phoneNumber && "invalid"
// }
/>
<ErrorMessage
component="span"
name="phoneNumber"
className={styles["invalid-form-feedback"]}
/>
</div>
<div className={styles["form-col"]}>
<label htmlFor="message">Instagram</label>
<Field
id="instagram"
name="instagram"
placeholder="@seuuser"
// className={errors.instagram && touched.instagram && "invalid"}
/>
<ErrorMessage
component="span"
name="instagram"
className={styles["invalid-form-feedback"]}
/>
</div>
<div className={styles["terms-col"]}>
<span>* </span>
<label htmlFor="acceptTerms">Declaro que li e aceito</label>
{/* <div className={styles["custom-checkbox"]}></div> */}
<Field
type="checkbox"
id="acceptTerms"
name="acceptTerms"
// className={`${"invalid" ? styles["invalid"] : ""}`}
// className={
// errors.acceptTerms && touched.acceptTerms && "invalid"
// }
/>
{/* <ErrorMessage
component="span"
name="acceptTerms"
className={styles["invalid-form-feedback"]}
/> */}
</div>
<button className={styles["submit-button"]} type="submit">
Cadastre-se
</button>
{hasSubmitCompleted && (
<span className={styles["success-message"]}>*Formulário enviado com sucesso!</span>
)}
</Form>
)}
</Formik>
</div>
);
};
export { ContactForm };

View File

@ -78,10 +78,20 @@
.main-content {
display: grid;
grid-template-columns: 302px 1fr;
grid-template-columns: 302px 1px 1fr;
@media screen and (width >= 2500px) {
grid-template-columns: 590px 1fr;
grid-template-columns: 590px 1px 1fr;
}
.horizontal-divider {
width: 1px;
height: 285px;
background: #000000;
@media screen and (width >= 2500px) {
height: 465px;
}
}
}
}

View File

@ -4,8 +4,6 @@ import { AsideMenu } from "../AsideMenu/AsideMenu";
import styles from "./MainLayout.module.scss";
// import "../../assets/svg/Vector.svg";
const MainLayout = () => {
return (
<main className={styles["main-container"]}>
@ -17,6 +15,7 @@ const MainLayout = () => {
<h1 className={styles["main-title"]}>Institucional</h1>
<div className={styles["main-content"]}>
<AsideMenu />
<div className={styles["horizontal-divider"]}></div>
<Outlet />
</div>
</main>

12
src/schema/FormSchema.ts Normal file
View File

@ -0,0 +1,12 @@
import * as Yup from "yup";
export default Yup.object().shape({
// melhorar validações: tipo de dado, minlength, formato
name: Yup.string().required("*Campo Obrigatório"),
email: Yup.string().required("*Campo Obrigatório").email("Email inválido"),
cpf: Yup.string().required("*Campo Obrigatório"),
dateOfBirth: Yup.string().required("*Campo Obrigatório"),
phoneNumber: Yup.string().required("*Campo Obrigatório"),
instagram: Yup.string(),
acceptTerms: Yup.boolean().required("*Campo Obrigatório"),
});