@availity/feedback
Version:
Availity feedback with simley faces react component.
217 lines (205 loc) • 6.05 kB
JavaScript
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import {
Button,
ModalBody,
ModalHeader,
ModalFooter,
FormGroup,
} from 'reactstrap';
import { avLogMessagesApi, avRegionsApi } from '@availity/api-axios';
import { useToggle } from '@availity/hooks';
import { AvForm, AvField } from 'availity-reactstrap-validation';
import { AvSelectField } from '@availity/reactstrap-validation-select';
import FeedbackButton from './FeedbackButton';
const FeedbackForm = ({
name,
onClose,
faceOptions,
aboutOptions,
onFeedbackSent,
prompt,
additionalComments,
staticFields,
}) => {
const [active, setActive] = useState(null);
const [invalid, toggleInvalid] = useToggle(false);
const [sent, setSent] = useState(null);
const sendFeedback = async values => {
if (!active && !invalid) {
toggleInvalid();
return;
}
const response = await avRegionsApi.getCurrentRegion();
await avLogMessagesApi.info({
surveyId: `${name.replace(/\s/g, '_')}_Smile_Survey`,
smileLocation: `${name}`,
smile: `icon-${active.icon}`,
url: window.location.href,
region: response.data.regions[0] && response.data.regions[0].id,
userAgent: window.navigator.userAgent,
submitTime: new Date(),
...values, // Spread the form values onto the logger
...staticFields, // Spread the static key value pairs onto the logger
});
setSent(values);
if (invalid) {
toggleInvalid();
}
};
// Close the Modal once sent after 2 seconds
useEffect(() => {
if (sent) {
setTimeout(() => {
onClose(); // Mostly for Screen Reader use but a nice to have for all
if (onFeedbackSent) {
onFeedbackSent({ active, sent });
}
}, 2000);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sent]);
return sent ? (
<ModalHeader
aria-live="assertive"
tabIndex="0"
className="d-flex justify-content-center"
>
Thank you for your feedback.
</ModalHeader>
) : (
<React.Fragment>
<ModalHeader aria-live="assertive" id="feedback-form-header">
{prompt || `Tell us what you think about ${name}`}
</ModalHeader>
<AvForm
aria-label="Feedback Form"
aria-describedby="feedback-form-header"
role="form"
name="feedack-form"
id="feedback-form"
data-testid="feedback-form"
onValidSubmit={(event, values) => sendFeedback(values)}
>
<ModalBody>
<FormGroup
size="lg"
id="face-options"
data-testid="face-options"
className="d-flex flex-row justify-content-between"
>
{faceOptions.map(option => (
<FeedbackButton
style={{ flex: 1, margin: '0 2% 0 2%' }}
key={option.icon}
icon={option.icon}
iconSize="2x"
active={active && active.icon}
onClick={() => setActive(option)}
>
{option.description}
</FeedbackButton>
))}
</FormGroup>
{active ? (
<React.Fragment>
{aboutOptions.length > 0 && (
<AvSelectField
name="feedbackApp"
id="about-options"
data-testid="about-options"
placeholder="This is about..."
options={aboutOptions}
required
/>
)}
<AvField
type="textarea"
name="feedback"
placeholder={
(active && active.placeholder) ||
'Feedback? Requests? Defects?'
}
style={{ resize: 'none' }}
rows="2"
validate={{
required: {
value: true,
errorMessage: 'This field is required.',
},
maxLength: { value: 200 },
}}
/>
{additionalComments && (
<AvField
type="textarea"
name="additionalFeedback"
placeholder="Additional Comments... (Optional)"
style={{ resize: 'none' }}
rows="2"
validate={{
required: { value: false },
maxLength: { value: 200 },
}}
/>
)}
</React.Fragment>
) : null}
</ModalBody>
<ModalFooter>
{onClose ? (
<Button onClick={onClose} color="secondary">
Close
</Button>
) : null}
<Button type="submit" color="primary" disabled={!active}>
Send Feedback
</Button>
</ModalFooter>
</AvForm>
</React.Fragment>
);
};
FeedbackForm.propTypes = {
name: PropTypes.string.isRequired,
onFeedbackSent: PropTypes.func,
faceOptions: PropTypes.arrayOf(
PropTypes.shape({
icon: PropTypes.string,
description: PropTypes.string,
placeholder: PropTypes.string,
})
),
aboutOptions: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
})
),
onClose: PropTypes.func,
prompt: PropTypes.string,
additionalComments: PropTypes.bool,
staticFields: PropTypes.object,
};
FeedbackForm.defaultProps = {
faceOptions: [
{
icon: 'smile',
description: 'Smiley face',
placeholder: 'What do you like?',
},
{
icon: 'meh',
description: 'Meh face',
placeholder: 'What would you improve?',
},
{
icon: 'frown',
description: 'Frowny face',
placeholder: "What don't you like?",
},
],
aboutOptions: [],
additionalComments: false,
};
export default FeedbackForm;