-
Notifications
You must be signed in to change notification settings - Fork 9
How to create new questionnaire component (FRONTEND)
This document will guide you through creating a new component for the questionnaire in user office software. Whenever the example code is provided it will be provided for a component called Interval
You should start by reading the other part of this guide which talks about creating backend functionality. https://github.com/UserOfficeProject/user-office-core/wiki/How-to-create-new-questionnaire-component-(BACKEND)
Let's start by adding a new section in FieldConfig fragment to the src/graphql/template/fragment.fieldConfig.graphql This should correspond to the fields you added in the backend earlier Example
... on IntervalConfig {
units
small_label
required
tooltip
}
Create a new folder in src/components/questionary/questionaryComponents where to keep all component files. e.g. Interval
In the folder, you just created, create a new file e.g. IntervalDefinition.ts
This file will be your component definition and it conforms with the QuestionaryComponentDefinition interface
This definition file is used as a facade single entry point from the questionnaire engine to the component.
Here are the field names and descriptions the definition has
| Property | Type | Description |
|---|---|---|
| dataType | DataType | The enum value from DataType |
| name | string | A human-readable name |
| questionaryComponent | (props: BasicComponentProps) => JSX.Element | null | The main component that is rendered in the questionnaire and visible by the user (more on this below) |
| questionForm | () => FormComponent | A form used in the administration panel to define a question (more on this below) |
| questionTemplateRelationForm | () => FormComponent | A form used in the administration panel to define a question template relation (more on that below) |
| renderers | Renderers | Rendering of the question and answer that is displayed in the review, you can import and use the defaultRenderer for this field for the default behavior. If you want to exclude your question from review completely you can set renderers to undefined
|
| createYupValidationSchema | CreateYupValidation | null | Yup validation rules for the answer |
| getYupInitialValue | GetYupInitialValue; | Initial value for Yup validation framework |
| searchCriteriaComponent | FC | UI component that controls filter for searching questionnaire by the answer |
| readonly | boolean; | if true then no answer will be produced. This could be set to true for special or decorative components |
| creatable | boolean; | if true then the question can be added to a questionnaire. Could be set to false for special-purpose components |
| icon | JSX.Element | The icon for the component |
After specifying the component definition you need to register it by adding the reference in the registry array variable in src/components/questionary/QuestionaryComponentRegistry.tsx
const registry = [
booleanDefinition,
dateDefinition,
embellishmentDefinition,
...
intervalDefinition,
];
This is the main component shown in the questionnaire for the user to collect an answer. To communicate to the outside world the questionnaire component accepts props of type BasicComponentProps
interface BasicComponentProps {
answer: Answer;
onComplete: (evt: React.ChangeEvent<any>, newValue: any) => void;
touched: any;
errors: any;
}
the answer is the object containing information about the answer, including the question. This data type is generated on the server and is located in SDK in the client
call onComplete when the user enters the answer. This could be finishing entering text or selecting an option in the dropdown, etc. After calling onComplete the whole form will be re-rendered.
touched and errors are properties coming from Formik, so you can use these to display errors or perform UI tweaks. You can read more about it here https://formik.org/docs/api/formik
This is the form used in the administration panel to render the form that configures questions. Essentially component can be anything you want. To communicate to the outside world the QuestionForm accepts props of type FormProps
interface FormProps<ValueObjectType> {
field: ValueObjectType;
template: Template;
dispatch: React.Dispatch<Event>;
closeMe: () => any;
}
the field is of type Question which contains data like question text, datatype, etc...
template an object containing the whole template
dispatch could be used for more advanced communication to the questionnaire engine. To save the question dispatch event
dispatch({
type: EventType.UPDATE_QUESTION_REQUESTED,
payload: {
field: { ...props.question, ...form },
},
}
closeMe - request window to be closed
You can have anything you like here but there are few React components to make constructing this form much easier.
QuestionFormShell
- a wrapper that wraps your content in formik form,
- includes form buttons
- dispatches save event when saving
- closes the window when done
- accepts yup validation form for your fields that are specified as children
TitledContainer
- visually groups multiple related inputs together
- accept the label as a parameter
NOTE: This form is very similar to QuestionForm and there is a plan to reduce the duplicated code between the two QuestionTemplateRelationForm is used in the administration panel to render the form that configures questions related to the template. This form's purpose is:
- override the default values that were specified in the Question.
- specify a dependency on other questions if needed. See FormikUICustomDependencySelector
By adding your component to the component registry in the step above component should show up in the template editor under the Add question menu. It will use the icon and name from the component definition to render the menu item.
-
Backend
Learn more on how to implement the backend side of the questionnaire component -
Validation library
It is recommended to implement a validation schema for your new component in thevalidationlibrary. -
Questionnaire ERD
Learn more about the underlying data structure of the Questionnaire