shopstyle-collective v10.49.1
Setup
Get the code
Fork the repo https://help.github.com/articles/fork-a-repo
Clone the repo and set up your remote fork
$ git clone git@github.rakops.com:ShopStyle/shopstyle-collective.git
$ cd shopstyle-collective
$ git remote add mine git@github.rakops.com:<GIT_USERNAME>/shopstyle-collective.git
If you get an error when you clone the repo, be sure that you have a SSH key added to your GitHub account or create a new one (https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/).
Install global dependencies
ShopStyle has various projects relying on various versions of node. The easiest way to deal with switching node versions is to use nvm. Follow the directions on the nvm gihub page for installation. ShopStyle Collective relies on node 16.17.0, so make sure to install and use that particular version to run this project.
Then, run these commands:
$ gem install sass -v 3.3.1
Install project dependencies
# If using nvm, run this to use the correct version of node
$ nvm use
$ npm install
Configuring your IDE
Prettier is used to format the code on pre-commit. If you would like to have the same configuration set on your editor, please follow these instructions. Then, you will need to update the settings on your editor to match the prettier
settings in package.json
and enable "Format On Save".
Configuring your /etc/hosts
Add the following entries to your /etc/hosts
127.0.0.1 app.collectivevoicelocal.com
127.0.0.1 connect.collectivevoicelocal.com
127.0.0.1 localwidgettest.shopstyleqa.com
Setup https and private keys
To run https locally, you will need to set up a self signed ssl cert. From your shopstyle-collective-frontend directory, create a host.key and host.cert
$ openssl genrsa -out host.key 1024
$ openssl req -new -key host.key -out host.csr
$ openssl x509 -req -in host.csr -signkey host.key -out host.cert
$ rm host.csr
Development Flow
Build the web app
Development mode (https & http)
To watch for any changes you make to the files, run the following command:
$ npm run watch
This will automatically open the browser on https://app.collectivevoice.com:5443/landing (collective app). If you are working on the connect app, go to https://connect.collectivevoice.com:5443.
If you need to run the website on http, please use:
$ npm run watch:http
Production mode
You do not need to use this command to develop but if you want to build a version the same way it is done for production:
$ npm run build
Testing
To run the unit tests locally, use the command:
$ npm run test
The unit tests will run when creating a PR (part of the Jenkinsfile checks) with the command npm run test:jenkins
.
Creating a Pull Request
Find the full guide here (Collective wiki)
Deployment
We have three branches - master, qa, and development. Master is the code that is currently deployed to the production environment, or code that could be deployed to prod at any time. QA is code we are testing - the release canidate. Development is where most changes should be merged. It is the most active branch.
The typical release cycle is to merge development into QA, deploy to test.shopstylecollective.com, and then test. If there are any bugs for that build, send them to QA. Once we are satisfied with the build, then we merge QA into master, and deploy master to prod. After that deployment we merge master back into development to make sure any changes we made during testing are merged in upstream. A hotfix change should get merged to master directly, then master can be deployed straight to prod.
More details about deployment and build captain duties here: FE Collective Build Captain Duties
Using the BRASS interface
The Jenkins job brass-quickactions-ssc is a convenient interface to perform the regular actions we perform throughout the weekly build and release lifecycle with single-click actions.
Weekly cutoff
To perform the weekly cutoff, build with these parameters:
ACTION
:Weekly cutoff (dev -> qa)
FIX_VERSION
: Determine the next using the release train
Please note that as part of the cutoff automation, the latest realtime microdata scraper (RTS) is also cut off. Any new commits on the scraper's master branch will be published and reflected on SSC QA.
QA builds
To perform regular QA builds after merging a PR to QA, build with these parameters:
ACTION
:QA build & deploy
FIX_VERSION
: Determine the next using the release train
Deploy the build on QA to prod
Once the build on the QA branch has been tested and approved for release by the QA team, we can use the BRASS interface to deploy to prod using these steps:
- Run the brass-quickactions-ssc job once with these parameters to merge and wait for it to complete:
ACTION
:Weekly cutoff (dev -> qa)
- Run the brass-quickactions-ssc job once with these parameters to deploy to prod:
ACTION
:Prod deploy (minor)
orProd deploy (major)
- Note:
minor
is typical
- Note:
FIX_VERSION
: Determine the next using the release train
This will automatically create a new entry in the release train. Visually inspect it and manually populate any missing information, if needed.
Deploy a hotfix to prod
The procedure for deploying a hotfix to prod is the same as a regular release for QA, except since fixes are presumed to be merged directly to master, we do not run a merge prior to the release.
Prior to a hotfix, determine the next hotfix fix version using the release train and ensure that has been manually added to the HF ticket. Next, test the hotfix by staging the master branch on QA with brass-quickactions-ssc and the following parameters:
ACTION
:Stage master on QA
FIX_VERSION
: (whatever was added to the ticket)
Once the fix has been validated on QA, we're ready to deploy to prod. Run the brass-quickactions-ssc job once with these parameters to deploy to prod:
ACTION
:Prod deploy (patch)
FIX_VERSION
: (whatever was added to the ticket)
Rolling back to a stable version
In an emergency, we have the ability to manually roll back to a previously-released version. For now, this should be done using the SS_Collective-Web_Deploy-New-alacarte job. The ENVIRONMENT
should be prod
, and the RELEASE_TAG
should be whatever the last stable release's tag was per the release train. FIX_VERSION
and ACTION
do not matter.
Deployment: RTS
When the Real Time Scraper needs to be deployed, the Collective app needs to explicitly pick up the latest version of the RTS. Here are all the steps necessary to deploy the RTS:
- Publish a new version of the RTS.
- Take note of the version number you have just published. If you can't find it, you can also take a look at the release page of the RTS where you can find all the versions that have been published.
- Update the version that is picked up by Collective by running the commands below.
nvm use
npm install @ssjs/shopstyle-microdata-scraper@1.49.0 --save --save-exact # where 1.49.0 is the latest version
npm shrinkwrap
Notes: Make sure the last command you run does update the version number on npm-shrinkwrap.json
. By having this shrinkwrap file, package.json
is ignored during the Jenkins build and therefore, the new version would not be picked up.
Coding Guidelines
Deprecated
We are hoping to upgrade this web app to Angular (from AngularJS) soon. In order to get ready for this migration, some important changes had been made that deprecated some of the code you will find in this repo.
Ng-include
ng-include
has been removed from Angular since it had some security and performance issues. If you need to create a new template for your view or modal, please create a new component.
Components
Components have been introduced in AngularJS 1.5 and substitute the binding of ctrl/view directly in the router config or directives. This is the way any ctrl/view should be added.
Types of components and examples
In our project, we have two types of components:
- Components that are considered a full page view, such as the landing page, and are bound to a specific URL in the router config (example). There is no reason to re-use them since they have the full structure of a page. They are located in /modules, grouped by categories (account, analytics, etc...). Full page "unsubscribe" module: /modules/unsubscribe
- Component with parameters (previously called "directives"), that are made to be re-used. They do not usually contains a full page structure but contains an HTML snippet (for a button, form, etc...) and they are located in /components Re-usable tooltip component: /components/click-tooltip
Migration of old controllers/directives to components
The first step consist in converting a controller (or link for directives) to a class and use the property controllerAs
. This property can be added first to the directive declaration/router config (below the property controller
) before converting fully the element to a component.
The value of controllerAs
, usually ctrl
, needs to be added to the view in front of each variable: ctrl.myVariable
.
If the directive is added to a view with a <div>
or other common HTML tags, this should be updated to the name of the component <my-new-component>
.
Here is an example of the changes required to convert a directive to a component: click-tooltip PR. Please note that you will also have to add a 'ngInject';
in between the constructor and injections for minification purposes as added in the final code here
Modals
Our modal service offers now the possibility of opening any component as a modal, with two data binding types supported: one-way (<
) and callbacks (&
).
// my-custom-modal component config
export default {
template: require('./my-custom-modal.tpl.html'),
controller: MyCustomModalCtrl,
controllerAs: 'ctrl',
bindings: {
myProperty: '<',
myCallback: '&'
}
};
// controller opening my-custom-modal component as a modal
this.ModalService.openComponent(
'my-custom-modal',
{
myProperty: 'first property',
callbacks: {
myCallback: () => this.onMyCustomModalCallback()
}
},
this.onMyCustomModalClose()
);
When possible, it is strongly recommended to use one of our predefined modal template, such as ModalService.openInfo()
, in order to keep consistency with the user experience across the web app. More information on how to use each of these methods in modal.service.js.
Avoiding binding this
With the conversion to components and the way our callback were configured beforehand, bound with '='
, we can easily run into context issues that requires: this.myFunction = this.myFunction.bind(this);
. To avoid using .bind(this)
, and to keep the original context of this
, the callback parameter needs to have the binding type '&'
, and the function passed as an ng-click, callback-param="myFunction()"
.
Here is an example of a component using a callback implementation with '&'
: multi-image-select.js
Scoped CSS
If the CSS of a component is not scoped, there is a risk of overriding CSS rules that apply to other components. Most of the new front-end frameworks have a built-in feature to scope CSS but this is not the case for AngularJS. Fortunately, the CSS can be scoped easily: a component is added to a page through a HTML tag so we can use this tag as a selector. Please, always scope the CSS when creating a new component.
// multi-image-select.scss (for a component named "multi-image-select")
multi-image-select {
// all the component's css goes here
}
Svg Icons
The icons used on this project come from the harmony-core library.
Using an icon
You can use these icons directly from a SCSS or HTML file if needed but we recommend adding them with the component svg-icon
coming from harmony-angularjs:
<svg-icon src="arrow-drop-down"></svg-icon>
Styling an icon
Implementing an icon with the component svg-icon
adds some predefined style to the icon, and a class name in order to select it. If you implement the arrow-drop-down
icon, you can select the icon with the class name svg-arrow-drop-down
and change its properties as follows:
.svg-arrow-drop-down {
/* added by default
display: inline-block;
fill: $black;
transition: fill $transition-fast;
*/
@include size-svg(20px); // update size (moving away from this and using the density param instead)
svg {
stroke: $black; // update icon stroke color
margin-top: $u1; // update position
path {
fill: $black; //to fill within the stoke of the icon, not just the borders
}
}
}
Note that to modify the size of the icon you can set a density param as follows:
<svg-icon density="sm" src="arrow-drop-down"></svg-icon>
You can see all the different density sizes in the harmony-angularjs folder svg-icon.scss
Harmony Styles
In order to have a consistent design on our website, we use Harmony:
The most important elements are listed below but there are plenty of other useful class names and mixins that can be found on these files such as h-btn--primary
, truncate-text
and arrow(up)
to mention a few.
Colors
Any color present on the website is one of the colors coming from harmony-core colors.scss
file.
- If the design you are implementing has an hexadecimal code that does not match one of these colors but is very close, please use one of the variables above.
- If you need to use a color from an external brand, please add it to the
brand colors
section.
Notes: do not use the filter colors
as they are not part of our branding. They are only used on the search page for filtering by colors.
Spacing unit
We have a base unit of 8px defined in variables.scss
, that helps us having consistent margin. Unless the positioning is critical (such as centering an element), please try to always use this unit when defining a margin, padding, position. If the final design you are implementing has only a couple pixels difference from this unit, stick to the unit. Using this unit for width and height is also nice to have but not mandatory. You can also use the unit for font-size, line-height, etc... but this is not required.
Breakpoints
The breakpoints used for responsive design are defined in variables.scss
. The design is usually implemented as a desktop version first and have rules for other screen sizes, from bigger to smaller, as follows:
.my-element {
// properties here for desktop
@include screen-md {
// properties for medium screen
}
@include screen-sm {
// properties for small screen
}
}
It is usually recommended to add this property to each of the elements that need to be responsive as shown above. If the layout has large modifications in between desktop and mobile, you can also add these mixins at the bottom of the file and style your elements inside:
@include screen-md {
.my-element {
// properties for medium screen for my-element
}
.other-element {
// properties for medium screen for other-element
}
}
Font style
The default font on the website is GT America. Browsers do not always recognize or apply correctly the strength to a font so it is NOT recommended to use font-weight: bold;
. Instead, please use the mixin h-body--strong
.
The font styles used on a website is usually repetitive so in order to achieve consistency and avoid duplicates, there are some defined styles that can be found in the typography section of mixins.scss
. The available styles goes from h-headline--1
to h-headline--4
; h-caption--md
, h-body--md
... The design to implement might have the style name set explicitly. If it is not the case, consult Harmony leaders.
Note that we also have the font size and font strength defined in their own mixins to make the code more readable.
- Sizes can go from
xs
toxl
(e.g.:h-button-xs
,h-body--xl
) - Strength are
h-body--strong
andh-text--muted
Elevation
Elevation... what? This is the concept used by Material Design of having a "relative distance between two surfaces along the z-axis" (different layers of elements on the page). If you have never heard of elevations, take a look at material documention, the first animation summarizes it all. We have currently 4 types of elevations, that can be found in mixins.scss
.
elevation-0
only applies a border to the element. This means that the element is on a layer right on top of the others -- at a distance 0. It is used for buttons, headers, anything that needs some separation and does not need to stand out.elevation-1
toelevation-3
applies a box-shadow to the element. This is used for the different kind of modals present on the website, or other elements that need to be at a certain distance from our base layer such as the mobile menu.
S3 Configs
To make changing config values and other non-code dependent changes we have files in an s3 bucket: https://console.aws.amazon.com/s3/buckets/spimobile/collective/config/production/v4/. These are split up by locale (e.g. http://spimobile.s3.amazonaws.com/collective/config/production/v4/en_US/appConfig.json). The local versions of these are located in the ShopStyle-App repository. If you need to make a change to them, edit the local file, send a PR, once approved and merged a script is run to deploy the changes to S3.
Optimizely
When developing features, we often gate them using opitimizely (https://app.optimizely.com/). In addition to adding the gate in the Optimizely dashboard, you will also need to add code to our config file (prod.config.js).
optimizely: {
newFeatureToGate: {
name: 'new_feature_to_gate', // will match feature key in optimizely
localOverride: null,
useVisitorId: true
},
}
The localOverride param is used to bypass calling the Optimizely api and manually enables or disables the feature for testing. If it is set to null, the Optimizely api will be called to determine if the feature is enabled.
The useVisitorId param is set to true if you have a test where you want to have the visitor id used throughout the duration of the test.
** When conducting an A/B test, the same id must be used throughout the duration of the test (cannot change after logging in or Optimizely will not track conversion events correctly). Use this parameter when you are starting a test from a logged out state and continue to track events when the user is logged in.
Translations
The update of the translation files is automated through the deployment process. However, if you need to update the translation files manually, please follow the instructions below.
Extracting translations
Used to extract, sort and add the translation keys from HTML and JS files to en.json. Integrated in the workflow as follows:
- Creating a PR: command will run to make sure there is no error in the translations (part of the Jenkinsfile checks)
- Merging dev into QA: command will run then commit the results to QA
make extract-translations
Update translations
Used to copy the source (en.json
) file to localized files (e.g. en_US.json
), formerly used to pull files from translation platform, then convert american to british spelling. Command will run when building the QA branch.
make update-translations
1 year ago