mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-03 12:49:57 -05:00
fixes some validations
This commit is contained in:
@@ -45,7 +45,7 @@ interface QuestionFormInputProps {
|
||||
updateQuestion?: (questionIdx: number, data: Partial<TSurveyElement>) => void;
|
||||
updateSurvey?: (data: Partial<TSurveyEndScreenCard> | Partial<TSurveyRedirectUrlCard>) => void;
|
||||
updateChoice?: (choiceIdx: number, data: Partial<TSurveyQuestionChoice>) => void;
|
||||
updateMatrixLabel?: (index: number, type: "row" | "column", data: Partial<TSurveyElement>) => void;
|
||||
updateMatrixLabel?: (index: number, type: "row" | "column", matrixLabel: TI18nString) => void;
|
||||
isInvalid: boolean;
|
||||
selectedLanguageCode: string;
|
||||
setSelectedLanguageCode: (languageCode: string) => void;
|
||||
|
||||
@@ -78,19 +78,47 @@ export function BlockConditional({
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// First, programmatically trigger validation on all question forms
|
||||
// Validate all forms and check for custom validation rules
|
||||
let firstInvalidForm: HTMLFormElement | null = null;
|
||||
|
||||
for (const element of block.elements) {
|
||||
const form = elementFormRefs.current.get(element.id);
|
||||
if (form) {
|
||||
// Check if form is valid using native validation
|
||||
// Check HTML5 validity first
|
||||
if (!form.checkValidity()) {
|
||||
if (!firstInvalidForm) {
|
||||
firstInvalidForm = form;
|
||||
}
|
||||
form.reportValidity();
|
||||
} else if (element.required) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Custom validation for ranking questions
|
||||
if (element.type === TSurveyElementTypeEnum.Ranking) {
|
||||
const response = value[element.id];
|
||||
const rankingElement = element;
|
||||
|
||||
// Check if ranking is incomplete
|
||||
const hasIncompleteRanking =
|
||||
(rankingElement.required &&
|
||||
(!Array.isArray(response) || response.length !== rankingElement.choices.length)) ||
|
||||
(!rankingElement.required &&
|
||||
Array.isArray(response) &&
|
||||
response.length > 0 &&
|
||||
response.length < rankingElement.choices.length);
|
||||
|
||||
if (hasIncompleteRanking) {
|
||||
// Trigger the ranking form's submit to show the error message
|
||||
form.requestSubmit();
|
||||
if (!firstInvalidForm) {
|
||||
firstInvalidForm = form;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// For other element types, check if required fields are empty
|
||||
if (element.required) {
|
||||
const response = value[element.id];
|
||||
const isEmpty =
|
||||
response === undefined ||
|
||||
@@ -100,12 +128,11 @@ export function BlockConditional({
|
||||
(typeof response === "object" && !Array.isArray(response) && Object.keys(response).length === 0);
|
||||
|
||||
if (isEmpty) {
|
||||
form.requestSubmit();
|
||||
if (!firstInvalidForm) {
|
||||
firstInvalidForm = form;
|
||||
}
|
||||
// Dispatch a submit event to trigger the form's onSubmit handler
|
||||
form.requestSubmit();
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,11 +175,7 @@ export function BlockConditional({
|
||||
const isFirstElement = index === 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={element.id}
|
||||
className={cn(
|
||||
index < block.elements.length - 1 ? "fb-border-b fb-border-slate-200 fb-pb-4" : ""
|
||||
)}>
|
||||
<div key={element.id} className={cn(index < block.elements.length - 1 ? "fb-pb-4" : "")}>
|
||||
<ElementConditional
|
||||
element={element}
|
||||
value={value[element.id]}
|
||||
|
||||
@@ -87,7 +87,14 @@ export function ElementConditional({
|
||||
choices: TSurveyQuestionChoice[]
|
||||
): string[] => {
|
||||
return value
|
||||
.map((label) => choices.find((choice) => getLocalizedValue(choice.label, languageCode) === label)?.id)
|
||||
.map((entry) => {
|
||||
// First check if entry is already a valid choice ID
|
||||
if (choices.some((c) => c.id === entry)) {
|
||||
return entry;
|
||||
}
|
||||
// Otherwise, treat it as a localized label and find the choice by label
|
||||
return choices.find((choice) => getLocalizedValue(choice.label, languageCode) === entry)?.id;
|
||||
})
|
||||
.filter((id): id is TSurveyQuestionChoice["id"] => id !== undefined);
|
||||
};
|
||||
|
||||
@@ -110,7 +117,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -125,7 +131,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={typeof value === "string" ? value : undefined}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -140,7 +145,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={Array.isArray(value) ? value : []}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -155,7 +159,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={typeof value === "number" ? value : undefined}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -189,7 +192,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={typeof value === "number" ? value : undefined}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -204,7 +206,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -219,7 +220,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -233,7 +233,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={Array.isArray(value) ? value : []}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -249,7 +248,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={Array.isArray(value) ? value : []}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
onFileUpload={onFileUpload}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
@@ -276,7 +274,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={typeof value === "object" && !Array.isArray(value) ? value : {}}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -288,7 +285,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={Array.isArray(value) ? value : undefined}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -302,7 +298,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={Array.isArray(value) ? getResponseValueForRankingQuestion(value, element.choices) : []}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
@@ -315,7 +310,6 @@ export function ElementConditional({
|
||||
question={element}
|
||||
value={Array.isArray(value) ? value : undefined}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
languageCode={languageCode}
|
||||
ttc={ttc}
|
||||
setTtc={setTtc}
|
||||
|
||||
@@ -15,7 +15,6 @@ interface AddressQuestionProps {
|
||||
question: TSurveyAddressElement;
|
||||
value?: string[];
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -29,7 +28,6 @@ export function AddressQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -95,12 +93,6 @@ export function AddressQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtc = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtc);
|
||||
const containsAllEmptyStrings = safeValue.length === 6 && safeValue.every((item) => item.trim() === "");
|
||||
if (containsAllEmptyStrings) {
|
||||
onSubmit({ [question.id]: [] }, updatedTtc);
|
||||
} else {
|
||||
onSubmit({ [question.id]: safeValue }, updatedTtc);
|
||||
}
|
||||
};
|
||||
|
||||
const addressRef = useCallback(
|
||||
|
||||
@@ -12,7 +12,6 @@ interface ConsentQuestionProps {
|
||||
question: TSurveyConsentElement;
|
||||
value: string;
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -26,7 +25,6 @@ export function ConsentQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -59,7 +57,6 @@ export function ConsentQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
onSubmit({ [question.id]: value }, updatedTtcObj);
|
||||
}}>
|
||||
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
|
||||
<Headline
|
||||
|
||||
@@ -14,7 +14,6 @@ interface ContactInfoQuestionProps {
|
||||
question: TSurveyContactInfoElement;
|
||||
value?: string[];
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
autoFocus?: boolean;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
@@ -29,7 +28,6 @@ export function ContactInfoQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -90,12 +88,6 @@ export function ContactInfoQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtc = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtc);
|
||||
const containsAllEmptyStrings = safeValue.length === 5 && safeValue.every((item) => item.trim() === "");
|
||||
if (containsAllEmptyStrings) {
|
||||
onSubmit({ [question.id]: [] }, updatedTtc);
|
||||
} else {
|
||||
onSubmit({ [question.id]: safeValue }, updatedTtc);
|
||||
}
|
||||
};
|
||||
|
||||
const contactInfoRef = useCallback(
|
||||
|
||||
@@ -17,7 +17,6 @@ interface DateQuestionProps {
|
||||
question: TSurveyDateElement;
|
||||
value: string;
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
autoFocus?: boolean;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
@@ -79,7 +78,6 @@ function CalendarCheckIcon() {
|
||||
export function DateQuestion({
|
||||
question,
|
||||
value,
|
||||
onSubmit,
|
||||
onChange,
|
||||
languageCode,
|
||||
setTtc,
|
||||
@@ -139,7 +137,6 @@ export function DateQuestion({
|
||||
}
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
onSubmit({ [question.id]: value }, updatedTtcObj);
|
||||
}}
|
||||
className="fb-w-full">
|
||||
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
|
||||
|
||||
@@ -16,7 +16,6 @@ interface FileUploadQuestionProps {
|
||||
question: TSurveyFileUploadElement;
|
||||
value: string[];
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
onFileUpload: (file: TJsFileUploadParams["file"], config?: TUploadFileConfig) => Promise<string>;
|
||||
surveyId: string;
|
||||
languageCode: string;
|
||||
@@ -31,7 +30,6 @@ export function FileUploadQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
surveyId,
|
||||
onFileUpload,
|
||||
languageCode,
|
||||
@@ -54,15 +52,9 @@ export function FileUploadQuestion({
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
if (question.required) {
|
||||
if (value && value.length > 0) {
|
||||
onSubmit({ [question.id]: value }, updatedTtcObj);
|
||||
} else {
|
||||
if (!(value && value.length > 0)) {
|
||||
alert(t("errors.please_upload_a_file"));
|
||||
}
|
||||
} else if (value) {
|
||||
onSubmit({ [question.id]: value }, updatedTtcObj);
|
||||
} else {
|
||||
onSubmit({ [question.id]: "skipped" }, updatedTtcObj);
|
||||
}
|
||||
}}
|
||||
className="fb-w-full">
|
||||
|
||||
@@ -14,7 +14,6 @@ interface MatrixQuestionProps {
|
||||
question: TSurveyMatrixElement;
|
||||
value: Record<string, string>;
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -26,7 +25,6 @@ export function MatrixQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -85,9 +83,8 @@ export function MatrixQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtc = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtc);
|
||||
onSubmit({ [question.id]: value }, updatedTtc);
|
||||
},
|
||||
[ttc, question.id, startTime, value, onSubmit, setTtc]
|
||||
[ttc, question.id, startTime, setTtc]
|
||||
);
|
||||
|
||||
const columnsHeaders = useMemo(
|
||||
|
||||
@@ -13,7 +13,6 @@ interface MultipleChoiceMultiProps {
|
||||
question: TSurveyMultipleChoiceElement;
|
||||
value: string[];
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -27,7 +26,6 @@ export function MultipleChoiceMultiQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -165,7 +163,6 @@ export function MultipleChoiceMultiQuestion({
|
||||
onChange({ [question.id]: newValue });
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
onSubmit({ [question.id]: newValue }, updatedTtcObj);
|
||||
}}
|
||||
className="fb-w-full">
|
||||
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
|
||||
|
||||
@@ -13,7 +13,6 @@ interface MultipleChoiceSingleProps {
|
||||
question: TSurveyMultipleChoiceElement;
|
||||
value?: string;
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -27,7 +26,6 @@ export function MultipleChoiceSingleQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -109,7 +107,6 @@ export function MultipleChoiceSingleQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
onSubmit({ [question.id]: value }, updatedTtcObj);
|
||||
}}
|
||||
className="fb-w-full">
|
||||
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
|
||||
|
||||
@@ -13,7 +13,6 @@ interface NPSQuestionProps {
|
||||
question: TSurveyNPSElement;
|
||||
value?: number;
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -27,7 +26,6 @@ export function NPSQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -45,14 +43,6 @@ export function NPSQuestion({
|
||||
onChange({ [question.id]: number });
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
setTimeout(() => {
|
||||
onSubmit(
|
||||
{
|
||||
[question.id]: number,
|
||||
},
|
||||
updatedTtcObj
|
||||
);
|
||||
}, 250);
|
||||
};
|
||||
|
||||
const getNPSOptionColor = (idx: number) => {
|
||||
@@ -69,7 +59,6 @@ export function NPSQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
onSubmit({ [question.id]: value ?? "" }, updatedTtcObj);
|
||||
}}>
|
||||
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
|
||||
<Headline
|
||||
|
||||
@@ -15,7 +15,6 @@ interface OpenTextQuestionProps {
|
||||
question: TSurveyOpenTextElement;
|
||||
value: string;
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
autoFocus?: boolean;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
@@ -30,7 +29,6 @@ export function OpenTextQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -95,7 +93,6 @@ export function OpenTextQuestion({
|
||||
|
||||
const updatedTtc = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtc);
|
||||
onSubmit({ [question.id]: value }, updatedTtc);
|
||||
};
|
||||
|
||||
const computedDir = !value ? dir : "auto";
|
||||
|
||||
@@ -16,7 +16,6 @@ interface PictureSelectionProps {
|
||||
question: TSurveyPictureSelectionElement;
|
||||
value: string[];
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -30,7 +29,6 @@ export function PictureSelectionQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -100,7 +98,6 @@ export function PictureSelectionQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
onSubmit({ [question.id]: value }, updatedTtcObj);
|
||||
}}
|
||||
className="fb-w-full">
|
||||
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
|
||||
|
||||
@@ -19,7 +19,6 @@ interface RankingQuestionProps {
|
||||
question: TSurveyRankingElement;
|
||||
value: string[];
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -32,7 +31,6 @@ export function RankingQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -83,9 +81,16 @@ export function RankingQuestion({
|
||||
|
||||
setLocalValue(newLocalValue);
|
||||
|
||||
// Immediately update parent state with the new ranking
|
||||
const sortedLabels = newLocalValue
|
||||
.map((id) => question.choices.find((c) => c.id === id))
|
||||
.filter((item): item is TSurveyQuestionChoice => item !== undefined)
|
||||
.map((item) => getLocalizedValue(item.label, languageCode));
|
||||
onChange({ [question.id]: sortedLabels });
|
||||
|
||||
setError(null);
|
||||
},
|
||||
[localValue]
|
||||
[localValue, question.choices, question.id, languageCode, onChange]
|
||||
);
|
||||
|
||||
const handleMove = useCallback(
|
||||
@@ -100,9 +105,16 @@ export function RankingQuestion({
|
||||
newLocalValue.splice(newIndex, 0, movedItem);
|
||||
setLocalValue(newLocalValue);
|
||||
|
||||
// Immediately update parent state with the new ranking
|
||||
const sortedLabels = newLocalValue
|
||||
.map((id) => question.choices.find((c) => c.id === id))
|
||||
.filter((item): item is TSurveyQuestionChoice => item !== undefined)
|
||||
.map((item) => getLocalizedValue(item.label, languageCode));
|
||||
onChange({ [question.id]: sortedLabels });
|
||||
|
||||
setError(null);
|
||||
},
|
||||
[localValue]
|
||||
[localValue, question.choices, question.id, languageCode, onChange]
|
||||
);
|
||||
|
||||
const handleSubmit = (e: Event) => {
|
||||
@@ -129,10 +141,7 @@ export function RankingQuestion({
|
||||
onChange({
|
||||
[question.id]: sortedItems.map((item) => getLocalizedValue(item.label, languageCode)),
|
||||
});
|
||||
onSubmit(
|
||||
{ [question.id]: sortedItems.map((item) => getLocalizedValue(item.label, languageCode)) },
|
||||
updatedTtcObj
|
||||
);
|
||||
// Note: onSubmit prop is () => {} in multi-element blocks, called by block instead
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -26,7 +26,6 @@ interface RatingQuestionProps {
|
||||
question: TSurveyRatingElement;
|
||||
value?: number;
|
||||
onChange: (responseData: TResponseData) => void;
|
||||
onSubmit: (data: TResponseData, ttc: TResponseTtc) => void;
|
||||
languageCode: string;
|
||||
ttc: TResponseTtc;
|
||||
setTtc: (ttc: TResponseTtc) => void;
|
||||
@@ -40,7 +39,6 @@ export function RatingQuestion({
|
||||
question,
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
languageCode,
|
||||
ttc,
|
||||
setTtc,
|
||||
@@ -58,14 +56,7 @@ export function RatingQuestion({
|
||||
onChange({ [question.id]: number });
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
setTimeout(() => {
|
||||
onSubmit(
|
||||
{
|
||||
[question.id]: number,
|
||||
},
|
||||
updatedTtcObj
|
||||
);
|
||||
}, 250);
|
||||
// Note: onSubmit prop is () => {} in multi-element blocks, called by block instead
|
||||
};
|
||||
|
||||
function HiddenRadioInput({ number, id }: { number: number; id?: string }) {
|
||||
@@ -112,7 +103,6 @@ export function RatingQuestion({
|
||||
e.preventDefault();
|
||||
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
|
||||
setTtc(updatedTtcObj);
|
||||
onSubmit({ [question.id]: value ?? "" }, updatedTtcObj);
|
||||
}}
|
||||
className="fb-w-full">
|
||||
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
|
||||
|
||||
Reference in New Issue
Block a user