ezbob v2.3.0-rc.6
Installation
Create an npm user and contact Ezbob support and ask for privileges. On your root app, run in command line:
npm login //Enter your credentials
npm install
npm start
//In another terminal - open a node.js server to retrieve the app token
cd server
npm start
Then your app should run on localhost:3000.
This project was bootstrapped with Create React App.
Available Scripts
In the project directory, you can run:
npm start
Runs the app in the development mode. Open http://localhost:3000 to view it in the browser.
The page will reload if you make edits. You will also see any lint errors in the console.
npm test
Launches the test runner in the interactive watch mode. See the section about running tests for more information.
npm run storybook
Runs the Storybook development environment. Presents an isolated view of the widgets library
npm run build
Builds the app for production in the build
folder.
Bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include hashes. Your app is ready to be deployed!
See the section about deployment for more information.
Configuration
App
Path: src/App.js
This is the staring point of the App. here you'll find the structure of the program. This is a regular React JSX file. Inside the render function you should wrap everything with UIFramework component.
The UIFramework will get a config object (defined below) and render its children. The structure should be:
<Flow>
<Header>
<ProgressBar>
<ProgressBarStep id={1} label={'label'} title="title"><div>Your icon here</div></ProgressBarStep>
<ProgressBarStep id={2} label={'label'} title="title"><div>Your icon here</div></ProgressBarStep>
<ProgressBarStep id={3} label={'label'} title="title"><div>Your icon here</div></ProgressBarStep>
<ProgressBarStep id={4} label={'label'} title="title"><div>Your icon here</div></ProgressBarStep>
</ProgressBar>
</Header>
<Body>
<Modal modalName='ModalName1'>
<ModalClass1/>
</Modal>
<Modal modalName='ModalName2'>
<ModalClass2/>
</Modal>
<Page routePath="routePath">
<Step stepName="stepName1">
<Widget1 name="widget1"/>
<Widget2 name="widget2"/>
<Widget3 name="widget3"/>
</Step>
</Page>
</Body>
<Footer name="footer"/>
</Flow>
widget's name
Most widgets have a "name" prop. This "name" prop is used to bind widgets with respective entries in config and translations.
For example:
<Input name="applicant.email"/>
When using this widget, "applicant.email" is the path in config.js's "widgetsConfig" property. It's also the path in the translations file:
config.js (src/config/config.js):
widgetsConfig: {
applicant: {
email: {
validationRules: 'required|min:3|email',
customErrorMessage: {
email: 'VALID_EMAIL',
required: 'REQUIRED',
min: 'MIN'
}
}
}
}
translations file (src/config/languages/en-US.json):
"applicant": {
"email": {
"label": "Email address",
"tooltip": {
"content": "We will use your email address to get in touch with you regarding your application or with important information about your Esme account.\nYour email address will also be your username when logging in to your account in future."
}
}
}
Translations
Path: src/config/languages/**
-**
.json
Language object is mapped to widgets structure. example:
"applicant": {
"fullName": {
"firstName": {
"label": "First Name"
},
"lastName": {
"label": "Surname"
},
"middleName": {
"label": "Middle name(s)"
}
}
}
The translations also handle messages not bound to a specific widget:
In config.js:
customErrorMessage: {
required: 'REQUIRED_ADDRESS',
address: 'ADDRESS'
}
And in translations file:
"clientMessages": {
"REQUIRED_ADDRESS": "Address is required",
"ADDRESS": "Address is not valid"
}
#####Accessing config variables: The config file is passed onto the translation function and is available for interpolation:
config.js:
system: {
vendorName: "Esme"
},
product: {
loanType: 'business loan'
}
And in translations file:
"translationName": "It's quick to apply for an {{system.vendorName}} {{product.loanType}}. We only need a few details to make a decision.",
#####Advanced usage: referencing config property with formatting options: A widget has the following config:
widgetsConfig:{
applicant:{
widgetExample:{
validationRules: 'required|numeric|min:15000|max:2000000',
customErrorMessage: {
required: 'REQUIRED',
numeric: 'NUMERIC',
min: 'MIN_AMOUNT',
max: 'MAX_AMOUNT'
}
}
}
}
To access the validationRules property, use standard formatting:
"translationName": "These are the validation rules: {{widgetsConfig.applicant.widgetExample.validationRules}}",
But to receive a certain value (max) returned from this string, a specific indication must be made:
"translationName": "This is the max amount: {{widgetsConfig.applicant.widgetExample.validationRules, validationRule:max}}",
This would trigger a format() function which takes the value ('validationRules') and formats it according the validationRule key, finding the 'max' value.
Currently we support dedicated formatting only for 'validationRule'
Config.js
Path: src/config/config.js Represents widgets validation rules, input formatting options, default values and general configuration.
Example:
widgetsConfig:{
loanee: {
annualDrawings: {
validationRules: 'required|numeric|max:999999999',
customErrorMessage: {
required: 'REQUIRED',
numeric: 'NUMERIC',
max: 'MAX_AMOUNT',
},
formattingOptions: {
numeral: true,
numeralThousandsGroupStyle: 'thousand',
numeralPositiveOnly: true,
prefix: locals.currencySign,
noImmediatePrefix: true,
numericOnly: true,
rawValueTrimPrefix: true,
trailingDecimalOnBlur: true
},
inputProps:{
autoComplete: 'off',
autoFocus: true
}
}
}
}
This section outlines the configuration for a widget with the name property of "loanee.annualDrawings".
The 'validationRules' and 'customErrorMessage' properties represent configuration options for validatorjs.
The 'formattingOptions' property represent input options for Cleave.js
The 'inputProps' property represent <input>
HTML tag options
formattingOptions and inputProps objects can be overridden by a widget's props:
widgetsConfig:{
applicant:{
email:{
inputProps:{autoComplete:'off'}
}
}
}
<Input name="applicant.email" inputProps={{autoComplete:'on'}}/>
In this case, the widget will pass on autoComplete:'on' onto its HTML tag.
loanee: {
typeOfBusiness: {
validationRules: 'required',
customErrorMessage: {
required: 'REQUIRED',
alpha: 'ALPHA_BUSINESS_TYPE'
},
values: [
{"value":"LIMITED_COMPANY"},
{"value":"SOLE_TRADER"}
]
}
}
Configuration for a Checkbox widget would look like this:
meta: {
consents: {
privacyNote: {
defaultValue: false,
validationRules: 'accepted',
customErrorMessage: {
accepted: 'REQUIRED'
}
}
}
}
Where defaultValue represent the initial value a widget receives when no other value has been set.
Other than validation, input options and drop down values, the config file may contain other configurable properties; Example:
loanee: {
loanRequest:{
amount: {
"LIMITED_COMPANY": {
defaultValue: 80000,
min: 10000,
max: 150000,
step: 500
},
"SOLE_TRADER": {
defaultValue: 87500,
min: 25000,
max: 150000,
step: 500
}
}
}
}
This is widget-specific data, used only by the Slider widget.
Another example for widget-specific data:
bankAccountStatement: {
linkAccountDetails: {
displayIcons: [
'HSBC', 'sage 50', 'Barclays', 'Lloyds', 'RBS', 'Santander', 'NatWest', 'Dag', 'Halifax', 'NationWide'
]
}
}
Another example is the configuration for the App's Steps:
steps: [
{stepName: 'registerAccount', label: 'Register', title: 'Register account'},
{stepName: 'personalInformation', label: 'Personal', title: 'Personal information'},
{stepName: 'businessInformation', label: 'Business', title: 'Business information'},
{stepName: 'linkAccounts', label: 'Accounts', title: 'Link accounts'},
]
####Route configuration: Each page has a key defined in this structure that bind to Page component in App.js.
url: the url of the page
title: title of the page
excludeModules: Array of modules to exclude from the view. the list is any widget with "name" props.
customerWizard is the main route and contain logoutURL.
pageRoutes: {
customerWizard: {
url: '/customer/wizard'
},
customerLogin: {
url: '/customer/login',
excludeModules: ['ProgressBar'],
title: 'pageRoutes.customerLogin'
},
forgotPassword: {
url: '/account/forgot-password',
excludeModules: ['ProgressBar'],
title: 'pageRoutes.forgotPassword'
},
accountSetPassword: {
url: '/account/set-password',
excludeModules: ['ProgressBar'],
title: 'pageRoutes.accountSetPassword'
},
accountVerifyEmail: {
url: '/account/verify-email',
excludeModules: ['ProgressBar'],
title: 'pageRoutes.accountVerifyEmail'
}
}
To manage google tag manager please use 'googleTagManager' config.
gtmId - is the GTM-ID from google
allowedTracking - define the events to track
VirtualPageview - fires on every Step/Page move
InputTracking - fires on input/dropdown onFocus/onBlur/checkboxClick events
ButtonTracking - fires on buttons and tooltips
googleTagManager: {
gtmId: 'GTM-WS8FGWH',
allowedTracking: {
VirtualPageview: ['Step', 'Page'],
InputTracking: ['onFocus', 'onBlur', 'checkboxClick'],
ButtonTracking: ['onClick', 'tooltipClick']
}
}
Lists
Path: src/config/lists/**
-**
.json
Lists are json files bound to Dropdown widgets by their name. These lists are arrays of object in the following shape:
[
{"value":"LIMITED_COMPANY"},
{"value":"SOLE_TRADER"}
]
The translated values
Common Actions
Actions are passed via MainContext and communicate with the framework's state.
CaseActions:
updateInCase
update entry in case with option to validate @param {string |{name, value, validate}} names - widget's name, or an array of {name, value, property} @param {*} value - widget's value @param {boolean} validate - whether or not should call validate on updated property
example:
const newVal = 'some new value';
actions.case.updateInCase('widget.name', newVal);
resetInCase
reset widget case entry, validation will still be applied in nextStep() @param {string|string[]} names - widget's name, or an array of names
example:
resetWidget = () => {
actions.case.resetInCase('widget.name');
}
getCaseValue
get value from case by name @param {string} name - widget's name @param {boolean=false} checkStep - if true, return value only if property shares the same step value as getCurrentStep() @returns {* | undefined} found value or undefined example:
const val = actions.case.getCaseValue('widget.name');
CaseValidationActions
getValidationStatus
get validatingStatus ('valid'|'invalid'|'neutral') from case by name @param {string} name - widget's name @returns {string} 'valid' | 'invalid' | 'neutral'
example:
const validationStatus = actions.caseValidation.getValidationStatus('widget.name');
getValidationStatus
get widgetsConfig's validationRules by name, and check if 'required' or 'accepted' is one of them @param {string} name - widget's name @returns {boolean}
example:
const isFieldRequired = actions.caseValidation.isRequired('widget.name');
SettingsActions
getUserConfigProp
get state's config by prop @param {string} prop - path by which to find prop in config @returns {Object} found value in config
example:
const listFromConfig = actions.settings.getUserConfigProp(`widgetsConfig.widget.name`);
ViewActions
toggleModal
set modal view or remove current modal from view @param {{modalName: string, props: object }} modal - modal's name (as defined in App.js) with optional additional props
example:
showModal = () => {
actions.view.toggleModal(`modalName`, {additionalProps:'additionalProps'});
}
closeModal = () => {
actions.view.toggleModal();
}
5 years ago