Skip to content

TypeScript Survey DefinitionΒ #166

@engineeringstuff

Description

@engineeringstuff

Not an Issue

This isn't an issue, but there's nowhere else for this to go.

I went through the mappers and hand-crafted this TypeScript definition of the JSON so that you don't have to.

The definition

interface Identifier {
  id: string;
}

interface TextChoice {
  id?: string | undefined;
  text: string;
  value?: string | undefined;
}

type Rule = ConditionalNavigationRule | DirectNavigationRule;

interface ConditionalNavigationRule {
  type: "conditional";
  triggerStepIdentifier: Identifier;
  values: Record<string, string>;
}

interface DirectNavigationRule {
  type: "direct";
  triggerStepIdentifier: Identifier;
  destinationStepIdentifier: string;
}

interface Step {
  id?: string | undefined;
  content: Content[];
  isMandatory?: boolean | undefined;
  answerFormat?: AnswerFormat | undefined;
  buttonText?: string | undefined;
}

type Content =
  | AudioContent
  | TextContent
  | VideoContent
  | MarkdownContent
  | LottieContent;

type AudioContent = {
  type: "audio";
  url: string | undefined;
  title?: string | undefined;
  subtitle?: string | undefined;
  externalLink?: string | undefined;
  id?: string;
};

type TextContent = {
  type: "text";
  text: string;
  fontSize?: number | undefined;
  textAlign?:
    | "left"
    | "center"
    | "right"
    | "justify"
    | "start"
    | "end"
    | undefined;
  id?: string;
};

type VideoContent = {
  type: "video";
  url: string;
  id?: string;
  autoPlay?: boolean | undefined;
  loop?: boolean | undefined;
  width?: number | undefined;
  height?: number | undefined;
  title?: string | undefined;
  subtitle?: string | undefined;
  externalLink?: string | undefined;
};

type MarkdownContent = {
  type: "markdown";
  text: string;
  id?: string;
};

type LottieContent = {
  type: "lottie";
  url: string;
  id?: string;
  width?: number | undefined;
  height?: number | undefined;
  repeat?: boolean | undefined;
  asset?: string | undefined;
};

type AnswerFormat =
  | MultipleChoiceAnswerFormat
  | SingleChoiceAnswerFormat
  | BooleanAnswerFormat
  | DateAnswerFormat
  | DoubleAnswerFormat
  | IntegerAnswerFormat
  | TextAnswerFormat
  | TimeAnswerFormat
  | ScaleAnswerFormat
  | MultipleChoiceAutoCompleteAnswerFormat
  | MultipleDoubleAnswerFormat;

interface MultipleChoiceAnswerFormat {
  type: "multi";
  textChoices: TextChoice[];
  otherField?: boolean | undefined;
  defaultSelection?: TextChoice | undefined;
  question?: string | undefined;
}

interface SingleChoiceAnswerFormat {
  type: "single";
  textChoices: TextChoice[];
  defaultSelection?: TextChoice | undefined;
  question?: string | undefined;
}

interface BooleanAnswerFormat {
  type: "bool";
  positiveAnswer: string;
  negativeAnswer: string;
  result?: "positive" | "negative" | "none";
  question?: string | undefined;
}

interface DateAnswerFormat {
  type: "date";
  minDate?: string | undefined;
  maxDate?: string | undefined;
  defaultDate?: string | undefined;
  question?: string | undefined;
}

interface DoubleAnswerFormat {
  type: "double";
  defaultValue?: number | undefined;
  question?: string | undefined;
  hint?: string | undefined;
}

interface IntegerAnswerFormat {
  type: "integer";
  defaultValue?: number | undefined;
  question?: string | undefined;
  hint?: string | undefined;
  min?: number | undefined;
  max?: number | undefined;
}

interface TextAnswerFormat {
  type: "text";
  maxLines?: number | undefined;
  validationRegEx?: string | undefined;
  hint?: string | undefined;
  question?: string | undefined;
}

interface TimeAnswerFormat {
  type: "time";
  defaultValue?:
    | {
        hour?: number | undefined;
        minute?: number | undefined;
      }
    | undefined;
  question?: string | undefined;
}

interface ScaleAnswerFormat {
  type: "scale";
  step: number;
  minimumValue: number;
  maximumValue: number;
  defaultValue: number;
  minimumValueDescription?: string | undefined;
  maximumValueDescription?: string | undefined;
  question?: string | undefined;
}

interface MultipleChoiceAutoCompleteAnswerFormat {
  type: "multiple_auto_complete";
  otherField?: boolean | undefined;
  textChoices: TextChoice[];
  defaultSelection?: TextChoice | undefined;
  suggestions?: TextChoice[] | undefined;
  question?: string | undefined;
}

interface MultipleDoubleAnswerFormat {
  type: "multiple_double";
  defaultValues?: { text: string; value: number }[] | undefined;
  question?: string | undefined;
  hints?: string[] | undefined;
}

interface NavigableTask {
  id?: string | undefined;
  type: "navigable";
  rules?: Rule[] | undefined;
  steps?: Step[] | undefined;
}

interface OrderedTask {
  id?: string | undefined;
  type: "ordered";
  steps?: Step[] | undefined;
}

type Survey = NavigableTask | OrderedTask;

Things to note

  • When mapping from JSON we are missing some Content types - this is a limitation of the auto-generated mappers.
  • When mapping from JSON we're getting 100% of the same functionality that the library claims to offer. For example, there is no intro or completion screens available when mapping from JSON - this is a limitation of the auto-generated mappers.
  • I used undefined but you (or Dart) may prefer to use null or even add null | undefined.
  • The example JSON is extremely out of date and should not be relied upon.
  • Some identifiers are just strings, others are an object with { id: string } - this is a limitation of the auto-generated mappers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions