Slimming World v2.0

Welcome to the React / Redux Frontend of Slimming World's Global Platform v2.0.

About this documentation

This repository includes API documentation rendered from JSDoc annotations and markdown files. Besides API documentation, it includes a list of tutorials on various core topics of this codebase.

Hosted version

To see a rendered version of this file and the rest of the documentation, consult the following links:

Rendering the documentation yourself

To render the latest version of the documentation locally, run the following command:

npm run docs

The documentation output is available in /docs/output/index.html and can be viewed using a web browser.

How do I get set up?

Add private package manager (myget & github)

  • You will need to have account for both myget and be apart of the slimming-world github to run the installl dependencies and run the project.
  • Add the registry path to your yarn config: yarn config set @slimmingworld:registry https://www.myget.org/F/testing-feed/npm/
  • Add registry with npm also npm config set @slimmingworld:registry https://www.myget.org/F/testing-feed/npm/
  • Log in to myget by following the prompts: npm login --scope=@slimmingworld --registry=https://www.myget.org/F/testing-feed/npm/
  • Log in to Github npm login --registry=https://npm.pkg.github.com --scope=@slimming-world
  • To authenticate by logging in to npm, use the npm login command, replacing USERNAME with your GitHub username, TOKEN with your personal access token you can generate the token, and PUBLIC-EMAIL-ADDRESS with your email address.
$ npm login --registry=https://npm.pkg.github.com --scope=@slimming-world
> Username: USERNAME
> Password: TOKEN
> Email: PUBLIC-EMAIL-ADDRESS

Install packages yarn (https://yarnpkg.com/en/docs/install).

  • If you're hitting 403 unauthorised errors after running yarn you may need to set npm config set always-auth true

More detailed instructions on setup are here: https://slimmingworlddigital.atlassian.net/wiki/spaces/FRO/pages/1039761761/Multi+repo+architecture+split

Commands

  • yarn
  • yarn set-dev-market -- <market name> #us or uk
  • yarn dev:member
  • yarn dev:pattern-lib
  • yarn dev:account
  • yarn dev:shop
  • yarn dev:planner
  • yarn dev:live
  • yarn dev:migration
  • yarn dev:public-uk

Ports are being used

  • 3000 member
  • 3001 pattern-lib
  • 3002 account
  • 3003 shop
  • 3004 planner
  • 3005 live
  • 3006 migration
  • 3007 public-uk

Environments and markets

Switching backend API environments

We currently have the following environments available for backend:

  • localhost when running a backend server locally
  • development when in doubt, use this
  • testa feature team A environment
  • testb feature team B environment
  • testg group-develop environment
  • test
  • acceptance cannot be used for local development
  • penetration cannot be used for local development
  • production cannot be used for local development

To switch to a different environment, you need to set the NODE_ENV environment variable which will cause the frontend to use a different environment configuration json. See Setting the NODE_ENV environment variable

Switching backend API markets

We have an alternative configuration json for the UK market. To use this configuration file, set the NODE_APP_INSTANCE environment variable to uk. The instructions for this are very similar to Setting the NODE_ENV environment variable

Switching frontend markets (theming and market switches)

yarn set-dev-market -- <market name>

Running account in Edge.js

To test some flows in account, a different development setup is required. See Running account Edge.js

Legacy node version

When you have to run the project on node 4, you can use the --legacy-node flag.

  • node account/scripts/start-dev-server.js --legacy-node
  • node member/scripts/start-dev-server.js --legacy-node
  • node pattern-lib/scripts/start-dev-server.js --legacy-node

Distribution build

To do a build for distribution:

  • npm run build:member -- --env.markets="<comma separated list of markets>"
  • npm run build:account -- --env.markets="<comma separated list of markets>"
  • npm run build:pattern-lib -- --env.markets="<comma separated list of markets>"

To do a distribution build and run the server locally:

npm run build-and-run -- --market=<market name> --service=<account|member>

Code style

Style guide

  • follow the airbnb es6 and react style guides
  • look at the example tutorials for other guidelines

Linting

Please make sure you have stylelint and eslint installed for your IDE / editor. SCSS is now handled via stylelint (previously scss-lint) which is a node module and doesn't require ruby, like it's predecessor. Follow the installation instructions here.

To run the linter from the command line:

npm run lint # runs them all
npm run lint:js # uses eslint
npm run lint:css # uses stylelint

Coding conventions

Splitting of code and moving functions to a utils file

  • When readability of component is lost
  • When unit tests are needed
  • When it can be used multiple times it must be in common

Functional vs class components

  • New components should be functional not doing so will be blocking in PR

H1 / headers

  • All pages should have an H1
  • Encourage semantic markup
  • Important for SEO (public) and accessibility (member). If you would like to read more about this see

Promise chains

  • Avoid long promise chains
  • Can you use await or then() which over is most readable in the context.
  • Consider if chaining actions are really required - should be flagged at PR time if they are not

SSR and client side api calls

  • When we are fetching unique data that is different for every member such as address or weight loss these calls should be done client-side within a useEffect hook instead of within withInitAction.
  • Is the data requied is non unique content such as recipes or feature we must perform the call serverside for caching benefit this is currently done via withInitAction. withInitAction documentation

Optional chaining + nullish coalescing usage

We should move away from usage of idx and start using both nullish coalescing to learn more about this here

CSS guidelines

The following rules are in place to ensure consistency across the website both visually and from code maintenance perspective, ultimately leading back to the higher level Digital vision of being Inspiring and on-brand & Easy and accessible.

The only exception to these rules is for seasonal public campaign landing pages

Margin & padding

In development when adding margin / padding you must keep to the table of 4th. We use a scss function called rem-size which takes pixel as an argument. This is used like so:

padding: rem-size(16);

This should always be used in favour of px values for some reasoning behind this see Guide: EM vs REM vs PX. Which should you use?

We also have a sizes scss function which multiplies the number passed in. For example:

 padding: size(1); // 8px (converted to rem 0.5rem will base font-size of 16px)

This function is optional in its usage and left the developer but not enforced. The pattern rem-size(16)is valid and should not be flagged to change at PR level.

If you find in a design the measurement is not within the table of 4th you should always align to closest 4th .

So for example if you found when measuring a design the padding was set at 17px you would align to 16px which in code would be rem-size(16) or`` size(2)`

Custom font sizes / weights We should always use the predesigned font types available in the codebase which can be found within the TextNew component. You should avoid setting custom font sizes & weightthe only exception to this is the script size font if a custom size is used it should be flagged at PR.

Shorthand for margin / padding

It is recommended that you margin shorthand but ultimately this should be thedeveloper�s preferences both shorthand or being explicit are valid. If this is flagged in PR, either way, it can stay as there no big value in aligning here as both are valid in CSS spec.

Borders

A border should always use the $borderSize variable - this helps enforce consistency across the site. The only time this would not be the case would be for campaigns.

We have a called $borderStyle which resolved to a border style of solid going forward this will not be used the reason we opted to move away from this is the border style had never changed and after reviewing with the wider team we felt the likelihood of us changes this across the board is extremely low. If variable should not be used in future work or flagged in PRs

Box shadows

For box shadows you should use the predefined box shadows found within in the _borders.js . If you find any of the presets do not fit closely enough with the design you should speak to the design team who can review the usage and if a new one needs to be defined.

Group common CSS

It is recommended, where possible, to group common scss For example

.class1 {
 margin: 16px;
 padding: 15px;
}

.class2 {
 margin: 16px;
 padding: 15px;
}

To become:

.class1, .class2 {
 margin: 16px;
 padding: 15px;
}

This helps with readability and maintainability of the code reducing manual changes.

Ordering of CSS properties

It's recommended that related properties should be grouped but is the developer�s preferenceshould not be flagged at the PR level.

Component organisation guidelines

We're using atomic design principles and the component structure should follow that. Components that are single usage should live under the component they are used in, those that are used many places on one service should live under that service’s components folder, and if they are used across many services they should then be moved into the shared components package.

Making changes - in order of preference, we should: Think about how we can avoid changing any components if possible and push back on changes to align functionality / design to be common across the platform. Then, if needed, amend existing components New components should be created as a last resort and include the wider design, UX & development team.

These should be flagged at PR time We should be aware of components that can be split / moved / renamed / combined and ticket these up.

Branch naming

Use giflow convention (plus our own rp/ prefix) Should be descriptive Include ticket number, convention at the beginning

Selector usage

Always create a selector Ideally use entity selectors, if you're selecting from an entity.

Forms

Migrate to Formik. Use Formik for new forms, tech debt the migrating of old forms, with a focus on public first as there are comparativley few forms. Review conventions now that we have a couple of Formik forms in use

Git Hooks

Upon running a fresh yarn, the Husky package will install some git hooks. Those hooks will run some checks when committing or pushing.

When you absolutely need to, you can skip the hook by appending --no-verify (e.g. when finishing releases and hotfix branches and having to push them develop and master, there is no need to run linting again, since no files have changed).

[TODO: link to confluence page when created]

Commit

Before commit, it verifies the commit message, it must include a reference to a jira ticket that has the correct development/progress status.

Besides that, please follow this guide on how to write proper commit messages.

Push

Before push, it will run yarn lint to verify the js and scss code style.

Git Flow

We follow Git Flow during development, please follow the information on this page.

You are not allowed to commit directly to develop or master (only specific people who manage releases and hotfixes). All development should happen in feature branches, which will be merged to develop via a bitbucket PR after review.

Pull requests

Before a branch can be merged back into develop or a rp(release prospect) it must first be reviewed and approved by two members of the frontend team. Once you have created your pull request you can share it within the fed-prs channel. If you need to fast track urgent PRs you can do so by marking the PR as so within channel.

Small and single responsibility

When picking up a large piece of work you should first think how to break it down into logical smaller pieces and avoid large PRs.

This gives the team good visibility of the changes from the get go and reduces chances of large changes being required, duplication of components and logic and allows the reviewer to focus on a single thing at one time.

Information given upfront

In order to get a PR reviewed in timely fashion the author must aim to give all of the requied information in description of the pull request. This can change per pull request but a general rule of thumb is to at least include a clear description and which services the change will impact.

There is a predefined template to fill in when opening a PR, the author can remove and add sections as they see fit.

Guideline what author should include in a PR

  • Description of change
  • Which environment to test against (e.g content or endpoint)
  • Account state (logins if necessary)
  • Screenshots (if a visible change)
  • Disclaimers - E.g work only partly complete within PR and more will be done in an additional one
  • Builds and has test(s) pass
  • Test coverage
  • Checklist
Checklist

Also consider the following when creating a PR (some of these will only apply to certain changes). These items are not requied to create a pull request however. For example you could put in a disclaimer that copy was still being finalized and would be in a future pull request (in these cases there should be a TODO added along with Jira ticket number)

  • Is all copy from content?
  • Is it accessible?
  • Does it handle error states and give appropriate feedback?
  • Manual design review - is it responsive, does it work on devices (ie11, mobile view etc)?
  • Tests are written to cover any changes in functionality.
  • Follow best practices which can be found in the README

Guideline for reviewer of a PR

When reviewing a PR think about the following:

  • Does it achieve what the ticket states?
  • Manual design review - is it responsive, does it work on devices (ie11, mobile view etc)?
  • Are tests written (see for more information on this here)
  • Does the code follow industry and company best practices(company specific guidelines can be found in this README!)
  • Could this code introduce any performance bottlenecks?

Rendermode

By default, our server uses server-side rendering to render the pre-render the page. This can make debugging more difficult, because errors in page rendering appear in the Node.JS server instead of the browser. To switch to client-side rendering for debugging, a cookie rendermode of value client needs to be set in the browser. On non-production servers, this can be done by navigating to a special route:

route to switch to client-side rendering

<base url>/rendermode/client

route to switch back to server-side rendering

<base url>/rendermode/server

Pattern Library

Please see Pattern Library

React performance profiling

A profiling utility has been added that will log potential React performance bottlenecks to the console in the browser. You can activate it for development builds by adding a truthy reactRenderPerf property to localStorage.

For more options, see Profiling Components with the Chrome Performance Tab

Forms and validation

We use the redux-form library for syncing input with Redux. However, we have our own wrapper around redux-form called redux-enhanced-form. For the differences between standard redux-form and the enhanced usage, please consult Forms and validation

Cleanup script

Once built, there is an asset-clean.js node script in the node output folder that will clean old assets from the wwwroot directory. You can use it like so:

node asset-cleanup <options>

Options:
  -d, --dry-run       only logs, does not delete any files
  -b, --before        delete all versions before the given unix timestamp       [number]

  -n, --num-versions  keep only this number of versions                         [number]

  -u, --unknown       remove files that aren't assets of any known version     [boolean]

  -a, --all           remove all versions                                      [boolean]

  -v, --verbose       verbose output                                           [boolean]

  -h, --help          Show help                                                [boolean]

Build documentation server

We have a server that contains both the US and UK pattern-lib, and also has js and scss documentation on it. To deploy this we have a single build command that:

  • builds pattern-lib for both markets
  • builds the js and scss docs
  • copies everything over to a folder with the correct folder structure

The command to invoke to build this is:

npm run build:documentation

The resulting folder structure would be:

  • /build-docs/
    • pattern-lib/
      • us/
        • wwwroot/ - needs virtual dir /pattern-lib/us
      • uk/
        • wwwroot/ - needs virtual dir /pattern-lib/uk
      • package.json - needs to run yarn install --production=true during deploy
    • docs - contains JS docs, needs virtual dir /docs
    • scssdocs - contains SCSS docs, needs virtual dir /scssdocs

As noted above, the following things have to be done:

  • create virtual dirs in Azure to point to the correct webroots
  • run yarn once for all pattern-lib installs
  • there is no build market or channel
  • build/deployment should be set up automatically on pushes to the develop branch