@qonsoll/asq
v0.1.0
Published
Type-Form
Downloads
5
Maintainers
Keywords
Readme
Qonsoll form documentation
Qonsoll form is a service for surveys' form builder. It makes collecting and sharing information comfortable and conversational. Current project is used as module in other projects.
- How to run app localy for further changes
- How to implement module in existing project
- How to run app with already installed module
- How to configure workflow
- How to configure and use module
- How to configure module theme
- How to configure translations
How to run app localy for further changes
Pull the project using folowing command:
git clone --recurse-submodules https://github.com/fractal-academy/qonsoll-form-wrapper
Switch to project folder:
cd qonsoll-form-wrapper
Install all dependecies and pull latest changes:
npm i
Some packages need manual instalation. Run following command:
npm i fuse.js use-media
❗ For correct work of components you'll need to add an index to your firebase. In console firebase select your project, go to Firestore Database menu item and choose Indexes tab.
Add formId
and order
as indexed fields for questions collection. Leave index rule default (ascending).
How to implement module in existing project
If it's first initialisation of module in project create folder for modules in directory of your existing project:
mkdir src/modules
Go to the created folder:
cd src/modules
Add typeform module to your project by following command:
git submodule add https://github.com/fractal-academy/qonsoll-form.git
Go to the /module folder:
cd qonsoll-form
Get newest changes of module:
git pull origin library
Go the directory of your project and install all of packages:
cd ../../../
npm install
Some packages need manual instalation. Run following command:
npm i fuse.js use-media
❗ For correct work of components you'll need to add an index to your firebase. In console firebase select your project, go to Firestore Database menu item and choose Indexes tab.
Add formId
and order
as indexed fields for questions collection. Leave index rule default (ascending).
How to run app with already installed module
After cloning existing project to your computer, install all packages:
npm install
Make shure that there's present /modules folder and .gitmodules file in your project. Go to /modules folder and use following comands:
git submodule update --init --recursive
git submodule update --recursive --remote
How to configure workflow
In block steps first you need to install all dependencies.
- run: npm install
Get the latest changes of module. Go to the modules directory:
- run: cd src/modules
By following commands update modules:
- run: git submodule update --init --recursive
- run: git submodule update --recursive --remote
Go back to your project directory and install node modules:
- run: cd ../../ && npm install
Next step - you need to build your application:
- run: npm run build:dev
If you project does'n run after following steps, that means that there's console warnings in you project. To fix that you need to add flag to you run command.
- run: CI=false npm run build:dev
After that, if there's exception that you have not enough memory in docker, you can run following command (it increases volume of memory to 8Gb):
- run: CI=false NODE_OPTIONS=--max-old-space-size=8192 npm run build:dev
How to configure and use module
For correct module work you need to fulfill next steps.
- To use qonsoll form component, you need to import it and propagate required properties. There are four in total components:
FormsAll
,FormEdit
,FormShow
andFormAnswers
. There's example ofFormsAll
component usage:
import React from 'react'
import { FormsAll } from 'qonsoll-form/src'
. . .
function YourComponentName() {
const history = useHistory()
//this name is required
const onFormItemClick = (id) => {
const path = generatePath(ROUTES_PATHS.FORM_EDIT, { id })
history.push(path)
}
return (
<FormAll
firebase={firebase}
actions={{
onFormItemClick: onFormItemClick
}}
/>
)
}
❗ Qonsollform module requires outer handling of routing. That means you need to have prepared constant with route name and propagate through actions
object routing function with correct naming.
FormsAll
has only one required property:firebase
. There's also optional properties:showHeader
- handles whether will be used header of module, or your own,wrapperPaddings
- handles size of outer wrapper of conponent; default value - 32px,translations
- object with translated UI texting (see this step for more information),childrenModal
- propagates node as child to form creation modal, if you need more form items,disableAddButton
- handles showing of form creation button.FormEdit
component hasid
(form id) andfirebase
as required properties. As optional it has alsoactions
property to be propagated. Example of needed functions:
const { id } = useParams()
const history = useHistory()
const onFormShow = (id) => {
const path = generatePath(ROUTES_PATHS.FORM_SHOW, { id })
history.push(path)
}
const onFormResultsShow = (id) => {
const path = generatePath(ROUTES_PATHS.FORM_ANSWERS, { id })
history.push(path)
}
Other optional properties: customHeader
(propagate node for custom header and null
to hide it), translations
, wrapperPaddings
(all are the same as in FormsAll
) and customQuestionTypes
- if you need to configure question type list (to remove excess question types), configure following array and propagate it through property:
[
{
type: QUESTION_TYPES.WELCOME_SCREEN,
description: welcomeScreenDesc || QUESTION_DESCRIPTIONS.WELCOME_SCREEN,
icon: <HomeOutlined />
},
{
type: QUESTION_TYPES.LONG_TEXT,
description: longTextDesc || QUESTION_DESCRIPTIONS.LONG_TEXT,
icon: <FileTextOutlined />
},
{
type: QUESTION_TYPES.SHORT_TEXT,
description: shortTextDesc || QUESTION_DESCRIPTIONS.SHORT_TEXT,
icon: <SmallDashOutlined />
},
{
type: QUESTION_TYPES.DATE,
description: dateDesc || QUESTION_DESCRIPTIONS.DATE,
icon: <CalendarOutlined />
},
{
type: QUESTION_TYPES.YES_NO,
description: yesnoDesc || QUESTION_DESCRIPTIONS.YES_NO,
icon: <ShareAltOutlined />
},
{
type: QUESTION_TYPES.CHOICE,
description: choiceDesc || QUESTION_DESCRIPTIONS.CHOICE,
icon: <GoldOutlined />
},
{
type: QUESTION_TYPES.PICTURE_CHOICE,
description: pictureChoiceDesc || QUESTION_DESCRIPTIONS.PICTURE_CHOICE,
icon: <PictureOutlined />
},
{
type: QUESTION_TYPES.OPINION_SCALE,
description: opinionDesc || QUESTION_DESCRIPTIONS.OPINION_SCALE,
icon: <HomeOutlined />
},
{
type: QUESTION_TYPES.RATING,
description: ratingDesc || QUESTION_DESCRIPTIONS.RATING,
icon: <StarOutlined />
},
{
type: QUESTION_TYPES.FILE_UPLOAD,
description: fileUploadDesc || QUESTION_DESCRIPTIONS.FILE_UPLOAD,
icon: <UploadOutlined />
},
{
type: QUESTION_TYPES.STATEMENT,
description: statementDesc || QUESTION_DESCRIPTIONS.STATEMENT,
icon: <CopyrightOutlined />
},
{
type: QUESTION_TYPES.VIDEO_ANSWER,
description: videoAnswerDesc || QUESTION_DESCRIPTIONS.VIDEO_ANSWER,
icon: <VideoCameraOutlined />
}
]
FormShow
component hasid
(form id) andfirebase
as required properties. As optional it has alsoshowHeader
,wrapperPaddings
,translations
andsubmitLoading
(action on form finish button) properties. Theactions
property is not needed.FormAnswers
component has alsoid
(form id) andfirebase
as required properties. As optional it has alsoshowHeader
,wrapperPaddings
andtranslations
properties. Theactions
property is not needed.- To correct work of components you need to add vars of qonsoll form. Check out next step for it.
How to configure module theme
- First of all, if you new to qonsoll/react-design package, check out this documentation. Qonsoll form is built using its components and theme.
- Qonsollform supports theme changing. Most of theme colors and spacings'll be taken from your original vars.css file, that was added to project earlier. Follow next steps to configure module theme.
- There's list of all vars, used in Qonsollform. If you need change something in module appearance, just rewrite suitable var with needed value. Due to unical name of variables, your app'll still remaining its previous appearence.
/* static list */
--qf-list-item-bg: var(--ql-color-dark-t-lighten5);
--qf-list-item-hover: var(--ql-color-dark-t-lighten6);
--qf-list-item-preview: var(--ql-color-white);
/* drag and drop */
--qf-dnd-item-badge-bg: var(--ql-color-dark-lighten1);
--qf-dnd-item-badge-color: var(--ql-color-white);
--qf-dnd-item-bg: var(--ql-color-dark-t-lighten5);
--qf-dnd-item-hover: var(--ql-color-dark-t-lighten4);
--qf-dnd-active-item-bg: var(--ql-color-accent1-t-lighten4);
--qf-dnd-active-item-hover: var(--ql-color-accent1-t-lighten3);
/* content card */
--qf-content-card-bg: var(--ql-color-white);
/* layout */
--qf-sidebar-bg: var(--ql-color-white);
--qf-sidebar-width: 350px;
--qf-header-mb: 8px;
/* button */
--qf-button-bg: var(--ql-color-dark-t-lighten5);
--qf-button-bg-hover: var(--ql-color-accent1-t-lighten4);
--qf-button-bg-active: var(--ql-color-accent1);
--qf-button-color: var(--ql-color-dark);
--qf-button-color-active: var(--ql-color-white);
--qf-keybox-bg: var(--ql-color-white);
--qf-keybox-bg-active: var(--ql-color-accent1);
--qf-keybox-color: var(--ql-color-dark);
--qf-keybox-color-active: var(--ql-color-white);
--qf-submit-button-font-size: var(--ql-font-size-h4);
/* input */
--qf-input-background: var(--ql-color-dark-t-lighten5);
/* tag */
--qf-tag-color: var(--ql-color-accent1);
/* uploader */
--qf-uploader-color: var(--ql-color-white);
--qf-uploader-bg: var(--ql-color-accent1);
--qf-uploader-hover: var(--ql-color-accent1-t-lighten1);
--qf-uploader-item-bg: var(--ql-color-dark-t-lighten5);
/* domain component: question */
--qf-question-type-icon-default: var(--ql-color-dark-t-lighten4);
--qf-question-type-icon-danger: var(--ql-color-danger-t-lighten3);
--qf-question-header-font-size: var(--ql-font-size-h3);
/*domain component: condition */
--qf-condition-item-bg: var(--ql-color-dark-t-lighten6);
--qf-condition-item-border: var(--ql-color-dark-t-lighten4);
/* typography */
--qf-typography-fs-title: var(--ql-font-size-h2);
--qf-typography-fs-body: var(--ql-font-size-body1);
--qf-typography-fs-caption: var(--ql-font-size-caption1);
--qf-typography-title-color: var(--ql-color-dark);
--qf-typography-subtitle-color: var(--ql-color-dark-t-lighten1);
--qf-typography-caption-color: var(--ql-color-dark-t-lighten2);
/* border radius */
--qf-border-radius-sm: var(--ql-border-radius-sm);
--qf-border-radius-md: var(--ql-border-radius-md);
--qf-border-radius-lg: var(--ql-border-radius-16);
--qf-border-radius-full: var(--ql-border-radius-full);
- Qonsoll form has also overwritten
antd
components vars. Use the following vars with care.
/* overwritten menu */
--ql-menu-item-active-bg: var(--ql-color-accent1-t-lighten3);
/* overwritten form */
--ql-form-item-vertical-spacing: 0;
How to configure translations
Qonsollform will perfectly fine work without translations propagating, but app will appear only in English. If you need to add another interface language, follow next steps:
- First you need to add object with translations to your constants. For example,
qformTranslations.js
. Add following object to it:
const qformTranslations = (t) => {
return {
//global components
requiredAnswerMessage: t('The answer is required'),
submitHint: t('Press enter'),
choicePlaceholder: t('Сhoice'),
conditionRemovingWarn: t('This option has connected logic, delete it anyway?'),
editButton: t('Edit'),
removeButton: t('Delete'),
createForm: t('Add new form'),
uploadImage: t('Upload new image'),
uploaderHint: t('Click or drag file to this area to upload'),
itemRemovingHint: t('Delete this item?'),
questionListTitle: t('Questions'),
endingListTitle: t('Endings'),
questionCreationTooltip: t('Create new question'),
endingCreationTooltip: t('Create new ending'),
formViewTooltip: t('Form preview'),
answerViewTooltip: t('Answers preview'),
longTextHint: t('Shift ⇧ + Enter ↵ to make a line break'),
textQuestionPlaceholder: t('Type your answer here'),
listItemNoDescription: t('No description'),
popconfirmDeleteFormTitle: t('Remove item?'),
popconfirmDeleteImageTitle: t('Remove image?'),
conditionModalIsUploaded: t('is uploaded'),
conditionModalIsRecorded: t('is recorded'),
emptyDescription: t('Nothing was found'),
ratingExtendedDefaultOption: t('Extended option'),
//domains: form components
conditionsEndingsTab: t('Endings'),
conditionsLogicJumpsTab: t('Logic jumps'),
conditionsQuizTab: t('Answer score configurations'),
conditionsNoData: t('There are no question to configure'),
conditionAddQuestionType: t('Please, add one of the following questions types'),
quizSwitcherText: t('Enable quiz system'),
formTitlePlaceholder: t('Form name'),
formSubtitlePlaceholder: t('Form short description'),
formModalCreateTitle: t('Create new form'),
formModalEditTitle: t('Edit form'),
formModalEditButton: t('Save changes'),
formModalCreateButton: t('Create form'),
formValidationRule: t('Please, enter form name'),
//domains: form routes
phoneBreakpointDummy: t('This feature is available only on desktop'),
formsAllTitle: t('Forms'),
formCounter: t('Amount of forms'),
formSearchPlaceholder: t('Search form by name'),
formDefaultWelcomeScreenTitle: t('Welcome screen'),
formDefaultEndingTitle: t('Thank you for attention!'),
//domains: condition components
conditionsEndingSelectPlaceholder: t('Select questions to call current ending'),
conditionModalTitle: t('Logic'),
conditionModalResetLogic: t('Reset logic'),
conditionModalResetLogicButton: t('Reset'),
conditionModalSubmitButton: t('Close'),
conditionRedirectPlaceholder: t('Select redirect rule'),
conditionsModalTooltip: t('Configure logic jumps'),
conditionModalAddCondition: t('+ Add condition'),
conditionTextInputPlaceholder: t('Enter value'),
conditionNextQuestionRedirect: t('Go to the next question'),
conditionRedirectRulePlaceholder: t('Select redirect rule'),
conditionIsEqual: t('is equal to'),
conditionIsntEqual: t('is not equal to'),
conditionBegins: t('begins with'),
conditionEnds: t('ends with'),
conditionContains: t('contains'),
conditionDoesntContains: t('does not contains'),
scoreWeightTitle: t('Enter score weight of answer'),
//domains: media library components
mediaLibraryCounter: t('Amount of shown files'),
mediaLibraryButton: t('Change'),
mediaLibrarySearchPlaceholder: t('Search media file by name'),
mediaLibraryTitle: t('Media library'),
mediaLibraryBrightness: t('Brightness'),
mediaLibraryTypeError: t('is not a picture'),
mediaLibraryCancelButton: t('Cancel'),
mediaLibrarySubmitButton: t('Continue'),
//domains: question components
questionFinishButton: t('Finish'),
questionStartButton: t('Start'),
questionVideo: t('Video question'),
questionRequiredSetting: t('Required'),
questionConfigurationTooltip: t('Configure question'),
questionTypeConfiguration: t('Question types'),
questionConfigurationTitle: t('settings'),
questionRangeBottomSetting: t('From'),
questionRangeUpperSetting: t('to'),
questionConfigurationOptions: t('Amount of options'),
questionEditableTitleHint: t('Editable question title'),
questionEditableSubtitleHint: t('Description (optional)'),
questionRemovingPopconfirm: t('Delete this question?'),
questionWithLogicRemovingPopconfirm: t('This question has connected logic, delete it anyway?'),
questionConfigurationExtended: t('Turn on extended options'),
questionConfigurationMultiple: t('Switch to multiple option'),
welcomeScreenTitle: t('Welcome screen'),
longTextTitle: t('Long text'),
shortTextTitle: t('Short text'),
dateTitle: t('Date'),
yesnoTitle: t('Yes')/t('No'),
yesButton: t('Yes'),
noButton: t('No'),
yesPressButtonLetter: t('Y'),
noPressButtonLetter: t('N'),
defaultChoiceTitle: t('Default'),
choiceTitle: t('Choice'),
pictureChoiceTitle: t('PictureChoice'),
opinionTitle: t('Opinion scale'),
ratingTitle: t('Rating'),
fileUploadTitle: t('File upload'),
statementTitle: t('Statement'),
welcomeScreenDesc: t('Invite your audience in'),
longTextDesc: t('More space to spill the beans'),
shortTextDesc: t('For short answers, like names'),
dateDesc: t('Collect answers in date format'),
fileUploadDesc: t('Upload a file up to 10MB'),
opinionDesc: t('A customizable, numbered scale'),
pictureChoiceDesc: t('Multiple choice but prettier'),
choiceDesc: t('Multiple choice'),
ratingDesc: t('Rate'),
statementDesc: t('Take the mic for a moment'),
yesnoDesc: t('Just 2 options, yes or no'),
questionTypeChangePopconfirm: t('Changing the question type will delete all connected logic'),
//domains: answer components
answerTitle: t('Answers'),
answerEmptyList: t('There is no responses yet'),
answerUserListTitle: t('Users'),
answersNoSelectedUser: t('Choose user to display their answers'),
answerTableQuestionTitle: t('Question'),
answerTableAnswerTitle: t('Answer'),
answerTableScoreTitle: t('Score')
}
}
export default qformTranslations
- In new component's file (with imported module component), import translations object and propagate it with translating function further:
import { FormsAll } from 'qonsoll-form/src'
import { useTranslations } from 'app/contexts'
. . .
function YourComponentName() {
const { t } = useTranslations()
const translations = useMemo(() => {
return qformTranslations(t)
}, [t])
return (
<FormAll
firebase={firebase}
translations={translations}
/>
)
}