Move SignupForm validation schema building to front end
This commit is contained in:
@@ -11,6 +11,7 @@ export interface SignupForm {
|
||||
questions: Question[];
|
||||
signups: string[];
|
||||
quota: number;
|
||||
schema: object;
|
||||
}
|
||||
|
||||
export async function getForms(): Promise<SignupForm[]> {
|
||||
|
||||
@@ -6,6 +6,7 @@ import Form from "react-jsonschema-form";
|
||||
import { createForm, getForm, updateForm, SignupForm } from "@models/SignupForm";
|
||||
import DatetimeWidget from "@components/DatetimeWidget";
|
||||
import SignupQuestionsWidget from "@components/SignupQuestionsWidget";
|
||||
import { buildQuestionsSchema } from "@views/SignUpPage/FormUtils";
|
||||
|
||||
const widgets = {
|
||||
datetime: DatetimeWidget,
|
||||
@@ -59,9 +60,11 @@ class SignupCreatePage extends React.Component<SignupCreatePageProps, SignupCrea
|
||||
|
||||
onSubmit = async (data: any) => {
|
||||
try {
|
||||
const questions = JSON.parse(data.formData.questions);
|
||||
const payload: SignupForm = {
|
||||
...data.formData,
|
||||
questions: JSON.parse(data.formData.questions)
|
||||
questions,
|
||||
schema: buildQuestionsSchema(questions)
|
||||
}
|
||||
|
||||
if (payload.id === undefined) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
// HTML 5 email regex
|
||||
export const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
|
||||
// export const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
import { Question } from "@components/SignupQuestionsWidget";
|
||||
import { SignupForm } from "@models/SignupForm";
|
||||
import { EMAIL_REGEX } from "@utils/regexes";
|
||||
|
||||
const questionToSchemaProp = (question: Question): {} => {
|
||||
let obj: any;
|
||||
@@ -51,8 +52,7 @@ const questionToSchemaProp = (question: Question): {} => {
|
||||
type: "number",
|
||||
multipleOf: 1.0,
|
||||
title: `${question.name} (Max: ${question.options[0]})`,
|
||||
maximum: question.options[0],
|
||||
exclusiveMaximum: false
|
||||
maximum: Number(question.options[0]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +61,8 @@ const questionToSchemaProp = (question: Question): {} => {
|
||||
type: "number",
|
||||
multipleOf: 1.0,
|
||||
title: `${question.name} (${question.options[0]} -- ${question.options[1]})`,
|
||||
minimum: question.options[0],
|
||||
maximum: question.options[1],
|
||||
exclusiveMaximum: false
|
||||
minimum: Number(question.options[0]),
|
||||
maximum: Number(question.options[1]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +103,68 @@ const questionToUISchemaProp = (question: Question): {} => {
|
||||
};
|
||||
}
|
||||
|
||||
const questionToValidationSchema = (question: Question) => {
|
||||
if (question.type === "text") {
|
||||
return {
|
||||
type: "string",
|
||||
};
|
||||
}
|
||||
|
||||
if (question.type == "email") {
|
||||
// Format is just a "FYI" field, so we also have pattern.
|
||||
return {
|
||||
type: "string",
|
||||
format: "email",
|
||||
pattern: EMAIL_REGEX.source
|
||||
}
|
||||
}
|
||||
if (question.type == "radiobutton") {
|
||||
return {
|
||||
"type": "string",
|
||||
"pattern": question.options.map(x => `^${x}$`).join("|"),
|
||||
}
|
||||
}
|
||||
if (question.type == "checkbox") {
|
||||
return {
|
||||
type: "array",
|
||||
uniqueItems: true,
|
||||
maxItems: question.options.length,
|
||||
items: {
|
||||
type: "string",
|
||||
pattern: question.options.map(x => `^${x}$`).join("|"),
|
||||
}
|
||||
}
|
||||
}
|
||||
// https://json-schema.org/understanding-json-schema/reference/numeric.html
|
||||
else if (question.type === "integer") {
|
||||
if (question.options.length === 1) {
|
||||
return {
|
||||
type: "number",
|
||||
multipleOf: 1.0,
|
||||
title: `${question.name} (Max: ${question.options[0]})`,
|
||||
maximum: Number(question.options[0]),
|
||||
}
|
||||
}
|
||||
else if (question.options.length === 2) {
|
||||
return {
|
||||
type: "number",
|
||||
multipleOf: 1.0,
|
||||
title: `${question.name} (${question.options[0]} -- ${question.options[1]})`,
|
||||
minimum: Number(question.options[0]),
|
||||
maximum: Number(question.options[1]),
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
type: "number",
|
||||
multipleOf: 1.0,
|
||||
title: question.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error(`No mapping to schema prop for question type ${question.type}`);
|
||||
}
|
||||
|
||||
export const buildSchema = (signUpForm: SignupForm) => {
|
||||
const {questions} = signUpForm;
|
||||
const schemaPropsArray = questions.map(questionToSchemaProp);
|
||||
@@ -125,6 +186,25 @@ export const buildSchema = (signUpForm: SignupForm) => {
|
||||
return schema;
|
||||
}
|
||||
|
||||
export const buildQuestionsSchema = (questions: Question[]) => {
|
||||
const schemaProps = {};
|
||||
const filtered = questions.filter(x => x.type !== "info");
|
||||
const ids = filtered.map(q => q.id);
|
||||
const schemaPropsArray = filtered.map(questionToValidationSchema);
|
||||
schemaPropsArray.forEach((schemaProp, idx) => {
|
||||
schemaProps[ids[idx]] = schemaProp;
|
||||
});
|
||||
|
||||
const validationSchema = {
|
||||
type: "object",
|
||||
required: ids,
|
||||
minProperties: ids.length,
|
||||
// maxProperties: ids.length,
|
||||
properties: schemaProps
|
||||
}
|
||||
return validationSchema;
|
||||
}
|
||||
|
||||
export const buildUISchema = (signUpForm: SignupForm) => {
|
||||
const {questions} = signUpForm;
|
||||
const uiSchemaPropsArray = questions.map(questionToUISchemaProp);
|
||||
|
||||
Reference in New Issue
Block a user