UNPKG

@navinc/base-react-components

Version:
249 lines (246 loc) 9.11 kB
var _a, _b; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState, useEffect } from 'react'; import propTypes from 'prop-types'; import styled, { keyframes, css } from 'styled-components'; import Cookies from 'js-cookie'; import inView from 'in-view'; import { track } from '@navinc/utils'; import Button from './button'; import Copy from './copy'; import Icon from './icon.js'; const { CLIENT_COOKIE_DOMAIN } = (_b = (_a = global === null || global === void 0 ? void 0 : global.process) === null || _a === void 0 ? void 0 : _a.env) !== null && _b !== void 0 ? _b : ''; const slideInFromSide = keyframes ` 0% { transform: translateX(50%); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } `; const slideInFromBottom = keyframes ` 0% { transform: translateY(50%); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } `; const slideOutAnimation = keyframes ` 0% { opacity: 1; transform: translateY(0); } 10% { transform: translateY(calc(100% - 4px)); opacity: 1; border-top: 4px solid ${({ theme }) => theme.border}; } 50% { opacity: 1; border-top: 4px solid ${({ theme }) => theme.oceanGreen200}; } 60% { opacity: 1; border-top: 4px solid ${({ theme }) => theme.oceanGreen200}; } 80% { transform: translateY(calc(100% - 4px)) translateX(0); opacity: 1; } 100% { transform: translateY(calc(100% - 4px)) translateX(100%); opacity: 0; } `; const slideOut = css ` opacity: 0; transform: translateY(100%); animation: ${slideOutAnimation} 2s ease-in-out; `; export const UserFeedbackContainer = styled.div ` position: relative; display: flex; height: 52px; max-height: 52px; min-width: 240px; margin-left: auto; opacity: 1; overflow: hidden; transition: opacity 0.2s linear 15s, height 0.2s linear 15s, max-height 0.2s linear; ${({ isTouched }) => isTouched && ` height: 0; opacity: 0; & > ${UserFeedbackPrompt} { opacity: 0; } `} ${({ shouldHideImmediately }) => shouldHideImmediately && ` max-height: 0; `} `; const UserFeedbackPrompt = styled.div ` display: flex; width: 100%; align-items: center; justify-content: flex-end; margin-top: 16px; opacity: 1; transition: opacity 0.2s linear; `; export const ThankYouMessage = styled.div ` position: absolute; top: 16px; right: 0; padding-left: 8px; overflow: hidden; animation: ${slideInFromSide} 0.4s ease-in-out; &::after { position: absolute; content: ''; top: 0; left: 0; width: 2px; height: 100%; border-radius: 2px; background: ${({ theme }) => theme.lightBlue400}; z-index: 5; } `; const IconButton = styled(Icon) ` height: 16px; color: ${({ theme }) => theme.neutral400}; transition: color 0.2s linear; cursor: pointer; `; const IconButtonPositive = styled(IconButton) ` &:hover { color: ${({ theme }) => theme.greenSheen500}; } `; const IconButtonNegative = styled(IconButton) ` &:hover { color: ${({ theme }) => theme.rose500}; } `; const MoreFeedbackLink = styled(Copy).attrs(() => ({ size: 'xs', as: 'a', })) ` color: ${({ theme }) => theme.azure}; align-content: center; cursor: pointer; `; export const AdditionalFeedbackContainer = styled.div ` position: fixed; bottom: 0; left: 0; width: 100%; border-top: 4px solid ${({ theme }) => theme.border}; background-color: ${({ theme }) => theme.white}; opacity: 1; transform: translateY(0); z-index: 60; animation: ${slideInFromBottom} 0.4s ease-in-out; ${({ shouldHide }) => shouldHide && slideOut} `; const Form = styled.div ` display: flex; flex-wrap: wrap; justify-content: flex-end; max-width: ${({ theme }) => theme.contentWidth}px; margin: 0 auto; padding: 16px; ${Copy} { width: 100%; max-width: 100%; text-align: center; } ${Button} { margin-left: 16px; } `; const Textarea = styled.textarea ` width: 100%; margin: 8px 0 16px; border: 1px solid ${({ theme }) => theme.border}; border-radius: 4px; `; export const UserFeedback = ({ trackingLabel = '', className, initialPrompt = 'Was this useful?', thumbsUpThankYouText = `We're glad this helps.`, thumbsDownThankYouText = `We're sorry this isn't helpful.`, thumbsUpAdditionalFeedbackPrompt = 'Tell us more', thumbsDownAdditionalFeedbackPrompt = 'Tell us how we can improve', additionalFeedbackQuestion = 'What can we do to improve your experience?', }) => { const [isTouched, setIsTouched] = useState(false); const [showAdditionalDialogue, setShowAdditionalDialogue] = useState(false); const [userReaction, setUserReaction] = useState(''); const [userFeedback, setUserFeedback] = useState(''); useEffect(() => { inView(`[data-id=user-feedback-${trackingLabel}]`).once('enter', () => { track({ payload: { label: `${trackingLabel}: was seen.`, name: `${trackingLabel}: was seen.`, }, type: 'user_feedback', }); }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const trackClick = (newUserReaction) => () => { setIsTouched(true); setUserReaction(newUserReaction); track({ payload: { label: `${trackingLabel}: ${newUserReaction}`, name: `${trackingLabel}: ${newUserReaction}`, }, type: 'user_feedback', }); Cookies.set(trackingLabel, true, { domain: CLIENT_COOKIE_DOMAIN, path: '/', expires: 30, }); }; const handleShowMoreFeedback = () => { setShowAdditionalDialogue(true); track({ payload: { label: `${trackingLabel}: ${userReaction} - Clicked Additional Feedback`, name: `${trackingLabel}: ${userReaction} - Clicked Additional Feedback`, }, type: 'user_feedback', }); }; const handleHideMoreFeedback = () => setShowAdditionalDialogue(false); const handleSubmitMoreFeedback = (event) => { event.preventDefault(); setShowAdditionalDialogue(false); track({ payload: { label: `${trackingLabel}: ${userReaction} - Additional Feedback Given`, name: `${trackingLabel}: ${userReaction} - Additional Feedback Given`, feedBack: userFeedback, }, type: 'user_feedback', }); }; const handleTextChange = ({ target }) => setUserFeedback(target.value); if (!isTouched && !showAdditionalDialogue && Cookies.get(trackingLabel)) return null; return (_jsxs(_Fragment, { children: [_jsxs(UserFeedbackContainer, Object.assign({ isTouched: isTouched, shouldHideImmediately: !!userFeedback, className: className, "data-id": `user-feedback-${trackingLabel}` }, { children: [_jsxs(UserFeedbackPrompt, { children: [_jsx(Copy, Object.assign({ size: "sm", light: true }, { children: initialPrompt }), void 0), _jsx(IconButtonPositive, { onClick: trackClick('Thumbs Up'), name: "feedback/thumbs-up", "data-testid": "user-feedback:button-positive" }, void 0), _jsx(IconButtonNegative, { onClick: trackClick('Thumbs Down'), name: "feedback/thumbs-down", "data-testid": "user-feedback:button-negative" }, void 0)] }, void 0), isTouched && (_jsxs(ThankYouMessage, { children: [_jsx(Copy, Object.assign({ size: "xs" }, { children: userReaction === 'Thumbs Up' ? thumbsUpThankYouText : thumbsDownThankYouText }), void 0), _jsx(MoreFeedbackLink, Object.assign({ onClick: handleShowMoreFeedback, "data-testid": "user-feedback:tell-us-more-link" }, { children: userReaction === 'Thumbs Up' ? thumbsUpAdditionalFeedbackPrompt : thumbsDownAdditionalFeedbackPrompt }), void 0)] }, void 0))] }), void 0), (showAdditionalDialogue || userFeedback) && (_jsx(AdditionalFeedbackContainer, Object.assign({ shouldHide: !showAdditionalDialogue }, { children: _jsxs(Form, { children: [_jsx(Copy, Object.assign({ bold: true }, { children: additionalFeedbackQuestion }), void 0), _jsx(Textarea, { onChange: handleTextChange, "data-testid": "user-feedback:text-area" }, void 0), _jsx(Button, Object.assign({ onClick: handleHideMoreFeedback, variation: "outline", "data-testid": "user-feedback:cancel" }, { children: "Cancel" }), void 0), _jsx(Button, Object.assign({ onClick: handleSubmitMoreFeedback, disabled: !userFeedback, "data-testid": "user-feedback:submit" }, { children: "Submit" }), void 0)] }, void 0) }), void 0))] }, void 0)); }; UserFeedback.propTypes = { trackingLabel: propTypes.string, initialPrompt: propTypes.string, thumbsUpThankYouText: propTypes.string, thumbsDownThankYouText: propTypes.string, thumbsUpAdditionalFeedbackPrompt: propTypes.string, thumbsDownAdditionalFeedbackPrompt: propTypes.string, additionalFeedbackQuestion: propTypes.string, }; export default styled(UserFeedback) ``; //# sourceMappingURL=user-feedback.js.map