forked from M3-Academy/desafio-react-e-typescript
fix: ajuste de formulario de contato #13
@ -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",
|
||||
|
@ -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>
|
||||
|
@ -32,6 +32,10 @@
|
||||
min-height: 15.62px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:1025px) {
|
||||
z-index: -99;
|
||||
}
|
||||
}
|
||||
|
||||
.routeName {
|
||||
|
@ -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"]}>
|
||||
|
@ -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>
|
||||
|
@ -453,6 +453,7 @@ a {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: all .45s;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.wrapper.aberto {
|
||||
|
@ -15,6 +15,7 @@ export const Home = () => {
|
||||
<Header />
|
||||
<BreadCrumb />
|
||||
<main className={styles["main"]}>
|
||||
|
||||
<Outlet />
|
||||
</main>
|
||||
|
||||
|
@ -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}
|
||||
</>
|
||||
)
|
||||
|
@ -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;
|
@ -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>
|
||||
)
|
||||
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -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';
|
||||
|
@ -17,7 +17,8 @@
|
||||
|
||||
@media (max-width:1024px) {
|
||||
margin: 0 16px;
|
||||
z-index: -9;
|
||||
// z-index: -9;
|
||||
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
@ -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], "*"),
|
||||
});
|
||||
|
@ -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}$/;
|
||||
|
38
yarn.lock
38
yarn.lock
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user