fix: validation and tweaks

This commit is contained in:
Dhruwang
2024-03-19 18:59:12 +05:30
parent d7237b81da
commit f27f55a655
3 changed files with 199 additions and 151 deletions

View File

@@ -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;
}

View File

@@ -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,
};
});
};

View File

@@ -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,
};
});
};