├── .eslintcache
├── .gitignore
├── README.md
├── img
└── thumb.png
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.js
├── componentes
└── Input.js
├── elementos
└── Formularios.js
├── estilos.css
└── index.js
/.eslintcache:
--------------------------------------------------------------------------------
1 | [{"D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\index.js":"1","D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\App.js":"2","D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\elementos\\Formularios.js":"3","D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\componentes\\Input.js":"4"},{"size":220,"mtime":1611429076875,"results":"5","hashOfConfig":"6"},{"size":4833,"mtime":1611452043009,"results":"7","hashOfConfig":"6"},{"size":2949,"mtime":1611517670476,"results":"8","hashOfConfig":"6"},{"size":1293,"mtime":1611451147204,"results":"9","hashOfConfig":"6"},{"filePath":"10","messages":"11","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"12"},"1st86mo",{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"12"},{"filePath":"15","messages":"16","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17","messages":"18","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"12"},"D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\index.js",[],["19","20"],"D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\App.js",[],"D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\elementos\\Formularios.js",[],"D:\\xampp\\htdocs\\tutoriales\\react\\validacion-formulario\\src\\componentes\\Input.js",[],{"ruleId":"21","replacedBy":"22"},{"ruleId":"23","replacedBy":"24"},"no-native-reassign",["25"],"no-negated-in-lhs",["26"],"no-global-assign","no-unsafe-negation"]
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Guía Completa para Principiantes de Validación de Formularios en React
2 | ### [Tutorial: https://youtu.be/tli5n_NqQW8 ](https://youtu.be/tli5n_NqQW8 )
3 |
4 | 
5 |
6 | Por: [FalconMasters](http://www.falconmasters.com)
--------------------------------------------------------------------------------
/img/thumb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/falconmasters/validacion-formularios-react/5d357b70bea37ab1c9b9801ea4c1b9192126ff94/img/thumb.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "validacion-formulario",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@fortawesome/fontawesome-svg-core": "^1.2.34",
7 | "@fortawesome/free-solid-svg-icons": "^5.15.2",
8 | "@fortawesome/react-fontawesome": "^0.1.14",
9 | "@testing-library/jest-dom": "^5.11.9",
10 | "@testing-library/react": "^11.2.3",
11 | "@testing-library/user-event": "^12.6.2",
12 | "react": "^17.0.1",
13 | "react-dom": "^17.0.1",
14 | "react-scripts": "4.0.1",
15 | "styled-components": "^5.2.1",
16 | "web-vitals": "^0.2.4"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test",
22 | "eject": "react-scripts eject"
23 | },
24 | "eslintConfig": {
25 | "extends": [
26 | "react-app",
27 | "react-app/jest"
28 | ]
29 | },
30 | "browserslist": {
31 | "production": [
32 | ">0.2%",
33 | "not dead",
34 | "not op_mini all"
35 | ],
36 | "development": [
37 | "last 1 chrome version",
38 | "last 1 firefox version",
39 | "last 1 safari version"
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/falconmasters/validacion-formularios-react/5d357b70bea37ab1c9b9801ea4c1b9192126ff94/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/falconmasters/validacion-formularios-react/5d357b70bea37ab1c9b9801ea4c1b9192126ff94/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/falconmasters/validacion-formularios-react/5d357b70bea37ab1c9b9801ea4c1b9192126ff94/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import {Formulario, Label, ContenedorTerminos, ContenedorBotonCentrado, Boton, MensajeExito, MensajeError} from './elementos/Formularios';
3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4 | import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
5 | import Input from './componentes/Input';
6 |
7 | const App = () => {
8 | const [usuario, cambiarUsuario] = useState({campo: '', valido: null});
9 | const [nombre, cambiarNombre] = useState({campo: '', valido: null});
10 | const [password, cambiarPassword] = useState({campo: '', valido: null});
11 | const [password2, cambiarPassword2] = useState({campo: '', valido: null});
12 | const [correo, cambiarCorreo] = useState({campo: '', valido: null});
13 | const [telefono, cambiarTelefono] = useState({campo: '', valido: null});
14 | const [terminos, cambiarTerminos] = useState(false);
15 | const [formularioValido, cambiarFormularioValido] = useState(null);
16 |
17 | const expresiones = {
18 | usuario: /^[a-zA-Z0-9_-]{4,16}$/, // Letras, numeros, guion y guion_bajo
19 | nombre: /^[a-zA-ZÀ-ÿ\s]{1,40}$/, // Letras y espacios, pueden llevar acentos.
20 | password: /^.{4,12}$/, // 4 a 12 digitos.
21 | correo: /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/,
22 | telefono: /^\d{7,14}$/ // 7 a 14 numeros.
23 | }
24 |
25 | const validarPassword2 = () => {
26 | if(password.campo.length > 0){
27 | if(password.campo !== password2.campo){
28 | cambiarPassword2((prevState) => {
29 | return {...prevState, valido: 'false'}
30 | });
31 | } else {
32 | cambiarPassword2((prevState) => {
33 | return {...prevState, valido: 'true'}
34 | });
35 | }
36 | }
37 | }
38 |
39 | const onChangeTerminos = (e) => {
40 | cambiarTerminos(e.target.checked);
41 | }
42 |
43 | const onSubmit = (e) => {
44 | e.preventDefault();
45 |
46 | if(
47 | usuario.valido === 'true' &&
48 | nombre.valido === 'true' &&
49 | password.valido === 'true' &&
50 | password2.valido === 'true' &&
51 | correo.valido === 'true' &&
52 | telefono.valido === 'true' &&
53 | terminos
54 | ){
55 | cambiarFormularioValido(true);
56 | cambiarUsuario({campo: '', valido: ''});
57 | cambiarNombre({campo: '', valido: null});
58 | cambiarPassword({campo: '', valido: null});
59 | cambiarPassword2({campo: '', valido: 'null'});
60 | cambiarCorreo({campo: '', valido: null});
61 | cambiarTelefono({campo: '', valido: null});
62 |
63 | // ...
64 | } else {
65 | cambiarFormularioValido(false);
66 | }
67 | }
68 |
69 | return (
70 |
71 |
72 |
82 |
92 |
101 |
110 |
120 |
130 |
131 |
132 |
133 |
134 |
144 |
145 | {formularioValido === false &&
146 |
147 |
148 | Error: Por favor rellena el formulario correctamente.
149 |
150 | }
151 |
152 | Enviar
153 | {formularioValido === true && Formulario enviado exitosamente!}
154 |
155 |
156 |
157 | );
158 | }
159 |
160 | export default App;
--------------------------------------------------------------------------------
/src/componentes/Input.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Input, Label, GrupoInput, LeyendaError, IconoValidacion} from './../elementos/Formularios';
3 | import { faCheckCircle, faTimesCircle } from '@fortawesome/free-solid-svg-icons';
4 |
5 | const ComponenteInput = ({estado, cambiarEstado, tipo, label, placeholder, name, leyendaError, expresionRegular, funcion}) => {
6 | const onChange = (e) => {
7 | cambiarEstado({...estado, campo: e.target.value});
8 | }
9 |
10 | const validacion = () => {
11 | if(expresionRegular){
12 | if(expresionRegular.test(estado.campo)){
13 | cambiarEstado({...estado, valido: 'true'});
14 | } else {
15 | cambiarEstado({...estado, valido: 'false'});
16 | }
17 | }
18 |
19 | if(funcion){
20 | funcion();
21 | }
22 | }
23 |
24 | return (
25 |
26 |
27 |
28 |
38 |
42 |
43 | {leyendaError}
44 |
45 | );
46 | }
47 |
48 | export default ComponenteInput;
--------------------------------------------------------------------------------
/src/elementos/Formularios.js:
--------------------------------------------------------------------------------
1 | import styled, {css} from 'styled-components';
2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3 |
4 | const colores = {
5 | borde: "#0075FF",
6 | error: "#bb2929",
7 | exito: "#1ed12d"
8 | }
9 |
10 | const Formulario = styled.form`
11 | display: grid;
12 | grid-template-columns: 1fr 1fr;
13 | gap: 20px;
14 |
15 | @media (max-width: 800px){
16 | grid-template-columns: 1fr;
17 | }
18 | `;
19 |
20 | const Label = styled.label`
21 | display: block;
22 | font-weight: 700;
23 | padding: 10px;
24 | min-height: 40px;
25 | cursor: pointer;
26 |
27 | ${props => props.valido === 'false' && css`
28 | color: ${colores.error};
29 | `}
30 | `;
31 |
32 | const GrupoInput = styled.div`
33 | position: relative;
34 | z-index: 90;
35 | `;
36 |
37 | const Input = styled.input`
38 | width: 100%;
39 | background: #fff;
40 | border-radius: 3px;
41 | height: 45px;
42 | line-height: 45px;
43 | padding: 0 40px 0 10px;
44 | transition: .3s ease all;
45 | border: 3px solid transparent;
46 |
47 | &:focus {
48 | border: 3px solid ${colores.borde};
49 | outline: none;
50 | box-shadow: 3px 0px 30px rgba(163,163,163, 0.4);
51 | }
52 |
53 | ${props => props.valido === 'true' && css`
54 | border: 3px solid transparent;
55 | `}
56 |
57 | ${props => props.valido === 'false' && css`
58 | border: 3px solid ${colores.error} !important;
59 | `}
60 | `;
61 |
62 | const LeyendaError = styled.p`
63 | font-size: 12px;
64 | margin-bottom: 0;
65 | color: ${colores.error};
66 | display: none;
67 |
68 | ${props => props.valido === 'true' && css`
69 | display: none;
70 | `}
71 |
72 | ${props => props.valido === 'false' && css`
73 | display: block;
74 | `}
75 | `;
76 |
77 | const IconoValidacion = styled(FontAwesomeIcon)`
78 | position: absolute;
79 | right: 10px;
80 | bottom: 14px;
81 | z-index: 100;
82 | font-size: 16px;
83 | opacity: 0;
84 |
85 | ${props => props.valido === 'false' && css`
86 | opacity: 1;
87 | color: ${colores.error};
88 | `}
89 |
90 | ${props => props.valido === 'true' && css`
91 | opacity: 1;
92 | color: ${colores.exito};
93 | `}
94 | `;
95 |
96 | const ContenedorTerminos = styled.div`
97 | grid-column: span 2;
98 |
99 | input {
100 | margin-right: 10px;
101 | }
102 |
103 | @media (max-width: 800px){
104 | grid-column: span 1;
105 | }
106 | `;
107 |
108 | const ContenedorBotonCentrado = styled.div`
109 | display: flex;
110 | flex-direction: column;
111 | align-items: center;
112 | grid-column: span 2;
113 |
114 | @media (max-width: 800px){
115 | grid-column: span 1;
116 | }
117 | `;
118 |
119 | const Boton = styled.button`
120 | height: 45px;
121 | line-height: 45px;
122 | width: 30%;
123 | background: #000;
124 | color: #fff;
125 | font-weight: bold;
126 | border: none;
127 | border-radius: 3px;
128 | cursor: pointer;
129 | transition: .1s ease all;
130 |
131 | &:hover {
132 | box-shadow: 3px 0px 30px rgba(163,163,163, 1);
133 | }
134 | `;
135 |
136 | const MensajeExito = styled.p`
137 | font-size: 14px;
138 | color: ${colores.exito};
139 | `;
140 |
141 | const MensajeError = styled.div`
142 | height: 45px;
143 | line-height: 45px;
144 | background: #F66060;
145 | padding: 0px 15px;
146 | border-radius: 3px;
147 | grid-column: span 2;
148 | p {
149 | margin: 0;
150 | }
151 | b {
152 | margin-left: 10px;
153 | }
154 | `;
155 |
156 | export {
157 | Formulario,
158 | Label,
159 | GrupoInput,
160 | Input,
161 | LeyendaError,
162 | IconoValidacion,
163 | ContenedorTerminos,
164 | ContenedorBotonCentrado,
165 | Boton,
166 | MensajeExito,
167 | MensajeError
168 | };
--------------------------------------------------------------------------------
/src/estilos.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background: #e5e5e5;
9 | font-family: 'Roboto', sans-serif;
10 | }
11 |
12 | main {
13 | max-width: 800px;
14 | width: 90%;
15 | margin: auto;
16 | padding: 40px;
17 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import './estilos.css';
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById('root')
11 | );
--------------------------------------------------------------------------------