|
- import React, { useEffect } from 'react'
- import PropTypes from 'prop-types'
- import { motion, AnimatePresence } from "framer-motion"
- import { Formik, Form } from 'formik'
- import { Persist } from 'formik-persist'
- import * as Yup from 'yup'
- import ReCAPTCHA from "react-google-recaptcha";
- import FormikControl from '../FormikControls'
- import ButtonPrimary from '../controls/ButtonPrimary'
- import { SubmitFormResult } from '../SubmitFormResult';
-
- export const FormFeedback = (props) => {
- const { setPopupTitle, setPopupContent, setPopupOpened } = props
-
- useEffect(() => {
- if (setPopupTitle) { setPopupTitle('Some feedback form example') }
- })
-
- const sections = [
- {
- label: 'User support',
- value: 'users'
- },
- {
- label: 'Partnership',
- value: 'partners'
- },
- ]
-
- const support_types = [
- {
- label: 'Consulting on product',
- value: 'product'
- },
- {
- label: 'Technical support',
- value: 'technical'
- },
- {
- label: 'Legal support',
- value: 'legal'
- },
- ]
-
- const support_types_values = support_types.map(val => val.value)
-
- const supportTypesMotionVariants = {
- hidden: {
- opacity: 0,
- scaleY: 0,
- transition: {
- type: "linear",
- duration: .2
- }
- },
- visible: {
- opacity: 1,
- scaleY: 1,
- transition: {
- type: "linear",
- duration: .2
- }
- },
- }
-
- const initialValues = {
- user_name: '',
- email: '',
- section: '',
- support_type: [],
- message: '',
- }
-
- const validationSchema = Yup.object({
- user_name: Yup.string()
- .required('Required'),
- email: Yup.string()
- .required('Required')
- .email('Must be a valid email address'),
- section: Yup.mixed()
- .required('Required')
- .oneOf(['users', 'partners'], 'Invalid section'),
- support_type: Yup.array(Yup.string()).ensure().when('section', {
- is: 'users',
- then: Yup.array().required('Required').test('is-valid-support-type', 'Invalid support type', val => {
- const sb = val.filter(n => !support_types_values.includes(n))
- return 0 === sb.length
- }),
- }),
- message: Yup.string()
- .required('Required')
- .max(500, val => `Maximum ${val.max} symbols`),
- })
-
- const recaptchaRef = React.useRef();
-
- const onSubmitWithReCAPTCHA = async (values, { resetForm }) => {
- setPopupOpened(false)
- if (recaptchaRef.current && recaptchaRef.current.executeAsync) {
-
- let token
- try {
- await Promise.race([
- new Promise((_, reject) => setTimeout(() => {
- reject(new Error('timeout'))
- }, 5000)),
- recaptchaRef.current.executeAsync(),
- ])
- .then((v) => {
- token = v
- })
- } catch (error) {
- console.error('app error - catch in try around Promise.race', error)
- token = false
- }
-
- if (token) {
- values.recaptcha = token
-
- // /* // <-- Stub code begin!
- console.log('values', values)
- resetForm()
- resetForm() //api bug workaround - need to call reset twice
- setPopupContent(<SubmitFormResult setPopupTitle={setPopupTitle} data={values} />)
- setPopupOpened(true)
- // */ // <-- Stub code end!
-
- /* // <-- Example code begin!
- const res = await someApiCall(values)
- if ('success' === res.state) {
- resetForm()
- resetForm() //api bug workaround - need to call reset twice
- setFormState('success')
- return
- } else if ('error' === res.state) {
- setFormMessage(res.payload)
- } else {
- setFormMessage('Incorrect server response')
- }
- // */ // <-- Example code end!
-
- } else {
- console.error('app error - reCaptcha token is empty')
- alert('reCaptcha token is empty')
- }
- } else {
- console.error('app error - reCaptcha is not rendered')
- alert('reCaptcha is not rendered')
- }
- }
-
- return (
- <Formik
- initialValues={initialValues}
- validationSchema={validationSchema}
- onSubmit={onSubmitWithReCAPTCHA}
- >
- {formik => {
- return (
- <div className="overflow-y-auto max-h-screen-80">
- <Form className="feedback-form" autoComplete="off">
- <div className="p-3">
- <FormikControl
- control='string'
- name='user_name'
- label='Your name *'
- placeholder='Enter your name'
- autoFocus={true}
- />
- <FormikControl
- control='string'
- name='email'
- label='Email *'
- placeholder='Enter email for reply'
- />
- <FormikControl
- control='radio-group'
- name='section'
- label='Section *'
- options={sections}
- />
- <AnimatePresence>
- {'users' === formik.values.section &&
- <motion.div
- variants={supportTypesMotionVariants}
- initial="hidden"
- animate="visible"
- exit="hidden"
- >
- <FormikControl
- control='checkbox-group'
- name='support_type'
- label='Required types of support *'
- options={support_types}
- />
- </motion.div>
- }
- </AnimatePresence>
- <FormikControl
- control='text'
- name='message'
- label='Message *'
- placeholder='Enter your message'
- />
-
- </div>
- <div className="px-2 pt-4 pb-3 mb-0 bg-primary-200 border-t sm:rounded-b-lg">
- <ButtonPrimary type="submit" text="Send" disabled={!formik.isValid || !formik.dirty} />
- {(!formik.isValid || !formik.dirty)
- ? <div className="error text-center text-sm text-red-700 mt-1 mr-1">Please fill all necessary form fields</div>
- : <div className="text-gray-900 text-center text-sm mt-1 mr-1">
- <div>This site is protected by reCAPTCHA and the Google </div>
- <div>
- <a href="https://policies.google.com/privacy" className="mx-1 hover:underline" rel="noopener noreferrer nofollow" target="_blank">Privacy Policy</a>
- <span> and </span>
- <a href="https://policies.google.com/terms" className="mx-1 hover:underline" rel="noopener noreferrer nofollow" target="_blank">Terms of Service</a> apply.
- </div>
- </div>
- }
- <ReCAPTCHA
- ref={recaptchaRef}
- size="invisible"
- sitekey={window?.appCfg?.reCaptchaSiteKey ?? 'SiteKeyNotFound'}
- />
- </div>
- <Persist name="feedback-form" isSessionStorage />
- </Form>
- </div>
- )
- }}
- </Formik>
- )
- }
-
- export default FormFeedback
-
- FormFeedback.propTypes = {
- setPopupTitle: PropTypes.func,
- setPopupContent: PropTypes.func,
- setPopupOpened: PropTypes.func,
- close: PropTypes.func,
- }
|