import * as React from 'react'; import { useEffect } from 'react'; import styled from 'styled-components'; import type { JSX } from 'react'; import type { OptionalEmailSettings } from '@redocly/config'; import type { ReasonsProps } from '@redocly/theme/components/Feedback/Reasons'; import { breakpoints } from '@redocly/theme/core/utils'; import { useThemeHooks } from '@redocly/theme/core/hooks'; import { RadioCheckButtonIcon } from '@redocly/theme/icons/RadioCheckButtonIcon/RadioCheckButtonIcon'; import { Comment } from '@redocly/theme/components/Feedback/Comment'; import { Reasons } from '@redocly/theme/components/Feedback/Reasons'; import { Button } from '@redocly/theme/components/Button/Button'; import { MAX_EMAIL_LENGTH } from '@redocly/theme/core/constants'; export const MAX_SCALE = 10; export type ScaleProps = { onSubmit: (value: { score: number; comment?: string; reasons?: string[]; max?: number; email?: string; }) => void; settings?: { label?: string; submitText?: string; leftScaleLabel?: string; rightScaleLabel?: string; comment?: { hide?: boolean; label?: string; }; reasons?: { hide?: boolean; label?: string; component?: string; items: string[]; }; optionalEmail?: OptionalEmailSettings; }; className?: string; }; export function Scale({ settings, onSubmit, className }: ScaleProps): JSX.Element { const { label, submitText, leftScaleLabel, rightScaleLabel, comment: commentSettings, reasons: reasonsSettings, optionalEmail: optionalEmailSettings, } = settings || {}; const [score, setScore] = React.useState(0); const [isSubmitted, setIsSubmitted] = React.useState(false); const [comment, setComment] = React.useState(''); const [reasons, setReasons] = React.useState([] as ReasonsProps['settings']['items']); const [email, setEmail] = React.useState(); const { useTranslate, useUserMenu } = useThemeHooks(); const { userData } = useUserMenu(); const { translate } = useTranslate(); const onEmailChange = (e: React.ChangeEvent) => { const value = e.target.value; setEmail(value || undefined); }; const scaleOptions = []; for (let i = 1; i <= MAX_SCALE; i++) { scaleOptions.push( , ); } const displayReasons = !!score && reasonsSettings && !reasonsSettings.hide; const displayComment = !!(score && !commentSettings?.hide); const displaySubmitBnt = !!score && (displayReasons || displayComment); const displayFeedbackEmail = !!score && !optionalEmailSettings?.hide && !userData.isAuthenticated; const handleCancel = () => { setScore(0); setComment(''); setReasons([]); setEmail(undefined); }; const onSubmitScaleForm = () => { const trimmedComment = comment?.trim() || undefined; const trimmedEmail = email?.trim() || undefined; onSubmit({ score, comment: trimmedComment, reasons, max: MAX_SCALE, email: trimmedEmail, }); setIsSubmitted(true); }; useEffect(() => { if (score && !displayComment && !displayReasons && !displayFeedbackEmail) { onSubmitScaleForm(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [score, displayComment, displayReasons, displayFeedbackEmail]); if (isSubmitted) { return ( ); } return ( {scaleOptions} {leftScaleLabel || translate('feedback.settings.leftScaleLabel', 'Not helpful at all')} {rightScaleLabel || translate('feedback.settings.rightScaleLabel', 'Extremely helpful')} {displayReasons && ( )} {displayComment && ( setComment(comment)} settings={{ label: commentSettings?.label || translate( 'feedback.settings.comment.label', 'Please share your feedback with us.', ), }} /> )} {displayFeedbackEmail && ( {optionalEmailSettings?.label || translate( 'feedback.settings.optionalEmail.label', 'Your email (optional, for follow-up)', )} { if (e.key === 'Enter') { e.preventDefault(); onSubmitScaleForm(); } }} /> )} {displaySubmitBnt && ( )} ); } const ScaleWrapper = styled.div` font-family: var(--feedback-font-family); display: flex; justify-content: space-between; align-items: center; `; const Label = styled.h4` font-family: var(--feedback-font-family); font-weight: var(--font-weight-regular); font-size: var(--feedback-header-font-size); line-height: var(--feedback-header-line-height); color: var(--feedback-header-text-color); margin: 0; width: 100%; `; const InputLabel = styled.h4` font-weight: var(--font-weight-regular); font-size: var(--feedback-font-size); line-height: var(--feedback-line-height); margin: 0; `; const SubLabelContainer = styled.div` display: flex; justify-content: space-between; width: 100%; flex-direction: row; `; const SubLabel = styled(Label)` width: fit-content; color: var(--text-color-description); font-size: var(--feedback-font-size); margin-bottom: var(--spacing-xxs); `; const StyledForm = styled.form` width: 100%; gap: var(--spacing-sm); display: flex; flex-direction: column; `; const ButtonsContainer = styled.div` display: flex; justify-content: end; margin-bottom: var(--spacing-xxs); gap: var(--spacing-xxs); `; const StyledFormOptionalFields = styled.div` display: flex; flex-flow: column; &:empty { display: none; } `; const StyledFormMandatoryFields = styled.div` display: flex; flex-direction: column; align-items: center; gap: var(--spacing-sm); align-items: center; `; const ScaleOptionsWrapper = styled.div` display: flex; justify-content: space-between; flex-direction: row; gap: var(--spacing-xxs); width: 100%; ${Button} { margin-left: 0; } @media screen and (max-width: ${breakpoints.small}) { gap: 2px; } `; const EmailInput = styled.input` background-color: var(--bg-color); border-radius: var(--border-radius-lg); border: var(--input-border); outline: none; color: var(--feedback-text-color); font-family: var(--feedback-font-family); padding: 10px; `;