diff --git a/.env.build.example b/.env.build.example index cae7cc9e9..8669d1f31 100644 --- a/.env.build.example +++ b/.env.build.example @@ -9,7 +9,7 @@ NODE_ENV=development APP_STAGE=development # The NRN preset used for the demo -NRN_PRESET=v1-ssr-mst-aptd-gcms-lcz-sty +NRN_PRESET=v1-hyb-mst-aptd-gcms-lcz-sty # The customer that is being deployed CUSTOMER_REF=customer1 diff --git a/.eslintrc.yml b/.eslintrc.yml index 7b7e8a4da..7918d6d58 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -44,9 +44,7 @@ rules: # See https://eslint.org/docs/rules strict: 'off' no-console: 1 # Shouldn't use "console", but "logger" instead allowArrowFunctions: 0 - no-unused-vars: - - warn # Warn otherwise it false-positive with needed React imports - - args: none # Allow to declare unused variables in function arguments, meant to be used later + no-unused-vars: 0 # Disabled, already handled by @typescript-eslint/no-unused-vars import/prefer-default-export: 0 # When there is only a single export from a module, don't enforce a default export, but rather let developer choose what's best no-else-return: 0 # Don't enforce, let developer choose. Sometimes we like to specifically use "return" for the sake of comprehensibility and avoid ambiguity no-underscore-dangle: 0 # Allow _ before/after variables and functions, convention for something meant to be "private" @@ -78,7 +76,7 @@ rules: # See https://eslint.org/docs/rules react-hooks/exhaustive-deps: warn react/jsx-no-target-blank: warn # Not using "noreferrer" is not a security risk, but "noopener" should always be used indeed react/prop-types: warn # Should be handled with TS instead - react/no-unescaped-entities: warn # Causes text mismatch when enabled + react/no-unescaped-entities: 0 # Causes text mismatch when enabled jsx-a11y/anchor-is-valid: warn linebreak-style: - error diff --git a/.github/workflows/deploy-zeit-production.yml b/.github/workflows/deploy-zeit-production.yml index 8c8394eb8..351cade28 100644 --- a/.github/workflows/deploy-zeit-production.yml +++ b/.github/workflows/deploy-zeit-production.yml @@ -13,13 +13,13 @@ jobs: # Configures the deployment environment, install dependencies (like node, npm, etc.) that are requirements for the upcoming jobs # Ex: Necessary to run `yarn deploy` setup-environment: - name: Setup deployment environment (Ubuntu 18.04 - Node 10.x) + name: Setup deployment environment (Ubuntu 18.04 - Node 12.x) runs-on: ubuntu-18.04 steps: - name: Installing node.js uses: actions/setup-node@v1 # Used to install node environment - XXX https://github.com/actions/setup-node with: - node-version: '10.x' # Use the same node.js version as the one Zeit's uses (currently node10.x) + node-version: '12.x' # Use the same node.js version as the one Zeit's uses (currently node12.x) # Starts a Zeit deployment, using the production configuration file of the default institution # The default institution is the one defined in the `now.json` file (which is a symlink to the actual file) diff --git a/.github/workflows/deploy-zeit-staging.yml b/.github/workflows/deploy-zeit-staging.yml index 2cecbe90b..7b01f4f5f 100644 --- a/.github/workflows/deploy-zeit-staging.yml +++ b/.github/workflows/deploy-zeit-staging.yml @@ -13,13 +13,13 @@ jobs: # Configures the deployment environment, install dependencies (like node, npm, etc.) that are requirements for the upcoming jobs # Ex: Necessary to run `yarn deploy` setup-environment: - name: Setup deployment environment (Ubuntu 18.04 - Node 10.x) + name: Setup deployment environment (Ubuntu 18.04 - Node 12.x) runs-on: ubuntu-18.04 steps: - name: Installing node.js uses: actions/setup-node@v1 # Used to install node environment - XXX https://github.com/actions/setup-node with: - node-version: '10.x' # Use the same node.js version as the one Zeit's uses (currently node10.x) + node-version: '12.x' # Use the same node.js version as the one Zeit's uses (currently node12.x) # Starts a Zeit deployment, using the staging configuration file of the default institution # The default institution is the one defined in the `now.json` file (which is a symlink to the actual file) @@ -46,13 +46,19 @@ jobs: else ZEIT_DEPLOYMENT_ALIAS=$(cat now.json | jq -r '.name')-${CURRENT_BRANCH##*/} fi - - # Zeit alias only allows 53 characters in the domain name, so we only keep the first 46 characters (because Zeit needs 7 chars for ".now.sh" at the end of the domain name) - # Also, in order to remove forbidden characters, we create a sequence from ascii numbers using ranges of numbers (we forbid characters by using `seq X Y` and we add others by using ';'). - # All special characters are converted to `-` (using `tr $0 $1` where $0 is replaced by $1), and only 0-9 and a-Z chars are kept intact. - # We then use `awk` to convert "ascii numbers" back into actual characters. - # You can find the numbers equivalence by tapping `man ascii` and look at the "decimal" set. - ZEIT_DEPLOYMENT_ALIAS=$(echo $ZEIT_DEPLOYMENT_ALIAS | head -c 46 | tr "`(seq 0 47 ; seq 58 64 ; seq 91 96 && seq 123 127) | awk '{printf("%c",$1)}'`" -).now.sh + + # Zeit alias only allows 53 characters in the domain name, so we only keep the first 45 (45 = 53 - 7 - 1) characters (because Zeit needs 7 chars for ".now.sh" at the end of the domain name, and count starts at 1, not 0) + # Also, in order to remove forbidden characters, we transform every characters which are not a "alnum" and \n or \r into '-' + + ZEIT_DEPLOYMENT_ALIAS=$(echo $ZEIT_DEPLOYMENT_ALIAS | head -c 45 | tr -c '[:alnum:]\r\n' - | tr '[:upper:]' '[:lower:]') + + # Recursively remove any trailing dash ('-') + while [[ "$ZEIT_DEPLOYMENT_ALIAS" == *- ]] + do + ZEIT_DEPLOYMENT_ALIAS=${ZEIT_DEPLOYMENT_ALIAS::-1} + done + + ZEIT_DEPLOYMENT_ALIAS=$ZEIT_DEPLOYMENT_ALIAS.now.sh echo "::set-env name=ZEIT_DEPLOYMENT_ALIAS::https://$ZEIT_DEPLOYMENT_ALIAS" npx now alias $ZEIT_DEPLOYMENT_URL https://$ZEIT_DEPLOYMENT_ALIAS --token $ZEIT_TOKEN diff --git a/.gitignore b/.gitignore index 95f6f4fbe..e8620c4d1 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ fabric.properties *.iml modules.xml .idea/misc.xml +.idea/codeStyles *.ipr vcs.xml diff --git a/.nowignore b/.nowignore index 4cbc376fd..bb18cd833 100644 --- a/.nowignore +++ b/.nowignore @@ -12,3 +12,7 @@ README.md schema.graphql yarn.lock yarn-error.log + +# Avoid tests being deployed as Vercel Serverless Functions (increases bundle size, and count towards limits) +src/pages/api/*.test.ts +src/pages/api/**/*.test.ts diff --git a/cypress/config-customer1.json b/cypress/config-customer1.json index 76a1e8ac6..6d260d39d 100644 --- a/cypress/config-customer1.json +++ b/cypress/config-customer1.json @@ -1,5 +1,5 @@ { - "baseUrl": "https://nrn-v1-ssr-mst-aptd-gcms-lcz-sty-c1.now.sh/", + "baseUrl": "https://nrn-v1-hyb-mst-aptd-gcms-lcz-sty-c1.now.sh/", "projectId": "4dvdog", "screenshotsFolder": "cypress/screenshots/customer1", "videosFolder": "cypress/videos/customer1", diff --git a/cypress/config-customer2.json b/cypress/config-customer2.json index 069f85bb9..804b80d31 100644 --- a/cypress/config-customer2.json +++ b/cypress/config-customer2.json @@ -1,5 +1,5 @@ { - "baseUrl": "https://nrn-v1-ssr-mst-aptd-gcms-lcz-sty-c2.now.sh/", + "baseUrl": "https://nrn-v1-hyb-mst-aptd-gcms-lcz-sty-c2.now.sh/", "projectId": "4dvdog", "screenshotsFolder": "cypress/screenshots/customer2", "videosFolder": "cypress/videos/customer2", diff --git a/cypress/integration/app/pages/index.js b/cypress/integration/app/pages/index.js index b20f25b23..379819f75 100644 --- a/cypress/integration/app/pages/index.js +++ b/cypress/integration/app/pages/index.js @@ -23,14 +23,17 @@ describe('Index page', () => { * Navbar section */ it('should have 5 links in the navigation bar', () => { - cy.get('#nav a.nav-link').should('have.length', 5); + cy.get('#nav .navbar-nav > .nav-item').should('have.length', 5); }); it('should have a link in the navbar that redirects to the examples page', () => { - cy.url().should('eq', `${baseUrl}/`); + cy.url().should('eq', `${baseUrl}/en`); cy.get('#nav-link-examples') .should('have.text', 'Examples') .click(); - cy.url().should('eq', `${baseUrl}/examples`); + cy.get('#nav-link-examples-static-i-18-n') + .should('have.text', 'Static i18n') + .click(); + cy.url().should('eq', `${baseUrl}/en/examples/built-in-features/static-i18n`); }); }); diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..45c150536 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,3 @@ +_site +.sass-cache +.jekyll-metadata diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 000000000..eeaa17753 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,25 @@ +--- +layout: default +nav_exclude: true +--- + + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 000000000..784f22778 --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,27 @@ +# XXX This file is only used when working on your local machine, in development +# Run `yarn doc:start` to start the development server +# Read ./CONTRIBUTING.md for further instructions + +source "https://rubygems.org" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +# If you have any plugins, put them here! +group :jekyll_plugins do + gem 'just-the-docs' # XXX Our Jekyll theme - See https://pmarsceill.github.io/just-the-docs/ + gem "github-pages" # XXX Necessary to reproduce the behaviour of GitHub Pages - When this is loaded, "jekyll" must not be bundled because it's included within + gem 'jemoji' # XXX GitHub-flavored Emoji plugin for Jekyll - See https://github.com/jekyll/jemoji +end + +# ------- WINDOWS SUPPORT --------- + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +# and associated library. +install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do + gem "tzinfo", "~> 1.2" + gem "tzinfo-data" +end + +# Performance-booster for watching directories on Windows +gem "wdm", "~> 0.1.0", :install_if => Gem.win_platform? + diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock new file mode 100644 index 000000000..97ae3223e --- /dev/null +++ b/docs/Gemfile.lock @@ -0,0 +1,261 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (6.0.2.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.11.1) + colorator (1.1.0) + commonmarker (0.17.13) + ruby-enum (~> 0.5) + concurrent-ruby (1.1.6) + dnsruby (1.61.3) + addressable (~> 2.5) + em-websocket (0.5.1) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) + ethon (0.12.0) + ffi (>= 1.3.0) + eventmachine (1.2.7) + execjs (2.7.0) + faraday (1.0.0) + multipart-post (>= 1.2, < 3) + ffi (1.12.2) + forwardable-extended (2.6.0) + gemoji (3.0.1) + github-pages (204) + github-pages-health-check (= 1.16.1) + jekyll (= 3.8.5) + jekyll-avatar (= 0.7.0) + jekyll-coffeescript (= 1.1.1) + jekyll-commonmark-ghpages (= 0.1.6) + jekyll-default-layout (= 0.1.4) + jekyll-feed (= 0.13.0) + jekyll-gist (= 1.5.0) + jekyll-github-metadata (= 2.13.0) + jekyll-mentions (= 1.5.1) + jekyll-optional-front-matter (= 0.3.2) + jekyll-paginate (= 1.1.0) + jekyll-readme-index (= 0.3.0) + jekyll-redirect-from (= 0.15.0) + jekyll-relative-links (= 0.6.1) + jekyll-remote-theme (= 0.4.1) + jekyll-sass-converter (= 1.5.2) + jekyll-seo-tag (= 2.6.1) + jekyll-sitemap (= 1.4.0) + jekyll-swiss (= 1.0.0) + jekyll-theme-architect (= 0.1.1) + jekyll-theme-cayman (= 0.1.1) + jekyll-theme-dinky (= 0.1.1) + jekyll-theme-hacker (= 0.1.1) + jekyll-theme-leap-day (= 0.1.1) + jekyll-theme-merlot (= 0.1.1) + jekyll-theme-midnight (= 0.1.1) + jekyll-theme-minimal (= 0.1.1) + jekyll-theme-modernist (= 0.1.1) + jekyll-theme-primer (= 0.5.4) + jekyll-theme-slate (= 0.1.1) + jekyll-theme-tactile (= 0.1.1) + jekyll-theme-time-machine (= 0.1.1) + jekyll-titles-from-headings (= 0.5.3) + jemoji (= 0.11.1) + kramdown (= 1.17.0) + liquid (= 4.0.3) + mercenary (~> 0.3) + minima (= 2.5.1) + nokogiri (>= 1.10.4, < 2.0) + rouge (= 3.13.0) + terminal-table (~> 1.4) + github-pages-health-check (1.16.1) + addressable (~> 2.3) + dnsruby (~> 1.60) + octokit (~> 4.0) + public_suffix (~> 3.0) + typhoeus (~> 1.3) + html-pipeline (2.12.3) + activesupport (>= 2) + nokogiri (>= 1.4) + http_parser.rb (0.6.0) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + jekyll (3.8.5) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (~> 0.7) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (~> 1.14) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + jekyll-avatar (0.7.0) + jekyll (>= 3.0, < 5.0) + jekyll-coffeescript (1.1.1) + coffee-script (~> 2.2) + coffee-script-source (~> 1.11.1) + jekyll-commonmark (1.3.1) + commonmarker (~> 0.14) + jekyll (>= 3.7, < 5.0) + jekyll-commonmark-ghpages (0.1.6) + commonmarker (~> 0.17.6) + jekyll-commonmark (~> 1.2) + rouge (>= 2.0, < 4.0) + jekyll-default-layout (0.1.4) + jekyll (~> 3.0) + jekyll-feed (0.13.0) + jekyll (>= 3.7, < 5.0) + jekyll-gist (1.5.0) + octokit (~> 4.2) + jekyll-github-metadata (2.13.0) + jekyll (>= 3.4, < 5.0) + octokit (~> 4.0, != 4.4.0) + jekyll-mentions (1.5.1) + html-pipeline (~> 2.3) + jekyll (>= 3.7, < 5.0) + jekyll-optional-front-matter (0.3.2) + jekyll (>= 3.0, < 5.0) + jekyll-paginate (1.1.0) + jekyll-readme-index (0.3.0) + jekyll (>= 3.0, < 5.0) + jekyll-redirect-from (0.15.0) + jekyll (>= 3.3, < 5.0) + jekyll-relative-links (0.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-remote-theme (0.4.1) + addressable (~> 2.0) + jekyll (>= 3.5, < 5.0) + rubyzip (>= 1.3.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-sitemap (1.4.0) + jekyll (>= 3.7, < 5.0) + jekyll-swiss (1.0.0) + jekyll-theme-architect (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-cayman (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-dinky (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-hacker (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-leap-day (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-merlot (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-midnight (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-minimal (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-modernist (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-primer (0.5.4) + jekyll (> 3.5, < 5.0) + jekyll-github-metadata (~> 2.9) + jekyll-seo-tag (~> 2.0) + jekyll-theme-slate (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-tactile (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-theme-time-machine (0.1.1) + jekyll (~> 3.5) + jekyll-seo-tag (~> 2.0) + jekyll-titles-from-headings (0.5.3) + jekyll (>= 3.3, < 5.0) + jekyll-watch (2.2.1) + listen (~> 3.0) + jemoji (0.11.1) + gemoji (~> 3.0) + html-pipeline (~> 2.2) + jekyll (>= 3.0, < 5.0) + just-the-docs (0.2.7) + jekyll (~> 3.8.5) + jekyll-seo-tag (~> 2.0) + rake (~> 12.3.1) + kramdown (1.17.0) + liquid (4.0.3) + listen (3.2.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + mercenary (0.3.6) + mini_portile2 (2.4.0) + minima (2.5.1) + jekyll (>= 3.5, < 5.0) + jekyll-feed (~> 0.9) + jekyll-seo-tag (~> 2.1) + minitest (5.14.0) + multipart-post (2.1.1) + nokogiri (1.10.9) + mini_portile2 (~> 2.4.0) + octokit (4.18.0) + faraday (>= 0.9) + sawyer (~> 0.8.0, >= 0.5.3) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + public_suffix (3.1.1) + rake (12.3.3) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + rouge (3.13.0) + ruby-enum (0.7.2) + i18n + rubyzip (2.3.0) + safe_yaml (1.0.5) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sawyer (0.8.2) + addressable (>= 2.3.5) + faraday (> 0.8, < 2.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + thread_safe (0.3.6) + typhoeus (1.3.1) + ethon (>= 0.9.0) + tzinfo (1.2.6) + thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) + unicode-display_width (1.7.0) + wdm (0.1.1) + zeitwerk (2.3.0) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages + jemoji + just-the-docs + tzinfo (~> 1.2) + tzinfo-data + wdm (~> 0.1.0) + +BUNDLED WITH + 1.17.3 diff --git a/docs/_config-development.yml b/docs/_config-development.yml new file mode 100644 index 000000000..70456bf23 --- /dev/null +++ b/docs/_config-development.yml @@ -0,0 +1,48 @@ +# XXX This file is only used when working on your local machine, in development +# Checkout https://pages.github.com/versions/ for the list of Github Pages built-in plugins + +# XXX --------- Specific to local config ------------ +theme: 'just-the-docs' # XXX Our Jekyll theme - See https://pmarsceill.github.io/just-the-docs/ + +# XXX --------- Common to all configs (local + GHP) -------------- + +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'bundle exec jekyll serve'. If you change this file, please restart the server process. + +# Site settings +# These are used to personalize your new site. If you look in the HTML files, +# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. +# You can create any custom variable you would like, and they will be accessible +# in the templates via {{ site.myvariable }}. +title: Next Right Now +description: >- # this means to ignore newlines until "baseurl:" + Flexible production-grade boilerplate with Next.js 9, Zeit and TypeScript. + Includes multiple opt-in presets using GraphQL, Analytics, CSS-in-JS, Monitoring, End-to-end testing, + Internationalization, CI/CD and B2B multiple single-tenants (monorepo) support +#baseurl: "" # the subpath of your site, e.g. /blog +#url: "" # the base hostname & protocol for your site, e.g. http://example.com XXX Auto-resolved by GitHub + +# Aux links for the upper right navigation +aux_links: + "Home": "/" + "Github": "https://github.com/UnlyEd/next-right-now" + "About us": "https://github.com/UnlyEd/Unly" + +footer_content: "Copyright © 2020 Unly. MIT license." +#color_scheme: "dark" + +plugins: + - jekyll-sitemap + - jemoji + +# Exclude from processing. +# The following items will not be processed, by default. Create a custom list +# to override the default setting. +# exclude: +# - Gemfile +# - Gemfile.lock +# - node_modules +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..2322318ba --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,49 @@ +# XXX This file is only used by GitHub Pages, when deploying online +# Checkout https://pages.github.com/versions/ for the list of Github Pages built-in plugins + +# XXX --------- Specific to GHP config ------------ +remote_theme: pmarsceill/just-the-docs # XXX Our Jekyll theme - See https://pmarsceill.github.io/just-the-docs/ +#ga_tracking: + +# XXX --------- Common to all configs (local + GHP) -------------- + +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'bundle exec jekyll serve'. If you change this file, please restart the server process. + +# Site settings +# These are used to personalize your new site. If you look in the HTML files, +# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. +# You can create any custom variable you would like, and they will be accessible +# in the templates via {{ site.myvariable }}. +title: Next Right Now +description: >- # this means to ignore newlines until "baseurl:" + Flexible production-grade boilerplate with Next.js 9, Zeit and TypeScript. + Includes multiple opt-in presets using GraphQL, Analytics, CSS-in-JS, Monitoring, End-to-end testing, + Internationalization, CI/CD and B2B multiple single-tenants (monorepo) support +#baseurl: "" # the subpath of your site, e.g. /blog +#url: "" # the base hostname & protocol for your site, e.g. http://example.com XXX Auto-resolved by GitHub + +# Aux links for the upper right navigation +aux_links: + "Home": "/" + "Github": "https://github.com/UnlyEd/next-right-now" + "About us": "https://github.com/UnlyEd/Unly" + +footer_content: "Copyright © 2020 Unly. MIT license." +#color_scheme: "dark" + +plugins: + - jekyll-sitemap + - jemoji + +# Exclude from processing. +# The following items will not be processed, by default. Create a custom list +# to override the default setting. +# exclude: +# - Gemfile +# - Gemfile.lock +# - node_modules +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/docs/_includes/nav.html b/docs/_includes/nav.html new file mode 100644 index 000000000..448df6196 --- /dev/null +++ b/docs/_includes/nav.html @@ -0,0 +1,58 @@ + diff --git a/docs/_includes/page-toc.md b/docs/_includes/page-toc.md new file mode 100644 index 000000000..57f2d2fe1 --- /dev/null +++ b/docs/_includes/page-toc.md @@ -0,0 +1,7 @@ +--- + +## Table of contents +{: .no_toc .text-delta } + +- TOC +{:toc} diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 000000000..b1d3c7243 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,102 @@ +--- +layout: table_wrappers +--- + + + + +{% include head.html %} + + + + Link + + + + +
+ +
+
+ +
+ {% unless page.url == "/" %} + {% if page.parent %} + + {% endif %} + {% endunless %} +
+ {% if site.heading_anchors != false %} + {% include vendor/anchor_headings.html html=content beforeHeading="true" anchorBody="" anchorClass="anchor-heading" %} + {% else %} + {{ content }} + {% endif %} + + {% if page.has_children == true and page.has_toc != false %} +
+

Table of contents

+ {% assign children_list = site.pages | sort:"nav_order" %} +
    + {% for child in children_list %} + {% if child.parent == page.title and child.title != page.title %} +
  • + {{ child.title }}{% if child.summary %} - {{ child.summary }}{% endif %} +
  • + {% endif %} + {% endfor %} +
+ {% endif %} + + {% if site.footer_content != nil %} +
+
+

{{ site.footer_content }}

+
+ {% endif %} + +
+
+
+
+ + + diff --git a/docs/_sass/overrides.scss b/docs/_sass/overrides.scss new file mode 100644 index 000000000..fbba33b73 --- /dev/null +++ b/docs/_sass/overrides.scss @@ -0,0 +1,33 @@ +// XXX Overrides CSS styles - See https://pmarsceill.github.io/just-the-docs/docs/customization/#override-styles + +blockquote { + border-left: #f4f1fa 1px solid; + padding-left: 25px; +} + +.pagination-section { + display: flex; + justify-content: space-between; + + &.space-even { + justify-content: space-evenly; + } +} + +// Overrides https://github.com/jekyll/jemoji for better positioning alongside text +img.emoji { + top: 5px; + position: relative; +} + +h1 { + code { + font-size: 36px; + } +} + +h2 { + code { + font-size: 24px; + } +} diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 000000000..73a07193f --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,21 @@ +--- +layout: default +title: CHANGELOG +nav_order: 80 +--- + +Changelog +=== + + +- v1.0.0 - 2020-02-28 + - Initial release, production-ready (doc to be improved) + + +--- + +
+ + [CONTRIBUTING](./contributing){: .btn .btn } + +
diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 000000000..9cb629a09 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,75 @@ +--- +layout: default +title: CONTRIBUTING +nav_order: 90 +--- + +# Contributing +{: .no_toc } + +{% include page-toc.md %} + +--- + +## Contributing about documentation + +Our documentation lives in the `docs/` folder. It is generated and hosted by Github Pages. + +Only the `master` branch generates the online documentation. + +It uses [Jekyll](https://jekyllrb.com/) behind the wheel, and [`just-the-docs`](https://pmarsceill.github.io/just-the-docs/) theme for Jekyll. + +--- + +### Installing Jekyll locally + +In order to contribute to the docs, you may need to install Jekyll locally (especially for non-trivial changes). +Jekyll needs Ruby binary. + +1. Install and configure Jekyll on your computer, follow [https://jekyllrb.com/docs/](https://jekyllrb.com/docs/) +1. Once Jekyll is installed, you can install all Ruby gems using `yarn doc:gem:install` +1. Once gems are installed, you can run the local Jekyll server by using `yarn doc:start` which will start the server at localhost:4000 + +--- + +### Configuring Jekyll properly + +Jekyll configuration uses 2 different files. +- [`docs/_config.yml`](docs/_config.yml) used by Github Pages +- [`docs/_config-development.yml`](docs/_config-development.yml) used by your local installation + +There are a few, but important differences between both. The custom configuration must be written at the top of each config file. +The shared configuration must be written below. + +> **N.B**: If you add custom/shared configuration, don't forget update both config files, as needed. + +--- + +### Reference + +Jekyll theme used: [`just-the-docs`](https://pmarsceill.github.io/just-the-docs/) + +#### How to build a custom TOC + +See [just-the-docs documentation](https://pmarsceill.github.io/just-the-docs/docs/navigation-structure/#in-page-navigation-with-table-of-contents) + +#### How to write comments in Markdown files + +```md +[//]: # (Some markdown comment) +``` + +--- + +### Known issues + +- Using `yarn doc:start` will rebuild the whole documentation but it's slower. Using `yarn doc:start:fast` won't rebuild the whole thing and it's faster. + If you're working on the navigation menu, be warned the fast mode won't apply changes and your menu links won't update. + +--- + +
+ + [CHANGELOG](./changelog){: .btn .btn } + +
diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 000000000..8a258869e Binary files /dev/null and b/docs/favicon.ico differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..1fcd15110 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,32 @@ +--- +layout: default +title: Introduction +nav_order: 10 +--- + +# My GitHub Pages docs site + +Hello! Welcome to your docs site that comes built-in with NRN :smiley: + +Take a look at the [CONTRIBUTING](./contributing) section about how to install/run those docs locally. + +All the documentation you need about how to build your own docs site is available at [`just-the-docs`](https://pmarsceill.github.io/just-the-docs/). + +If you want to look at a more complex example, take a look at the [NRN docs source code](https://github.com/UnlyEd/next-right-now/tree/gh-pages)! + +One small difference though, NRN docs lives at the / folder, because it uses gh-pages, but the built-in docs that comes with a NRN preset are in the `docs/` folder instead. + +Using a `gh-pages` or `master` dedicated branch, or using your `master` branch `docs` folder really is up to you, you can choose what option you want on your GitHub Settings pages, in the **GitHub Pages** section. + +By default, GitHub won't use your `/docs` folder, until you manually configure it. + +> You can definitely leave this folder be for now on, and keep it around for a later use, or remove it altogether. +> It's completely unrelated to the rest of this boilerplate and won't have any side effect. + +--- + +
+ + [CONTRIBUTING](./contributing){: .btn .btn } + +
diff --git a/docs/sep-faq.md b/docs/sep-faq.md new file mode 100644 index 000000000..f4dd0ced1 --- /dev/null +++ b/docs/sep-faq.md @@ -0,0 +1,5 @@ +--- +layout: default +title: "-" +nav_order: 61 +--- diff --git a/next.config.js b/next.config.js index cdd89c1aa..68a27e520 100644 --- a/next.config.js +++ b/next.config.js @@ -1,11 +1,21 @@ const withSourceMaps = require('@zeit/next-source-maps')(); -const withCSS = require('@zeit/next-css'); // Allows to import ".css" files, like bootstrap.css const packageJson = require('./package'); const date = new Date(); +const i18nConfig = require('./src/i18nConfig'); +const supportedLocales = i18nConfig.supportedLocales.map((supportedLocale) => { + return supportedLocale.name; +}); +const noRedirectBlacklistedPaths = ['_next']; // Paths that mustn't have rewrite applied to them, to avoid the whole app to behave inconsistently +const publicBasePaths = ['robots', 'static', 'favicon.ico']; // All items (folders, files) under /public directory should be added there, to avoid redirection when an asset isn't found +const noRedirectBasePaths = [...supportedLocales, ...publicBasePaths, ...noRedirectBlacklistedPaths]; // Will disable url rewrite for those items (should contain all supported languages and all public base paths) +const withBundleAnalyzer = require('@next/bundle-analyzer')({ // Run with "yarn next:bundle" - See https://www.npmjs.com/package/@next/bundle-analyzer + enabled: process.env.ANALYZE_BUNDLE === 'true', +}) console.debug(`Building Next with NODE_ENV="${process.env.NODE_ENV}" APP_STAGE="${process.env.APP_STAGE}" for CUSTOMER_REF="${process.env.CUSTOMER_REF}"`); -module.exports = withCSS(withSourceMaps({ +module.exports = withBundleAnalyzer(withSourceMaps({ + // target: 'serverless', // Automatically enabled on Vercel, you may need to manually opt-in if you're not using Vercel - See https://nextjs.org/docs/api-reference/next.config.js/build-target#serverless-target env: { // XXX Duplication of the environment variables, this is only used locally (See https://github.com/zeit/next.js#build-time-configuration) // while now.json:build:env will be used on the Now platform (See https://zeit.co/docs/v2/build-step/#providing-environment-variables) @@ -26,12 +36,58 @@ module.exports = withCSS(withSourceMaps({ APP_VERSION: packageJson.version, UNLY_SIMPLE_LOGGER_ENV: process.env.APP_STAGE, // Used by @unly/utils-simple-logger - Fix missing staging logs because it believes we're in production }, + experimental: { + redirects() { + const redirects = [ + { + // Redirect root link with trailing slash to non-trailing slash, avoids 404 - See https://github.com/zeit/next.js/discussions/10651#discussioncomment-8270 + source: '/:locale/', + destination: '/:locale', + permanent: process.env.APP_STAGE !== 'development', // Do not use permanent redirect locally to avoid browser caching when working on it + }, + { + // Redirect link with trailing slash to non-trailing slash (any depth), avoids 404 - See https://github.com/zeit/next.js/discussions/10651#discussioncomment-8270 + source: '/:locale/:path*/', + destination: '/:locale/:path*', + permanent: process.env.APP_STAGE !== 'development', // Do not use permanent redirect locally to avoid browser caching when working on it + }, + ]; + + if (process.env.APP_STAGE === 'development') { + console.info('Using experimental redirects:', redirects); + } + + return redirects; + }, + rewrites() { + const rewrites = [ + { + // XXX Doesn't work locally (maybe because of rewrites), but works online + source: '/', + destination: '/api/autoRedirectToLocalisedPage', + }, + { + source: `/:locale((?!${noRedirectBasePaths.join('|')})[^/]+)(.*)`, + destination: '/api/autoRedirectToLocalisedPage', + }, + ]; + + if (process.env.APP_STAGE === 'development') { + console.info('Using experimental rewrites:', rewrites); + } + + return rewrites; + }, + }, webpack: (config, { isServer, buildId }) => { const APP_VERSION_RELEASE = `${packageJson.version}_${buildId}`; - - // Dynamically add some "env" variables that will be replaced during the build - config.plugins[1].definitions['process.env.APP_RELEASE'] = JSON.stringify(buildId); - config.plugins[1].definitions['process.env.APP_VERSION_RELEASE'] = JSON.stringify(APP_VERSION_RELEASE); + config.plugins.map((plugin, i) => { + if (plugin.definitions) { // If it has a "definitions" key, then we consider it's the DefinePlugin where ENV vars are stored + // Dynamically add some "env" variables that will be replaced during the build in "DefinePlugin" + plugin.definitions['process.env.APP_RELEASE'] = JSON.stringify(buildId); + plugin.definitions['process.env.APP_VERSION_RELEASE'] = JSON.stringify(APP_VERSION_RELEASE); + } + }); if (isServer) { // Trick to only log once console.debug(`[webpack] Building release "${APP_VERSION_RELEASE}"`); diff --git a/now.customer1.production.json b/now.customer1.production.json index cfe62438f..751945996 100644 --- a/now.customer1.production.json +++ b/now.customer1.production.json @@ -1,17 +1,17 @@ { "version": 2, - "name": "nrn-v1-ssr-mst-aptd-gcms-lcz-sty-c1", + "name": "nrn-v1-hyb-mst-aptd-gcms-lcz-sty-c1", "scope": "team_qnVfSEVc2WwmOE1OYhZr4VST", "env": {}, "build": { "env": { "APP_STAGE": "production", - "NRN_PRESET": "v1-ssr-mst-aptd-gcms-lcz-sty", + "NRN_PRESET": "v1-hyb-mst-aptd-gcms-lcz-sty", "CUSTOMER_REF": "customer1", "GRAPHQL_API_ENDPOINT": "https://api-euwest.graphcms.com/v1/ck73ixhlv09yt01dv2ga1bkbp/master", "GRAPHQL_API_KEY": "@nrn-graphql-api-key", "LOCIZE_PROJECT_ID": "@nrn-locize-project-id", - "LOCIZE_API_KEY": "@nrn-locize-api-key", + "LOCIZE_API_KEY": "The Locize API Key shouldn't be used in production (see https://github.com/locize/i18next-locize-backend#backend-options) because it's related to development-only features, and it's sensitive.", "AMPLITUDE_API_KEY": "@nrn-amplitude-api-key-production", "SENTRY_DSN": "@nrn-sentry-dsn" } diff --git a/now.customer1.staging.json b/now.customer1.staging.json index 6aafacc70..1b2697883 100644 --- a/now.customer1.staging.json +++ b/now.customer1.staging.json @@ -1,17 +1,17 @@ { "version": 2, - "name": "nrn-v1-ssr-mst-aptd-gcms-lcz-sty-c1", + "name": "nrn-v1-hyb-mst-aptd-gcms-lcz-sty-c1", "scope": "team_qnVfSEVc2WwmOE1OYhZr4VST", "env": {}, "build": { "env": { "APP_STAGE": "staging", - "NRN_PRESET": "v1-ssr-mst-aptd-gcms-lcz-sty", + "NRN_PRESET": "v1-hyb-mst-aptd-gcms-lcz-sty", "CUSTOMER_REF": "customer1", "GRAPHQL_API_ENDPOINT": "https://api-euwest.graphcms.com/v1/ck73ixhlv09yt01dv2ga1bkbp/master", "GRAPHQL_API_KEY": "@nrn-graphql-api-key", "LOCIZE_PROJECT_ID": "@nrn-locize-project-id", - "LOCIZE_API_KEY": "@nrn-locize-api-key", + "LOCIZE_API_KEY": "@nrn-locize-api-key-staging", "AMPLITUDE_API_KEY": "@nrn-amplitude-api-key-staging", "SENTRY_DSN": "@nrn-sentry-dsn" } diff --git a/now.customer2.production.json b/now.customer2.production.json index bbb2a3b44..43ee285cd 100644 --- a/now.customer2.production.json +++ b/now.customer2.production.json @@ -1,17 +1,17 @@ { "version": 2, - "name": "nrn-v1-ssr-mst-aptd-gcms-lcz-sty-c2", + "name": "nrn-v1-hyb-mst-aptd-gcms-lcz-sty-c2", "scope": "team_qnVfSEVc2WwmOE1OYhZr4VST", "env": {}, "build": { "env": { "APP_STAGE": "production", - "NRN_PRESET": "v1-ssr-mst-aptd-gcms-lcz-sty", + "NRN_PRESET": "v1-hyb-mst-aptd-gcms-lcz-sty", "CUSTOMER_REF": "customer2", "GRAPHQL_API_ENDPOINT": "https://api-euwest.graphcms.com/v1/ck73ixhlv09yt01dv2ga1bkbp/master", "GRAPHQL_API_KEY": "@nrn-graphql-api-key", "LOCIZE_PROJECT_ID": "@nrn-locize-project-id", - "LOCIZE_API_KEY": "@nrn-locize-api-key", + "LOCIZE_API_KEY": "The Locize API Key shouldn't be used in production (see https://github.com/locize/i18next-locize-backend#backend-options) because it's related to development-only features, and it's sensitive.", "AMPLITUDE_API_KEY": "@nrn-amplitude-api-key-production", "SENTRY_DSN": "@nrn-sentry-dsn" } diff --git a/now.customer2.staging.json b/now.customer2.staging.json index d5940d475..dbe16a6ad 100644 --- a/now.customer2.staging.json +++ b/now.customer2.staging.json @@ -1,17 +1,17 @@ { "version": 2, - "name": "nrn-v1-ssr-mst-aptd-gcms-lcz-sty-c2", + "name": "nrn-v1-hyb-mst-aptd-gcms-lcz-sty-c2", "scope": "team_qnVfSEVc2WwmOE1OYhZr4VST", "env": {}, "build": { "env": { "APP_STAGE": "staging", - "NRN_PRESET": "v1-ssr-mst-aptd-gcms-lcz-sty", + "NRN_PRESET": "v1-hyb-mst-aptd-gcms-lcz-sty", "CUSTOMER_REF": "customer2", "GRAPHQL_API_ENDPOINT": "https://api-euwest.graphcms.com/v1/ck73ixhlv09yt01dv2ga1bkbp/master", "GRAPHQL_API_KEY": "@nrn-graphql-api-key", "LOCIZE_PROJECT_ID": "@nrn-locize-project-id", - "LOCIZE_API_KEY": "@nrn-locize-api-key", + "LOCIZE_API_KEY": "@nrn-locize-api-key-staging", "AMPLITUDE_API_KEY": "@nrn-amplitude-api-key-staging", "SENTRY_DSN": "@nrn-sentry-dsn" } diff --git a/package.json b/package.json index b160080eb..041a2afe6 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "start": "now dev --listen 8888", "build": "yarn test:once && next build", "next": "next start", - "svg": "npx svgr -d src/svg src/svg --ext tsx --template ./src/utils/svgTemplate.ts", + "next:bundle": "ANALYZE_BUNDLE=true yarn start", + "svg": "npx svgr -d src/svg src/svg --ext tsx --template src/utils/svg/svgTemplate.ts", "deploy": "yarn deploy:customer1", "deploy:all": "yarn deploy:customer1 && yarn deploy:customer2", "deploy:all:production": "yarn deploy:customer1:production && yarn deploy:customer2:production", @@ -50,25 +51,28 @@ }, "dependencies": { "@amplitude/react-amplitude": "1.0.0", - "@apollo/react-ssr": "3.1.4", + "@apollo/react-hooks": "3.1.5", + "@apollo/react-ssr": "3.1.5", "@emotion/core": "10.0.28", "@emotion/styled": "10.0.27", "@fortawesome/fontawesome-svg-core": "1.2.28", "@fortawesome/free-brands-svg-icons": "5.13.0", + "@fortawesome/free-regular-svg-icons": "5.13.0", "@fortawesome/free-solid-svg-icons": "5.13.0", "@fortawesome/react-fontawesome": "0.1.9", - "@sentry/browser": "5.15.4", - "@sentry/node": "5.15.4", + "@sentry/browser": "5.15.5", + "@sentry/node": "5.15.5", + "@types/lodash.filter": "4.6.6", "@unly/universal-language-detector": "2.0.3", "@unly/utils": "1.0.3", "@unly/utils-simple-logger": "1.4.0", - "amplitude-js": "5.10.0", - "animate.css": "3.7.2", - "apollo-boost": "0.4.7", - "apollo-cache-inmemory": "1.6.5", - "apollo-client": "2.6.8", - "apollo-link-http": "1.5.16", - "bootstrap": "4.4.1", + "amplitude-js": "6.2.0", + "animate.css": "4.1.0", + "apollo-boost": "0.4.9", + "apollo-cache-inmemory": "1.6.6", + "apollo-client": "2.6.10", + "apollo-link-http": "1.5.17", + "bootstrap": "4.5.0", "classnames": "2.2.6", "cookies": "0.8.0", "css-to-react-native": "3.0.0", @@ -76,33 +80,37 @@ "emotion-theming": "10.0.27", "graphql": "15.0.0", "graphql-tag": "2.10.3", - "i18next": "19.3.4", - "i18next-locize-backend": "3.1.1", - "i18next-node-locize-backend": "3.1.0", - "isomorphic-unfetch": "3.0.0", + "i18next": "19.4.4", + "i18next-locize-backend": "4.0.8", "js-cookie": "2.2.1", "json-stringify-safe": "5.0.1", "locize-editor": "3.0.0", - "locize-node-lastused": "2.0.0", + "locize-lastused": "3.0.4", "lodash.clonedeep": "4.5.0", + "lodash.filter": "4.6.0", "lodash.find": "4.6.0", "lodash.get": "4.4.2", "lodash.includes": "4.3.0", "lodash.isarray": "4.0.0", "lodash.isempty": "4.4.0", "lodash.isplainobject": "4.0.6", + "lodash.kebabcase": "4.1.1", "lodash.map": "4.6.0", "lodash.remove": "4.7.0", + "lodash.size": "4.2.0", + "lodash.some": "4.6.0", + "lodash.startswith": "4.2.1", "lodash.xorby": "4.7.0", - "next": "9.3.4", + "next": "9.4.4", "next-cookies": "2.0.3", - "next-with-apollo": "5.0.0", + "next-with-apollo": "5.0.1", "prop-types": "15.7.2", "rc-tooltip": "4.0.3", "react": "16.13.1", - "react-apollo": "3.1.4", + "react-apollo": "3.1.5", + "react-code-blocks": "0.0.7", "react-dom": "16.13.1", - "react-i18next": "11.3.4", + "react-i18next": "11.4.0", "react-style-proptype": "3.2.2", "reactstrap": "8.4.1", "recompose": "0.30.0", @@ -110,12 +118,13 @@ "winston": "3.2.1" }, "devDependencies": { - "@now/node": "1.5.0", - "@svgr/cli": "5.3.0", - "@types/amplitude-js": "5.8.0", + "@next/bundle-analyzer": "9.4.1", + "@now/node": "1.6.1", + "@svgr/cli": "5.4.0", + "@types/amplitude-js": "5.11.0", "@types/cookies": "0.7.4", - "@types/jest": "25.1.5", - "@types/js-cookie": "2.2.5", + "@types/jest": "25.2.2", + "@types/js-cookie": "2.2.6", "@types/lodash.clonedeep": "4.5.6", "@types/lodash.find": "4.6.6", "@types/lodash.get": "4.4.6", @@ -123,33 +132,39 @@ "@types/lodash.isarray": "4.0.6", "@types/lodash.isempty": "4.4.6", "@types/lodash.isplainobject": "4.0.6", + "@types/lodash.kebabcase": "4.1.6", "@types/lodash.map": "4.6.13", "@types/lodash.remove": "4.7.6", + "@types/lodash.size": "4.2.6", + "@types/lodash.some": "4.6.6", + "@types/lodash.startswith": "4.2.6", "@types/lodash.xorby": "4.7.6", - "@types/react": "16.9.32", - "@types/webfontloader": "1.6.29", - "@types/webpack-env": "1.15.1", - "@typescript-eslint/eslint-plugin": "2.26.0", - "@typescript-eslint/parser": "2.26.0", - "@zeit/next-css": "1.0.1", + "@types/popper.js": "1.11.0", + "@types/react": "16.9.35", + "@types/reactstrap": "8.4.2", + "@types/webfontloader": "1.6.30", + "@types/webpack-env": "1.15.2", + "@typescript-eslint/eslint-plugin": "2.33.0", + "@typescript-eslint/parser": "2.33.0", + "@welldone-software/why-did-you-render": "4.2.2", "@zeit/next-source-maps": "0.0.4-canary.1", - "concurrently": "5.1.0", + "concurrently": "5.2.0", "cross-env": "7.0.2", - "cypress": "4.3.0", - "del-cli": "3.0.0", - "eslint": "6.8.0", - "eslint-plugin-jest": "23.8.2", + "cypress": "4.5.0", + "del-cli": "3.0.1", + "eslint": "7.0.0", + "eslint-plugin-jest": "23.13.1", "eslint-plugin-jsx-a11y": "6.2.3", - "eslint-plugin-react": "7.19.0", - "eslint-plugin-react-hooks": "3.0.0", + "eslint-plugin-react": "7.20.0", + "eslint-plugin-react-hooks": "4.0.2", "eslint-watch": "6.0.1", - "jest": "25.2.7", + "jest": "26.0.1", "jest-extended": "0.11.5", "node-mocks-http": "1.8.1", "now": "17.1.1", "react-test-renderer": "16.13.1", - "ts-jest": "25.3.0", - "typescript": "3.8.3", + "ts-jest": "26.0.0", + "typescript": "3.9.2", "version-bump-prompt": "6.0.3" } } diff --git a/public/static/CDN/detect-outdated-browser/outdated-browser-rework.min.js b/public/static/CDN/detect-outdated-browser/outdated-browser-rework.min.js index c4b7db4e7..b82bbbb79 100644 --- a/public/static/CDN/detect-outdated-browser/outdated-browser-rework.min.js +++ b/public/static/CDN/detect-outdated-browser/outdated-browser-rework.min.js @@ -1,4 +1,6 @@ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).outdatedBrowserRework=e()}}(function(){return function u(r,s,l){function n(i,e){if(!s[i]){if(!r[i]){var o="function"==typeof require&&require;if(!e&&o)return o(i,!0);if(d)return d(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var t=s[i]={exports:{}};r[i][0].call(t.exports,function(e){var o=r[i][1][e];return n(o||e)},t,t.exports,u,r,s,l)}return s[i].exports}for(var d="function"==typeof require&&require,e=0;e"+f.update.web+''+f.callToAction+"

",googlePlay:"

"+f.update.googlePlay+''+f.callToAction+"

",appStore:"

"+f.update[u]+"

"}[u],v=f.outOfDate,k()&&f.unsupported&&(v=f.unsupported),'
'+v+"
"+h+'

×

'),c=document.getElementById("buttonCloseUpdateBrowser"),w=document.getElementById("buttonUpdateBrowser"),i.style.backgroundColor=t,i.style.color=r,i.children[0].children[0].style.color=r,i.children[0].children[1].style.color=r,w&&(w.style.color=r,w.style.borderColor&&(w.style.borderColor=r),w.onmouseover=function(){this.style.color=t,this.style.backgroundColor=r},w.onmouseout=function(){this.style.color=r,this.style.backgroundColor=t}),c.style.color=r,c.onmousedown=function(){return!(i.style.display="none")}}},o=window.onload;"function"!=typeof window.onload?window.onload=e:window.onload=function(){o&&o(),e()}}},{"./extend":1,"./languages.json":3,"ua-parser-js":4}],3:[function(e,o,i){o.exports={br:{outOfDate:"O seu navegador está desatualizado!",update:{web:"Atualize o seu navegador para ter uma melhor experiência e visualização deste site. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#br",callToAction:"Atualize o seu navegador agora",close:"Fechar"},ca:{outOfDate:"El vostre navegador no està actualitzat!",update:{web:"Actualitzeu el vostre navegador per veure correctament aquest lloc web. ",googlePlay:"Instal·leu Chrome des de Google Play",appStore:"Actualitzeu iOS des de l'aplicació Configuració"},url:"https://browser-update.org/update-browser.html#es",callToAction:"Actualitzar el meu navegador ara",close:"Tancar"},cn:{outOfDate:"您的浏览器已过时",update:{web:"要正常浏览本网站请升级您的浏览器。",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#cn",callToAction:"现在升级",close:"关闭"},cz:{outOfDate:"Váš prohlížeč je zastaralý!",update:{web:"Pro správné zobrazení těchto stránek aktualizujte svůj prohlížeč. ",googlePlay:"Nainstalujte si Chrome z Google Play",appStore:"Aktualizujte si systém iOS"},url:"https://browser-update.org/update-browser.html#cz",callToAction:"Aktualizovat nyní svůj prohlížeč",close:"Zavřít"},da:{outOfDate:"Din browser er forældet!",update:{web:"Opdatér din browser for at få vist denne hjemmeside korrekt. ",googlePlay:"Installér venligst Chrome fra Google Play",appStore:"Opdatér venligst iOS"},url:"https://browser-update.org/update-browser.html#da",callToAction:"Opdatér din browser nu",close:"Luk"},de:{outOfDate:"Ihr Browser ist veraltet!",update:{web:"Bitte aktualisieren Sie Ihren Browser, um diese Website korrekt darzustellen. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#de",callToAction:"Den Browser jetzt aktualisieren ",close:"Schließen"},ee:{outOfDate:"Sinu veebilehitseja on vananenud!",update:{web:"Palun uuenda oma veebilehitsejat, et näha lehekülge korrektselt. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#ee",callToAction:"Uuenda oma veebilehitsejat kohe",close:"Sulge"},en:{outOfDate:"Your browser is out-of-date!",update:{web:"Update your browser to view this website correctly. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#",callToAction:"Update my browser now",close:"Close"},es:{outOfDate:"¡Tu navegador está anticuado!",update:{web:"Actualiza tu navegador para ver esta página correctamente. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#es",callToAction:"Actualizar mi navegador ahora",close:"Cerrar"},fa:{rightToLeft:!0,outOfDate:"مرورگر شما منسوخ شده است!",update:{web:"جهت مشاهده صحیح این وبسایت، مرورگرتان را بروز رسانی نمایید. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#",callToAction:"همین حالا مرورگرم را بروز کن",close:"Close"},fi:{outOfDate:"Selaimesi on vanhentunut!",update:{web:"Lataa ajantasainen selain nähdäksesi tämän sivun oikein. ",googlePlay:"Asenna uusin Chrome Google Play -kaupasta",appStore:"Päivitä iOS puhelimesi asetuksista"},url:"https://browser-update.org/update-browser.html#fi",callToAction:"Päivitä selaimeni nyt ",close:"Sulje"},fr:{outOfDate:"Votre navigateur n'est plus compatible !",update:{web:"Mettez à jour votre navigateur pour afficher correctement ce site Web. ",googlePlay:"Merci d'installer Chrome depuis le Google Play Store",appStore:"Merci de mettre à jour iOS depuis l'application Réglages"},url:"https://browser-update.org/update-browser.html#fr",callToAction:"Mettre à jour maintenant ",close:"Fermer"},hu:{outOfDate:"A böngészője elavult!",update:{web:"Firssítse vagy cserélje le a böngészőjét. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#hu",callToAction:"A böngészőm frissítése ",close:"Close"},id:{outOfDate:"Browser yang Anda gunakan sudah ketinggalan zaman!",update:{web:"Perbaharuilah browser Anda agar bisa menjelajahi website ini dengan nyaman. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#",callToAction:"Perbaharui browser sekarang ",close:"Close"},it:{outOfDate:"Il tuo browser non è aggiornato!",update:{web:"Aggiornalo per vedere questo sito correttamente. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#it",callToAction:"Aggiorna ora",close:"Chiudi"},lt:{outOfDate:"Jūsų naršyklės versija yra pasenusi!",update:{web:"Atnaujinkite savo naršyklę, kad galėtumėte peržiūrėti šią svetainę tinkamai. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#",callToAction:"Atnaujinti naršyklę ",close:"Close"},nl:{outOfDate:"Je gebruikt een oude browser!",update:{web:"Update je browser om deze website correct te bekijken. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#nl",callToAction:"Update mijn browser nu ",close:"Sluiten"},pl:{outOfDate:"Twoja przeglądarka jest przestarzała!",update:{web:"Zaktualizuj swoją przeglądarkę, aby poprawnie wyświetlić tę stronę. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#pl",callToAction:"Zaktualizuj przeglądarkę już teraz",close:"Close"},pt:{outOfDate:"O seu browser está desatualizado!",update:{web:"Atualize o seu browser para ter uma melhor experiência e visualização deste site. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#pt",callToAction:"Atualize o seu browser agora",close:"Fechar"},ro:{outOfDate:"Browserul este învechit!",update:{web:"Actualizați browserul pentru a vizualiza corect acest site. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#",callToAction:"Actualizați browserul acum!",close:"Close"},ru:{outOfDate:"Ваш браузер устарел!",update:{web:"Обновите ваш браузер для правильного отображения этого сайта. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#ru",callToAction:"Обновить мой браузер ",close:"Закрыть"},si:{outOfDate:"Vaš brskalnik je zastarel!",update:{web:"Za pravilen prikaz spletne strani posodobite vaš brskalnik. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#si",callToAction:"Posodobi brskalnik ",close:"Zapri"},sv:{outOfDate:"Din webbläsare stödjs ej längre!",update:{web:"Uppdatera din webbläsare för att webbplatsen ska visas korrekt. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#",callToAction:"Uppdatera min webbläsare nu",close:"Stäng"},ua:{outOfDate:"Ваш браузер застарів!",update:{web:"Оновіть ваш браузер для правильного відображення цього сайта. ",googlePlay:"Please install Chrome from Google Play",appStore:"Please update iOS from the Settings App"},url:"https://browser-update.org/update-browser.html#ua",callToAction:"Оновити мій браузер ",close:"Закрити"}}},{}],4:[function(e,k,P){!function(t,p){"use strict";var c="function",e="undefined",o="model",i="name",a="type",r="vendor",s="version",l="architecture",n="console",d="mobile",u="tablet",w="smarttv",m="wearable",g={extend:function(e,o){var i={};for(var a in e)o[a]&&o[a].length%2==0?i[a]=o[a].concat(e[a]):i[a]=e[a];return i},has:function(e,o){return"string"==typeof e&&-1!==o.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()},major:function(e){return"string"==typeof e?e.replace(/[^\d\.]/g,"").split(".")[0]:p},trim:function(e){return e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")}},b={rgx:function(e,o){for(var i,a,t,r,s,l,n=0;n = (props): JSX.Element => { + return ( + + {` + This component is a template meant to be duplicated to quickly get started with new React components. + + Feel free to adapt it at your convenience + `} + + ); +}; + +export default ComponentTemplate; diff --git a/src/components/ErrorDebug.tsx b/src/components/ErrorDebug.tsx deleted file mode 100644 index 0fba26507..000000000 --- a/src/components/ErrorDebug.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import * as Sentry from '@sentry/node'; -import { isBrowser } from '@unly/utils'; -import { createLogger } from '@unly/utils-simple-logger'; -import * as React from 'react'; -import { Button } from 'reactstrap'; - -const logger = createLogger({ - label: 'pages/error', -}); - -/** - * We don't want to log errors when running in the browser in production environment. - * In any other circumstances, we should log the debug message to help debug the issue. (dev, staging, and from prod server) - * - * @return {boolean} - */ -export const shouldLog = (): boolean => { - if (process.env.APP_STAGE === 'production') { - return !isBrowser(); - } else { - return true; - } -}; - -const ErrorDebug = (props: Props): JSX.Element => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const { error, context }: Props = props; - const { message, stack } = error; - - let stringifiedContext; - try { - stringifiedContext = JSON.stringify(context, null, 2); - } catch (e) { - stringifiedContext = null; - } - - Sentry.configureScope((scope) => { - scope.setExtra('context', stringifiedContext); - }); - const errorEventId = Sentry.captureException(error); - - if (shouldLog()) { - logger.error(message); - logger.error(stack, 'stack'); - logger.error(stringifiedContext, 'context'); - } - - // @ts-ignore - return ( - <> -
- Service unavailable. -
- -
-

- -

-

- -

-
- - { - process.env.APP_STAGE !== 'production' && ( -
-            Message:
- {message} -
- Context:
- {stringifiedContext} -
- Stack:
- {stack} -
-
- ) - } - - ); -}; - -type Props = { - error?: Error; - context?: any; // eslint-disable-line @typescript-eslint/no-explicit-any - t?: Function; -} - -export default ErrorDebug; diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx deleted file mode 100644 index 910683606..000000000 --- a/src/components/Footer.tsx +++ /dev/null @@ -1,181 +0,0 @@ -/** @jsx jsx */ -import { css, jsx } from '@emotion/core'; -import * as Sentry from '@sentry/node'; -import { isBrowser } from '@unly/utils'; -import Link from 'next/link'; -import React from 'react'; -import { useTranslation, withTranslation } from 'react-i18next'; -import { Button, Col, Row } from 'reactstrap'; -import { compose } from 'recompose'; - -import EnglishFlag from '../components/svg/EnglishFlag'; -import FrenchFlag from '../components/svg/FrenchFlag'; -import { Customer } from '../types/data/Customer'; -import { Theme } from '../types/data/Theme'; -import { LANG_EN, LANG_FR } from '../utils/i18n'; -import { SIZE_XS } from '../utils/logo'; -import { getValue, getValueFallback } from '../utils/record'; -import UniversalCookiesManager from '../utils/UniversalCookiesManager'; -import GraphCMSAsset from './GraphCMSAsset'; -import Logo from './Logo'; -import Tooltip from './Tooltip'; - -const fileLabel = 'components/Footer'; - -const Footer: React.FunctionComponent = (props: Props) => { - const { - customer, - theme, - lang, - } = props; - const { t } = useTranslation(); - const logoSizesMultipliers = [ - { - size: SIZE_XS, - multiplier: 1, // We wanna keep the logos in the footer big and visible even on small devices, we've got enough space - }, - ]; - - Sentry.addBreadcrumb({ // See https://docs.sentry.io/enriching-error-data/breadcrumbs - category: fileLabel, - message: `Rendering footer (${isBrowser() ? 'browser' : 'server'})`, - level: Sentry.Severity.Debug, - }); - - // Resolve values, handle multiple fallback levels - const copyrightOwner = getValueFallback([ - { record: customer, key: 'label' }, - ]); - const currentYear = (new Date()).getFullYear(); - return ( - - - ); -}; - -type Props = { - customer: Customer; - theme: Theme; - t: Function; - lang: string; -} - -export default compose( - withTranslation(['common']), -)(Footer); diff --git a/src/components/Head.tsx b/src/components/Head.tsx deleted file mode 100644 index db268be3c..000000000 --- a/src/components/Head.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { isBrowser } from '@unly/utils'; -import NextHead from 'next/head'; -import React from 'react'; - -import { NRN_DEFAULT_SERVICE_LABEL } from '../constants'; - -const defaultTitle = NRN_DEFAULT_SERVICE_LABEL; -const defaultDescription = ''; // TODO -const defaultOGURL = ''; // TODO -const defaultOGImage = ''; // TODO -const defaultFavicon = 'https://storage.googleapis.com/the-funding-place/assets/images/default_favicon.ico'; - -/** - * Custom Head component - * - * https://github.com/zeit/next.js#populating-head - * - * @param title - * @param description - * @param ogImage - * @param url - * @param favicon - * @param lang - * @constructor - */ -const Head: React.FunctionComponent = ( - { - title, - description, - ogImage, - url, - favicon, - additionalContent, - }, -): JSX.Element => { - if (isBrowser()) { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const WebFontLoader = require('webfontloader'); - - // Load our fonts. Until they're loaded, their fallback fonts will be used - // This fixed an issue when loading fonts from external sources that don't show the text until the font is loaded - // With this, instead of not showing any text, it'll show the text using its fallback font, and then show the font once loaded - // Note that we must load the font file synchronously to avoid a FOUT effect (see below) - // XXX See https://www.npmjs.com/package/webfontloader#custom - WebFontLoader.load({ - custom: { - families: ['neuzeit-grotesk'], - }, - }); - } - - return ( - - - {title || defaultTitle} - - - - - - - - - - - - - - - - - - - - {/* Detect outdated browser and display a popup about how to upgrade to a more recent browser/version */} - {/* XXX See public/static/CDN/README.md */} -