wallet-core/packages/merchant-backoffice-ui/DESIGN.md

196 lines
5.8 KiB
Markdown
Raw Normal View History

# Page internal routing
* The SPA is loaded from the BACKOFFICE_URL
* The view to be rendered is decided by the URL fragment
* Query parameters that may affect routing
- instance: use from the default instance to mimic another instance management
* The user must provide BACKEND_URL or BACKOFFICE_URL will use as default
* Token for querying the backend will be saved in localStorage under
backend-token-${name}
# HTTP queries to the backend
HTTP queries will have 4 states:
* loading: request did not end yet. data and error are undefined
* ok: data has information, http response status == 200
* clientError: http response status is between 400 and 499
- notfound: http status 404
- unauthorized: http status 401
* serverError: http response status is grater than 500
There are categories of queries:
* sync: getting information for the page rendering
* async: performing an CRUD operation
## Loading the page information (sync)
In this scenario, a failed request will make the app flow to break.
When receiving an not found error a generic not found page will be shown. If the
BACKEND_URL points to a default instance it should send the user to create the
instance.
When receiving an unauthorized error, the user should be prompted with a login form.
When receiving an another error (400 < http status < 600), the login form should
be shown with an error message using the hint from the backend.
On other unexpected error (like network error), the login form should be shown
with an error message.
## CRUD operation (async)
In this scenario, a failed request does not break the flow but a message will be
prompted.
# Forms
All the input components should be placed in the folder `src/components/from`.
The core concepts are:
* <FormProvider<T> /> places instead of <form /> it should be mapped to an
object of type T
* <Input /> an others: defines UI, create <input /> DOM controls and access the
form with useField()
To use it you will need a state somewhere with the object holding all the form
information.
```
const [state, setState] = useState({ name: '', age: 11 })
```
Optionally an error object an be built with the error messages
```
const errors = {
field1: undefined,
field2: 'should be greater than 18',
}
```
These 3 elements are used to setup the FormProvider
```
<FormProvider errors={errors} object={state} valueHandler={setState}>
...inputs
</FormProvider>
```
Inputs should handle UI rendering and use `useField(name)` to get:
* error: the field has been modified and the value is not correct
* required: the field need to be corrected
* value: the current value of the object
* initial: original value before change
* onChange: function to update the current field
Also, every input must be ready to receive these properties
* name: property of the form object being manipulated
* label: how the name of the property will be shown in the UI
* placeholder: optional, inplace text when there is no value yet
* readonly: default to false, will prevent change the value
* help: optional, example text below the input text to help the user
* tooltip: optional, will add a (i) with a popup to describe the field
# Custom Hooks
All the general purpose hooks should be placed in folder `src/hooks` and tests
under `tests/hooks`. Starts with the `use` word.
# Contexts
All the contexts should be placed in the folder `src/context` as a function.
Should expose provider as a component `<XxxContextProvider />` and consumer as a
hook function `useXxxContext()` (where XXX is the name)
# Components
Type of components:
* main entry point: src/index.tsx, mostly initialization
* routing: in the `src` folder, deciding who is going to take the work. That's
when the page is loading but also create navigation handlers
* pages: in the `paths` folder, setup page information (like querying the
backend for the list of things), handlers for CRUD events, delegated routing
to parent and UI to children.
Some other guidelines:
* Hooks over classes are preferred
* Components that are ready to be reused on any place should be in
`src/components` folder
* Since one of the build targets is a single bundle with all the pages, we are
avoiding route based code splitting
https://github.com/preactjs/preact-cli#route-based-code-splitting
# Testing
Every components should have examples using storybook (xxx.stories.tsx). There
is an automated test that check that every example can be rendered so we make
sure that we do not add a regression.
Every hook should have examples under `tests/hooks` with common usage trying to
follow this structure:
* (Given) set some context of the initial condition
* (When) some action to be tested. May be the initialization of a hook or an
action associated with it
* (Then) a particular set of observable consequences should be expected
# Accessibility
Pages and components should be built with accessibility in mind.
https://github.com/nickcolley/jest-axe
https://orkhanhuseyn.medium.com/accessibility-testing-in-react-with-jest-axe-e08c2a3f3289
http://accesibilidadweb.dlsi.ua.es/?menu=jaws
https://webaim.org/projects/screenreadersurvey8/#intro
https://www.gov.uk/service-manual/technology/testing-with-assistive-technologies#how-to-test
https://es.reactjs.org/docs/accessibility.html
# Internationalization
Every non translated message should be written in English and wrapped into:
* i18n function from useTranslator() hook
* <Translate /> component
Makefile has a i18n that will parse source files and update the po template.
When *.po are updated, running the i18n target will create the strings.ts that
the application will use in runtime.
# Documentation Conventions
* labels
* begin w/ a capital letter
* acronyms (e.g., "URL") are upper case
* tooltips
* begin w/ a lower case letter
* do not end w/ punctuation (period)
* avoid leading article ("a", "an", "the")