Add Contact page

master
Ian Mancini 4 years ago
parent 7e11780f1c
commit 8f25dce7cb

41
package-lock.json generated

@ -8937,6 +8937,11 @@
"shallowequal": "^1.1.0"
}
},
"react-hook-form": {
"version": "6.12.2",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-6.12.2.tgz",
"integrity": "sha512-O72E2DXyk7djFqyy6eYi5yESGweKe0CNHHPS0Mx4JazpLbE4Ox+66ldZ23f0J5ZN/krEjDWRD+hUfg5Shvfhtw=="
},
"react-icons": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.11.0.tgz",
@ -9031,6 +9036,16 @@
}
}
},
"react-textarea-autosize": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.0.tgz",
"integrity": "sha512-3GLWFAan2pbwBeoeNDoqGmSbrShORtgWfaWX0RJDivsUrpShh01saRM5RU/i4Zmf+whpBVEY5cA90Eq8Ub1N3w==",
"requires": {
"@babel/runtime": "^7.10.2",
"use-composed-ref": "^1.0.0",
"use-latest": "^1.0.0"
}
},
"react-textfit": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/react-textfit/-/react-textfit-1.1.0.tgz",
@ -10870,6 +10885,11 @@
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA=="
},
"ts-essentials": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz",
"integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w=="
},
"ts-pnp": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
@ -11190,6 +11210,27 @@
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.4.tgz",
"integrity": "sha512-rXpsyvOnqdScyied4Uglsp14qzag1JIemLeTWGKbwpotWht57hbP78aNT+Q4wdFKQfQibbUX4fb6Qb4y11aVOQ=="
},
"use-composed-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz",
"integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==",
"requires": {
"ts-essentials": "^2.0.3"
}
},
"use-isomorphic-layout-effect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.0.tgz",
"integrity": "sha512-kady5Z1O1qx5RitodCCKbpJSVEtECXYcnBnb5Q48Bz5V6gBmTu85ZcGdVwVFs8+DaOurNb/L5VdGHoQRMknghw=="
},
"use-latest": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz",
"integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==",
"requires": {
"use-isomorphic-layout-effect": "^1.0.0"
}
},
"use-sidecar": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.3.tgz",

@ -43,8 +43,10 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-headroom": "^3.0.0",
"react-hook-form": "^6.12.2",
"react-icons": "^3.11.0",
"react-markdown": "^5.0.3",
"react-textarea-autosize": "^8.3.0",
"react-textfit": "^1.1.0",
"responsive-loader": "^2.2.0",
"sharp": "^0.26.3",

@ -0,0 +1,185 @@
import { useState, forwardRef } from 'react'
import { useFormContext } from 'react-hook-form'
import TextareaAutosize from 'react-textarea-autosize'
import {
Button,
Flex,
Stack,
Box,
Text,
Input,
FormControl,
FormErrorMessage,
InputProps,
Textarea,
} from '@chakra-ui/react'
const CustomInput = forwardRef<HTMLInputElement, InputProps>(
({ name, ...props }, ref) => {
return (
<Input
name={name}
type="text"
variant="flushed"
borderColor="gray"
borderBottomWidth="1px"
focusBorderColor="primary"
ref={ref}
_disabled={{ color: 'gray' }}
_autofill={{ background: 'none' }}
{...props}
/>
)
},
)
CustomInput.displayName = 'CustomInput'
type FormFields = {
name: string
email: string
message: string
}
const sendMessage = async () => {
return new Promise((resolve) => {
setTimeout(() => {
alert('¡Este formulario no es real!')
resolve(true)
}, 1500)
})
}
const ContactForm: React.FC = () => {
const [sending, setSending] = useState(false)
const [error, setError] = useState(false)
const { formState, register, handleSubmit, errors, reset } = useFormContext()
const { isSubmitSuccessful } = formState
const onSubmit = async (/* data: FormFields */) => {
setSending(true)
setError(false)
sendMessage()
.then(() => {
setSending(false)
setError(false)
})
.catch(() => {
setSending(false)
setError(true)
})
}
const buttonText = (() => {
if (sending) {
return 'Enviando'
}
if (isSubmitSuccessful) {
return '¡Enviado!'
}
return 'Enviar'
})()
return (
<Box w="100%">
<Stack
as="form"
onSubmit={handleSubmit(onSubmit)}
flexDir="column"
flexWrap="nowrap"
w="480px"
maxW="calc(100% - 4rem)"
m="2rem auto"
spacing="3rem"
>
<FormControl id="name" isInvalid={errors.name}>
<CustomInput
name="name"
placeholder="Nombre"
aria-label="Nombre"
disabled={isSubmitSuccessful}
ref={register({ required: true })}
/>
<FormErrorMessage>Este campo es obligatorio</FormErrorMessage>
</FormControl>
<FormControl id="email" isInvalid={errors.email}>
<CustomInput
name="email"
placeholder="e-mail"
aria-label="e-mail"
disabled={isSubmitSuccessful}
ref={register({
required: true,
pattern: /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/,
})}
/>
<FormErrorMessage>
{errors.email
? errors.email.type === 'required'
? 'Este campo es obligatorio'
: null || errors.email.type === 'pattern'
? 'La dirección de correo electrónico no es válida'
: null
: null}
</FormErrorMessage>
</FormControl>
<FormControl id="message" isInvalid={errors.message}>
<Textarea
as={TextareaAutosize}
minRows={1}
borderBottomWidth="1px"
name="message"
aria-label="mensaje"
placeholder="Mensaje"
resize="none"
minH={0}
variant="flushed"
borderColor="gray"
focusBorderColor="primary"
overflow="hidden"
disabled={isSubmitSuccessful}
ref={register({ required: true })}
_disabled={{ color: 'gray' }}
/>
<FormErrorMessage>Este campo es obligatorio</FormErrorMessage>
</FormControl>
<Flex>
<Input
type="submit"
disabled={sending || isSubmitSuccessful}
opacity="1 !important"
value={buttonText}
bg={sending ? 'lightGray' : isSubmitSuccessful ? 'green' : 'blue'}
borderRadius="primary"
color={sending ? 'gray' : 'white'}
cursor={!sending || !isSubmitSuccessful ? 'pointer' : 'default'}
fontWeight="bold"
border="none"
outline="none"
py="1em"
fontSize="xl"
h="auto"
w="100%"
/>
</Flex>
{error ? (
<Text color="red.500">
Ocurrió un error. Por favor, intentalo nuevamente más tarde.
</Text>
) : null}
{isSubmitSuccessful ? (
<Button variant="link" onClick={() => reset()}>
Enviar un nuevo mensaje
</Button>
) : null}
</Stack>
</Box>
)
}
export default ContactForm

@ -1,4 +1,6 @@
import { Flex, ChakraProvider } from '@chakra-ui/react'
import { FormProvider, useForm } from 'react-hook-form'
import { AppProps } from 'next/app'
import { useRouter } from 'next/router'
import NProgress from 'nprogress'
@ -14,6 +16,7 @@ import theme from '../theme'
const App: React.FC<AppProps> = ({ Component, pageProps }) => {
const router = useRouter()
const methods = useForm({ shouldUnregister: false })
useEffect(() => {
const setDocHeight = () => {
@ -47,10 +50,12 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<ChakraProvider theme={theme} resetCSS>
<FormProvider {...methods}>
<Flex direction="column" minH="calc(var(--vh, 1vh) * 100)" w="100%">
<NavBar />
<Component {...pageProps} />
</Flex>
</FormProvider>
</ChakraProvider>
</>
)

@ -0,0 +1,40 @@
import { Heading, Text, Box, Flex } from '@chakra-ui/react'
import ReactMarkdown from 'react-markdown'
import SEO from '../components/SEO'
import Form from '../components/Form'
const Contact: React.FC = () => {
return (
<>
<SEO title="Contact" />
<Box w={['100%', '100%', '1220px']} pt="2rem" px="1rem" mx="auto">
<Flex wrap="wrap">
<Box w="50%" pr="3rem">
<Heading fontSize={['3xl', '3xl', '7xl']} mb="3rem">
¡Trabajemos juntes!
</Heading>
</Box>
<Box w="50%" pt="6rem">
<Text
as={ReactMarkdown}
fontWeight="300"
lineHeight="1.9"
pb="2rem"
sx={{ p: { display: 'block', pb: '2rem' } }}
>
Mandanos un mensaje y encaremos ese proyecto que tenés en mente :D
</Text>
<Form />
</Box>
</Flex>
</Box>
</>
)
}
export default Contact
export async function getStaticProps() {
return { props: {} }
}

@ -54,6 +54,9 @@ const customTheme = extendTheme({
'.lock-scroll': {
overflow: 'hidden !important',
},
[`input:-internal-autofill-selected`]: {
backgroundColor: 'black !important',
},
// '*': {
// scrollbarWidth: 'auto',
// scrollbarColor: `${green} black`,

Loading…
Cancel
Save