From dbb6ec4e1f8678572cb4cc02cc055b3c520366a4 Mon Sep 17 00:00:00 2001 From: Francisco Monleon Date: Mon, 6 Mar 2023 13:29:44 +0100 Subject: [PATCH 1/3] init branch froms --- src/03-forms/styles/styles.css | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/03-forms/styles/styles.css diff --git a/src/03-forms/styles/styles.css b/src/03-forms/styles/styles.css new file mode 100644 index 000000000..8ef67738e --- /dev/null +++ b/src/03-forms/styles/styles.css @@ -0,0 +1,25 @@ +form { + display: flex; + flex-direction: column; + width: 400px; +} + +input, select { + margin-top: 5px; + outline: none; + padding: 10px; +} + + +button { + margin-top: 20px; + padding: 10px; +} + +span, .error-message { + color: red; +} + +.has-error { + border: 1px solid red; +} \ No newline at end of file From 7796d00620b1a17e71fec8e4ac689093a6f26e7a Mon Sep 17 00:00:00 2001 From: Francisco Monleon Date: Mon, 3 Apr 2023 21:35:27 +0200 Subject: [PATCH 2/3] formik - components - field --- package.json | 4 +- src/03-forms/components/MyCheckBox.tsx | 23 +++++ src/03-forms/components/MySelect.tsx | 22 +++++ src/03-forms/components/MyTextInput.tsx | 28 ++++++ src/03-forms/components/index.ts | 3 + src/03-forms/hooks/useForm.ts | 35 ++++++++ src/03-forms/pages/FormikAbstractionPage.tsx | 92 +++++++++++++++++++ src/03-forms/pages/FormikBasicPage.tsx | 95 ++++++++++++++++++++ src/03-forms/pages/FormikComponentPage.tsx | 87 ++++++++++++++++++ src/03-forms/pages/FormikYupPage.tsx | 68 ++++++++++++++ src/03-forms/pages/RegisterPage.tsx | 86 ++++++++++++++++++ src/03-forms/pages/index.ts | 5 ++ src/routes/Navigation.tsx | 40 ++++++++- yarn.lock | 66 +++++++++++++- 14 files changed, 648 insertions(+), 6 deletions(-) create mode 100644 src/03-forms/components/MyCheckBox.tsx create mode 100644 src/03-forms/components/MySelect.tsx create mode 100644 src/03-forms/components/MyTextInput.tsx create mode 100644 src/03-forms/components/index.ts create mode 100644 src/03-forms/hooks/useForm.ts create mode 100644 src/03-forms/pages/FormikAbstractionPage.tsx create mode 100644 src/03-forms/pages/FormikBasicPage.tsx create mode 100644 src/03-forms/pages/FormikComponentPage.tsx create mode 100644 src/03-forms/pages/FormikYupPage.tsx create mode 100644 src/03-forms/pages/RegisterPage.tsx create mode 100644 src/03-forms/pages/index.ts diff --git a/package.json b/package.json index d9a0e2130..52fe7caf0 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,14 @@ "@types/node": "^12.0.0", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", + "formik": "^2.2.9", "react": "^17.0.2", "react-dom": "^17.0.2", "react-router-dom": "^5.3.0", "react-scripts": "4.0.3", "typescript": "^4.1.2", - "web-vitals": "^1.0.1" + "web-vitals": "^1.0.1", + "yup": "^1.0.2" }, "scripts": { "start": "react-scripts start", diff --git a/src/03-forms/components/MyCheckBox.tsx b/src/03-forms/components/MyCheckBox.tsx new file mode 100644 index 000000000..a55656e08 --- /dev/null +++ b/src/03-forms/components/MyCheckBox.tsx @@ -0,0 +1,23 @@ +import { ErrorMessage, useField } from 'formik'; + +interface Props { + label: string; + name: string; + [x: string]: any; +} + + +export const MyCheckbox = ({ label, ...props }: Props ) => { + + const [ field ] = useField({ ...props, type: 'checkbox' }); + + return ( + <> + + + + ) +} diff --git a/src/03-forms/components/MySelect.tsx b/src/03-forms/components/MySelect.tsx new file mode 100644 index 000000000..3a9477ceb --- /dev/null +++ b/src/03-forms/components/MySelect.tsx @@ -0,0 +1,22 @@ +import { ErrorMessage, useField } from 'formik'; + +interface Props { + label: string; + name: string; + placeholder?: string; + [x: string]: any; +} + + +export const MySelect = ( { label, ...props }: Props ) => { + + const [ field ] = useField(props) + + return ( + <> + + + + {/* { + meta.touched && meta?.error && ( + {meta.error} + ) + } */} + + ) +} diff --git a/src/03-forms/components/index.ts b/src/03-forms/components/index.ts new file mode 100644 index 000000000..17683fdba --- /dev/null +++ b/src/03-forms/components/index.ts @@ -0,0 +1,3 @@ +export * from "./MyCheckBox"; +export * from "./MyTextInput"; +export * from "./MySelect"; diff --git a/src/03-forms/hooks/useForm.ts b/src/03-forms/hooks/useForm.ts new file mode 100644 index 000000000..0693bf1fb --- /dev/null +++ b/src/03-forms/hooks/useForm.ts @@ -0,0 +1,35 @@ +import { ChangeEvent, FormEvent, useState } from "react"; + +export const useForm = (initialData: T) => { + const [formData, setFormData] = useState(initialData); + + const onChange = (event: ChangeEvent) => { + setFormData({ + ...formData, + [event.target.name]: event.target.value, + }); + }; + + const onSubmit = (e: FormEvent) => { + e.preventDefault(); + console.log({ formData }); + }; + + const reset = () => { + setFormData({ ...initialData }); + }; + + const isValidEmail = ( email: string ) => { + const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(email); + } + + return { + ...formData, + formData, + onChange, + onSubmit, + reset, + isValidEmail + }; +}; diff --git a/src/03-forms/pages/FormikAbstractionPage.tsx b/src/03-forms/pages/FormikAbstractionPage.tsx new file mode 100644 index 000000000..05b747ab7 --- /dev/null +++ b/src/03-forms/pages/FormikAbstractionPage.tsx @@ -0,0 +1,92 @@ +import { Formik, Form } from 'formik'; +import * as Yup from 'yup'; + +import { MyCheckbox, MyTextInput, MySelect } from '../components' + +import '../styles/styles.css' + + + +const FormikAbstractionPage = () => { + + return ( +
+

Formik Abstractation

+ + { + console.log( values ) + }} + validationSchema={Yup.object({ + firstName: Yup.string() + .max(15, 'Debe de tener 15 caracteres o menos') + .required('Requerido'), + lastName: Yup.string() + .max(15, 'Debe de tener 15 caracteres o menos') + .required('Requerido'), + email: Yup.string() + .email('El correo no tiene un formato válido') + .required('Requerido'), + terms: Yup.boolean() + .oneOf([true], 'Debe de aceptar las condiciones'), + jobType: Yup.string() + .notOneOf([ 'it-jr' ], 'Esta opción no es permitida.') + .required('Requerido') + }) + }> + + {(formik) => ( +
+ + + + + + + + + + + + + + + + + + + + ) + } + + +
+ + + + +
+ ) +} + +export default FormikAbstractionPage \ No newline at end of file diff --git a/src/03-forms/pages/FormikBasicPage.tsx b/src/03-forms/pages/FormikBasicPage.tsx new file mode 100644 index 000000000..f866de853 --- /dev/null +++ b/src/03-forms/pages/FormikBasicPage.tsx @@ -0,0 +1,95 @@ +import { FormikErrors, useFormik } from 'formik' +import React from 'react' +import '../styles/styles.css' + +interface FormValues { + firstName: string + lastName: string + email: string +} + +const FormikBasicPage = () => { + + const validate = ({ firstName, lastName, email }:FormValues) => { + + const errors:FormikErrors = {} + + if (!firstName) { + errors.firstName = 'El nombre is required' + }else if(firstName.length < 3 ){ + errors.firstName = 'El nombre min length >=3' + } + if (!lastName) { + errors.lastName = 'El apellido is required' + }else if(lastName.length < 3 ){ + errors.lastName = 'El apellido min length >=3' + } + if (!email) { + errors.email = 'El email is required'; + } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) { + errors.email = 'Invalid email address'; + } + + return errors + } + + const { handleChange, values, handleSubmit, errors, touched, handleBlur } = useFormik({ + initialValues: { + firstName: '', + lastName: '', + email: '' + }, + onSubmit: (values) => { + console.log({values}) + }, + validate: (values) => validate(values) + }) + + + return ( +
+

Formik Basic Tutorial

+
+ + + { touched.firstName && errors.firstName && {errors.firstName} } + + + + { touched.lastName && errors.lastName && {errors.lastName} } + + + + { touched.email && errors.email && {errors.email} } + + +
+
+ ) +} + +export default FormikBasicPage \ No newline at end of file diff --git a/src/03-forms/pages/FormikComponentPage.tsx b/src/03-forms/pages/FormikComponentPage.tsx new file mode 100644 index 000000000..8c37360a1 --- /dev/null +++ b/src/03-forms/pages/FormikComponentPage.tsx @@ -0,0 +1,87 @@ +import { Field, ErrorMessage, Form, Formik } from 'formik' +import React from 'react' +import * as Yup from 'yup' +import '../styles/styles.css' + + + +const FormikComponentPage = () => { + + + return ( +
+

Formik Component Tutorial

+ { + console.log( values ) + }} + validationSchema={Yup.object({ + firstName: Yup.string() + .max(15, 'Debe de tener 15 caracteres o menos') + .required('Requerido'), + lastName: Yup.string() + .max(15, 'Debe de tener 15 caracteres o menos') + .required('Requerido'), + email: Yup.string() + .email('El correo no tiene un formato válido') + .required('Requerido'), + terms: Yup.boolean() + .oneOf([true], 'Debe de aceptar las condiciones'), + jobType: Yup.string() + .notOneOf([ 'it-jr' ], 'Esta opción no es permitida.') + .required('Requerido') + }) + }> + + {(formik) => ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + } + + +
+ +
+ ) +} + +export default FormikComponentPage \ No newline at end of file diff --git a/src/03-forms/pages/FormikYupPage.tsx b/src/03-forms/pages/FormikYupPage.tsx new file mode 100644 index 000000000..dbd9c14cd --- /dev/null +++ b/src/03-forms/pages/FormikYupPage.tsx @@ -0,0 +1,68 @@ +import { useFormik } from 'formik' +import React from 'react' +import * as Yup from 'yup' +import '../styles/styles.css' + + + +const FormikYupPage = () => { + + + const { + handleSubmit, errors, + touched, getFieldProps +} = useFormik({ + initialValues: { + firstName: '', + lastName: '', + email: '' + }, + onSubmit: (values) => { + console.log({values}) + }, + validationSchema: Yup.object({ + firstName: Yup.string().required('El nombre es requerido').min(3, 'Minimo 3 caracteres'), + lastName: Yup.string().required('El apellido es requerido').min(3, 'Minimo 3 caracteres'), + email: Yup.string().required('El nombre es requerido').email('Debe de ser un email valido') + }) + }) + + + return ( +
+

Formik Yup Tutorial

+
+ + + { touched.firstName && errors.firstName && {errors.firstName} } + + + + { touched.lastName && errors.lastName && {errors.lastName} } + + + + { touched.email && errors.email && {errors.email} } + + +
+
+ ) +} + +export default FormikYupPage \ No newline at end of file diff --git a/src/03-forms/pages/RegisterPage.tsx b/src/03-forms/pages/RegisterPage.tsx new file mode 100644 index 000000000..4bf2e1d9e --- /dev/null +++ b/src/03-forms/pages/RegisterPage.tsx @@ -0,0 +1,86 @@ +import { useRef } from 'react' +import { useForm } from '../hooks/useForm' +import '../styles/styles.css' + +type DataForm = { + name: string + email: string + password1: string + password2: string +} + + +const RegisterPage = () => { + + const { formData: { name, email, password1, password2 }, onChange, onSubmit, reset, isValidEmail } = useForm({ + name: '', + email: '', + password1: '', + password2: '' + }) + + const nameFocus = useRef(false) + const emailFocus = useRef(false) + const password1Focus = useRef(false) + const password2Focus = useRef(false) + + return ( +
+

RegisterPage

+
onSubmit(e)}> + { + nameFocus.current = true + }} + className={ nameFocus.current && name.trim().length <= 3 ? 'has-error' : ''} + type="text" name="name" + id="name" + placeholder='Name' + value={name} + onChange={(e) => onChange(e)} /> + { nameFocus.current && name.trim().length <= 0 && Este campo es necesario} + { + emailFocus.current = true + }} + className= {emailFocus.current && (!isValidEmail(email.trim()) || email.trim().length <= 0 ) ? 'has-error' : ''} + type="email" + name="email" + id="email" + placeholder='Email' + value={email} + onChange={(e) => onChange(e)} /> + { emailFocus.current && !isValidEmail(email.trim()) && El formato de email no es correcto} + { + password1Focus.current = true + }} + className= { password1Focus.current && (password1.trim().length < 6) ? 'has-error' : ''} + type="password" + name="password1" + id="password1" + placeholder='Password' + value={password1} + onChange={(e) => onChange(e)}/> + { password1Focus.current && password1.trim().length < 6 && Minimo 6 caracteres} + { + password2Focus.current = true + }} + className= { password2Focus.current && (password2.trim() !== password1.trim()) ? 'has-error' : ''} + type="password" + name="password2" + id="password2" + placeholder='Repeat password' + value={password2} + onChange={(e) => onChange(e)} /> + { password2Focus.current && password2.trim() !== password1.trim() && Las dos contraseñas deben ser iguales} + + +
+
+ + ) +} + +export default RegisterPage \ No newline at end of file diff --git a/src/03-forms/pages/index.ts b/src/03-forms/pages/index.ts new file mode 100644 index 000000000..f2b557f0f --- /dev/null +++ b/src/03-forms/pages/index.ts @@ -0,0 +1,5 @@ +export * as FormikAbstractionPage from './FormikAbstractionPage' +export * as FormikYupPage from './FormikYupPage' +export * as FormikComponentPage from './FormikComponentPage' +export * as FormikBasicPage from './FormikBasicPage' +export * as RegisterPage from './RegisterPage' diff --git a/src/routes/Navigation.tsx b/src/routes/Navigation.tsx index a9bfe83b0..1be46cdaa 100644 --- a/src/routes/Navigation.tsx +++ b/src/routes/Navigation.tsx @@ -4,8 +4,15 @@ import { Route, NavLink } from 'react-router-dom'; - import logo from '../logo.svg'; +import RegisterPage from '../03-forms/pages/RegisterPage'; +import FormikBasicPage from '../03-forms/pages/FormikBasicPage'; +import FormikYupPage from '../03-forms/pages/FormikYupPage'; +import FormikComponentPage from '../03-forms/pages/FormikComponentPage'; +import FormikAbstractionPage from '../03-forms/pages/FormikAbstractionPage'; + + + export const Navigation = () => { return ( @@ -17,6 +24,22 @@ export const Navigation = () => {
  • Home
  • + +
  • + Register Page +
  • +
  • + Formik Basic +
  • +
  • + Formik Yup +
  • +
  • + Formik Component +
  • +
  • + Formik Abstraction +
  • About
  • @@ -29,6 +52,21 @@ export const Navigation = () => { {/* A looks through its children s and renders the first one that matches the current URL. */} + + + + + + + + + + + + + + +

    About

    diff --git a/yarn.lock b/yarn.lock index de24f7d62..7dc79833e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4001,6 +4001,11 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" @@ -5125,6 +5130,19 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formik@^2.2.9: + version "2.2.9" + resolved "https://registry.yarnpkg.com/formik/-/formik-2.2.9.tgz#8594ba9c5e2e5cf1f42c5704128e119fc46232d0" + integrity sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA== + dependencies: + deepmerge "^2.1.1" + hoist-non-react-statics "^3.3.0" + lodash "^4.17.21" + lodash-es "^4.17.21" + react-fast-compare "^2.0.1" + tiny-warning "^1.0.2" + tslib "^1.10.0" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -5510,7 +5528,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.1.0: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -7008,6 +7026,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -7043,7 +7066,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8907,6 +8930,11 @@ prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +property-expr@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" + integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== + proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -9118,6 +9146,11 @@ react-error-overlay@^6.0.9: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== +react-fast-compare@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -10626,12 +10659,17 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-case@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" + integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== + tiny-invariant@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== -tiny-warning@^1.0.0, tiny-warning@^1.0.3: +tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -10688,6 +10726,11 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" + integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== + tough-cookie@^2.3.3, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -10732,7 +10775,7 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -10805,6 +10848,11 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -11617,3 +11665,13 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yup@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/yup/-/yup-1.0.2.tgz#1cf485f407f77e0407b450311f2981a1e66f7c58" + integrity sha512-Lpi8nITFKjWtCoK3yQP8MUk78LJmHWqbFd0OOMXTar+yjejlQ4OIIoZgnTW1bnEUKDw6dZBcy3/IdXnt2KDUow== + dependencies: + property-expr "^2.0.5" + tiny-case "^1.0.3" + toposort "^2.0.2" + type-fest "^2.19.0" From b59d66436b8dca4595f33e69317c247a9ae0cf55 Mon Sep 17 00:00:00 2001 From: Francisco Monleon Date: Wed, 12 Apr 2023 20:16:30 +0200 Subject: [PATCH 3/3] formualrios dinamicos --- src/03-forms/data/custom-form.json | 46 ++++++++++ src/03-forms/pages/FormikAbstractionPage.tsx | 1 + src/03-forms/pages/FormikDynamicForm.tsx | 89 ++++++++++++++++++++ src/03-forms/pages/RegisterFormikPage.tsx | 78 +++++++++++++++++ src/03-forms/pages/index.ts | 1 + src/routes/Navigation.tsx | 14 +++ 6 files changed, 229 insertions(+) create mode 100644 src/03-forms/data/custom-form.json create mode 100644 src/03-forms/pages/FormikDynamicForm.tsx create mode 100644 src/03-forms/pages/RegisterFormikPage.tsx diff --git a/src/03-forms/data/custom-form.json b/src/03-forms/data/custom-form.json new file mode 100644 index 000000000..58624d76e --- /dev/null +++ b/src/03-forms/data/custom-form.json @@ -0,0 +1,46 @@ +[ + { + "type": "input", + "inputType": "text", + "name": "firstName", + "placeholder": "your name", + "label": "First Name", + "value": "", + "validations": [{ "type": "required" }, { "type": "minLength", "value": 3 }] + }, + { + "type": "input", + "inputType": "text", + "name": "lastName", + "placeholder": "your last name", + "label": "Last Name", + "value": "", + "validations": [{ "type": "required" }, { "type": "minLength", "value": 3 }] + }, + { + "type": "input", + "inputType": "email", + "name": "email", + "placeholder": "your email @", + "label": "Email", + "value": "", + "validations": [ + { "type": "required" }, + { "type": "email" } + ] + }, + { + "type": "select", + "inputType": "", + "name": "favouriteGame", + "placeholder": "", + "label": "Favourite Game", + "value": "", + "validations": [{ "type": "required" }], + "options": [ + { "id": 1, "label": "Super Smash" }, + { "id": 2, "label": "Metal Gear" }, + { "id": 3, "label": "Resident Evil" } + ] + } +] diff --git a/src/03-forms/pages/FormikAbstractionPage.tsx b/src/03-forms/pages/FormikAbstractionPage.tsx index 05b747ab7..e44104208 100644 --- a/src/03-forms/pages/FormikAbstractionPage.tsx +++ b/src/03-forms/pages/FormikAbstractionPage.tsx @@ -74,6 +74,7 @@ const FormikAbstractionPage = () => { + ) diff --git a/src/03-forms/pages/FormikDynamicForm.tsx b/src/03-forms/pages/FormikDynamicForm.tsx new file mode 100644 index 000000000..ed7f29e49 --- /dev/null +++ b/src/03-forms/pages/FormikDynamicForm.tsx @@ -0,0 +1,89 @@ +import React from 'react' +import {Field, Form, Formik} from 'formik' +import formJson from '../data/custom-form.json' +import { MySelect, MyTextInput } from '../components' +import * as Yup from 'yup'; + +const initialValues: { [key:string] : any} = {} +const requiredFields: { [key:string] : any} = {} + +for (const item of formJson) { + Object.assign(initialValues, {[item.name]: item.value}) + + if (!item.validations) { continue } + let schema = Yup.string() + for (const validation of item.validations) { + if (validation.type === 'required') { + schema = schema.required("Required") + } + if (validation.type === 'email') { + schema = schema.email("Formato de email no valido") + } + if (validation.type === 'minLength') { + schema = schema.min((validation as any).value, `Minimo ${(validation as any).value} caracteres`) + } + } + requiredFields[item.name] = schema +} + +const FormikDynamicFormPage = () => { + return ( +
    +

    Formik Dynamic Form

    + { + console.log({values}) + }} + validationSchema={ + Yup.object({...requiredFields}) + } + > + {(formik)=>( +
    + { + formJson.map( ({label, name, type, inputType, placeholder, options}) => { + + if (type == "input") { + return + + } + + if (type === 'select') { + return + + { + + options!.map( item =>( + + )) + } + + } + + throw new Error(`Campo ${type} no soportado`); + + + }) + } + + + + )} +
    +
    + ) +} + +export default FormikDynamicFormPage \ No newline at end of file diff --git a/src/03-forms/pages/RegisterFormikPage.tsx b/src/03-forms/pages/RegisterFormikPage.tsx new file mode 100644 index 000000000..1cad5c1fb --- /dev/null +++ b/src/03-forms/pages/RegisterFormikPage.tsx @@ -0,0 +1,78 @@ +import '../styles/styles.css' +import { ErrorMessage, Field, Form, Formik } from 'formik' +import * as Yup from 'yup' +import { MyTextInput } from '../components/MyTextInput'; + +type DataForm = { + name: string + email: string + password1: string + password2: string +} + + +const RegisterFormikPage = () => { + + return ( +
    +

    Register Formik Page

    + { + console.log( values ) + }} + onReset={ ()=> console.log('reset') } + validationSchema={Yup.object({ + name: Yup.string() + .required('Requerido') + .min(3, 'Debe de tener 3 o mas caracteres') + .max(15, 'Debe de tener 15 caracteres o menos'), + email: Yup.string() + .required('Requerido') + .email('El correo no tiene un formato válido'), + password1: Yup.string() + .required() + .min(6, 'Minimo 6 caracteres'), + password2: Yup.string() + .required() + .min(6, 'Minimo 6 caracteres' ) + .oneOf([Yup.ref('password1')], 'Los password deben ser iguales') + }) + } + > + + { + (formik) => ( +
    + + + + + + + + + + < MyTextInput + label='password2' + name='password2' + type='password' + /> + + + + ) + } +
    + +
    + + ) +} + +export default RegisterFormikPage \ No newline at end of file diff --git a/src/03-forms/pages/index.ts b/src/03-forms/pages/index.ts index f2b557f0f..10084f18b 100644 --- a/src/03-forms/pages/index.ts +++ b/src/03-forms/pages/index.ts @@ -3,3 +3,4 @@ export * as FormikYupPage from './FormikYupPage' export * as FormikComponentPage from './FormikComponentPage' export * as FormikBasicPage from './FormikBasicPage' export * as RegisterPage from './RegisterPage' +export * as FormikDynamicFormPage from './FormikDynamicForm' diff --git a/src/routes/Navigation.tsx b/src/routes/Navigation.tsx index 1be46cdaa..efc48972e 100644 --- a/src/routes/Navigation.tsx +++ b/src/routes/Navigation.tsx @@ -10,6 +10,8 @@ import FormikBasicPage from '../03-forms/pages/FormikBasicPage'; import FormikYupPage from '../03-forms/pages/FormikYupPage'; import FormikComponentPage from '../03-forms/pages/FormikComponentPage'; import FormikAbstractionPage from '../03-forms/pages/FormikAbstractionPage'; +import RegisterFormikPage from '../03-forms/pages/RegisterFormikPage'; +import FormikDynamicFormPage from '../03-forms/pages/FormikDynamicForm'; @@ -28,6 +30,9 @@ export const Navigation = () => {
  • Register Page
  • +
  • + Register Formik Page +
  • Formik Basic
  • @@ -40,6 +45,9 @@ export const Navigation = () => {
  • Formik Abstraction
  • +
  • + Formik Dynamic +
  • About
  • @@ -55,6 +63,9 @@ export const Navigation = () => { + + + @@ -67,6 +78,9 @@ export const Navigation = () => { + + +

    About