Move SignupForm validation schema building to front end

This commit is contained in:
Aarni Halinen
2020-07-23 23:49:06 +03:00
parent 949d3a0d00
commit 4d3217fcc2
4 changed files with 94 additions and 6 deletions
+1
View File
@@ -11,6 +11,7 @@ export interface SignupForm {
questions: Question[];
signups: string[];
quota: number;
schema: object;
}
export async function getForms(): Promise<SignupForm[]> {
+4 -1
View File
@@ -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) {
+4
View File
@@ -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,}))$/
+85 -5
View File
@@ -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);