mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-20 02:30:18 -05:00
refactor: update validation rule types for survey elements
- Replace TValidationRule with specific validation rule types for each survey element in their respective forms. - Ensure type safety by introducing TValidationRulesFor* types for Address, Cal, Consent, Contact Info, CTA, Date, File Upload, Matrix, Multiple Choice, NPS, Open Text, Picture Selection, Ranking, and Rating elements. - Update the ZSurveyElement definitions to include the new validation rules schemas.
This commit is contained in:
@@ -4,9 +4,9 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { type JSX, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyAddressElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurveyAddressElement, TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForAddress } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -165,7 +165,7 @@ export const AddressElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.Address}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForAddress) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { type JSX, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyCalElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurveyCalElement, TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForCal } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -149,7 +149,7 @@ export const CalElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.Cal}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForCal) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { type JSX } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyConsentElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurveyConsentElement, TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForConsent } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -108,7 +108,7 @@ export const ConsentElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.Consent}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForConsent) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { type JSX, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyContactInfoElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurveyContactInfoElement, TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForContactInfo } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -162,7 +162,7 @@ export const ContactInfoElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.ContactInfo}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForContactInfo) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { type JSX } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyCTAElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurveyCTAElement, TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForCTA } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -148,7 +148,7 @@ export const CTAElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.CTA}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForCTA) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { type JSX } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyDateElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurveyDateElement, TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForDate } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -132,7 +132,7 @@ export const DateElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.Date}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForDate) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { TAllowedFileExtension, ZAllowedFileExtension } from "@formbricks/types/storage";
|
||||
import { TSurveyElementTypeEnum, TSurveyFileUploadElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForFileUpload } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -231,7 +231,7 @@ export const FileUploadElementForm = ({
|
||||
|
||||
updateElement(elementIdx, { maxSizeInMB: parseInt(e.target.value, 10) });
|
||||
}}
|
||||
className="ml-2 mr-2 inline w-20 bg-white text-center text-sm"
|
||||
className="mr-2 ml-2 inline w-20 bg-white text-center text-sm"
|
||||
/>
|
||||
MB
|
||||
</p>
|
||||
@@ -296,7 +296,7 @@ export const FileUploadElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.FileUpload}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForFileUpload) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { TI18nString } from "@formbricks/types/i18n";
|
||||
import { TSurveyElementTypeEnum, TSurveyMatrixElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForMatrix } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -353,7 +353,7 @@ export const MatrixElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.Matrix}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForMatrix) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -12,7 +12,10 @@ import { getLanguageLabel } from "@formbricks/i18n-utils/src/utils";
|
||||
import { TI18nString } from "@formbricks/types/i18n";
|
||||
import { TSurveyElementTypeEnum, TSurveyMultipleChoiceElement } from "@formbricks/types/surveys/elements";
|
||||
import { TShuffleOption, TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import {
|
||||
TValidationRulesForMultipleChoiceMulti,
|
||||
TValidationRulesForMultipleChoiceSingle,
|
||||
} from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -405,7 +408,7 @@ export const MultipleChoiceElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.MultipleChoiceMulti}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForMultipleChoiceMulti) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
@@ -415,7 +418,7 @@ export const MultipleChoiceElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.MultipleChoiceSingle}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForMultipleChoiceSingle) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { type JSX } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyNPSElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForNPS } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -146,7 +146,7 @@ export const NPSElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.NPS}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForNPS) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
TSurveyOpenTextElementInputType,
|
||||
} from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForOpenText } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -146,7 +146,7 @@ export const OpenElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.OpenText}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForOpenText) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { type JSX } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyPictureSelectionElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForPictureSelection } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { cn } from "@/lib/cn";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
@@ -176,7 +176,7 @@ export const PictureSelectionForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.PictureSelection}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForPictureSelection) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { TI18nString } from "@formbricks/types/i18n";
|
||||
import { TSurveyElementTypeEnum, TSurveyRankingElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForRanking } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -252,7 +252,7 @@ export const RankingElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.Ranking}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForRanking) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { HashIcon, PlusIcon, SmileIcon, StarIcon } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSurveyElementTypeEnum, TSurveyRatingElement } from "@formbricks/types/surveys/elements";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TValidationRule } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TValidationRulesForRating } from "@formbricks/types/surveys/validation-rules";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
|
||||
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
|
||||
@@ -195,7 +195,7 @@ export const RatingElementForm = ({
|
||||
<ValidationRulesEditor
|
||||
elementType={TSurveyElementTypeEnum.Rating}
|
||||
validationRules={element.validationRules ?? []}
|
||||
onUpdateRules={(rules: TValidationRule[]) => {
|
||||
onUpdateRules={(rules: TValidationRulesForRating) => {
|
||||
updateElement(elementIdx, {
|
||||
validationRules: rules,
|
||||
});
|
||||
|
||||
@@ -3,7 +3,22 @@ import { ZUrl } from "../common";
|
||||
import { ZI18nString } from "../i18n";
|
||||
import { ZAllowedFileExtension } from "../storage";
|
||||
import { FORBIDDEN_IDS } from "./validation";
|
||||
import { TValidationRule, ZValidationRules } from "./validation-rules";
|
||||
import {
|
||||
ZValidationRulesForAddress,
|
||||
ZValidationRulesForCal,
|
||||
ZValidationRulesForConsent,
|
||||
ZValidationRulesForContactInfo,
|
||||
ZValidationRulesForDate,
|
||||
ZValidationRulesForFileUpload,
|
||||
ZValidationRulesForMatrix,
|
||||
ZValidationRulesForMultipleChoiceMulti,
|
||||
ZValidationRulesForMultipleChoiceSingle,
|
||||
ZValidationRulesForNPS,
|
||||
ZValidationRulesForOpenText,
|
||||
ZValidationRulesForPictureSelection,
|
||||
ZValidationRulesForRanking,
|
||||
ZValidationRulesForRating,
|
||||
} from "./validation-rules";
|
||||
|
||||
// Element Type Enum (same as question types)
|
||||
export enum TSurveyElementTypeEnum {
|
||||
@@ -50,9 +65,8 @@ export const ZSurveyElementId = z.string().superRefine((id, ctx) => {
|
||||
|
||||
export type TSurveyElementId = z.infer<typeof ZSurveyElementId>;
|
||||
|
||||
const ZValidationRulesSafe: z.ZodType<TValidationRule[]> = z.lazy(() => ZValidationRules);
|
||||
|
||||
// Base element (like ZSurveyQuestionBase but WITHOUT logic, buttonLabel, backButtonLabel)
|
||||
// Note: validationRules is not included in base - each element type will add its own narrowed schema
|
||||
export const ZSurveyElementBase = z.object({
|
||||
id: ZSurveyElementId,
|
||||
type: z.nativeEnum(TSurveyElementTypeEnum),
|
||||
@@ -64,7 +78,6 @@ export const ZSurveyElementBase = z.object({
|
||||
scale: z.enum(["number", "smiley", "star"]).optional(),
|
||||
range: z.union([z.literal(5), z.literal(3), z.literal(4), z.literal(7), z.literal(10)]).optional(),
|
||||
isDraft: z.boolean().optional(),
|
||||
validationRules: ZValidationRulesSafe.optional(),
|
||||
});
|
||||
|
||||
// OpenText Element
|
||||
@@ -84,6 +97,7 @@ export const ZSurveyOpenTextElement = ZSurveyElementBase.extend({
|
||||
max: z.number().optional(),
|
||||
})
|
||||
.default({ enabled: false }),
|
||||
validationRules: ZValidationRulesForOpenText.optional(),
|
||||
}).superRefine((data, ctx) => {
|
||||
if (data.charLimit.enabled && data.charLimit.min === undefined && data.charLimit.max === undefined) {
|
||||
ctx.addIssue({
|
||||
@@ -120,6 +134,7 @@ export type TSurveyOpenTextElement = z.infer<typeof ZSurveyOpenTextElement>;
|
||||
export const ZSurveyConsentElement = ZSurveyElementBase.extend({
|
||||
type: z.literal(TSurveyElementTypeEnum.Consent),
|
||||
label: ZI18nString,
|
||||
validationRules: ZValidationRulesForConsent.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyConsentElement = z.infer<typeof ZSurveyConsentElement>;
|
||||
@@ -135,18 +150,34 @@ export type TSurveyElementChoice = z.infer<typeof ZSurveyElementChoice>;
|
||||
export const ZShuffleOption = z.enum(["none", "all", "exceptLast"]);
|
||||
export type TShuffleOption = z.infer<typeof ZShuffleOption>;
|
||||
|
||||
export const ZSurveyMultipleChoiceElement = ZSurveyElementBase.extend({
|
||||
type: z.union([
|
||||
z.literal(TSurveyElementTypeEnum.MultipleChoiceSingle),
|
||||
z.literal(TSurveyElementTypeEnum.MultipleChoiceMulti),
|
||||
]),
|
||||
// Multiple Choice Single Element
|
||||
export const ZSurveyMultipleChoiceSingleElement = ZSurveyElementBase.extend({
|
||||
type: z.literal(TSurveyElementTypeEnum.MultipleChoiceSingle),
|
||||
choices: z
|
||||
.array(ZSurveyElementChoice)
|
||||
.min(2, { message: "Multiple Choice Element must have at least two choices" }),
|
||||
shuffleOption: ZShuffleOption.optional(),
|
||||
otherOptionPlaceholder: ZI18nString.optional(),
|
||||
validationRules: ZValidationRulesForMultipleChoiceSingle.optional(),
|
||||
});
|
||||
|
||||
// Multiple Choice Multi Element
|
||||
export const ZSurveyMultipleChoiceMultiElement = ZSurveyElementBase.extend({
|
||||
type: z.literal(TSurveyElementTypeEnum.MultipleChoiceMulti),
|
||||
choices: z
|
||||
.array(ZSurveyElementChoice)
|
||||
.min(2, { message: "Multiple Choice Element must have at least two choices" }),
|
||||
shuffleOption: ZShuffleOption.optional(),
|
||||
otherOptionPlaceholder: ZI18nString.optional(),
|
||||
validationRules: ZValidationRulesForMultipleChoiceMulti.optional(),
|
||||
});
|
||||
|
||||
// Union type for Multiple Choice Elements
|
||||
export const ZSurveyMultipleChoiceElement = z.union([
|
||||
ZSurveyMultipleChoiceSingleElement,
|
||||
ZSurveyMultipleChoiceMultiElement,
|
||||
]);
|
||||
|
||||
export type TSurveyMultipleChoiceElement = z.infer<typeof ZSurveyMultipleChoiceElement>;
|
||||
|
||||
// NPS Element
|
||||
@@ -155,6 +186,7 @@ export const ZSurveyNPSElement = ZSurveyElementBase.extend({
|
||||
lowerLabel: ZI18nString.optional(),
|
||||
upperLabel: ZI18nString.optional(),
|
||||
isColorCodingEnabled: z.boolean().optional().default(false),
|
||||
validationRules: ZValidationRulesForNPS.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyNPSElement = z.infer<typeof ZSurveyNPSElement>;
|
||||
@@ -206,6 +238,7 @@ export const ZSurveyRatingElement = ZSurveyElementBase.extend({
|
||||
lowerLabel: ZI18nString.optional(),
|
||||
upperLabel: ZI18nString.optional(),
|
||||
isColorCodingEnabled: z.boolean().optional().default(false),
|
||||
validationRules: ZValidationRulesForRating.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyRatingElement = z.infer<typeof ZSurveyRatingElement>;
|
||||
@@ -224,6 +257,7 @@ export const ZSurveyPictureSelectionElement = ZSurveyElementBase.extend({
|
||||
choices: z
|
||||
.array(ZSurveyPictureChoice)
|
||||
.min(2, { message: "Picture Selection element must have a minimum of 2 choices" }),
|
||||
validationRules: ZValidationRulesForPictureSelection.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyPictureSelectionElement = z.infer<typeof ZSurveyPictureSelectionElement>;
|
||||
@@ -233,6 +267,7 @@ export const ZSurveyDateElement = ZSurveyElementBase.extend({
|
||||
type: z.literal(TSurveyElementTypeEnum.Date),
|
||||
html: ZI18nString.optional(),
|
||||
format: z.enum(["M-d-y", "d-M-y", "y-M-d"]),
|
||||
validationRules: ZValidationRulesForDate.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyDateElement = z.infer<typeof ZSurveyDateElement>;
|
||||
@@ -243,6 +278,7 @@ export const ZSurveyFileUploadElement = ZSurveyElementBase.extend({
|
||||
allowMultipleFiles: z.boolean(),
|
||||
maxSizeInMB: z.number().optional(),
|
||||
allowedFileExtensions: z.array(ZAllowedFileExtension).optional(),
|
||||
validationRules: ZValidationRulesForFileUpload.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyFileUploadElement = z.infer<typeof ZSurveyFileUploadElement>;
|
||||
@@ -252,6 +288,7 @@ export const ZSurveyCalElement = ZSurveyElementBase.extend({
|
||||
type: z.literal(TSurveyElementTypeEnum.Cal),
|
||||
calUserName: z.string().min(1, { message: "Cal user name is required" }),
|
||||
calHost: z.string().optional(),
|
||||
validationRules: ZValidationRulesForCal.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyCalElement = z.infer<typeof ZSurveyCalElement>;
|
||||
@@ -269,6 +306,7 @@ export const ZSurveyMatrixElement = ZSurveyElementBase.extend({
|
||||
rows: z.array(ZSurveyMatrixElementChoice),
|
||||
columns: z.array(ZSurveyMatrixElementChoice),
|
||||
shuffleOption: ZShuffleOption.optional().default("none"),
|
||||
validationRules: ZValidationRulesForMatrix.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyMatrixElement = z.infer<typeof ZSurveyMatrixElement>;
|
||||
@@ -290,6 +328,7 @@ export const ZSurveyAddressElement = ZSurveyElementBase.extend({
|
||||
state: ZToggleInputConfig,
|
||||
zip: ZToggleInputConfig,
|
||||
country: ZToggleInputConfig,
|
||||
validationRules: ZValidationRulesForAddress.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyAddressElement = z.infer<typeof ZSurveyAddressElement>;
|
||||
@@ -303,6 +342,7 @@ export const ZSurveyRankingElement = ZSurveyElementBase.extend({
|
||||
.max(25, { message: "Ranking Element can have at most 25 options" }),
|
||||
otherOptionPlaceholder: ZI18nString.optional(),
|
||||
shuffleOption: ZShuffleOption.optional(),
|
||||
validationRules: ZValidationRulesForRanking.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyRankingElement = z.infer<typeof ZSurveyRankingElement>;
|
||||
@@ -315,6 +355,7 @@ export const ZSurveyContactInfoElement = ZSurveyElementBase.extend({
|
||||
email: ZToggleInputConfig,
|
||||
phone: ZToggleInputConfig,
|
||||
company: ZToggleInputConfig,
|
||||
validationRules: ZValidationRulesForContactInfo.optional(),
|
||||
});
|
||||
|
||||
export type TSurveyContactInfoElement = z.infer<typeof ZSurveyContactInfoElement>;
|
||||
@@ -323,7 +364,8 @@ export type TSurveyContactInfoElement = z.infer<typeof ZSurveyContactInfoElement
|
||||
export const ZSurveyElement = z.union([
|
||||
ZSurveyOpenTextElement,
|
||||
ZSurveyConsentElement,
|
||||
ZSurveyMultipleChoiceElement,
|
||||
ZSurveyMultipleChoiceSingleElement,
|
||||
ZSurveyMultipleChoiceMultiElement,
|
||||
ZSurveyNPSElement,
|
||||
ZSurveyCTAElement,
|
||||
ZSurveyRatingElement,
|
||||
|
||||
@@ -248,3 +248,213 @@ export type TValidationRulesForAddress = TValidationRulesForElementType<typeof A
|
||||
export type TValidationRulesForContactInfo = TValidationRulesForElementType<typeof CONTACT_INFO_RULES>;
|
||||
export type TValidationRulesForCal = TValidationRulesForElementType<typeof CAL_RULES>;
|
||||
export type TValidationRulesForCTA = TValidationRulesForElementType<typeof CTA_RULES>;
|
||||
|
||||
// Element-specific validation rules schemas (manually created for type safety)
|
||||
// These are narrowed versions of ZValidationRule that only include applicable rule types
|
||||
export const ZValidationRulesForOpenText: z.ZodType<TValidationRulesForOpenText> = z.array(
|
||||
z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("minLength"),
|
||||
params: ZValidationRuleParamsMinLength,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("maxLength"),
|
||||
params: ZValidationRuleParamsMaxLength,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("pattern"),
|
||||
params: ZValidationRuleParamsPattern,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("email"),
|
||||
params: ZValidationRuleParamsEmail,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("url"),
|
||||
params: ZValidationRuleParamsUrl,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("phone"),
|
||||
params: ZValidationRuleParamsPhone,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("minValue"),
|
||||
params: ZValidationRuleParamsMinValue,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("maxValue"),
|
||||
params: ZValidationRuleParamsMaxValue,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
])
|
||||
);
|
||||
|
||||
export const ZValidationRulesForMultipleChoiceSingle: z.ZodType<TValidationRulesForMultipleChoiceSingle> =
|
||||
z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForMultipleChoiceMulti: z.ZodType<TValidationRulesForMultipleChoiceMulti> =
|
||||
z.array(
|
||||
z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("minSelections"),
|
||||
params: ZValidationRuleParamsMinSelections,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("maxSelections"),
|
||||
params: ZValidationRuleParamsMaxSelections,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
])
|
||||
);
|
||||
|
||||
export const ZValidationRulesForRating: z.ZodType<TValidationRulesForRating> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForNPS: z.ZodType<TValidationRulesForNPS> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForDate: z.ZodType<TValidationRulesForDate> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForConsent: z.ZodType<TValidationRulesForConsent> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForMatrix: z.ZodType<TValidationRulesForMatrix> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForRanking: z.ZodType<TValidationRulesForRanking> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForFileUpload: z.ZodType<TValidationRulesForFileUpload> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForPictureSelection: z.ZodType<TValidationRulesForPictureSelection> = z.array(
|
||||
z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("minSelections"),
|
||||
params: ZValidationRuleParamsMinSelections,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("maxSelections"),
|
||||
params: ZValidationRuleParamsMaxSelections,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
}),
|
||||
])
|
||||
);
|
||||
|
||||
export const ZValidationRulesForAddress: z.ZodType<TValidationRulesForAddress> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForContactInfo: z.ZodType<TValidationRulesForContactInfo> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForCal: z.ZodType<TValidationRulesForCal> = z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
type: z.literal("required"),
|
||||
params: ZValidationRuleParamsRequired,
|
||||
customErrorMessage: ZI18nString.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const ZValidationRulesForCTA: z.ZodType<TValidationRulesForCTA> = z.array(z.never());
|
||||
|
||||
Reference in New Issue
Block a user