fix: UX improvement (#2791)

Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
This commit is contained in:
Piyush Gupta
2024-06-26 15:59:09 +05:30
committed by GitHub
parent 81a4da6199
commit d6e4b7700f
9 changed files with 84 additions and 19 deletions

View File

@@ -291,7 +291,7 @@ export const AddIntegrationModal = ({
<div className="space-y-4">
<div>
<Label htmlFor="Surveys">Questions</Label>
<div className="mt-1 rounded-lg border border-slate-200">
<div className="mt-1 max-h-[15vh] overflow-y-auto rounded-lg border border-slate-200">
<div className="grid content-center rounded-lg bg-slate-50 p-3 text-left text-sm text-slate-900">
{replaceHeadlineRecall(selectedSurvey, "default", attributeClasses)?.questions.map(
(question) => (

View File

@@ -229,7 +229,7 @@ export const AddIntegrationModal = ({
<div className="space-y-4">
<div>
<Label htmlFor="Surveys">Questions</Label>
<div className="mt-1 rounded-lg border border-slate-200">
<div className="mt-1 max-h-[15vh] overflow-y-auto rounded-lg border border-slate-200">
<div className="grid content-center rounded-lg bg-slate-50 p-3 text-left text-sm text-slate-900">
{replaceHeadlineRecall(selectedSurvey, "default", attributeClasses)?.questions.map(
(question) => (

View File

@@ -231,7 +231,7 @@ export const AddChannelMappingModal = ({
<div>
<div>
<Label htmlFor="Surveys">Questions</Label>
<div className="mt-1 rounded-lg border border-slate-200">
<div className="mt-1 max-h-[15vh] overflow-y-auto rounded-lg border border-slate-200">
<div className="grid content-center rounded-lg bg-slate-50 p-3 text-left text-sm text-slate-900">
{replaceHeadlineRecall(selectedSurvey, "default", attributeClasses)?.questions?.map(
(question) => (

View File

@@ -1,21 +1,21 @@
import { JSX } from "preact";
import { useCallback } from "preact/hooks";
interface SubmitButtonProps {
interface SubmitButtonProps extends JSX.HTMLAttributes<HTMLButtonElement> {
buttonLabel: string | undefined;
isLastQuestion: boolean;
onClick?: () => void;
focus?: boolean;
tabIndex?: number;
type?: "submit" | "button";
}
export const SubmitButton = ({
buttonLabel,
isLastQuestion,
onClick = () => {},
tabIndex = 1,
focus = false,
type = "submit",
onClick,
disabled,
type,
...props
}: SubmitButtonProps) => {
const buttonRef = useCallback(
(currentButton: HTMLButtonElement | null) => {
@@ -30,13 +30,15 @@ export const SubmitButton = ({
return (
<button
{...props}
dir="auto"
ref={buttonRef}
type={type}
tabIndex={tabIndex}
autoFocus={focus}
className="bg-brand border-submit-button-border text-on-brand focus:ring-focus rounded-custom flex items-center border px-3 py-3 text-base font-medium leading-4 shadow-sm hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-offset-2"
onClick={onClick}>
onClick={onClick}
disabled={disabled}>
{buttonLabel || (isLastQuestion ? "Finish" : "Next")}
</button>
);

View File

@@ -29,5 +29,9 @@ export const ProgressBar = ({ survey, questionId }: ProgressBarProps) => {
return survey.questions.map((_, index) => calculateProgress(index, survey.questions.length));
}, [calculateProgress, survey]);
return <Progress progress={questionId === "end" ? 1 : progressArray[currentQuestionIdx]} />;
return (
<Progress
progress={questionId === "end" ? 1 : questionId === "start" ? 0 : progressArray[currentQuestionIdx]}
/>
);
};

View File

@@ -253,6 +253,7 @@ export const Survey = ({
if (questionIdx === -1) {
return (
<WelcomeCard
key="start"
headline={survey.welcomeCard.headline}
html={survey.welcomeCard.html}
fileUrl={survey.welcomeCard.fileUrl}
@@ -263,11 +264,13 @@ export const Survey = ({
responseCount={responseCount}
autoFocusEnabled={autoFocusEnabled}
replaceRecallInfo={replaceRecallInfo}
isCurrent={offset === 0}
/>
);
} else if (questionIdx === survey.questions.length) {
return (
<ThankYouCard
key="end"
headline={replaceRecallInfo(
getLocalizedValue(survey.thankYouCard.headline, selectedLanguage),
responseData
@@ -279,11 +282,13 @@ export const Survey = ({
isResponseSendingFinished={isResponseSendingFinished}
buttonLabel={getLocalizedValue(survey.thankYouCard.buttonLabel, selectedLanguage)}
buttonLink={survey.thankYouCard.buttonLink}
survey={survey}
imageUrl={survey.thankYouCard.imageUrl}
videoUrl={survey.thankYouCard.videoUrl}
redirectUrl={survey.redirectUrl}
isRedirectDisabled={isRedirectDisabled}
autoFocusEnabled={autoFocusEnabled}
isCurrent={offset === 0}
/>
);
} else {
@@ -291,6 +296,7 @@ export const Survey = ({
return (
question && (
<QuestionConditional
key={question.id}
surveyId={survey.id}
question={parseRecallInformation(question, selectedLanguage, responseData)}
value={responseData[question.id]}

View File

@@ -5,6 +5,8 @@ import { QuestionMedia } from "@/components/general/QuestionMedia";
import { RedirectCountDown } from "@/components/general/RedirectCountdown";
import { Subheader } from "@/components/general/Subheader";
import { ScrollableContainer } from "@/components/wrappers/ScrollableContainer";
import { useEffect } from "preact/hooks";
import { TSurvey } from "@formbricks/types/surveys";
interface ThankYouCardProps {
headline?: string;
@@ -17,6 +19,8 @@ interface ThankYouCardProps {
videoUrl?: string;
isResponseSendingFinished: boolean;
autoFocusEnabled: boolean;
isCurrent: boolean;
survey: TSurvey;
}
export const ThankYouCard = ({
@@ -30,6 +34,8 @@ export const ThankYouCard = ({
videoUrl,
isResponseSendingFinished,
autoFocusEnabled,
isCurrent,
survey,
}: ThankYouCardProps) => {
const media = imageUrl || videoUrl ? <QuestionMedia imgUrl={imageUrl} videoUrl={videoUrl} /> : null;
const checkmark = (
@@ -51,6 +57,30 @@ export const ThankYouCard = ({
</div>
);
const handleSubmit = () => {
if (buttonLink) window.location.replace(buttonLink);
};
useEffect(() => {
const handleEnter = (e: KeyboardEvent) => {
if (e.key === "Enter") {
handleSubmit();
}
};
if (isCurrent && survey.type === "link") {
document.addEventListener("keydown", handleEnter);
} else {
document.removeEventListener("keydown", handleEnter);
}
return () => {
document.removeEventListener("keydown", handleEnter);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isCurrent]);
return (
<ScrollableContainer>
<div className="text-center">
@@ -66,10 +96,7 @@ export const ThankYouCard = ({
buttonLabel={buttonLabel}
isLastQuestion={false}
focus={autoFocusEnabled}
onClick={() => {
if (!buttonLink) return;
window.location.replace(buttonLink);
}}
onClick={handleSubmit}
/>
</div>
)}

View File

@@ -1,6 +1,7 @@
import { SubmitButton } from "@/components/buttons/SubmitButton";
import { ScrollableContainer } from "@/components/wrappers/ScrollableContainer";
import { calculateElementIdx } from "@/lib/utils";
import { useEffect } from "preact/hooks";
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TResponseData, TResponseTtc } from "@formbricks/types/responses";
import { TI18nString, TSurvey } from "@formbricks/types/surveys";
@@ -18,6 +19,7 @@ interface WelcomeCardProps {
responseCount?: number;
autoFocusEnabled: boolean;
replaceRecallInfo: (text: string, responseData: TResponseData) => string;
isCurrent: boolean;
}
const TimerIcon = () => {
@@ -68,6 +70,7 @@ export const WelcomeCard = ({
responseCount,
autoFocusEnabled,
replaceRecallInfo,
isCurrent,
}: WelcomeCardProps) => {
const calculateTimeToComplete = () => {
let idx = calculateElementIdx(survey, 0);
@@ -100,6 +103,30 @@ export const WelcomeCard = ({
const timeToFinish = survey.welcomeCard.timeToFinish;
const showResponseCount = survey.welcomeCard.showResponseCount;
const handleSubmit = () => {
onSubmit({ ["welcomeCard"]: "clicked" }, {});
};
useEffect(() => {
const handleEnter = (e: KeyboardEvent) => {
if (e.key === "Enter") {
handleSubmit();
}
};
if (isCurrent && survey.type === "link") {
document.addEventListener("keydown", handleEnter);
} else {
document.removeEventListener("keydown", handleEnter);
}
return () => {
document.removeEventListener("keydown", handleEnter);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isCurrent]);
return (
<div>
<ScrollableContainer>
@@ -124,10 +151,9 @@ export const WelcomeCard = ({
buttonLabel={getLocalizedValue(buttonLabel, languageCode)}
isLastQuestion={false}
focus={autoFocusEnabled}
onClick={() => {
onSubmit({ ["welcomeCard"]: "clicked" }, {});
}}
onClick={handleSubmit}
type="button"
onKeyDown={(e) => e.key === "Enter" && e.preventDefault()}
/>
</div>

View File

@@ -50,7 +50,7 @@ export const DropdownSelector = ({
{!disabled && (
<DropdownMenuPortal>
<DropdownMenuContent
className="z-50 max-h-64 min-w-[220px] max-w-[90%] overflow-auto rounded-md bg-white text-sm text-slate-800 shadow-md"
className="z-50 max-h-64 min-w-[220px] max-w-96 overflow-auto rounded-md bg-white text-sm text-slate-800 shadow-md"
align="start">
{items
.sort((a, b) => a.name?.localeCompare(b.name))