18F/e-QIP-prototype

View on GitHub
docs/frontend-architecture.md

Summary

Maintainability
Test Coverage
# Frontend Architecture

Major areas of the frontend code base include:

- React Components (located in [src/components](../src/components) and [src/views](../src/views))
  - These render the UI of the application. The views directory contains components that correspond to specific URLs of the app, and the components directory contains both UI components that are shared in many places, as well as the specific components that make up each section and subsection of the form (located in [/src/components/Section](../src/components/Section)). These Section components are where the actual questions and inputs for the form get rendered.
  - All Section components get connected to Redux using the [SubsectionConnector](../src/components/Section/shared/SubsectionConnector.jsx) [higher-order component](https://reactjs.org/docs/higher-order-components.html). This passes in the relevant data for that section, any data needed from other sections, and top-level form logic (such as which questions are required based on the form type). It also passes in the `onUpdate` prop, which handles sending updated input values back up to Redux. Finally, an `onError` prop is also passed that saves validation Errors in Redux -- however, this is part of the legacy validation code, and should be deprecated as part of the Validation Refactor (UI) project (see the [frontend roadmap](frontend-roadmap.md)).
  - Form Components ([/src/components/Form](../src/components/Form)) are the building blocks for the various form fields and inputs. This includes both standard HTML inputs such as Text, Radio, and Checkbox, as well as eApp-specific UI components such as Accordion, BranchCollection and DateControl. While these components are basically functional, many of them contain React anti-patterns (such as maintaining local component state where it's not necessary), which has led to bugs, performance issues, and made them difficult to test reliably.
- Redux and related code ([/src/services/store.js](../src/services/store.js), [/src/actions](../src/actions), [/src/reducers](../src/reducers), [/src/selectors](../src/selectors), [/src/sagas](../src/sagas))
  - Redux is used in eApp to maintain global-level application state. The data stored in Redux can be accessed at any level of the application (usually using the Redux `connect()` higher-order component), so typically it should be reserved for state that needs to be shared across concerns. In eApp, this means the entirety of the form data, as well as its current error and validity status, is stored in Redux, so that components such as the sidebar navigation and Review & Submit section can know whether the form is valid or not. Other global-level data such as the form type (i.e., SF-86) and version are stored there as well.
  - Sagas are used to control application flow and side effects using Redux actions and ES6 generator functions (requiring inclusion of the `@babel/polyfill` package). Currently, sagas are used to handle the user session, updating and validating form data, and some (but not all) API interactions.
- Form data validation ([/src/models](../src/models), [/src/validators](../src/validators))
  - eApp uses the validateJS library to define objects (models) that describe the validation constraints for the various data structures present in the form. These are all located in [/src/models](../src/models). Each section of the form has a corresponding model (these are mapped in [/src/helpers/validation.js](../src/helpers/validation.js)), and when an input is changed the section data is checked against that model, and any resulting errors are stored in Redux. If there are no errors, the section is considered valid and completed.
  - ValidateJS allows you to define custom validator functions (see https://validatejs.org/#custom-validator). Due to the deeply-nested nature of many of the data structures in the form, we have needed to use this feature to define validators that can validate nested data structures against other models or constraints. Custom validators can be found in [/src/models/validators](../src/models/validators) and are all initialized in [/src/models/validateConfig.js](../src/models/validateConfig.js)
  - There are also validation functions located in [/src/validators](../src/validators) – these are primarily legacy artifacts resulting from a validation refactor effort. Most of them are becoming redundant, and can likely be deprecated fully in the near future.
- API interactions, form data persistence ([/src/schema](../src/schema), [/src/services/api.js](../src/services/api.js))
  - The Axios library is used for making fetch requests to the API.
  - Some API calls (`api.form, api.status, api.login, api.refresh, api.logout`) are controlled using Redux sagas. This makes it easy to control the user flow around API calls and error handling.
  - Form data is saved one section at a time to the API using the `saveSection` function in [/src/components/SavedIndicator/persistence-helpers.js](../src/components/SavedIndicator/persistence-helpers.js). This function uses a `schema` function to format the data (based on which section is being saved) into the structure expected by the API. This structure has proved to be unnecessarily unwieldy because it is so deeply nested, and would benefit from being simplified. Saving data occurs at the following times:
    - When the route changes
    - User clicks the save button
    - User logs out
    - Right before user session times out
- Miscellaneous
  - internationalization (i18n) is used for displaying text content (some of which uses Markdown syntax for formatting). The content itself is located in [/src/config/locales](../src/config/locales). eApp is in mid-migration from a homegrown i18n implementation ([/src/config/locales/i18n.js](../src/config/locales/i18n.js)) to a 3rd-party library called i18next ([/src/util/i18n.js](../src/util/i18n.js)).
  - luxon is used for date/time handling. Similar to i18n, eApp is in mid-migration from homegrown datetime handling code to a 3rd-party library called luxon. New date helper functions can be found in [/src/helpers/date.js](../src/helpers/date.js). Legacy code such as that found in [/src/components/Section/History/dateranges.js](../src/components/Section/History/dateranges.js) is prone to bugs and should be deprecated.
  - There are various files for defining and working with the different form types, form sections, and the configurations for each. These can be found in [/src/config/forms.js](../src/config/forms.js), [/src/config/formTypes.js](../src/config/formTypes.js), and [/src/config/formSections](../src/config/formSections).