1 | import React, { useState, useEffect } from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import {
|
4 | Button,
|
5 | ModalBody,
|
6 | ModalHeader,
|
7 | ModalFooter,
|
8 | FormGroup,
|
9 | } from 'reactstrap';
|
10 | import { avLogMessagesApi, avRegionsApi } from '@availity/api-axios';
|
11 | import { Form, Field } from '@availity/form';
|
12 | import { SelectField } from '@availity/select';
|
13 | import * as yup from 'yup';
|
14 | import SmileField from './SmileField';
|
15 |
|
16 | yup.addMethod(yup.string, 'isRequired', function format(isRequired, msg) {
|
17 | return this.test({
|
18 | name: 'dateRange',
|
19 | exclusive: true,
|
20 | message: msg || 'This field is required.',
|
21 | test(value) {
|
22 | if (isRequired) {
|
23 | return value !== undefined;
|
24 | }
|
25 | return true;
|
26 | },
|
27 | });
|
28 | });
|
29 |
|
30 | const FeedbackForm = ({
|
31 | name,
|
32 | onClose,
|
33 | faceOptions,
|
34 | aboutOptions,
|
35 | onFeedbackSent,
|
36 | prompt,
|
37 | additionalComments,
|
38 | staticFields,
|
39 | analytics,
|
40 | modalHeaderProps,
|
41 | ...formProps
|
42 | }) => {
|
43 | const [active, setActive] = useState(null);
|
44 | const [sent, setSent] = useState(null);
|
45 |
|
46 | const sendFeedback = async ({ smileField, ...values }) => {
|
47 | const response = await avRegionsApi.getCurrentRegion();
|
48 |
|
49 | await analytics.info({
|
50 | surveyId: `${name.replace(/\s/g, '_')}_Smile_Survey`,
|
51 | smileLocation: `${name}`,
|
52 | smile: `icon-${smileField.icon}`,
|
53 | url: window.location.href,
|
54 | region: response.data.regions[0] && response.data.regions[0].id,
|
55 | userAgent: window.navigator.userAgent,
|
56 | submitTime: new Date(),
|
57 | ...values,
|
58 | ...staticFields,
|
59 | });
|
60 |
|
61 | setSent(values);
|
62 | };
|
63 |
|
64 |
|
65 | useEffect(() => {
|
66 | if (sent) {
|
67 | setTimeout(() => {
|
68 | if (onClose) {
|
69 | onClose();
|
70 | }
|
71 | if (onFeedbackSent) {
|
72 | Object.keys(sent).forEach(
|
73 | (key) => sent[key] === undefined && delete sent[key]
|
74 | );
|
75 |
|
76 | onFeedbackSent({
|
77 | active: active.icon,
|
78 | ...sent,
|
79 | });
|
80 | }
|
81 | }, 2000);
|
82 | }
|
83 |
|
84 | }, [sent]);
|
85 |
|
86 | return sent ? (
|
87 | <ModalHeader
|
88 | aria-live="assertive"
|
89 | tabIndex="0"
|
90 | className="d-flex justify-content-center"
|
91 | {...modalHeaderProps}
|
92 | >
|
93 | Thank you for your feedback.
|
94 | </ModalHeader>
|
95 | ) : (
|
96 | <>
|
97 | <ModalHeader
|
98 | aria-live="assertive"
|
99 | id="feedback-form-header"
|
100 | {...modalHeaderProps}
|
101 | >
|
102 | {prompt || `Tell us what you think about ${name}`}
|
103 | </ModalHeader>
|
104 | <Form
|
105 | aria-label="Feedback Form"
|
106 | aria-describedby="feedback-form-header"
|
107 | role="form"
|
108 | data-testid="feedback-form"
|
109 | initialValues={{
|
110 | 'face-options': undefined,
|
111 | additionalFeedback: undefined,
|
112 | feedback: undefined,
|
113 | feedbackApp: undefined,
|
114 | smileField: undefined,
|
115 | }}
|
116 | validationSchema={yup.object().shape({
|
117 | feedback: yup
|
118 | .string()
|
119 | .max(200, 'Additional Feedback cannot exceed 200 characters.')
|
120 | .required('This field is required.'),
|
121 | additionalFeedback: yup
|
122 | .string()
|
123 | .max(200, 'Additional Feedback cannot exceed 200 characters.'),
|
124 | smileField: yup
|
125 | .object()
|
126 | .shape({
|
127 | icon: yup.string().required(),
|
128 | description: yup.string(),
|
129 | placeholder: yup.string(),
|
130 | })
|
131 | .required('This field is required.'),
|
132 | feedbackApp: yup
|
133 | .string()
|
134 | .isRequired(aboutOptions.length > 0, 'This field is required.'),
|
135 | })}
|
136 | {...formProps}
|
137 | onSubmit={(values) => sendFeedback(values)}
|
138 | >
|
139 | <ModalBody>
|
140 | <FormGroup
|
141 | size="lg"
|
142 | id="face-options"
|
143 | data-testid="face-options"
|
144 | className="d-flex flex-row justify-content-between"
|
145 | >
|
146 | <SmileField
|
147 | options={faceOptions}
|
148 | name="smileField"
|
149 | onChange={(option) => setActive(option)}
|
150 | />
|
151 | </FormGroup>
|
152 | {active ? (
|
153 | <>
|
154 | {aboutOptions.length > 0 && (
|
155 | <SelectField
|
156 | name="feedbackApp"
|
157 | id="about-options"
|
158 | data-testid="about-options"
|
159 | placeholder="This is about..."
|
160 | options={aboutOptions}
|
161 | />
|
162 | )}
|
163 | <Field
|
164 | type="textarea"
|
165 | name="feedback"
|
166 | placeholder={
|
167 | (active && active.placeholder) ||
|
168 | 'Feedback? Requests? Defects?'
|
169 | }
|
170 | style={{ resize: 'none' }}
|
171 | rows="2"
|
172 | />
|
173 | {additionalComments && (
|
174 | <Field
|
175 | type="textarea"
|
176 | name="additionalFeedback"
|
177 | placeholder="Additional Comments... (Optional)"
|
178 | style={{ resize: 'none' }}
|
179 | rows="2"
|
180 | />
|
181 | )}
|
182 | </>
|
183 | ) : null}
|
184 | </ModalBody>
|
185 |
|
186 | <ModalFooter>
|
187 | {onClose ? (
|
188 | <Button
|
189 | onClick={onClose}
|
190 | color="secondary"
|
191 | onKeyDown={({ keyCode }) => keyCode === 13 && onClose()}
|
192 | >
|
193 | Close
|
194 | </Button>
|
195 | ) : null}
|
196 | <Button type="submit" color="primary" disabled={!active}>
|
197 | Send Feedback
|
198 | </Button>
|
199 | </ModalFooter>
|
200 | </Form>
|
201 | </>
|
202 | );
|
203 | };
|
204 |
|
205 | FeedbackForm.propTypes = {
|
206 | name: PropTypes.string.isRequired,
|
207 | onFeedbackSent: PropTypes.func,
|
208 | faceOptions: PropTypes.arrayOf(
|
209 | PropTypes.shape({
|
210 | icon: PropTypes.string,
|
211 | description: PropTypes.string,
|
212 | placeholder: PropTypes.string,
|
213 | })
|
214 | ),
|
215 | aboutOptions: PropTypes.arrayOf(
|
216 | PropTypes.shape({
|
217 | name: PropTypes.string,
|
218 | value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
219 | })
|
220 | ),
|
221 | onClose: PropTypes.func,
|
222 | prompt: PropTypes.string,
|
223 | additionalComments: PropTypes.bool,
|
224 | staticFields: PropTypes.object,
|
225 | modalHeaderProps: PropTypes.shape({ ...ModalHeader.propTypes }),
|
226 | analytics: PropTypes.shape({
|
227 | info: PropTypes.func.isRequired,
|
228 | }),
|
229 | };
|
230 |
|
231 | FeedbackForm.defaultProps = {
|
232 | aboutOptions: [],
|
233 | additionalComments: false,
|
234 | modalHeaderProps: {},
|
235 | analytics: avLogMessagesApi,
|
236 | };
|
237 |
|
238 | export default FeedbackForm;
|