feat: optional back button (#4813)

Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
Co-authored-by: Anshuman Pandey <54475686+pandeymangg@users.noreply.github.com>
This commit is contained in:
Dhruwang Jariwala
2025-02-26 17:06:16 +05:30
committed by GitHub
parent b84d3d5806
commit 9f6fb8a387
32 changed files with 110 additions and 20 deletions

View File

@@ -61,6 +61,7 @@ export const getSurveysForEnvironmentState = reactCache(
displayLimit: true,
displayOption: true,
hiddenFields: true,
isBackButtonHidden: true,
triggers: {
select: {
actionClass: {

View File

@@ -7064,5 +7064,6 @@ export const previewSurvey = (projectName: string, t: TFnType) => {
triggers: [],
showLanguageSwitch: false,
followUps: [],
isBackButtonHidden: false,
} as TSurvey;
};

View File

@@ -205,6 +205,10 @@ export const ResponseOptionsCard = ({
}
};
const handleHideBackButtonToggle = () => {
setLocalSurvey({ ...localSurvey, isBackButtonHidden: !localSurvey.isBackButtonHidden });
};
useEffect(() => {
if (!!localSurvey.surveyClosedMessage) {
setSurveyClosedMessage({
@@ -515,6 +519,13 @@ export const ResponseOptionsCard = ({
</AdvancedOptionToggle>
</>
)}
<AdvancedOptionToggle
htmlId="hideBackButton"
isChecked={localSurvey.isBackButtonHidden}
onToggle={handleHideBackButtonToggle}
title={t("environments.surveys.edit.hide_back_button")}
description={t("environments.surveys.edit.hide_back_button_description")}
/>
</div>
</Collapsible.CollapsibleContent>
</Collapsible.Root>

View File

@@ -41,6 +41,7 @@ export const selectSurvey = {
pin: true,
resultShareKey: true,
showLanguageSwitch: true,
isBackButtonHidden: true,
languages: {
select: {
default: true,

View File

@@ -41,4 +41,5 @@ export const getMinimalSurvey = (t: TFnType): TSurvey => ({
isSingleResponsePerEmailEnabled: false,
variables: [],
followUps: [],
isBackButtonHidden: false,
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -47,7 +47,8 @@
"xm-and-surveys/surveys/general-features/shareable-dashboards",
"xm-and-surveys/surveys/general-features/schedule-start-end-dates",
"xm-and-surveys/surveys/general-features/metadata",
"xm-and-surveys/surveys/general-features/variables"
"xm-and-surveys/surveys/general-features/variables",
"xm-and-surveys/surveys/general-features/hide-back-button"
]
},
{

View File

@@ -0,0 +1,11 @@
---
title: Hide Back Button
description: Learn how to hide the back button in surveys.
icon: arrow-left
---
Surveys display a back button by default. If you want to prevent respondents from returning to previous questions, you'll need to disable this feature explicitly.
To disable the back button, navigate to the survey settings and select the Response options tab.
![Hide back button](/images/xm-and-surveys/surveys/general-features/hide-back-button/hide-back-button.webp)

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Response" ALTER COLUMN "updated_at" SET DEFAULT CURRENT_TIMESTAMP;

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Survey" ADD COLUMN "isBackButtonHidden" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -410,6 +410,7 @@ model Survey {
verifyEmail Json? // deprecated
isVerifyEmailEnabled Boolean @default(false)
isSingleResponsePerEmailEnabled Boolean @default(false)
isBackButtonHidden Boolean @default(false)
pin String?
resultShareKey String? @unique
displayPercentage Decimal?

View File

@@ -69,6 +69,7 @@ export const selectSurvey = {
autoComplete: true,
isVerifyEmailEnabled: true,
isSingleResponsePerEmailEnabled: true,
isBackButtonHidden: true,
redirectUrl: true,
projectOverwrites: true,
styling: true,

View File

@@ -185,6 +185,7 @@ const baseSurveyProperties = {
displayLimit: 3,
welcomeCard: mockWelcomeCard,
questions: [mockQuestion],
isBackButtonHidden: false,
endings: [
{
id: "umyknohldc7w26ocjdhaa62c",

View File

@@ -41,6 +41,7 @@ interface QuestionConditionalProps {
surveyId: string;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function QuestionConditional({
@@ -60,6 +61,7 @@ export function QuestionConditional({
onFileUpload,
autoFocusEnabled,
currentQuestionId,
isBackButtonHidden,
}: QuestionConditionalProps) {
const getResponseValueForRankingQuestion = (
value: string[],
@@ -93,6 +95,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.MultipleChoiceSingle ? (
<MultipleChoiceSingleQuestion
@@ -109,6 +112,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.MultipleChoiceMulti ? (
<MultipleChoiceMultiQuestion
@@ -125,6 +129,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.NPS ? (
<NPSQuestion
@@ -141,6 +146,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.CTA ? (
<CTAQuestion
@@ -157,6 +163,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.Rating ? (
<RatingQuestion
@@ -173,6 +180,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.Consent ? (
<ConsentQuestion
@@ -189,6 +197,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.Date ? (
<DateQuestion
@@ -205,6 +214,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.PictureSelection ? (
<PictureSelectionQuestion
@@ -221,6 +231,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.FileUpload ? (
<FileUploadQuestion
@@ -239,6 +250,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.Cal ? (
<CalQuestion
@@ -255,6 +267,7 @@ export function QuestionConditional({
autoFocusEnabled={autoFocusEnabled}
setTtc={setTtc}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.Matrix ? (
<MatrixQuestion
@@ -269,6 +282,7 @@ export function QuestionConditional({
ttc={ttc}
setTtc={setTtc}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.Address ? (
<AddressQuestion
@@ -284,6 +298,7 @@ export function QuestionConditional({
setTtc={setTtc}
currentQuestionId={currentQuestionId}
autoFocusEnabled={autoFocusEnabled}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.Ranking ? (
<RankingQuestion
@@ -299,6 +314,7 @@ export function QuestionConditional({
setTtc={setTtc}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={currentQuestionId}
isBackButtonHidden={isBackButtonHidden}
/>
) : question.type === TSurveyQuestionTypeEnum.ContactInfo ? (
<ContactInfoQuestion
@@ -314,6 +330,7 @@ export function QuestionConditional({
setTtc={setTtc}
currentQuestionId={currentQuestionId}
autoFocusEnabled={autoFocusEnabled}
isBackButtonHidden={isBackButtonHidden}
/>
) : null;
}

View File

@@ -399,6 +399,7 @@ export function Survey({
languageCode={selectedLanguage}
autoFocusEnabled={autoFocusEnabled}
currentQuestionId={questionId}
isBackButtonHidden={localSurvey.isBackButtonHidden}
/>
)
);

View File

@@ -25,6 +25,7 @@ interface AddressQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
currentQuestionId: TSurveyQuestionId;
autoFocusEnabled: boolean;
isBackButtonHidden: boolean;
}
export function AddressQuestion({
@@ -40,6 +41,7 @@ export function AddressQuestion({
setTtc,
currentQuestionId,
autoFocusEnabled,
isBackButtonHidden,
}: AddressQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -179,7 +181,7 @@ export function AddressQuestion({
isLastQuestion={isLastQuestion}
/>
<div />
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -24,6 +24,7 @@ interface CalQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function CalQuestion({
@@ -38,6 +39,7 @@ export function CalQuestion({
ttc,
setTtc,
currentQuestionId,
isBackButtonHidden,
}: CalQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -95,7 +97,7 @@ export function CalQuestion({
/>
)}
<div />
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}
onClick={() => {

View File

@@ -23,6 +23,7 @@ interface ConsentQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function ConsentQuestion({
@@ -38,6 +39,7 @@ export function ConsentQuestion({
setTtc,
currentQuestionId,
autoFocusEnabled,
isBackButtonHidden,
}: ConsentQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -126,7 +128,7 @@ export function ConsentQuestion({
isLastQuestion={isLastQuestion}
/>
<div />
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -25,6 +25,7 @@ interface ContactInfoQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
currentQuestionId: TSurveyQuestionId;
autoFocusEnabled: boolean;
isBackButtonHidden: boolean;
}
export function ContactInfoQuestion({
@@ -40,6 +41,7 @@ export function ContactInfoQuestion({
setTtc,
currentQuestionId,
autoFocusEnabled,
isBackButtonHidden,
}: ContactInfoQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -181,7 +183,7 @@ export function ContactInfoQuestion({
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -23,6 +23,7 @@ interface CTAQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function CTAQuestion({
@@ -37,6 +38,7 @@ export function CTAQuestion({
setTtc,
autoFocusEnabled,
currentQuestionId,
isBackButtonHidden,
}: CTAQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -92,7 +94,7 @@ export function CTAQuestion({
</button>
)}
</div>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -28,6 +28,7 @@ interface DateQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
function CalendarIcon() {
@@ -91,6 +92,7 @@ export function DateQuestion({
setTtc,
ttc,
currentQuestionId,
isBackButtonHidden,
}: DateQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const [errorMessage, setErrorMessage] = useState("");
@@ -272,7 +274,7 @@ export function DateQuestion({
isLastQuestion={isLastQuestion}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -28,6 +28,7 @@ interface FileUploadQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function FileUploadQuestion({
@@ -44,6 +45,7 @@ export function FileUploadQuestion({
ttc,
setTtc,
currentQuestionId,
isBackButtonHidden,
}: FileUploadQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -110,7 +112,7 @@ export function FileUploadQuestion({
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -24,6 +24,7 @@ interface MatrixQuestionProps {
ttc: TResponseTtc;
setTtc: (ttc: TResponseTtc) => void;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function MatrixQuestion({
@@ -38,6 +39,7 @@ export function MatrixQuestion({
ttc,
setTtc,
currentQuestionId,
isBackButtonHidden,
}: MatrixQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -210,7 +212,7 @@ export function MatrixQuestion({
isLastQuestion={isLastQuestion}
tabIndex={isCurrent ? 0 : -1}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}
onClick={handleBackButtonClick}

View File

@@ -24,6 +24,7 @@ interface MultipleChoiceMultiProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function MultipleChoiceMultiQuestion({
@@ -39,6 +40,7 @@ export function MultipleChoiceMultiQuestion({
setTtc,
autoFocusEnabled,
currentQuestionId,
isBackButtonHidden,
}: MultipleChoiceMultiProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -293,7 +295,7 @@ export function MultipleChoiceMultiQuestion({
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -24,6 +24,7 @@ interface MultipleChoiceSingleProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function MultipleChoiceSingleQuestion({
@@ -39,6 +40,7 @@ export function MultipleChoiceSingleQuestion({
setTtc,
autoFocusEnabled,
currentQuestionId,
isBackButtonHidden,
}: MultipleChoiceSingleProps) {
const [startTime, setStartTime] = useState(performance.now());
const [otherSelected, setOtherSelected] = useState(false);
@@ -250,7 +252,7 @@ export function MultipleChoiceSingleQuestion({
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}
tabIndex={isCurrent ? 0 : -1}

View File

@@ -24,6 +24,7 @@ interface NPSQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function NPSQuestion({
@@ -38,6 +39,7 @@ export function NPSQuestion({
ttc,
setTtc,
currentQuestionId,
isBackButtonHidden,
}: NPSQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const [hoveredNumber, setHoveredNumber] = useState(-1);
@@ -153,14 +155,16 @@ export function NPSQuestion({
</div>
</ScrollableContainer>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-px-6 fb-py-4">
{!question.required && (
{question.required ? (
<></>
) : (
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
/>
)}
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -25,6 +25,7 @@ interface OpenTextQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function OpenTextQuestion({
@@ -40,6 +41,7 @@ export function OpenTextQuestion({
setTtc,
autoFocusEnabled,
currentQuestionId,
isBackButtonHidden,
}: OpenTextQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const [currentLength, setCurrentLength] = useState(value.length || 0);
@@ -161,7 +163,7 @@ export function OpenTextQuestion({
isLastQuestion={isLastQuestion}
onClick={() => {}}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -25,6 +25,7 @@ interface PictureSelectionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function PictureSelectionQuestion({
@@ -39,6 +40,7 @@ export function PictureSelectionQuestion({
ttc,
setTtc,
currentQuestionId,
isBackButtonHidden,
}: PictureSelectionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
@@ -209,7 +211,7 @@ export function PictureSelectionQuestion({
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -29,6 +29,7 @@ interface RankingQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function RankingQuestion({
@@ -44,6 +45,7 @@ export function RankingQuestion({
setTtc,
autoFocusEnabled,
currentQuestionId,
isBackButtonHidden,
}: RankingQuestionProps) {
const [startTime, setStartTime] = useState(performance.now());
const isCurrent = question.id === currentQuestionId;
@@ -272,7 +274,7 @@ export function RankingQuestion({
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
/>
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}
tabIndex={isCurrent ? 0 : -1}

View File

@@ -37,6 +37,7 @@ interface RatingQuestionProps {
setTtc: (ttc: TResponseTtc) => void;
autoFocusEnabled: boolean;
currentQuestionId: TSurveyQuestionId;
isBackButtonHidden: boolean;
}
export function RatingQuestion({
@@ -51,6 +52,7 @@ export function RatingQuestion({
ttc,
setTtc,
currentQuestionId,
isBackButtonHidden,
}: RatingQuestionProps) {
const [hoveredNumber, setHoveredNumber] = useState(0);
const [startTime, setStartTime] = useState(performance.now());
@@ -259,7 +261,9 @@ export function RatingQuestion({
</div>
</ScrollableContainer>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-px-6 fb-py-4">
{!question.required && (
{question.required ? (
<></>
) : (
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
@@ -267,7 +271,7 @@ export function RatingQuestion({
/>
)}
<div />
{!isFirstQuestion && (
{!isFirstQuestion && !isBackButtonHidden && (
<BackButton
tabIndex={isCurrent ? 0 : -1}
backButtonLabel={getLocalizedValue(question.backButtonLabel, languageCode)}

View File

@@ -35,6 +35,7 @@ export const ZJsEnvironmentStateSurvey = ZSurvey.innerType()
displayPercentage: true,
delay: true,
projectOverwrites: true,
isBackButtonHidden: true,
})
.superRefine(ZSurvey._def.effect.type === "refinement" ? ZSurvey._def.effect.refinement : () => null);

View File

@@ -868,13 +868,14 @@ export const ZSurvey = z
singleUse: ZSurveySingleUse.nullable(),
isVerifyEmailEnabled: z.boolean(),
isSingleResponsePerEmailEnabled: z.boolean(),
isBackButtonHidden: z.boolean(),
pin: z.string().min(4, { message: "PIN must be a four digit number" }).nullish(),
resultShareKey: z.string().nullable(),
displayPercentage: z.number().min(0.01).max(100).nullable(),
languages: z.array(ZSurveyLanguage),
})
.superRefine((survey, ctx) => {
const { questions, languages, welcomeCard, endings } = survey;
const { questions, languages, welcomeCard, endings, isBackButtonHidden } = survey;
let multiLangIssue: z.IssueData | null;
@@ -943,7 +944,9 @@ export const ZSurvey = z
];
const fieldsToValidate =
questionIndex === 0 ? initialFieldsToValidate : [...initialFieldsToValidate, "backButtonLabel"];
questionIndex === 0 || isBackButtonHidden
? initialFieldsToValidate
: [...initialFieldsToValidate, "backButtonLabel"];
for (const field of fieldsToValidate) {
// Skip label validation for consent questions as its called checkbox label