mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-11 19:08:20 -05:00
fix: validation and tweaks
This commit is contained in:
@@ -63,7 +63,7 @@ const validationRules = {
|
||||
];
|
||||
|
||||
for (const field of fieldsToValidate) {
|
||||
if (question[field] && question[field][defaultLanguageCode]) {
|
||||
if (question[field] && typeof question[field][defaultLanguageCode] !== "undefined") {
|
||||
isValid =
|
||||
isValid && isLabelValidForAllLanguages(question[field], languages) && isValidCTADismissLabel;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,12 @@ import {
|
||||
TSurveyRatingQuestion,
|
||||
TSurveyThankYouCard,
|
||||
TSurveyWelcomeCard,
|
||||
ZSurvey,
|
||||
ZSurveyCTAQuestion,
|
||||
ZSurveyCalQuestion,
|
||||
ZSurveyConsentQuestion,
|
||||
ZSurveyFileUploadQuestion,
|
||||
ZSurveyMultipleChoiceMultiQuestion,
|
||||
ZSurveyMultipleChoiceSingleQuestion,
|
||||
ZSurveyNPSQuestion,
|
||||
ZSurveyOpenTextQuestion,
|
||||
@@ -170,7 +172,9 @@ const translateQuestion = (
|
||||
clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion
|
||||
).otherOptionPlaceholder = createI18nString(question.otherOptionPlaceholder ?? "", languages);
|
||||
}
|
||||
return ZSurveyMultipleChoiceSingleQuestion.parse(clonedQuestion);
|
||||
if (question.type === "multipleChoiceSingle") {
|
||||
return ZSurveyMultipleChoiceSingleQuestion.parse(clonedQuestion);
|
||||
} else return ZSurveyMultipleChoiceMultiQuestion.parse(clonedQuestion);
|
||||
|
||||
case "cta":
|
||||
if (typeof question.dismissButtonLabel === "string") {
|
||||
@@ -255,10 +259,10 @@ export const translateSurvey = (
|
||||
const translatedWelcomeCard = translateWelcomeCard(survey.welcomeCard, languages);
|
||||
const translatedThankYouCard = translateThankYouCard(survey.thankYouCard, languages);
|
||||
const translatedSurvey = structuredClone(survey);
|
||||
return {
|
||||
return ZSurvey.parse({
|
||||
...translatedSurvey,
|
||||
questions: translatedQuestions,
|
||||
welcomeCard: translatedWelcomeCard,
|
||||
thankYouCard: translatedThankYouCard,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,16 +1,41 @@
|
||||
import {
|
||||
TLegacySurveyChoice,
|
||||
TLegacySurveyQuestion,
|
||||
TLegacySurveyThankYouCard,
|
||||
TLegacySurveyWelcomeCard,
|
||||
} from "@formbricks/types/LegacySurvey";
|
||||
import { TLanguage } from "@formbricks/types/product";
|
||||
import {
|
||||
TI18nString,
|
||||
TSurvey,
|
||||
TSurveyCTAQuestion,
|
||||
TSurveyChoice,
|
||||
TSurveyConsentQuestion,
|
||||
TSurveyLanguage,
|
||||
TSurveyMultipleChoiceMultiQuestion,
|
||||
TSurveyMultipleChoiceSingleQuestion,
|
||||
TSurveyNPSQuestion,
|
||||
TSurveyOpenTextQuestion,
|
||||
TSurveyQuestion,
|
||||
TSurveyRatingQuestion,
|
||||
TSurveyThankYouCard,
|
||||
TSurveyWelcomeCard,
|
||||
ZSurvey,
|
||||
ZSurveyCTAQuestion,
|
||||
ZSurveyCalQuestion,
|
||||
ZSurveyConsentQuestion,
|
||||
ZSurveyFileUploadQuestion,
|
||||
ZSurveyMultipleChoiceMultiQuestion,
|
||||
ZSurveyMultipleChoiceSingleQuestion,
|
||||
ZSurveyNPSQuestion,
|
||||
ZSurveyOpenTextQuestion,
|
||||
ZSurveyPictureSelectionQuestion,
|
||||
ZSurveyQuestion,
|
||||
ZSurveyRatingQuestion,
|
||||
ZSurveyThankYouCard,
|
||||
ZSurveyWelcomeCard,
|
||||
} from "@formbricks/types/surveys";
|
||||
import {
|
||||
TSurvey,
|
||||
TSurveyLanguage,
|
||||
TSurveyMultipleChoiceMultiQuestion,
|
||||
TSurveyQuestion,
|
||||
} from "@formbricks/types/surveys";
|
||||
|
||||
// Helper function to create an i18nString from a regular string.
|
||||
@@ -92,185 +117,204 @@ export const getEnabledLanguages = (surveyLanguages: TSurveyLanguage[]) => {
|
||||
return surveyLanguages.filter((surveyLanguage) => surveyLanguage.enabled);
|
||||
};
|
||||
|
||||
// LGEGACY
|
||||
// Helper function to maintain backwards compatibility for old survey objects before Multi Language
|
||||
export const translateWelcomeCard = (
|
||||
welcomeCard: TSurveyWelcomeCard,
|
||||
languages: string[],
|
||||
targetLanguageCode?: string
|
||||
): TSurveyWelcomeCard => {
|
||||
const clonedWelcomeCard = structuredClone(welcomeCard);
|
||||
if (welcomeCard.headline) {
|
||||
clonedWelcomeCard.headline = createI18nString(welcomeCard.headline, languages, targetLanguageCode);
|
||||
const translateChoice = (choice: TSurveyChoice | TLegacySurveyChoice, languages: string[]): TSurveyChoice => {
|
||||
if (typeof choice.label === "string") {
|
||||
return {
|
||||
...choice,
|
||||
label: createI18nString(choice.label, languages),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...choice,
|
||||
label: choice.label,
|
||||
};
|
||||
}
|
||||
if (welcomeCard.html) {
|
||||
clonedWelcomeCard.html = createI18nString(welcomeCard.html, languages, targetLanguageCode);
|
||||
}
|
||||
if (clonedWelcomeCard.buttonLabel) {
|
||||
clonedWelcomeCard.buttonLabel = createI18nString(
|
||||
clonedWelcomeCard.buttonLabel,
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
|
||||
return clonedWelcomeCard;
|
||||
};
|
||||
|
||||
// LGEGACY
|
||||
// Helper function to maintain backwards compatibility for old survey objects before Multi Language
|
||||
export const translateThankYouCard = (
|
||||
thankYouCard: TSurveyThankYouCard,
|
||||
languages: string[],
|
||||
targetLanguageCode?: string
|
||||
): TSurveyThankYouCard => {
|
||||
const clonedThankYouCard = structuredClone(thankYouCard);
|
||||
if (thankYouCard.headline) {
|
||||
clonedThankYouCard.headline = createI18nString(thankYouCard.headline, languages, targetLanguageCode);
|
||||
export const translateWelcomeCard = (
|
||||
welcomeCard: TSurveyWelcomeCard | TLegacySurveyWelcomeCard,
|
||||
languages: string[]
|
||||
): TSurveyWelcomeCard => {
|
||||
const clonedWelcomeCard = structuredClone(welcomeCard);
|
||||
if (typeof welcomeCard.headline === "string") {
|
||||
clonedWelcomeCard.headline = createI18nString(welcomeCard.headline ?? "", languages);
|
||||
}
|
||||
if (thankYouCard.subheader) {
|
||||
clonedThankYouCard.subheader = createI18nString(thankYouCard.subheader, languages, targetLanguageCode);
|
||||
if (typeof welcomeCard.html === "string") {
|
||||
clonedWelcomeCard.html = createI18nString(welcomeCard.html ?? "", languages);
|
||||
}
|
||||
if (thankYouCard.buttonLabel) {
|
||||
clonedThankYouCard.buttonLabel = createI18nString(
|
||||
thankYouCard.buttonLabel,
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
if (typeof welcomeCard.buttonLabel === "string") {
|
||||
clonedWelcomeCard.buttonLabel = createI18nString(clonedWelcomeCard.buttonLabel ?? "", languages);
|
||||
}
|
||||
|
||||
return clonedThankYouCard;
|
||||
return ZSurveyWelcomeCard.parse(clonedWelcomeCard);
|
||||
};
|
||||
|
||||
// LGEGACY
|
||||
// Helper function to maintain backwards compatibility for old survey objects before Multi Language
|
||||
const translateThankYouCard = (
|
||||
thankYouCard: TSurveyThankYouCard | TLegacySurveyThankYouCard,
|
||||
languages: string[]
|
||||
): TSurveyThankYouCard => {
|
||||
const clonedThankYouCard = structuredClone(thankYouCard);
|
||||
|
||||
if (typeof thankYouCard.headline === "string") {
|
||||
clonedThankYouCard.headline = createI18nString(thankYouCard.headline ?? "", languages);
|
||||
}
|
||||
|
||||
if (typeof thankYouCard.subheader === "string") {
|
||||
clonedThankYouCard.subheader = createI18nString(thankYouCard.subheader ?? "", languages);
|
||||
}
|
||||
|
||||
if (typeof clonedThankYouCard.buttonLabel === "string") {
|
||||
clonedThankYouCard.buttonLabel = createI18nString(thankYouCard.buttonLabel ?? "", languages);
|
||||
}
|
||||
return ZSurveyThankYouCard.parse(clonedThankYouCard);
|
||||
};
|
||||
|
||||
// LGEGACY
|
||||
// Helper function to maintain backwards compatibility for old survey objects before Multi Language
|
||||
export const translateQuestion = (
|
||||
question: TSurveyQuestion,
|
||||
languages: string[],
|
||||
targetLanguageCode?: string
|
||||
) => {
|
||||
question: TLegacySurveyQuestion | TSurveyQuestion,
|
||||
languages: string[]
|
||||
): TSurveyQuestion => {
|
||||
// Clone the question to avoid mutating the original
|
||||
const clonedQuestion = structuredClone(question);
|
||||
|
||||
clonedQuestion.headline = createI18nString(question.headline, languages, targetLanguageCode);
|
||||
if (clonedQuestion.subheader) {
|
||||
clonedQuestion.subheader = createI18nString(question.subheader ?? "", languages, targetLanguageCode);
|
||||
//common question properties
|
||||
if (typeof question.headline === "string") {
|
||||
clonedQuestion.headline = createI18nString(question.headline ?? "", languages);
|
||||
}
|
||||
|
||||
if (clonedQuestion.buttonLabel) {
|
||||
clonedQuestion.buttonLabel = createI18nString(question.buttonLabel ?? "", languages, targetLanguageCode);
|
||||
if (typeof question.subheader === "string") {
|
||||
clonedQuestion.subheader = createI18nString(question.subheader ?? "", languages);
|
||||
}
|
||||
|
||||
if (clonedQuestion.backButtonLabel) {
|
||||
clonedQuestion.backButtonLabel = createI18nString(
|
||||
question.backButtonLabel ?? "",
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
if (typeof question.buttonLabel === "string") {
|
||||
clonedQuestion.buttonLabel = createI18nString(question.buttonLabel ?? "", languages);
|
||||
}
|
||||
|
||||
if (question.type === "multipleChoiceSingle" || question.type === "multipleChoiceMulti") {
|
||||
(clonedQuestion as TSurveyMultipleChoiceMultiQuestion | TSurveyMultipleChoiceMultiQuestion).choices =
|
||||
question.choices.map((choice) => ({
|
||||
...choice,
|
||||
label: createI18nString(choice.label, languages, targetLanguageCode),
|
||||
}));
|
||||
(
|
||||
clonedQuestion as TSurveyMultipleChoiceMultiQuestion | TSurveyMultipleChoiceMultiQuestion
|
||||
).otherOptionPlaceholder = question.otherOptionPlaceholder
|
||||
? createI18nString(question.otherOptionPlaceholder, languages, targetLanguageCode)
|
||||
: undefined;
|
||||
if (typeof question.backButtonLabel === "string") {
|
||||
clonedQuestion.backButtonLabel = createI18nString(question.backButtonLabel ?? "", languages);
|
||||
}
|
||||
if (question.type === "openText") {
|
||||
if (question.placeholder) {
|
||||
(clonedQuestion as TSurveyOpenTextQuestion).placeholder = createI18nString(
|
||||
question.placeholder,
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
}
|
||||
if (question.type === "cta") {
|
||||
if (question.dismissButtonLabel) {
|
||||
(clonedQuestion as TSurveyCTAQuestion).dismissButtonLabel = createI18nString(
|
||||
question.dismissButtonLabel,
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
if (question.html) {
|
||||
(clonedQuestion as TSurveyCTAQuestion).html = createI18nString(
|
||||
question.html,
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
}
|
||||
if (question.type === "consent") {
|
||||
if (question.html) {
|
||||
(clonedQuestion as TSurveyConsentQuestion).html = createI18nString(
|
||||
question.html,
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
|
||||
if (question.label) {
|
||||
(clonedQuestion as TSurveyConsentQuestion).label = createI18nString(
|
||||
question.label,
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
switch (question.type) {
|
||||
case "openText":
|
||||
if (typeof question.placeholder === "string") {
|
||||
(clonedQuestion as TSurveyOpenTextQuestion).placeholder = createI18nString(
|
||||
question.placeholder ?? "",
|
||||
languages
|
||||
);
|
||||
}
|
||||
return ZSurveyOpenTextQuestion.parse(clonedQuestion);
|
||||
|
||||
case "multipleChoiceSingle":
|
||||
case "multipleChoiceMulti":
|
||||
(clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion).choices =
|
||||
question.choices.map((choice) => {
|
||||
return translateChoice(choice, languages);
|
||||
});
|
||||
if (
|
||||
typeof (clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion)
|
||||
.otherOptionPlaceholder === "string"
|
||||
) {
|
||||
(
|
||||
clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion
|
||||
).otherOptionPlaceholder = createI18nString(question.otherOptionPlaceholder ?? "", languages);
|
||||
}
|
||||
if (question.type === "multipleChoiceSingle") {
|
||||
return ZSurveyMultipleChoiceSingleQuestion.parse(clonedQuestion);
|
||||
} else return ZSurveyMultipleChoiceMultiQuestion.parse(clonedQuestion);
|
||||
|
||||
case "cta":
|
||||
if (typeof question.dismissButtonLabel === "string") {
|
||||
(clonedQuestion as TSurveyCTAQuestion).dismissButtonLabel = createI18nString(
|
||||
question.dismissButtonLabel ?? "",
|
||||
languages
|
||||
);
|
||||
}
|
||||
if (typeof question.html === "string") {
|
||||
(clonedQuestion as TSurveyCTAQuestion).html = createI18nString(question.html ?? "", languages);
|
||||
}
|
||||
return ZSurveyCTAQuestion.parse(clonedQuestion);
|
||||
|
||||
case "consent":
|
||||
if (typeof question.html === "string") {
|
||||
(clonedQuestion as TSurveyConsentQuestion).html = createI18nString(question.html ?? "", languages);
|
||||
}
|
||||
|
||||
if (typeof question.label === "string") {
|
||||
(clonedQuestion as TSurveyConsentQuestion).label = createI18nString(question.label ?? "", languages);
|
||||
}
|
||||
return ZSurveyConsentQuestion.parse(clonedQuestion);
|
||||
|
||||
case "nps":
|
||||
if (typeof question.lowerLabel === "string") {
|
||||
(clonedQuestion as TSurveyNPSQuestion).lowerLabel = createI18nString(
|
||||
question.lowerLabel ?? "",
|
||||
languages
|
||||
);
|
||||
}
|
||||
if (typeof question.upperLabel === "string") {
|
||||
(clonedQuestion as TSurveyNPSQuestion).upperLabel = createI18nString(
|
||||
question.upperLabel ?? "",
|
||||
languages
|
||||
);
|
||||
}
|
||||
return ZSurveyNPSQuestion.parse(clonedQuestion);
|
||||
|
||||
case "rating":
|
||||
if (typeof question.lowerLabel === "string") {
|
||||
(clonedQuestion as TSurveyRatingQuestion).lowerLabel = createI18nString(
|
||||
question.lowerLabel ?? "",
|
||||
languages
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof question.upperLabel === "string") {
|
||||
(clonedQuestion as TSurveyRatingQuestion).upperLabel = createI18nString(
|
||||
question.upperLabel ?? "",
|
||||
languages
|
||||
);
|
||||
}
|
||||
return ZSurveyRatingQuestion.parse(clonedQuestion);
|
||||
|
||||
case "fileUpload":
|
||||
return ZSurveyFileUploadQuestion.parse(clonedQuestion);
|
||||
|
||||
case "pictureSelection":
|
||||
return ZSurveyPictureSelectionQuestion.parse(clonedQuestion);
|
||||
|
||||
case "cal":
|
||||
return ZSurveyCalQuestion.parse(clonedQuestion);
|
||||
|
||||
default:
|
||||
return ZSurveyQuestion.parse(clonedQuestion);
|
||||
}
|
||||
if (question.type === "nps") {
|
||||
(clonedQuestion as TSurveyNPSQuestion).lowerLabel = createI18nString(
|
||||
question.lowerLabel ?? "",
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
(clonedQuestion as TSurveyNPSQuestion).upperLabel = createI18nString(
|
||||
question.upperLabel ?? "",
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
if (question.type === "rating") {
|
||||
(clonedQuestion as TSurveyRatingQuestion).lowerLabel = createI18nString(
|
||||
question.lowerLabel ?? "",
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
(clonedQuestion as TSurveyRatingQuestion).upperLabel = createI18nString(
|
||||
question.upperLabel ?? "",
|
||||
languages,
|
||||
targetLanguageCode
|
||||
);
|
||||
}
|
||||
return clonedQuestion;
|
||||
};
|
||||
|
||||
export const extractLanguageIds = (languages: TLanguage[]): string[] => {
|
||||
return languages.map((language) => language.id);
|
||||
};
|
||||
|
||||
// LGEGACY
|
||||
// Helper function to maintain backwards compatibility for old survey objects before Multi Language
|
||||
export const translateSurvey = (
|
||||
survey: TSurvey,
|
||||
surveyLanguages: TSurveyLanguage[],
|
||||
targetLanguageCode?: string
|
||||
): TSurvey => {
|
||||
const languages = extractLanguageCodes(surveyLanguages);
|
||||
|
||||
survey: Pick<TSurvey, "questions" | "welcomeCard" | "thankYouCard">,
|
||||
surveyLanguages: TLanguage[]
|
||||
): Pick<TSurvey, "questions" | "welcomeCard" | "thankYouCard"> => {
|
||||
const languages = extractLanguageIds(surveyLanguages);
|
||||
const translatedQuestions = survey.questions.map((question) => {
|
||||
return translateQuestion(question, languages, targetLanguageCode);
|
||||
return translateQuestion(question, languages);
|
||||
});
|
||||
const translatedWelcomeCard =
|
||||
survey.welcomeCard && translateWelcomeCard(survey.welcomeCard, languages, targetLanguageCode);
|
||||
const translatedThankYouCard =
|
||||
survey.thankYouCard && translateThankYouCard(survey.thankYouCard, languages, targetLanguageCode);
|
||||
const translatedWelcomeCard = translateWelcomeCard(survey.welcomeCard, languages);
|
||||
const translatedThankYouCard = translateThankYouCard(survey.thankYouCard, languages);
|
||||
const translatedSurvey = structuredClone(survey);
|
||||
return {
|
||||
return ZSurvey.parse({
|
||||
...translatedSurvey,
|
||||
questions: translatedQuestions,
|
||||
welcomeCard: translatedWelcomeCard,
|
||||
thankYouCard: translatedThankYouCard,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user