AFE Quick Check @afequickcheck
Arthur-Fischer-Erfinderpreis Quick Check / REACT APP
Table of contents
Author
RSM Integral
Hendrik Reimers hendrik.reimers@ressourcenmangel.de
Date: 07/2023
Introduction
This app is a simple questioning application. The user will be asked a few questions and at the end he gets the result (decision).
Basic Structure
- Configuration of each Question Step: Configuration/AppData.js
- Steps Layout: Components/Steps/...
- Animation Styles: Styles/App.scss
Integration
Take care that you have a div element like this in your project:
<div id="afe-quick-check-app"></div>
The JS code of this project should do the rest for you.
See the following script for the main call:
src/javascripts/afe-react-components.js
It's done like this:
import React from 'react';
import ReactDOM from 'react-dom';
import { AfeQuickCheckApp } from 'components/react/AfeQuickCheck/AfeQuickCheckApp';
// Initialize the Arthur-Fischer-Enfinderpreis Quick Check App
const afeDomNode = document.getElementById('afe-quick-check-app');
ReactDOM.render(<AfeQuickCheckApp />, afeDomNode);
Configuration
General Configuration
The basic configuration of each available step is defined in the Configuration/AppData.js file. It includes different routes with a "default" route (_default). So you're able to give the user a different journey based on their selection. See later for route / journey handling. See example below:
/**
* Definition of the global configuration initial used by the application
*
*/
export const initialAppData = {
currentStep: 'start',
currentJourney: '_default',
direction: 'left', // Initial value
document: {
title: document.title // Initial value
},
steps: {
_default: {
start: {
componentName: 'StepInitial'
},
questionA: {
componentName: 'StepKategorie',
finished: false, // Initial value
answer: false // Initial value
},
questionB: {
componentName: 'StepBewerber',
finished: false, // Initial value
answer: false // Initial value
},
questionC: {
componentName: 'StepSchutzrecht',
finished: false, // Initial value
answer: false // Initial value
},
result: {
componentName: 'StepErgebnis',
finished: false // Initial value
}
},
schueler: {
questionA: {
componentName: 'StepKategorie',
finished: false, // Initial value
answer: false // Initial value
},
questionC: {
componentName: 'StepSchutzrecht',
finished: false, // Initial value
answer: false // Initial value
},
result: {
componentName: 'StepErgebnis',
finished: false // Initial value
}
},
privatePerson: {
questionB: {
componentName: 'StepBewerber',
finished: false, // Initial value
answer: false // Initial value
},
result: {
componentName: 'StepErgebnis',
finished: false // Initial value
}
}
}
};
The React App will automatically generate the Routes for this steps (see Components/AppContentRouter.js).
Step and Question / Answers configuration
The questions as well as the value used for the answer is defined in each step: See Components/Step02-[...].js for details and examples.
import React, { useEffect } from 'react';
import AnswerButton from '../Buttons/AnswerButton';
import { useCounter } from '../../Handler/CounterHandler';
import useDocTitle from '../../Handler/DocTitleHandler';
/**
* Arthur-Fischer-Erfinderpreis Quick Check App
*
* Step B
*
* @param props
* @returns {JSX.Element}
* @constructor
*/
const StepKategorie = props => {
// Use the context for global data storage and state management
const { setDocTitle } = useDocTitle();
const { counterCurrent, counterTotal } = useCounter();
// Changes the doc title
useEffect(() => {
setDocTitle(`Schritt ${counterCurrent}/${counterTotal}`);
}, [counterCurrent]);
return (<>
<div className="text text--small text--afp-quickcheck text--counter">{counterCurrent} / {counterTotal}</div>
<h2 className="headline headline--2">Was trifft zu?</h2>
<div className="text text--afp-quickcheck">
Wähle die passende Antwort aus
</div>
<div className="container__afp-quickcheck-answers">
<AnswerButton answer={true}>Schüler / Gruppe</AnswerButton>
<AnswerButton answer={true} route={'privatePerson'}>Privat Erfinder mit Patent</AnswerButton>
<AnswerButton answer={false}>Schüler / Gruppe mit Patent</AnswerButton>
{/* <AnswerButton answer={false} nextStep={'result'}>Schüler / Gruppe mit Patent</AnswerButton> */}
</div>
</>);
}
export default StepKategorie;
Each step has a basic layout and uses the AnswerButton Component to save the selected result in the AppData and will redirect to the next possible step.
Important
Each new step has to be imported into the following file, to be sure that the component is loaded:
/Components/Steps/_Steps.js
For example:
// List of all Step Components for easier importing in AppContentRouter Component
export {default as StepInitial} from './Step01-Initial'
export {default as StepKategorie} from './Step02-WhichApplies'
export {default as StepBewerber} from './Step03-Who'
export {default as StepSchutzrecht} from './Step04-PropertyRights'
export {default as StepErgebnis} from './Step05-Result'
Result Handling
The handling of each answer is currently handled in the last Step (see Components/Steps/Step-Ergebnis.js). Currently it just looks, whether each step is finished and the "answer" value is set to true.
// Returns true only if everyone returns true
// (ignores this current result step and first step)
/*
const result = Object.values(appData.journeys[appData.currentJourney])
.slice(0, -1)
.every( step => step.finished && step.answer);
*/
// Alternative to check answers only for finished steps
const result = Object.values(appData.journeys[appData.currentJourney])
.filter(step => step.finished)
.every( step => step.answer);
setResultPositive(result);
Then the visibilityStateForTrue and visibilityStateForFalse will be used to show the correct content with the result.
Feel free to modify it like you need it.
Hints
AnswerButton Features
The AnswerButton component has another property for "nextStep". So if you want to decide to move directly to another step. You can do it like as follows:
<AnswerButton answer={false} nextStep={'result'}>Schüler / Gruppe mit Patent</AnswerButton>
Alternatively you can define a different user journey (route):
<AnswerButton answer={false} route={'schueler'}>Schüler / Gruppe mit Patent</AnswerButton>
Different answer values
You don't have to set the answer as a boolean. You can define whatever you want. But take care that you change the behaviour of the result step which decides which result should be displayed.
Counter Handler
Theres a handler to show the progress. Currently it ignores the first and the last step for that count. If you want to change that behaviour take a look into: /Handler/CounterHandler.js
Manually set a step finished and answered
This could be helpful in some cases, when your step is just a informational step or something like that, but you need it to be finished and answered.
// Set this step to finished for the result calculation
const newAppData = {};
newAppData[`journeys.${appData.currentJourney}.${appData.currentStep}.answer`] = true;
newAppData[`journeys.${appData.currentJourney}.${appData.currentStep}.finished`] = true;
updateAppData(newAppData);
updateAppData
If you just want to update a single value in your store you can do it like the following line:
updateAppData('journeys.questionB.myProperty', 'new value');
but if you need to change more than one value at once it's not recommended to do this:
updateAppData(`journeys.${appData.currentJourney}.questionB.myProperty_Lorem`, 'new value');
updateAppData(`journeys.${appData.currentJourney}.questionB.myProperty_Ipsum`, 'new value');
Because in some cases it could break your functionality or other effects, because the state is updated not at once. In that case you can do this instead:
const newAppData = {};
newAppData[`journeys.${appData.currentJourney}.${appData.currentStep}.answer`] = true;
newAppData[`journeys.${appData.currentJourney}.${appData.currentStep}.finished`] = true;
updateAppData(newAppData);
or this:
updateAppData({
`journeys.${appData.currentJourney}.questionB.myProperty_Lorem`: 'new value',
`journeys.${appData.currentJourney}.questionB.myProperty_Ipsum`: 'new value',
});
<div id="afe-quick-check-app"></div>