fix: ajuste de formulario de contato #13

Merged
emmanuelvitor merged 1 commits from feature/organizationContactForm into development 2023-01-18 01:08:20 +00:00
15 changed files with 179 additions and 76 deletions
Showing only changes of commit d910b1efba - Show all commits

View File

@ -10,11 +10,14 @@
"@types/node": "^16.7.13",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react-input-mask": "^3.0.2",
"@types/react-maskedinput": "^4.0.6",
"formik": "^2.2.9",
"node-sass": "^8.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-headless-accordion": "^1.0.2",
"react-input-mask": "^2.0.4",
"react-router-dom": "^6.6.2",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",

View File

@ -17,7 +17,7 @@ export const BreadCrumb = () => {
{pathname !== "/" && (
<ul className={styles["breadNav"]}>
<li className={styles["navItem"]}>
<Link to="/institucional/sobre">
<Link to="/institucional">
<img src={homeIcon} alt="Icone de home" />
</Link>
</li>

View File

@ -32,6 +32,10 @@
min-height: 15.62px;
}
}
@media (max-width:1025px) {
z-index: -99;
}
}
.routeName {

View File

@ -10,7 +10,7 @@ export const HeaderTop = () => {
return (
<div className={styleHeader["header__top"]}>
<div className={styleHeader["container__header__top"]}>
<Link to="/institucional/sobre" className={styleHeader["container__logo"]}>
<Link to="/" className={styleHeader["container__logo"]}>
< img src={logo} alt="Logo M3" className={styleHeader["container__logo__img"]} />
</Link>
<form className={styleHeader["container__search"]}>

View File

@ -1,4 +1,5 @@
import React from "react";
import { Link } from "react-router-dom";
import closeIcon from "../assets/svgs/icon-close.svg";
import styleHeader from '../styles/Header.module.scss';
@ -31,15 +32,15 @@ export const BurguerMenu = ({ isOpenMenu, setisOpenMenu }: MenuMobile) => {
{/* Esse nav vai viraar um componente */}
<nav className={styleHeader["navBar__items"]}>
{/* esse "a" vai virar um componente */}
<a className={styleHeader["list__items__link"]} href="/cursos">
<Link className={styleHeader["list__items__link"]} to="/cursos">
Cursos
</a>
<a className={styleHeader["list__items__link"]} href="/saiba-mais">
</Link>
<Link className={styleHeader["list__items__link"]} to="/saiba-mais">
Saiba Mais
</a>
<a className={styleHeader["list__items__link"]} href="/institucionais">
Institucionais
</a>
</Link>
<Link className={styleHeader["list__items__link"]} to="/institucional/">
Institucional
</Link>
</nav>
</div>

View File

@ -453,6 +453,7 @@ a {
opacity: 0;
pointer-events: none;
transition: all .45s;
z-index: 9;
}
.wrapper.aberto {

View File

@ -15,6 +15,7 @@ export const Home = () => {
<Header />
<BreadCrumb />
<main className={styles["main"]}>
<Outlet />
</main>

View File

@ -4,13 +4,14 @@ import React, { ReactNode } from 'react';
interface ArticleProps {
title: string;
className?: string;
children: ReactNode;
}
export const Article = ({ children, title }: ArticleProps) => {
export const Article = ({ children, title, className }: ArticleProps) => {
return (
<>
<h2>{title}</h2>
<h2 >{title}</h2>
{children}
</>
)

View File

@ -1,5 +1,3 @@
// @import "../components/Variables.scss";
.formulario {
display: flex;
flex-direction: column;
@ -12,13 +10,16 @@
@media (min-width: 1025px) {
width: 100%;
padding: 12px 30px;
padding: 0px;
}
.label__form {
margin: 12px 0;
}
input {
padding: 15px 20px;
margin: 12px 0;
border: 1px solid #000;
border: 1px solid #100D0E;
border-radius: 25px;
font-family: "Roboto";
font-style: normal;
@ -26,12 +27,37 @@
font-size: 14px;
line-height: 16px;
color: #000;
outline: none;
&::placeholder {
color: gray;
}
}
.invalid {
border: 1px solid red;
}
.error {
display: flex;
justify-content: end;
font-family: "Roboto";
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: red;
}
.form-ivalid-feedback {
background-color: aqua;
}
button {
padding: 17px;
background: #000;
@ -39,11 +65,10 @@
color: #fff;
}
div {
.checkbox_wrapper {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 12px;
label {
order: 2;

View File

@ -1,17 +1,15 @@
import React from 'react';
import { Article } from './Article';
import { Formik, Form, Field, ErrorMessage } from "formik";
import contactFormSchema from "../../schema/ContactFormSchema";
import "./Contact.module.scss";
import ContactFormSchema from "../../schema/ContactFormSchema";
import { Article } from "./Article";
import style from "./Contato.module.scss";
import InputMask from 'react-input-mask';
interface IFormikValues {
name: string;
email: string;
cpf: string;
dateBirth: string;
phone: string;
data: string;
telefone: string;
instagram?: string;
checkbox: boolean;
}
@ -20,8 +18,8 @@ const initialValues = {
name: "",
email: "",
cpf: "",
dateBirth: "",
phone: "",
data: "",
telefone: "",
instagram: "",
checkbox: false,
};
@ -30,83 +28,98 @@ const formSubmit = (values: IFormikValues) => {
console.log(values);
};
export const Contato = () => {
return (
<Article title='Contato'>
<Article title="Preencha o formulario" className={style["title-contact"]}>
<Formik
onSubmit={formSubmit}
initialValues={initialValues}
validationSchema={contactFormSchema}
validationSchema={ContactFormSchema}
>
{({ errors, touched }) => (
<Form className="formulario">
<label htmlFor="name">Nome</label>
<Form className={style["formulario"]}>
<label className={style["label__form"]} htmlFor="name">Nome</label>
<span className={style["error"]}>
<ErrorMessage name="name" className={style["form-ivalid-feedback"]} />
</span>
<Field
id="name"
name="name"
placeholder="Seu nome completo"
className={errors.name && touched.name && "invalid"}
className={errors.name && touched.name && style["invalid"]}
/>
<ErrorMessage name="name" className="form-ivalid-feedback" />
<label htmlFor="email">E-mail</label>
<label className={style["label__form"]} htmlFor="email">E-mail</label>
<span className={style["error"]}>
<ErrorMessage name="email" className={style["form-ivalid-feedback"]} />
</span>
<Field
id="email"
name="email"
placeholder="Seu e-mail"
className={errors.email && touched.email && "invalid"}
className={errors.email && touched.email && style["invalid"]}
/>
<ErrorMessage name="email" className="form-ivalid-feedback" />
<label htmlFor="cpf">CPF</label>
<label className={style["label__form"]} htmlFor="cpf">CPF</label>
<span className={style["error"]}>
<ErrorMessage name="cpf" className={style["form-ivalid-feedback"]} />
</span>
<Field
id="cpf"
name="cpf"
name="cpf" as={InputMask} mask="999.999.999-99"
type="tel"
placeholder="000.000.000-00"
className={errors.cpf && touched.cpf && "invalid"}
className={errors.cpf && touched.cpf && style["invalid"]}
/>
<ErrorMessage name="cpf" className="form-ivalid-feedback" />
<label htmlFor="data">Data de Nascimento:</label>
<label className={style["label__form"]} htmlFor="data">Data de Nascimento:</label>
<span className={style["error"]}>
<ErrorMessage name="data" className={style["form-ivalid-feedback"]} />
</span>
<Field
id="dateBirth"
name="dateBirth"
id="data"
name="data" as={InputMask} mask="99.99.9999"
type="string"
placeholder="00.00.0000"
className={errors.dateBirth && touched.dateBirth && "invalid"}
className={errors.data && touched.data && style["invalid"]}
/>
<ErrorMessage name="dateBirth" className="form-ivalid-feedback" />
<label htmlFor="phone">Telefone:</label>
<label className={style["label__form"]} htmlFor="telefone">Telefone:</label>
<span className={style["error"]}>
<ErrorMessage name="telefone" className={style["form-ivalid-feedback"]} />
</span>
<Field
id="phone"
name="phone"
id="telefone"
name="telefone"
type="tel"
placeholder="(00) 00000-0000"
className={errors.phone && touched.phone && "invalid"}
className={errors.telefone && touched.telefone && [style["invalid"]]}
/>
<ErrorMessage name="phone" className="form-ivalid-feedback" />
<label htmlFor="instagram">Instagram</label>
<label className={style["label__form"]} htmlFor="instagram">Instagram</label>
<span>
<ErrorMessage name="instagram" className={style["form-ivalid-feedback"]} />
</span>
<Field id="instagram" name="instagram" placeholder="@seuuser" />
<ErrorMessage name="instagram" className="form-ivalid-feedback" />
<div>
<label htmlFor="checkbox">Declaro que li e aceito</label>
<div className={style["checkbox_wrapper"]}>
<label className={style["label__form"]} htmlFor="checkbox">Declaro que li e aceito</label>
<span className={style["error"]}>
<ErrorMessage name="checkbox" className={style["form-ivalid-feedback"]} />
</span>
<Field
type="checkbox"
id="checkbox"
name="checkbox"
className={errors.checkbox && touched.checkbox && "invalid"}
className={errors.checkbox && touched.checkbox && style["invalid"]}
/>
<ErrorMessage name="checkbox" className="form-ivalid-feedback" />
</div>
<button type="submit">CADASTRE-SE</button>
</Form>
)}
</Formik>
</Article>
)
}
);
};

View File

@ -2,7 +2,7 @@
display: flex;
gap: 30px;
height: 100%;
max-height: 465px;
// max-height: 465px;
margin: 80px 0 70px;
@media (max-width:1024px) {
@ -43,12 +43,14 @@
width: 100%;
min-width: 302px;
height: 100%;
max-height: 285px;
padding: 0;
margin: 0;
@media (min-width:2500px) {
min-width: 590px;
max-height: 465px;
}
@ -103,7 +105,11 @@
width: 100%;
height: 100%;
h2 {
@media (max-width:1024px) {
text-align: center;
}
}
p {
font-family: 'Roboto';

View File

@ -17,7 +17,8 @@
@media (max-width:1024px) {
margin: 0 16px;
z-index: -9;
// z-index: -9;
}
h1 {

View File

@ -1,20 +1,30 @@
import * as Yup from "yup";
import { cpfRegex, phoneRegex, instaRegex } from "./ContactValidations";
import {
cpfRegex,
dateRegex,
instaRegex,
phoneRegex
} from "./ContactValidations";
export default Yup.object().shape({
name: Yup.string().required("*Campo Obrigatório"),
name: Yup.string()
.min(3, "O campo deve ter no mínimo 3 caracteres")
.required("*Campo Obrigatório"),
email: Yup.string()
.email()
.required("*Campo Obrigatório")
.email("E-mail inválido"),
cpf: Yup.string()
.matches(cpfRegex, "CPF inválido")
.required("*Campo Obrigatório"),
.required("*Campo Obrigatório")
.matches(cpfRegex, 'CPF inválido'),
telefone: Yup.string()
.matches(phoneRegex, "numero inválido")
.required("*Campo Obrigatório"),
.required("*Campo Obrigatório")
.matches(phoneRegex, 'Número de telefone inválido'),
instagram: Yup.string().matches(instaRegex, "conta inválida"),
data: Yup.date().required("*Campo Obrigatório"),
data: Yup.date()
.required("*Campo Obrigatório")
.max(new Date(),'Data de nascimento inválida'),
checkbox: Yup.boolean().oneOf([true], "*"),
});

View File

@ -1,3 +1,4 @@
export const phoneRegex = /\([1-9]{2}\) [1-9]{2}\d{3}-\d{4}/;
export const cpfRegex = /\d{3}.\d{3}.\d{3}-\d{2}/;
export const phoneRegex =/^\([1-9]{2}\) [2-9][0-9]{3,4}\-[0-9]{4}$/;
export const cpfRegex = /^[0-9]{3}\.?[0-9]{3}\.?[0-9]{3}\-?[0-9]{2}$/
export const instaRegex = /(?:^|[^\w])(?:@)([\w-](?:(?:[\w-]|(?:\.(?!\.))){0,28}(?:[\w-]))?)/;
export const dateRegex = /^[0-9]{1,2}.[0-9]{1,2}.[0-9]{4}$/;

View File

@ -2100,6 +2100,20 @@
dependencies:
"@types/react" "*"
"@types/react-input-mask@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/react-input-mask/-/react-input-mask-3.0.2.tgz#60df645cdb2415c97a8f97316011eb3ede78dc1e"
integrity sha512-WTli3kUyvUqqaOLYG/so2pLqUvRb+n4qnx2He5klfqZDiQmRyD07jVIt/bco/1BrcErkPMtpOm+bHii4Oed6cQ==
dependencies:
"@types/react" "*"
"@types/react-maskedinput@^4.0.6":
version "4.0.6"
resolved "https://registry.yarnpkg.com/@types/react-maskedinput/-/react-maskedinput-4.0.6.tgz#cbb3a689d81b594b9d3bb2d359e86d1e628cb41b"
integrity sha512-rLm0t4CcCE0smsOVgZTzwT/amDDBh1sL46V+V22JIeyChibCM7Oe3TNSk66oJK0fHishDyzRg7pd+sH4sozGqg==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.0":
version "18.0.26"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.26.tgz#8ad59fc01fef8eaf5c74f4ea392621749f0b7917"
@ -5357,6 +5371,13 @@ internal-slot@^1.0.3:
has "^1.0.3"
side-channel "^1.0.4"
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
@ -6469,7 +6490,7 @@ lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.1.0, loose-envify@^1.4.0:
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@ -8121,6 +8142,14 @@ react-headless-accordion@^1.0.2:
resolved "https://registry.yarnpkg.com/react-headless-accordion/-/react-headless-accordion-1.0.2.tgz#df45168fc379a9014bd7becc2f4be100af456b6e"
integrity sha512-wKBTB/+aAr9MGX5RYi3sdmKOSzevKdmbGRw9JTe7XONiHlTo+pC1OiggL9NUxp5QeQcTnX0rryhuySeGsqBfBg==
react-input-mask@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-input-mask/-/react-input-mask-2.0.4.tgz#9ade5cf8196f4a856dbf010820fe75a795f3eb14"
integrity sha512-1hwzMr/aO9tXfiroiVCx5EtKohKwLk/NT8QlJXHQ4N+yJJFyUuMT+zfTpLBwX/lK3PkuMlievIffncpMZ3HGRQ==
dependencies:
invariant "^2.2.4"
warning "^4.0.2"
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@ -9626,6 +9655,13 @@ walker@^1.0.7:
dependencies:
makeerror "1.0.12"
warning@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"