diff --git a/.circleci/config.yml b/.circleci/config.yml
index 285a9daca3..90e9879f0b 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -12,8 +12,6 @@ version: 2.1
# Orbs - preconfigured environments for running specific jobs
######################################################################################################
-# node: circleci/node@4.1.0
-# cypress: cypress-io/cypress@1
orbs:
# for use with cimg image, to install web browsers
browser-tools: circleci/browser-tools@1.1.3
@@ -24,9 +22,21 @@ orbs:
# Aliases - code snippets that can be included inline in any other markup
######################################################################################################
aliases:
- # use a base image running node v16 with chrome/firefox browsers preinstalled
+ # use a base image running node v18 with chrome/firefox browsers preinstalled
+ # This can be applied to any job via `docker: *docker` syntax
- &docker
- - image: cimg/node:16.13.1-browsers
+ - image: cimg/node:18.13.0-browsers
+
+ # Use base image with support for node version parameter and matrix
+ # This can be applied to any job via `<<: *docker_matrix` syntax
+ - docker_matrix: &docker_matrix
+ parameters:
+ node-version:
+ type: string
+ default: 18.13.0-browsers
+ docker:
+ - image: cimg/node:<< parameters.node-version >>
+
# These can also be created as commands, but slighly tidier to just use inline
# restore/install/save can all be done with a single circle-ci orb, but less flexible and breaks intellisense
- &restore_yarn_cache
@@ -215,7 +225,7 @@ jobs:
rm package.json
npm config set package-lock false
npm i @types/node @commitlint/types @commitlint/config-conventional --force
- npx commitlint --from=$(git merge-base remotes/origin/${CIRCLE_BRANCH} master) --verbose
+ npx @commitlint/cli@17.4.2 --from=$(git merge-base remotes/origin/${CIRCLE_BRANCH} master) --verbose
lint:
docker: *docker
steps:
@@ -270,13 +280,16 @@ jobs:
name: Install dependencies
command: yarn workspaces focus one-army-community-platform
- run:
- command: yarn build:components && yarn run test:unit
+ # NOTE - run-in-band to try reduce memory leaks (https://github.com/facebook/jest/issues/7874)
+ command: yarn build:components && yarn run test:unit:ci
build:
- docker: *docker
+ <<: *docker_matrix
environment:
GENERATE_SOURCEMAP: 'false'
SKIP_PREFLIGHT_CHECK: 'true'
- # `medium` is the max allowed size for free builds (helps with out-of-memory issues) - https://circleci.com/docs/2.0/configuration-reference/#resourceclass
+ NODE_OPTIONS: '--max-old-space-size=5632'
+ # If experiencing out-of-memory issues can increase resource_class below and max space size above
+ # https://circleci.com/docs/2.0/configuration-reference/#resourceclass
resource_class: medium+
steps:
# whilst checkout-install could be persisted from previous step, that is less efficient than just using caching
@@ -291,12 +304,11 @@ jobs:
name: Set branch environment
command: |
echo 'export REACT_APP_BRANCH=${CIRCLE_BRANCH}' >> $BASH_ENV
- echo 'export NODE_OPTIONS=--max-old-space-size=4096' >> $BASH_ENV
echo 'export REACT_APP_PROJECT_VERSION=${CIRCLE_SHA1}' >> $BASH_ENV
- run:
name: Check environment variables
command: |
- echo REACT_APP_BRANCH=$REACT_APP_BRANCH NODE_OPTIONS=$NODE_OPTIONS
+ echo REACT_APP_BRANCH=$REACT_APP_BRANCH
echo $REACT_APP_PROJECT_VERSION
- run:
command: yarn build
@@ -306,7 +318,7 @@ jobs:
- build
storybook:
docker: *docker
- resource_class: medium+
+ resource_class: medium
steps:
- setup_repo
- attach_workspace:
@@ -428,6 +440,17 @@ workflows:
- 'Lint code'
name: Build Application
context: build-context
+ - build:
+ requires:
+ - 'Lint code'
+ # Main build/deploy runs on LTS node, however still check compatibility for local dev work on other versions
+ name: Build Application (Node << matrix.node-version >>)
+ context: build-context
+ matrix:
+ parameters:
+ node-version:
+ - '16.13.1-browsers'
+ - 'current-browsers' # latest version supported https://circleci.com/developer/images/image/cimg/node
- test_unit:
name: 'Unit tests'
requires:
diff --git a/.cspell.json b/.cspell.json
index f2223ade77..170186d72f 100644
--- a/.cspell.json
+++ b/.cspell.json
@@ -31,6 +31,7 @@
"microservices",
"mockup",
"mockups",
+ "nodenv",
"onearmy",
"onearmyworld",
"phonebloks",
diff --git a/.env-cmdrc.js b/.env-cmdrc.js
new file mode 100644
index 0000000000..93f01c3355
--- /dev/null
+++ b/.env-cmdrc.js
@@ -0,0 +1,46 @@
+// Run a pre-flight check that developer environment setup in compatible way
+const { envCheck } = require('./scripts/envCheck')
+if (!process.env.CI) {
+ envCheck()
+}
+
+// Specific settings to use when running anything that requires a webpack compiler
+// Enabled when npm command specifies `env-cmd -e webpack`
+let webpack = {
+ NODE_OPTIONS: getNodeOptions(),
+}
+
+// Specific env to use with react-scripts / create-react-app
+// Enabled when npm command specifies `env-cmd -e cra`
+let cra = {
+ ...webpack,
+ FAST_REFRESH: false,
+}
+
+exports.cra = cra
+exports.webpack = webpack
+
+/** Determine what node_options to provide depending on context */
+function getNodeOptions() {
+ // Depending on node version use different environment variables to fix
+ // specific build or run issues
+ const NODE_VERSION = process.versions.node.split('.')[0]
+
+ let NODE_OPTIONS = process.env.NODE_OPTIONS || ''
+
+ // fix out-of-memory issues - default to 4GB but allow override from CI
+ // NOTE - would like to auto-calculate but does not support CI (https://github.com/nodejs/node/issues/27170)
+ if (!NODE_OPTIONS.includes('--max-old-space-size')) {
+ NODE_OPTIONS += ` --max-old-space-size=4096`
+ }
+ if (NODE_VERSION > '17') {
+ // fix https://github.com/facebook/create-react-app/issues/11708
+ // https://github.com/facebook/create-react-app/issues/12431
+ NODE_OPTIONS += ' --openssl-legacy-provider --no-experimental-fetch'
+ }
+
+ if (process.env.CI) {
+ console.log('NODE_OPTIONS', NODE_OPTIONS, '\n')
+ }
+ return NODE_OPTIONS.trim()
+}
diff --git a/.eslintrc.json b/.eslintrc.json
index 1c6f1e53b8..b3a218bd88 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -5,7 +5,8 @@
"@typescript-eslint",
"prettier",
"unicorn",
- "sort-class-members"
+ "sort-class-members",
+ "jest"
],
"extends": [
"plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react
@@ -55,6 +56,7 @@
"prefer": "type-imports"
}
],
+ "jest/no-focused-tests": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/interface-name-prefix": "off",
diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml
index 59ffdb8a31..8bcf17443b 100644
--- a/.github/workflows/pr-preview.yml
+++ b/.github/workflows/pr-preview.yml
@@ -27,9 +27,9 @@ jobs:
with:
# pull the repo from the pull request source, not the default local repo
ref: ${{ github.event.pull_request.head.sha }}
- - uses: actions/setup-node@v2
+ - uses: actions/setup-node@v3
with:
- node-version: '16'
+ node-version: '18'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
diff --git a/.github/workflows/reset-staging-site.yml b/.github/workflows/reset-staging-site.yml
index d09bd99cdc..86abdb2a59 100644
--- a/.github/workflows/reset-staging-site.yml
+++ b/.github/workflows/reset-staging-site.yml
@@ -4,7 +4,7 @@ name: Reset Staging Site
on:
# Run weekly on a Sunday at 02:00
schedule:
- - cron: "0 0 * * SUN"
+ - cron: '0 0 * * SUN'
# Allow the script to be triggered directly from GitHub
workflow_dispatch:
jobs:
@@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-node@v3
with:
- node-version: 16
+ node-version: 18
- name: Set up Cloud SDK
uses:
google-github-actions/setup-gcloud@master
diff --git a/.gitignore b/.gitignore
index 1a772c4d74..7ace0c4845 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,7 +32,6 @@ yarn-error.log*
# IntelliJ
/.idea
functions/firebase-debug.log
-.env-*
# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
.yarn/*
diff --git a/.gitpod.yml b/.gitpod.yml
index 205317ad7f..73dcde1c6a 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -1,4 +1,4 @@
-image: node:16
+image: node:18
tasks:
- init: yarn install && yarn run build
command: yarn run start
@@ -10,4 +10,4 @@ ports:
github:
prebuilds:
- branches: true
\ No newline at end of file
+ branches: true
diff --git a/.node-version b/.node-version
index 6e9d5a1ef2..ecb0f8a99c 100644
--- a/.node-version
+++ b/.node-version
@@ -1 +1 @@
-16.13.1
\ No newline at end of file
+18.13.0
\ No newline at end of file
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000000..25bf17fc5a
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+18
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f0a80bac40..391b406298 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -45,7 +45,7 @@ You can find useful links to learn more about these technologies [in the resourc
**Prerequisites**
-- [Node.js v16](https://nodejs.org/en/download/)
+- [Node.js v18](https://nodejs.org/en/download/)
- [Yarn v3](https://yarnpkg.com/getting-started/install)
With the above tools available, you are ready:
diff --git a/commitlint.config.ts b/commitlint.config.ts
index 79a92e3ac4..feacc159bb 100644
--- a/commitlint.config.ts
+++ b/commitlint.config.ts
@@ -1,7 +1,7 @@
import type { UserConfig } from '@commitlint/types'
import path from 'path'
-const Configuration: UserConfig = {
+export const Configuration: UserConfig = {
extends: ['@commitlint/config-conventional'],
/** Add optional custom formatter */
formatter: path.resolve(__dirname, 'commitlint.format.ts'),
diff --git a/commitlint.format.ts b/commitlint.format.ts
index 537d361e13..7dce4ef2d0 100644
--- a/commitlint.format.ts
+++ b/commitlint.format.ts
@@ -1,7 +1,7 @@
import type { Formatter, FormattableReport } from '@commitlint/types'
// Custom formatter for commitlint message
-const formatter: Formatter = function (report, options) {
+export const formatter: Formatter = function (report, options) {
const { results, valid } = report as IFormatReport
if (results && !valid) {
console.log('\nCommit needs to be formatted as conventional commit')
diff --git a/config/.gitignore b/config/.gitignore
deleted file mode 100644
index 94a2dd146a..0000000000
--- a/config/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.json
\ No newline at end of file
diff --git a/craco.config.ts b/craco.config.ts
new file mode 100644
index 0000000000..3b02490ae5
--- /dev/null
+++ b/craco.config.ts
@@ -0,0 +1,68 @@
+import type { WebpackConfigOverride } from '@craco/types'
+import { DefinePlugin, ProvidePlugin } from 'webpack'
+import type { RuleSetRule } from 'webpack'
+
+/**
+ * Craco is used to provide config overrides to the default webpack config that is called
+ * from react-scripts.
+ */
+module.exports = {
+ webpack: {
+ configure: (webpackConfig: WebpackConfigOverride['webpackConfig']) => {
+ // Add polyfills for node (mostly imports for pino-logflare)
+ // https://github.com/facebook/create-react-app/issues/11756
+ // https://stackoverflow.com/questions/68707553/uncaught-referenceerror-buffer-is-not-defined
+ webpackConfig.resolve!.fallback = {
+ stream: require.resolve('stream-browserify'),
+ buffer: require.resolve('buffer'),
+ }
+ webpackConfig.module!.rules = hackUpdateRulesToSupportCJS(
+ webpackConfig.module!.rules as RuleSetRule[],
+ )
+ webpackConfig.plugins = [
+ ...(webpackConfig.plugins as any[]),
+ // Fix calls to process (pino-logflare and cypress calling db.ts outside of cra)
+ // NOTE - react creates 'process.env' variable but does not assign anything to 'process'
+ // https://github.com/facebook/create-react-app/issues/11951
+ new DefinePlugin({
+ process: {},
+ }),
+ new ProvidePlugin({
+ Buffer: ['buffer', 'Buffer'],
+ }),
+ ]
+ // Fix sourcemap warning
+ // https://github.com/facebook/create-react-app/discussions/11767
+ webpackConfig.ignoreWarnings = [
+ function ignoreSourcemapsloaderWarnings(warning) {
+ return (
+ warning.module &&
+ (warning.module as any).resource.includes('node_modules') &&
+ warning.details &&
+ warning.details.includes('source-map-loader')
+ )
+ },
+ ]
+ return webpackConfig
+ },
+ },
+}
+
+/**
+ * Prepend a custom rule to support CJS files
+ *
+ * NOTE - should be resolved in future CRA release pending merge of
+ * https://github.com/facebook/create-react-app/pull/12021
+ */
+const hackUpdateRulesToSupportCJS = (rules: RuleSetRule[]) => {
+ return rules.map((rule) => {
+ if (rule.oneOf instanceof Array) {
+ rule.oneOf[rule.oneOf.length - 1].exclude = [
+ /\.(js|mjs|jsx|cjs|ts|tsx)$/,
+ /\.html$/,
+ /\.json$/,
+ ]
+ }
+ return rule
+ })
+}
diff --git a/functions/package.json b/functions/package.json
index 0bb3a4b55c..e94a55b57e 100644
--- a/functions/package.json
+++ b/functions/package.json
@@ -1,9 +1,9 @@
{
"name": "functions",
"version": "1.0.0",
- "__NOTE__:": "avoid hoisting for webpack and other conflicts (should test, might be ok now)",
- "resolutions": {
- "webpack": "^4.46.0"
+ "__NOTE__:": "avoid hoisting for webpack and other conflicts",
+ "installConfig": {
+ "hoistingLimits": "workspaces"
},
"scripts": {
"start": "ts-node scripts/start.ts",
@@ -27,9 +27,9 @@
"cors": "^2.8.5",
"dateformat": "^3.0.3",
"express": "^4.17.1",
- "firebase-admin": "11.2.0",
- "firebase-functions": "3.24.1",
- "firebase-tools": "11.15.0",
+ "firebase-admin": "11.4.1",
+ "firebase-functions": "4.1.1",
+ "firebase-tools": "11.18.0",
"fs-extra": "^9.0.1",
"google-auth-library": "^6.1.1",
"googleapis": "^61.0.0",
@@ -47,35 +47,29 @@
"@types/cors": "^2.8.8",
"@types/dateformat": "^3.0.1",
"@types/fs-extra": "^9.0.2",
- "@types/generate-json-webpack-plugin": "^0.3.3",
"@types/jest": "^29.2.0",
- "@types/node": "16",
+ "@types/node": "18",
"@types/request": "^2.48.5",
"@types/sharp": "^0.26.0",
"@types/uuid": "^9.0.0",
- "@types/webpack": "^4.41.29",
- "@types/webpack-node-externals": "^2.5.1",
+ "@types/webpack": "^5.28.0",
+ "@types/webpack-node-externals": "^2.5.3",
"awesome-typescript-loader": "^5.2.1",
- "clean-webpack-plugin": "^4.0.0-alpha.0",
"concurrently": "^6.2.0",
- "copy-webpack-plugin": "^6.4.1",
+ "copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"firebase-functions-test": "^3.0.0",
- "generate-json-webpack-plugin": "^1.0.0",
"jest": "29.2.2",
"ts-jest": "29.0.3",
"ts-node": "^10.0.0",
"tslint": "^6.1.3",
"typescript": "4.5.5",
- "webpack": "^4.46.0",
- "webpack-cli": "^4.7.0",
+ "webpack": "5.75.0",
+ "webpack-cli": "5.0.1",
"webpack-node-externals": "^3.0.0"
},
"engines": {
- "node": "16"
- },
- "installConfig": {
- "hoistingLimits": "workspaces"
+ "node": "18"
},
"private": true
}
diff --git a/functions/webpack.config.ts b/functions/webpack.config.ts
index a55e1ed89a..1c59090f7d 100644
--- a/functions/webpack.config.ts
+++ b/functions/webpack.config.ts
@@ -22,12 +22,8 @@ import path from 'path'
import nodeExternals from 'webpack-node-externals'
import webpack from 'webpack'
-import { CleanWebpackPlugin } from 'clean-webpack-plugin'
-import GenerateJsonPlugin from 'generate-json-webpack-plugin'
import CopyWebpackPlugin from 'copy-webpack-plugin'
-import PackageJson from './package.json'
-
const config: webpack.Configuration = {
target: 'node',
mode: 'production',
@@ -53,17 +49,19 @@ const config: webpack.Configuration = {
],
},
plugins: [
- // Copy package json for upload
- // new CopyPlugin({
- // patterns: [{ from: 'package.dist.json', to: 'package.json' }],
- // }),
- // clear dist folder
- new CleanWebpackPlugin(),
- // copy package.json
- new GenerateJsonPlugin('package.json', generatePackageJson(), null, 2),
- // copy src index.html to be served during seoRender function
new CopyWebpackPlugin({
patterns: [
+ // rewrite package.json to remove workspace refs
+ {
+ from: path.resolve(__dirname, 'package.json'),
+ to: 'package.json',
+ transform: (content) => {
+ const packageJson = JSON.parse(content.toString('utf8'))
+ const updatedPackageJson = rewritePackageJson(packageJson)
+ return Buffer.from(JSON.stringify(updatedPackageJson))
+ },
+ },
+ // copy src index.html to be served during seoRender function
{
from: path.resolve(__dirname, '../build/index.html'),
to: 'index.html',
@@ -75,6 +73,7 @@ const config: webpack.Configuration = {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
libraryTarget: 'commonjs',
+ clean: true,
},
optimization: {
minimize: false,
@@ -99,8 +98,7 @@ export default config
*
* Take the existing package.json and create a minimal copy without workspace entries
*/
-function generatePackageJson() {
- const json = PackageJson
+function rewritePackageJson(json: any) {
const workspacePrefixes = ['oa-', 'one-army', 'onearmy', '@oa', '@onearmy']
// TODO - could generate actual workspace list from `yarn workspace list --json`
// remove workspace dependencies
diff --git a/package.json b/package.json
index 9d9560b90d..2272fddeae 100644
--- a/package.json
+++ b/package.json
@@ -16,12 +16,12 @@
"scripts": {
"start": "concurrently --kill-others --names components,platform --prefix-colors blue,magenta \"yarn start:components\" \"yarn start:platform\"",
"start:components": "yarn workspace oa-components dev",
- "start:platform": "yarn build:shared && cross-env FAST_REFRESH=false yarn react-scripts start",
+ "start:platform": "yarn build:shared && env-cmd -e cra yarn craco start",
"start:emulated": "concurrently --kill-others --names functions,components,platform --prefix-colors yellow,blue,magenta \"yarn workspace functions start\" \"yarn start:components\" \"cross-env PORT=4000 yarn start:platform\"",
"start:emulated:docker": "concurrently --names functions,components,platform,emulators --prefix-colors yellow,blue,magenta,green --kill-others \"yarn workspace functions watch\" \"yarn workspace oa-components dev\" \"cross-env PORT=4000 yarn start:platform\" \"yarn workspace oa-emulators-docker start\"",
"start:emulated:docker:local": "concurrently --names functions,components,platform,emulators --prefix-colors yellow,blue,magenta,green --kill-others \"yarn workspace functions watch\" \"yarn workspace oa-components dev\" \"cross-env PORT=4000 yarn start:platform\" \"yarn workspace oa-emulators-docker start --repo=\"",
"build:components": "yarn workspace oa-components build",
- "build:cra": "react-scripts build",
+ "build:cra": "env-cmd -e cra craco build",
"build:post": "yarn workspace oa-scripts post-cra-build",
"build:inject-config": "yarn build:post",
"build:shared": "yarn workspace oa-shared build",
@@ -37,13 +37,15 @@
"format:style": "prettier --write '**/*.{md,json,js,tsx,ts}'",
"serve": "npx serve -s build",
"test": "yarn workspace oa-cypress start",
- "test:unit": "react-scripts test --env=jsdom",
+ "test:unit": "env-cmd -e cra craco test --env=jsdom",
+ "test:unit:ci": "env-cmd -e cra craco test --env=jsdom --runInBand --logHeapUsage",
"storybook": "yarn workspace oa-components start",
"docs": "yarn workspace oa-docs start",
"analyze": "npx cra-bundle-analyzer && npx open-cli build/report.html",
"install:clean": "yarn workspace oa-scripts install:clean",
"postinstall": "husky install",
- "commit": "git-cz"
+ "commit": "git-cz",
+ "healthcheck": "node scripts/healthcheck.js"
},
"config": {
"commitizen": {
@@ -62,16 +64,6 @@
"last 1 safari version"
]
},
- "resolutions": {
- "__NOTE__": "2021-05-28 storybook clash: https://github.com/storybookjs/storybook/issues/6505",
- "webpack": "4.44.2",
- "__NOTE2__": "2021-07-06 ram issues: https://github.com/facebook/create-react-app/issues/10154",
- "react-scripts/eslint-webpack-plugin": "2.4.1",
- "__NOTE3__": "2021-10-03 terser issues: https://github.com/facebook/create-react-app/issues/6334",
- "terser-webpack-plugin": "4.2.3",
- "__NOTE4__": "2022-04-28 webpack issue: https://github.com/gregberge/svgr/issues/665",
- "@svgr/webpack": "5.5.0"
- },
"dependencies": {
"@emotion/react": "^11.8.2",
"@emotion/styled": "^11.8.1",
@@ -124,7 +116,7 @@
"react-router-breadcrumbs-hoc": "^3.2.0",
"react-router-dom": "^5.2.0",
"react-router-hash-link": "^2.4.3",
- "react-scripts": "4.0.3",
+ "react-scripts": "5.0.1",
"react-slick": "^0.25.2",
"react-table": "^6.11.5",
"react-tooltip": "^4.2.20",
@@ -142,6 +134,8 @@
"@commitlint/cli": "^16.2.3",
"@commitlint/config-conventional": "^16.2.1",
"@commitlint/cz-commitlint": "^16.2.3",
+ "@craco/craco": "^7.0.0",
+ "@craco/types": "^7.0.0",
"@faker-js/faker": "^7.6.0",
"@semantic-release/changelog": "^6.0.1",
"@semantic-release/git": "^10.0.1",
@@ -150,8 +144,8 @@
"@testing-library/user-event": "^12.1.10",
"@types/browser-image-compression": "^1.0.9",
"@types/flux-standard-action": "1.1.0",
- "@types/jest": "^26.0.15",
- "@types/node": "16",
+ "@types/jest": "^27.4.3",
+ "@types/node": "18",
"@types/pubsub-js": "^1.5.18",
"@types/react": "^16.9.53",
"@types/react-dom": "^17.0.3",
@@ -170,15 +164,17 @@
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.26.0",
"all-contributors-cli": "^6.20.0",
+ "buffer": "^6.0.3",
"chai-subset": "^1.6.0",
"commitizen": "^4.2.4",
"concurrently": "^6.2.0",
"cra-bundle-analyzer": "^0.1.0",
- "cross-env": "^6.0.3",
"cspell": "^6.1.0",
+ "env-cmd": "^10.1.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.26.0",
+ "eslint-plugin-jest": "^27.2.1",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-sort-class-members": "^1.15.2",
"eslint-plugin-unicorn": "^36.0.0",
@@ -189,6 +185,7 @@
"prettier": "^2.6.1",
"react-dev-utils": "^11.0.4",
"start-server-and-test": "^1.11.0",
+ "stream-browserify": "^3.0.0",
"terser": "3.14.1",
"ts-loader": "^7.0.5",
"typescript": "4.5.5",
@@ -207,5 +204,9 @@
"workbox-strategies": "^6.1.5",
"workbox-streams": "^6.1.5"
},
+ "engines": {
+ "npm": "please-use-yarn",
+ "node": ">=16.10.0 <19.0.0"
+ },
"packageManager": "yarn@3.3.0"
}
diff --git a/packages/components/.storybook/main.js b/packages/components/.storybook/main.js
index f44162cc00..d8b63c6ae3 100644
--- a/packages/components/.storybook/main.js
+++ b/packages/components/.storybook/main.js
@@ -5,6 +5,9 @@ const paths = {
const webpack = require('webpack')
module.exports = {
+ core: {
+ builder: 'webpack5',
+ },
stories: ['../src/**/*.stories.tsx', '../src/stories.mdx'],
features: {
emotionAlias: false,
diff --git a/packages/components/package.json b/packages/components/package.json
index 9f9f026271..39f22af656 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -33,21 +33,23 @@
"react-router-dom": "^5.2.0",
"react-select": "^5.4.0",
"react-tooltip": "^4.2.21",
- "storybook": "^6.4.22",
+ "storybook": "^6.5.15",
"theme-ui": "^0.14.1",
"use-debounce": "^8.0.4",
- "webpack": "^5.72.0"
+ "webpack": "^5.75.0"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@react-theming/storybook-addon": "^1.1.5",
- "@storybook/addon-actions": "^6.4.22",
- "@storybook/addon-docs": "^6.4.22",
- "@storybook/addon-essentials": "^6.4.22",
- "@storybook/addon-links": "^6.4.22",
- "@storybook/addons": "^6.4.22",
- "@storybook/react": "^6.4.22",
- "@storybook/theming": "^6.4.22",
+ "@storybook/addon-actions": "^6.5.15",
+ "@storybook/addon-docs": "^6.5.15",
+ "@storybook/addon-essentials": "^6.5.15",
+ "@storybook/addon-links": "^6.5.15",
+ "@storybook/addons": "^6.5.15",
+ "@storybook/builder-webpack5": "^6.5.15",
+ "@storybook/manager-webpack5": "^6.5.15",
+ "@storybook/react": "^6.5.15",
+ "@storybook/theming": "^6.5.15",
"@types/mustache": "^4.1.2",
"@types/react-flag-icon-css": "^1.0.5",
"@types/react-portal": "^4.0.4",
diff --git a/packages/components/src/SiteFooter/SiteFooter.tsx b/packages/components/src/SiteFooter/SiteFooter.tsx
index f4edec51c6..6b0a6650ab 100644
--- a/packages/components/src/SiteFooter/SiteFooter.tsx
+++ b/packages/components/src/SiteFooter/SiteFooter.tsx
@@ -63,8 +63,15 @@ export const SiteFooter = () => {
- Running on our Platform software,{' '}
- help us build it
+ Please{' '}
+
+ sponsor the work
+ {' '}
+ or{' '}
+
+ help us build the software
+
+ .
)
diff --git a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx
index ec51e616ad..401057cda7 100644
--- a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx
+++ b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx
@@ -52,7 +52,12 @@ export const UsefulStatsButton = (props: IProps) => {
data-cy="vote-useful"
variant="subtle"
onClick={handleUsefulClick}
- sx={{ fontSize: 2, ml: 1, background: theme.colors.softyellow }}
+ sx={{
+ fontSize: 2,
+ ml: 1,
+ background: 'softyellow',
+ borderColor: 'softyellow',
+ }}
icon={hasUserVotedUseful ? 'star-active' : 'star'}
>
Useful {votedUsefulCount ? votedUsefulCount : ''}
@@ -66,7 +71,8 @@ export const UsefulStatsButton = (props: IProps) => {
data-tip={'Login to add your vote'}
sx={{
...theme.buttons.subtle,
- background: theme.colors.softyellow,
+ borderColor: 'softyellow',
+ background: 'softyellow',
display: 'inline-flex',
fontSize: 2,
paddingY: 2,
diff --git a/packages/cypress/cypress.config.ts b/packages/cypress/cypress.config.ts
new file mode 100644
index 0000000000..3d3fcb42da
--- /dev/null
+++ b/packages/cypress/cypress.config.ts
@@ -0,0 +1,34 @@
+import { defineConfig } from 'cypress'
+
+export default defineConfig({
+ defaultCommandTimeout: 15000,
+ watchForFileChanges: true,
+ chromeWebSecurity: false,
+ // "Disable video records to improve test execution as it's not worth",
+ video: false,
+ reporter: 'junit',
+ reporterOptions: {
+ mochaFile: 'coverage/out-[hash].xml',
+ },
+ downloadsFolder: 'src/downloads',
+ fixturesFolder: 'src/fixtures',
+ screenshotsFolder: 'src/screenshots',
+ videosFolder: 'src/videos',
+ projectId: '4s5zgo',
+ viewportWidth: 1000,
+ viewportHeight: 1000,
+ retries: {
+ runMode: 2,
+ openMode: 0,
+ },
+ e2e: {
+ // We've imported your old cypress plugins here.
+ // You may want to clean this up later by importing these.
+ setupNodeEvents(on, config) {
+ return require('./src/plugins/index.js')(on, config)
+ },
+ baseUrl: 'http://localhost:3456',
+ specPattern: 'src/integration/**/*.{js,jsx,ts,tsx}',
+ supportFile: 'src/support/index.ts',
+ },
+})
diff --git a/packages/cypress/cypress.json b/packages/cypress/cypress.json
deleted file mode 100644
index d8f827612d..0000000000
--- a/packages/cypress/cypress.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "baseUrl": "http://localhost:3456",
- "defaultCommandTimeout": 15000,
- "watchForFileChanges": true,
- "chromeWebSecurity": false,
- "video_comment": "Disable video records to improve test execution as it's not worth",
- "video": false,
- "reporter": "junit",
- "reporterOptions": {
- "mochaFile": "coverage/out-[hash].xml"
- },
- "downloadsFolder": "src/downloads",
- "fixturesFolder": "src/fixtures",
- "integrationFolder": "src/integration",
- "screenshotsFolder": "src/screenshots",
- "videosFolder": "src/videos",
- "supportFile": "src/support/index.ts",
- "pluginsFile": "src/plugins/index.js",
- "projectId": "4s5zgo",
- "viewportWidth": 1000,
- "viewportHeight": 1000,
- "retries": {
- "runMode": 2,
- "openMode": 0
- }
-}
diff --git a/packages/cypress/package.json b/packages/cypress/package.json
index 3fe7ee4ad9..8847ec85a5 100644
--- a/packages/cypress/package.json
+++ b/packages/cypress/package.json
@@ -7,19 +7,19 @@
"db:teardown": "TODO"
},
"dependencies": {
- "cypress": "9.4",
+ "cypress": "12.3.0",
"cypress-file-upload": "5.0.8",
"oa-shared": "workspace:*"
},
"devDependencies": {
- "@cypress/webpack-preprocessor": "^5.9.1",
+ "@cypress/webpack-preprocessor": "^5.16.1",
"@types/fs-extra": "^9.0.13",
"@types/wait-on": "^5.3.1",
"cross-env": "^7.0.3",
"dotenv": "^10.0.0",
"fs-extra": "^10.0.0",
"ts-node": "^10.2.1",
- "wait-on": "^6.0.0"
+ "wait-on": "^7.0.1"
},
"installConfig": {
"hoistingLimits": "workspaces"
diff --git a/packages/cypress/scripts/start.ts b/packages/cypress/scripts/start.ts
index 3e2b56c5e9..6a118ecb4d 100644
--- a/packages/cypress/scripts/start.ts
+++ b/packages/cypress/scripts/start.ts
@@ -1,5 +1,4 @@
#!/usr/bin/env ts-node
-console.log('start')
import PATHS from './paths'
import { spawnSync, spawn } from 'child_process'
@@ -88,14 +87,14 @@ async function startAppServer() {
const crossEnvArgs = `FORCE_COLOR=1 REACT_APP_SITE_VARIANT=test-ci`
// run local debug server for testing unless production build specified
- let serverCmd = `${CROSSENV_BIN} ${crossEnvArgs} BROWSER=none PORT=3456 npm run start`
+ let serverCmd = `${CROSSENV_BIN} ${crossEnvArgs} BROWSER=none PORT=3456 yarn start`
// for production will instead serve from production build folder
if (useProductionBuild) {
// create local build if not running on ci (which will have build already generated)
if (!isCi) {
// specify CI=false to prevent throwing lint warnings as errors
- spawnSync(`${CROSSENV_BIN} ${crossEnvArgs} CI=false npm run build`, {
+ spawnSync(`${CROSSENV_BIN} ${crossEnvArgs} CI=false yarn build`, {
shell: true,
stdio: ['inherit', 'inherit', 'pipe'],
})
@@ -131,7 +130,7 @@ async function startAppServer() {
// do not end function until server responsive on port 3456
// give up if not reponsive after 5 minutes (assume uncaught error somewhere)
const timeout = 5 * 60 * 1000
- await waitOn({ resources: ['http-get://localhost:3456'], timeout })
+ await waitOn({ resources: ['http-get://127.0.0.1:3456'], timeout })
}
function randomString(length) {
diff --git a/packages/cypress/src/integration/howto/read.spec.ts b/packages/cypress/src/integration/howto/read.spec.ts
index 7fabb572e6..c91644dd16 100644
--- a/packages/cypress/src/integration/howto/read.spec.ts
+++ b/packages/cypress/src/integration/howto/read.spec.ts
@@ -1,4 +1,4 @@
-import crypto from 'crypto'
+import { v4 as uuid } from 'uuid'
describe('[How To]', () => {
const SKIP_TIMEOUT = { timeout: 300 }
@@ -212,15 +212,15 @@ describe('[How To]', () => {
})
describe('[Fail to find a How-to]', () => {
- const uuid = crypto.randomBytes(16).toString('hex')
- const howToNotFoundUrl = `/how-to/this-how-to-does-not-exist-${uuid}`
+ const id = uuid()
+ const howToNotFoundUrl = `/how-to/this-how-to-does-not-exist-${id}`
it('[Redirects to search]', () => {
cy.visit(howToNotFoundUrl)
cy.location('pathname').should('eq', '/how-to')
cy.location('search').should(
'eq',
- `?search=this+how+to+does+not+exist+${uuid}&source=how-to-not-found`,
+ `?search=this+how+to+does+not+exist+${id}&source=how-to-not-found`,
)
})
})
diff --git a/packages/cypress/src/integration/sign-in.spec.ts b/packages/cypress/src/integration/sign-in.spec.ts
index 0f44dd1166..0cb469acea 100644
--- a/packages/cypress/src/integration/sign-in.spec.ts
+++ b/packages/cypress/src/integration/sign-in.spec.ts
@@ -24,6 +24,7 @@ describe('[Sign in]', () => {
})
describe('[Sign-in - authenticated user]', () => {
it('redirects to home page', () => {
+ cy.visit('/sign-in')
cy.login('howto_reader@test.com', 'test1234')
cy.wait(3000)
cy.visit('/sign-in').url().should('include', '/')
diff --git a/packages/cypress/src/support/db/endpoints.ts b/packages/cypress/src/support/db/endpoints.ts
index 3d63512575..4c09245e68 100644
--- a/packages/cypress/src/support/db/endpoints.ts
+++ b/packages/cypress/src/support/db/endpoints.ts
@@ -2,7 +2,8 @@ import { generateDBEndpoints } from 'oa-shared'
// React apps populate a process variable, however it might not always be accessible outside
// (e.g. cypress will instead use it's own env to populate a prefix)
-const e = process ? process.env : ({} as any)
+const process = globalThis.process || ({} as any)
+const e = process.env || ({} as any)
/**
* A prefix can be used to simplify large-scale schema changes or multisite hosting
diff --git a/packages/documentation/docs/Getting Started/setup.md b/packages/documentation/docs/Getting Started/setup.md
index f003a916a0..b5f586ee29 100644
--- a/packages/documentation/docs/Getting Started/setup.md
+++ b/packages/documentation/docs/Getting Started/setup.md
@@ -14,9 +14,13 @@ title: Local Setup
This will be used to run the local server. It included the `npm` package manager
:::tip
- The recommended version of node to use is **node 16** as this is what also runs in the production environment. If running a higher version and experiencing issues please file a bug report.
+ The recommended version of node to use is **node 18** as this is what also runs in the production environment. If running a higher version and experiencing issues please file a bug report.
- You can use tools like [fnm](https://github.com/Schniz/fnm) or [nvm](https://github.com/nvm-sh/nvm) to run multiple versions of node on the same machine
+ You can use tools like
+ [nodenv](https://github.com/nodenv/nodenv)
+ [fnm](https://github.com/Schniz/fnm)
+ [nvm](https://github.com/nvm-sh/nvm)
+ to run multiple versions of node on the same machine
:::
3. [Download and install Yarn](https://yarnpkg.com/getting-started/install) (v3)
diff --git a/packages/emulators-docker/Dockerfile b/packages/emulators-docker/Dockerfile
index b8fa60b9b4..98e2f9f744 100644
--- a/packages/emulators-docker/Dockerfile
+++ b/packages/emulators-docker/Dockerfile
@@ -1,12 +1,11 @@
-FROM node:16-alpine AS community-platform-builder
-################################################################################
-# Loosely based on
-# https://github.com/AndreySenov/firebase-tools-docker/blob/main/Dockerfile
-# https://github.com/goat-io/fluent/blob/master/src/Docker/Database/Firebase/Dockerfile
-################################################################################
+# Use bullseye instead of alpine due to v11.18 pubsub crash issue (could try revert post emulator 0.7.1)
+# https://github.com/firebase/firebase-tools/issues/5256
+# https://github.com/micrometer-metrics/micrometer/issues/2776)
+
+FROM node:18-bullseye-slim AS community-platform-builder
-ARG BUILD_DATE
ARG FIREBASE_TOOLS_VERSION
+ARG BUILD_DATE
ARG VCS_REF
LABEL org.label-schema.schema-version="1.0" \
org.label-schema.name="" \
@@ -16,15 +15,17 @@ LABEL org.label-schema.schema-version="1.0" \
org.label-schema.url="" \
org.label-schema.vcs-url="" \
org.label-schema.vcs-ref=${VCS_REF}
-ENV FIREBASE_TOOLS_VERSION="${FIREBASE_TOOLS_VERSION}"
+
ENV HOME=/home/node
-# Install Java, Curl and Firebase-Tools
-RUN apk --no-cache add curl openjdk11-jre bash && \
- yarn global add firebase-tools@${FIREBASE_TOOLS_VERSION} && \
- yarn cache clean
-# Check versions
-RUN firebase -V && \
+# Install Java and curl
+# NOTE - this will not cache unless running with buildkit
+RUN apt-get update && apt-get -y install openjdk-11-jre-headless dos2unix curl && apt-get clean
+
+# Install firebase and check versions
+RUN \
+ yarn global add firebase-tools@${FIREBASE_TOOLS_VERSION} && \
+ firebase -V && \
java -version && \
chown -R node:node $HOME
@@ -35,10 +36,6 @@ RUN firebase setup:emulators:database && \
firebase setup:emulators:storage && \
firebase setup:emulators:ui
-# Install gcloud commmand utilities to use default login (requires python)
-# RUN curl -sSL https://sdk.cloud.google.com > /tmp/gcl && bash /tmp/gcl --install-dir=~/gcloud --disable-prompts
-# ENV PATH $PATH:~/gcloud/google-cloud-sdk/bin
-
WORKDIR /app
# Copy dist package.json and install (step will be cached unless changed)
@@ -61,8 +58,7 @@ COPY ./seed_data/pp-2022-12-04 /app/seed_data
# Copy config files. Ensure executable and lf line format
RUN mkdir -p /app/config
COPY ./config /app/config
-RUN dos2unix /app/config/bootstrap.sh
-RUN chmod +x /app/config/bootstrap.sh
+RUN dos2unix /app/config/bootstrap.sh && chmod +x /app/config/bootstrap.sh
# Prompt firebase to use json credentials for login by exporting variable
ENV GOOGLE_APPLICATION_CREDENTIALS=/app/credentials.json
@@ -73,6 +69,9 @@ ENV CLOUD_RUNTIME_CONFIG=/app/functions/.runtimeconfig.json
# https://github.com/firebase/firebase-admin-node/issues/116
ENV FIREBASE_DATABASE_EMULATOR_HOST = 'http://127.0.0.1:4006'
+# Troubleshooting - can just run to get cli access to exec below manually and check logs
+# CMD [ "/bin/sh" ]
+
# Prepare seed data used in the app
RUN \
# Include a temporary env file to avoid timeouts (https://github.com/firebase/firebase-tools/issues/2837)
@@ -85,17 +84,18 @@ RUN \
"/bin/bash /app/config/bootstrap.sh" \
# Check that data exists and remove seed once complete
&& rm -R /app/seed_data \
- && rm -R /app/functions/dist/.env.local
+ && rm -R /app/functions/dist/.env.local \
+ # Clear global firebase-tools (will run from local node_modules which is pinned to same version), and dangling emulator zips
+ # shaves around 200MB off final image
+ && yarn global remove firebase-tools && yarn cache clean --all\
+ && rm /home/node/.cache/firebase/emulators/*.zip
# TODO - find a way to run the functions test spec against emulator
# Exposed Ports - These should match firebase.json config
EXPOSE 4001 4002 4003 4004 4005 4006 4007 5000
-# Troubleshooting - can just run to get cli access
-# CMD [ "/bin/sh" ]
-
-CMD firebase emulators:start \
+CMD ./functions/dist/node_modules/.bin/firebase emulators:start \
--only auth,functions,firestore,pubsub,storage,hosting,database \
--project ${FIRESTORE_PROJECT_NAME:-community-platform-emulated} \
--import=/app/import
\ No newline at end of file
diff --git a/packages/emulators-docker/README.md b/packages/emulators-docker/README.md
index 3ffaded823..b8eebe82e2 100644
--- a/packages/emulators-docker/README.md
+++ b/packages/emulators-docker/README.md
@@ -33,7 +33,7 @@ By providing a docker image we can address all issues above and provide better p
- DB can only make write updates from client sdk if project names match, and so the DOCKER file may need to be updated if using a project name that is not the same as the one hardcoded into the frontend (currently `community-platform-emulated`)
- Changes made within the workspace package.json will not be reflected in the container.
- Node_modules cannot be bound via volumes as they depend on OS, and so updating package.json will require new build with updated modules. Workaround would be binding full functions src with platform-specific docker image (e.g. node-16-win/node-16-linux) or just documenting required build update (discussion about node-windows support: https://github.com/nodejs/docker-node/pull/362)
+ Node_modules cannot be bound via volumes as they depend on OS, and so updating package.json will require new build with updated modules. Workaround would be binding full functions src with platform-specific docker image (e.g. node-18-win/node-18-linux) or just documenting required build update (discussion about node-windows support: https://github.com/nodejs/docker-node/pull/362)
- Live-reload function changes (doesn't seem to detect through volumes on WSL)
https://forums.docker.com/t/file-system-watch-does-not-work-with-mounted-volumes/12038/20
diff --git a/scripts/envCheck.js b/scripts/envCheck.js
new file mode 100644
index 0000000000..50e0e0beb6
--- /dev/null
+++ b/scripts/envCheck.js
@@ -0,0 +1,38 @@
+/** Check that developer environment setup as expected */
+function envCheck() {
+ const tests = [
+ {
+ message: 'Use Yarn (not npm)',
+ exec: () => /yarn/.test(process.env.npm_execpath),
+ },
+ {
+ message: 'Use Node v18',
+ exec: () => process.versions.node.split('.')[0] === '18',
+ },
+ ]
+
+ let failures = 0
+ let output = '\n'
+
+ for (const test of tests) {
+ if (!test.exec()) {
+ failures = failures + 1
+ output += `❌ ${test.message}\n`
+ } else {
+ output += `✅ ${test.message}\n`
+ }
+ }
+
+ if (failures > 0) {
+ console.log(output)
+ console.log(
+ '💻 Please setup your dev environment to meet requirements\n\nFor more info see:',
+ )
+ console.log('https://onearmy.github.io/community-platform/\n\n')
+ process.exit(1)
+ }
+}
+if (require.main === module) {
+ envCheck()
+}
+exports.envCheck = envCheck
diff --git a/shared/models/db.ts b/shared/models/db.ts
index 17999b8181..f7db72dc38 100644
--- a/shared/models/db.ts
+++ b/shared/models/db.ts
@@ -29,10 +29,15 @@ export const dbEndpointSubollections = {
howtos: ['stats'],
research: ['stats'],
}
-
// React apps populate a process variable, however it might not always be accessible outside
// (e.g. cypress will instead use it's own env to populate a prefix)
-const e = process ? process.env : ({} as any)
+
+// Hack - allow calls to process from cypress testing (react polyfills process.env otherwise)
+if (!('process' in globalThis)) {
+ globalThis.process = {} as any
+}
+
+const e = process.env || ({} as any)
// Check if sessionStorage exists (e.g. running in browser environment), and use if available
const storage =
diff --git a/src/assets/css/slick.min.css b/src/assets/css/slick.min.css
index bac1e8aed9..93dc3950fd 100644
--- a/src/assets/css/slick.min.css
+++ b/src/assets/css/slick.min.css
@@ -1 +1,83 @@
-.slick-list,.slick-slider,.slick-track{position:relative;display:block}.slick-loading .slick-slide,.slick-loading .slick-track{visibility:hidden}.slick-slider{box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none;-khtml-user-select:none;-ms-touch-action:pan-y;touch-action:pan-y;-webkit-tap-highlight-color:transparent}.slick-list{overflow:hidden;margin:0;padding:0}.slick-list:focus{outline:0}.slick-list.dragging{cursor:pointer;cursor:hand}.slick-slider .slick-list,.slick-slider .slick-track{-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.slick-track{top:0;left:0}.slick-track:after,.slick-track:before{display:table;content:''}.slick-track:after{clear:both}.slick-slide{display:none;float:left;height:100%;min-height:1px}[dir=rtl] .slick-slide{float:right}.slick-slide img{display:block}.slick-slide.slick-loading img{display:none}.slick-slide.dragging img{pointer-events:none}.slick-initialized .slick-slide{display:block}.slick-vertical .slick-slide{display:block;height:auto;border:1px solid transparent}.slick-arrow.slick-hidden{display:none}/*# sourceMappingURL=slick.min.css.map */
\ No newline at end of file
+.slick-list,
+.slick-slider,
+.slick-track {
+ position: relative;
+ display: block;
+}
+.slick-loading .slick-slide,
+.slick-loading .slick-track {
+ visibility: hidden;
+}
+.slick-slider {
+ box-sizing: border-box;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-touch-callout: none;
+ -khtml-user-select: none;
+ -ms-touch-action: pan-y;
+ touch-action: pan-y;
+ -webkit-tap-highlight-color: transparent;
+}
+.slick-list {
+ overflow: hidden;
+ margin: 0;
+ padding: 0;
+}
+.slick-list:focus {
+ outline: 0;
+}
+.slick-list.dragging {
+ cursor: pointer;
+ cursor: hand;
+}
+.slick-slider .slick-list,
+.slick-slider .slick-track {
+ -webkit-transform: translate3d(0, 0, 0);
+ -moz-transform: translate3d(0, 0, 0);
+ -ms-transform: translate3d(0, 0, 0);
+ -o-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+}
+.slick-track {
+ top: 0;
+ left: 0;
+}
+.slick-track:after,
+.slick-track:before {
+ display: table;
+ content: '';
+}
+.slick-track:after {
+ clear: both;
+}
+.slick-slide {
+ display: none;
+ float: left;
+ height: 100%;
+ min-height: 1px;
+}
+[dir='rtl'] .slick-slide {
+ float: right;
+}
+.slick-slide img {
+ display: block;
+}
+.slick-slide.slick-loading img {
+ display: none;
+}
+.slick-slide.dragging img {
+ pointer-events: none;
+}
+.slick-initialized .slick-slide {
+ display: block;
+}
+.slick-vertical .slick-slide {
+ display: block;
+ height: auto;
+ border: 1px solid transparent;
+}
+.slick-arrow.slick-hidden {
+ display: none;
+}
diff --git a/src/assets/icons/map-collection-verified.svg b/src/assets/icons/map-collection-verified.svg
index d4bf2cf753..2b8c921d3b 100644
--- a/src/assets/icons/map-collection-verified.svg
+++ b/src/assets/icons/map-collection-verified.svg
@@ -1,117 +1 @@
-
-
+
\ No newline at end of file
diff --git a/src/assets/icons/map-community-verified.svg b/src/assets/icons/map-community-verified.svg
index 8501302126..b8ca50b501 100644
--- a/src/assets/icons/map-community-verified.svg
+++ b/src/assets/icons/map-community-verified.svg
@@ -1,150 +1 @@
-
-
+
\ No newline at end of file
diff --git a/src/assets/icons/map-machine-verified.svg b/src/assets/icons/map-machine-verified.svg
index 6172aa9544..c6c7937a3f 100644
--- a/src/assets/icons/map-machine-verified.svg
+++ b/src/assets/icons/map-machine-verified.svg
@@ -1,137 +1 @@
-
-
+
\ No newline at end of file
diff --git a/src/assets/icons/map-workspace-verified.svg b/src/assets/icons/map-workspace-verified.svg
index e5430f7da7..c76960d65f 100644
--- a/src/assets/icons/map-workspace-verified.svg
+++ b/src/assets/icons/map-workspace-verified.svg
@@ -1,484 +1 @@
-
-
+
\ No newline at end of file
diff --git a/src/logger/index.ts b/src/logger/index.ts
index 247c29ea14..bde445c9c8 100644
--- a/src/logger/index.ts
+++ b/src/logger/index.ts
@@ -4,8 +4,7 @@ import { getConfigurationOption } from 'src/config/config'
const logLevel = getConfigurationOption('REACT_APP_LOG_LEVEL', 'info')
-let loggerInstance
-
+let loggerInstance: Logger.Logger
if (getConfigurationOption('REACT_APP_LOGFLARE_KEY', '')) {
const logflareConfiguration = {
apiKey: getConfigurationOption('REACT_APP_LOGFLARE_KEY', ''),
@@ -24,7 +23,10 @@ if (getConfigurationOption('REACT_APP_LOGFLARE_KEY', '')) {
createWriteStream(logflareConfiguration),
)
} else {
- loggerInstance = Logger({ browser: { asObject: false }, level: logLevel })
+ loggerInstance = Logger({
+ browser: { asObject: false },
+ level: logLevel,
+ })
}
export const logger = loggerInstance
diff --git a/src/mocks/Selectors.tsx b/src/mocks/Selectors.tsx
deleted file mode 100644
index bae3c3c832..0000000000
--- a/src/mocks/Selectors.tsx
+++ /dev/null
@@ -1,159 +0,0 @@
-export const COM_TYPE_MOCKS = [
- {
- value: 'website',
- label: 'website',
- },
- {
- value: 'social media',
- label: 'social media',
- },
- {
- value: 'bazar',
- label: 'bazar',
- },
- {
- value: 'email',
- label: 'email',
- },
-]
-
-export const WEEK_DAYS = [
- {
- value: 'Monday',
- label: 'Monday',
- },
- {
- value: 'Tuesday',
- label: 'Tuesday',
- },
- {
- value: 'Wednesday',
- label: 'Wednesday',
- },
- {
- value: 'Thursday',
- label: 'Thursday',
- },
- {
- value: 'Friday',
- label: 'Friday',
- },
- {
- value: 'Saturday',
- label: 'Saturday',
- },
- {
- value: 'Sunday',
- label: 'Sunday',
- },
-]
-
-export const OPENING_HOURS = [
- {
- value: '01:00 AM',
- label: '01:00 AM',
- },
- {
- value: '02:00 AM',
- label: '02:00 AM',
- },
- {
- value: '03:00 AM',
- label: '03:00 AM',
- },
- {
- value: '04:00 AM',
- label: '04:00 AM',
- },
- {
- value: '05:00 AM',
- label: '05:00 AM',
- },
- {
- value: '06:00 AM',
- label: '06:00 AM',
- },
- {
- value: '07:00 AM',
- label: '07:00 AM',
- },
- {
- value: '08:00 AM',
- label: '08:00 AM',
- },
- {
- value: '09:00 AM',
- label: '09:00 AM',
- },
- {
- value: '10:00 AM',
- label: '10:00 AM',
- },
- {
- value: '11:00 AM',
- label: '11:00 AM',
- },
- {
- value: '12:00 AM',
- label: '12:00 AM',
- },
- {
- value: '01:00 PM',
- label: '01:00 PM',
- },
- {
- value: '02:00 PM',
- label: '02:00 PM',
- },
- {
- value: '03:00 PM',
- label: '03:00 PM',
- },
- {
- value: '04:00 PM',
- label: '04:00 PM',
- },
- {
- value: '05:00 PM',
- label: '05:00 PM',
- },
- {
- value: '06:00 PM',
- label: '06:00 PM',
- },
- {
- value: '07:00 PM',
- label: '07:00 PM',
- },
- {
- value: '08:00 PM',
- label: '08:00 PM',
- },
- {
- value: '09:00 PM',
- label: '09:00 PM',
- },
- {
- value: '10:00 PM',
- label: '10:00 PM',
- },
- {
- value: '11:00 PM',
- label: '11:00 PM',
- },
- {
- value: '12:00 PM',
- label: '12:00 PM',
- },
-]
-
-export const STATUS_MOCKS = [
- {
- value: 'approved',
- label: 'approved',
- },
- {
- value: 'pending',
- label: 'pending',
- },
-]
diff --git a/src/mocks/_template.mock.tsx b/src/mocks/_template.mock.tsx
deleted file mode 100644
index 7fbce6484a..0000000000
--- a/src/mocks/_template.mock.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import type { ITemplateData } from 'src/models/_template.model'
-import { MOCK_USER } from './user.mock'
-
-export const TemplateMock: ITemplateData[] = [
- {
- id: 1,
- message: { message: 'hello', read: true, type: 'short' },
- _createdBy: MOCK_USER.userName,
- _created: new Date(),
- _modified: new Date(),
- },
- {
- id: 2,
- message: { message: 'ahoyhoy', read: false, type: 'short' },
- _created: new Date(),
- _modified: new Date(),
- },
-]
-
-/*************************************************************************************
-General Q & A
-
-Q. What are mocks?
-These are simply dummy datasets for use in development. They often mimic data that
-would be populated from the main database
-
-Q. What does ITemplateData[] mean?
-We have defined the shape of our data using ITemplateData model. The extra [] simply
-means we expect an array of items all matching that data structure
-(for more info see https://www.typescriptlang.org/docs/handbook/basic-types.html)
-
-Q. Isn't the data incomplete?
-No, _createdBy is an optional field (denoted by ? in the model)
-
-
-Anything else you want to know? Add it to a git issue and so we can make the
-template even more useful
-
-**************************************************************************************/
diff --git a/src/mocks/category.mock.tsx b/src/mocks/category.mock.tsx
deleted file mode 100644
index 5d73b979c1..0000000000
--- a/src/mocks/category.mock.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-export const CATEGORY_MOCKS = [
- {
- created: new Date(),
- label: 'Plastic, Materials',
- },
- {
- created: new Date(),
- label: 'Product Design',
- },
- {
- created: new Date(),
- label: 'Building',
- },
- {
- created: new Date(),
- label: 'Workspace',
- },
-]
diff --git a/src/mocks/db.mock.tsx b/src/mocks/db.mock.tsx
deleted file mode 100644
index 754ab7bca5..0000000000
--- a/src/mocks/db.mock.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { DBDoc } from 'src/models/common.models'
-import { randomID } from 'src/utils/helpers'
-
-// helper methods used in generation of mock db data
-export const MOCK_DB_META = (id?: string) => {
- const d1 = randomDate(new Date(2012, 0, 1), new Date())
- const d2 = randomDate(d1, new Date())
- const meta: DBDoc = {
- _created: d1.toISOString(),
- _modified: d2.toISOString(),
- _deleted: false,
- _id: id ? id : randomID(),
- }
- return meta
-}
-
-// generate a random date between start and end
-function randomDate(start: Date, end: Date) {
- return new Date(
- start.getTime() + Math.random() * (end.getTime() - start.getTime()),
- )
-}
diff --git a/src/mocks/events.mock.tsx b/src/mocks/events.mock.tsx
deleted file mode 100644
index dde33b07c3..0000000000
--- a/src/mocks/events.mock.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import type { IEventFilters, IEvent } from 'src/models/events.models'
-import { MOCK_DB_META } from './db.mock'
-import { MOCK_LOCATION } from './location.mock'
-
-const d = new Date()
-export const EVENT_FILTERS: IEventFilters = {
- dateFrom: d,
- dateTo: new Date(d.getFullYear() + 1, d.getMonth(), d.getDay()),
- location: '',
- project: '',
- type: 'All',
-}
-
-export const EVENT_PROJECTS = [
- { label: 'All Projects', value: '' },
- { label: 'Precious Plastic', value: 'precious-plastic' },
- { label: 'Project Kamp', value: 'project-kamp' },
- { label: 'Story Hopper', value: 'story-hopper' },
-]
-
-export const EVENT_LOCATIONS = [
- { label: 'Everywhere', value: '' },
- { label: 'Netherlands', value: 'NL' },
-]
-
-export const EVENT_TYPES = [
- 'All',
- 'Workshops',
- 'Community Meetups',
- 'Exhibitions',
- 'Open Workspace',
- 'Talks',
- 'Clean Ups',
- 'Everything Else',
-]
-
-export const TIMEFRAMES = [
- { value: 'weekend', label: 'This Weekend' },
- { value: 'week', label: 'This Week' },
- { value: 'month', label: 'This Month' },
- { value: 'year', label: 'This Year' },
-]
-
-export const EVENTS: IEvent[] = [
- {
- title: 'Open Workspace and Free Lunch - Eindhoven',
- location: MOCK_LOCATION(1),
- ...MOCK_DB_META('event1'),
- date: new Date('Friday, January 2, 2015 12:59 AM').toISOString(),
- slug: 'open-workshop-and-free-lunch---brighton',
- tags: {},
- isDigital: true,
- url: 'http://fakeurl.com',
- _createdBy: 'exampleUser',
- moderation: 'awaiting-moderation',
- },
- {
- title: 'Beach Clean in Brighton',
- location: MOCK_LOCATION(2),
- ...MOCK_DB_META('event2'),
- date: new Date('Friday, January 2, 2015 12:59 AM').toISOString(),
- slug: 'open-workshop-and-free-lunch---brighton',
- tags: {},
- isDigital: false,
- url: 'http://fakeurl.com',
- _createdBy: 'exampleUser',
- moderation: 'rejected',
- },
- {
- title: 'Beach Clean in Tel Aviv',
- location: MOCK_LOCATION(2),
- ...MOCK_DB_META('event2'),
- date: new Date('Friday, January 2, 2015 12:59 AM').toISOString(),
- slug: 'open-workshop-and-free-lunch---brighton',
- tags: {},
- isDigital: false,
- url: 'http://fakeurl.com',
- _createdBy: 'exampleUser',
- moderation: 'accepted',
- },
-]
-
-export const MONTHS = [
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December',
-]
diff --git a/src/mocks/howto.mock.tsx b/src/mocks/howto.mock.tsx
deleted file mode 100644
index f333d5a72b..0000000000
--- a/src/mocks/howto.mock.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import type { IHowto } from '../models/howto.models'
-import type { IUploadedFileMeta } from 'src/stores/storage'
-import { MOCK_DB_META } from './db.mock'
-
-const exampleUploadImage: IUploadedFileMeta = {
- downloadUrl: 'http://placekitten.com/g/400/250',
- fullPath: '',
- name: '250.jpg',
- size: 11035,
- timeCreated: '',
- updated: '',
- type: 'image/jpg',
-}
-
-export const HOWTO_MOCK: IHowto[] = [
- {
- cover_image: exampleUploadImage,
- title: 'How-To 1',
- slug: 'how-to-1',
- description: 'this is a great description 1',
- difficulty_level: 'Hard',
- time: '30 hours',
- steps: [
- {
- images: [],
- text: 'this text is wonderful oh my god',
- title: 'My super step1 title',
- },
- {
- images: [exampleUploadImage, exampleUploadImage],
- text: 'this text is wonderful oh my god',
- title: 'My super step2 title',
- },
- ],
- tags: {},
- files: [],
- mentions: [],
- ...MOCK_DB_META('howTo1'),
- _createdBy: 'ExampleUser',
- moderation: 'draft',
- creatorCountry: 'nl',
- },
- {
- cover_image: exampleUploadImage,
- title: 'How-to 2',
- slug: 'how-to-2',
- description: 'this is a great description 2',
- difficulty_level: 'Hard',
- time: '30 hours',
- steps: [
- {
- images: [exampleUploadImage, exampleUploadImage],
- text: 'this text is wonderful oh my god',
- title: 'My super step1 title',
- },
- {
- images: [exampleUploadImage],
- text: 'this text is wonderful oh my god',
- title: 'My super step2 title',
- },
- ],
- tags: {},
- files: [],
- mentions: [],
- ...MOCK_DB_META('howTo2'),
- _createdBy: 'ExampleUser',
- moderation: 'awaiting-moderation',
- creatorCountry: 'fr',
- },
- {
- cover_image: exampleUploadImage,
- title: 'How-to 3',
- slug: 'how-to-3',
- description: 'this is a great description 3',
- difficulty_level: 'Hard',
- time: '30 days',
- steps: [
- {
- images: [exampleUploadImage],
- text: 'this text is wonderful oh my god',
- title: 'My super step1 title',
- },
- {
- images: [exampleUploadImage],
- text: 'this text is wonderful oh my god',
- title: 'My super step2 title',
- },
- ],
- tags: {},
- files: [],
- mentions: [],
- ...MOCK_DB_META('howTo3'),
- _createdBy: 'ExampleUser',
- moderation: 'accepted',
- creatorCountry: 'es',
- },
-]
diff --git a/src/mocks/location.mock.tsx b/src/mocks/location.mock.tsx
deleted file mode 100644
index a4170ee1b5..0000000000
--- a/src/mocks/location.mock.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import type { ILocation } from 'src/models/common.models'
-
-/**
- * Generate mock location data matching algolia places format
- * @param i Optional - provide a specific location index
- * 1:Twickenham, 2:Eindhoven, 3:Brighton, 4:Paris, 5:Madrid
- */
-export const MOCK_LOCATION = (i?: number) => {
- // pick random location from list below
- return i
- ? LOCATIONS[i]
- : LOCATIONS[Math.floor(Math.random() * LOCATIONS.length)]
-}
-
-// Example outputs generated at: https://community.algolia.com/places/
-const LOCATIONS: ILocation[] = [
- {
- name: 'Twickenham',
- administrative: 'England',
- country: 'United Kingdom',
- countryCode: 'gb',
- latlng: {
- lat: 51.4468,
- lng: -0.328339,
- },
- postcode: 'TW1 3RZ',
- value:
- 'Twickenham, London Borough of Richmond upon Thames, England, United Kingdom',
- },
- {
- name: 'Eindhoven',
- administrative: 'Noord-Brabant',
- country: 'The Netherlands',
- countryCode: 'nl',
- latlng: {
- lat: 51.4393,
- lng: 5.47863,
- },
- postcode: '5611',
- value: 'Eindhoven, Noord-Brabant, The Netherlands',
- },
- {
- name: 'Brighton',
- administrative: 'England',
- country: 'United Kingdom',
- countryCode: 'gb',
- latlng: {
- lat: 50.8419,
- lng: -0.12791,
- },
- postcode: 'BN2',
- value: 'Brighton, England, United Kingdom',
- },
- {
- name: 'Paris',
- administrative: 'Île-de-France',
- country: 'France',
- countryCode: 'fr',
- latlng: {
- lat: 48.8546,
- lng: 2.34771,
- },
- postcode: '75000',
- value: 'Paris, Île-de-France, France',
- },
- {
- name: 'Madrid',
- administrative: 'Comunidad de Madrid',
- country: 'Spain',
- countryCode: 'es',
- latlng: {
- lat: 40.4167,
- lng: -3.70358,
- },
- postcode: '28001',
- value: 'Madrid, Comunidad de Madrid, Spain',
- },
-]
diff --git a/src/mocks/projects.mock.tsx b/src/mocks/projects.mock.tsx
deleted file mode 100644
index 6f4166f9de..0000000000
--- a/src/mocks/projects.mock.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-export const PROJECTS_MOCKS = [
- {
- label: 'Project Kamp',
- value: 'project-kamp',
- },
- {
- label: 'Precious Plastic',
- value: 'precious-plastic',
- },
- {
- label: 'Story Hooper',
- value: 'story-hooper',
- },
-]
diff --git a/src/mocks/research.mocks.tsx b/src/mocks/research.mocks.tsx
deleted file mode 100644
index 7fa9d5ff3b..0000000000
--- a/src/mocks/research.mocks.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import type { IResearch } from '../models/research.models'
-import { MOCK_DB_META } from './db.mock'
-
-export const MOCK_RESEARCH_ITEMS: IResearch.ItemDB[] = [
- {
- ...MOCK_DB_META(),
- moderation: 'accepted',
- title: 'Make a big 244 x 122 sheetpress?',
- description: 'We want to see whether we can make a big sheetpress',
- slug: 'make-a-big-244-x-122-sheetpress',
- tags: { 'Plastic Hero': true, 'Another tag': true },
- updates: [
- {
- ...MOCK_DB_META(),
- title: 'Research Online',
- description: 'We looked into some online reach that you can find',
- images: [],
- },
- ],
- _createdBy: 'Precious Plastic Malesia',
- },
- {
- ...MOCK_DB_META(),
- moderation: 'accepted',
- title: 'Run the injection machine on Solar?',
- description: 'Run the injection machine on Solar?',
- slug: 'run-the-injection-machine-on-solar',
- tags: { 'Plastic Hero': true, any: true },
- updates: [
- {
- ...MOCK_DB_META(),
- title: 'Research Online',
- description: 'We looked into some online reach that you can find',
- images: [],
- },
- ],
- _createdBy: 'Zelenew',
- },
-]
-
-export const MOCK_UPDATES: IResearch.Update[] = [
- {
- title: 'Trying a small version',
- description: `Ad minus expedita quibusdam. Amet quia recusandae quia sequi. Molestiae adipisci officia rerum officia. Itaque eveniet natus dolores et at quae non hic. Qui odio consequatur id quia quam.
- Consequuntur possimus dolorem dignissimos beatae saepe. Ipsam nemo eos magnam sed. Recusandae modi eum dolorem autem voluptas dolor est.`,
- images: [
- {
- fullPath: 'uploads/howtos/KEhA3Ei4NSmdQgShl9Vp/IMG_20170909_173730.jpg',
- updated: '2020-10-05T09:53:31.625Z',
- name: 'IMG_20170909_173730.jpg',
- contentType: 'image/jpeg',
- size: 255946,
- type: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2Fhowtos%2FKEhA3Ei4NSmdQgShl9Vp%2FIMG_20170909_173730.jpg?alt=media&token=2464cb94-ed53-4853-acac-9626b8fec079',
- timeCreated: '2020-10-05T09:53:31.625Z',
- },
- {
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2Fhowtos%2FKEhA3Ei4NSmdQgShl9Vp%2FD2rZFtOX4AAY8cv.jpg?alt=media&token=0c3645ee-8551-4247-b5df-d03529a55f57',
- updated: '2020-10-05T09:53:30.263Z',
- name: 'D2rZFtOX4AAY8cv.jpg',
- type: 'image/jpeg',
- contentType: 'image/jpeg',
- timeCreated: '2020-10-05T09:53:30.263Z',
- size: 248912,
- fullPath: 'uploads/howtos/KEhA3Ei4NSmdQgShl9Vp/D2rZFtOX4AAY8cv.jpg',
- },
- ],
- },
- {
- title: 'Melt the HDPE',
- description: `Ad minus expedita quibusdam. Amet quia recusandae quia sequi. Molestiae adipisci officia rerum officia. Itaque eveniet natus dolores et at quae non hic. Qui odio consequatur id quia quam.
- Consequuntur possimus dolorem dignissimos beatae saepe. Ipsam nemo eos magnam sed. Recusandae modi eum dolorem autem voluptas dolor est.`,
- images: [
- {
- fullPath: 'uploads/howtos/KEhA3Ei4NSmdQgShl9Vp/IMG_20170909_173730.jpg',
- updated: '2020-10-05T09:53:31.625Z',
- name: 'IMG_20170909_173730.jpg',
- contentType: 'image/jpeg',
- size: 255946,
- type: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2Fhowtos%2FKEhA3Ei4NSmdQgShl9Vp%2FIMG_20170909_173730.jpg?alt=media&token=2464cb94-ed53-4853-acac-9626b8fec079',
- timeCreated: '2020-10-05T09:53:31.625Z',
- },
- ],
- },
- {
- title: 'Build a kitchen and workspace in a container',
- description: `Ad minus expedita quibusdam. Amet quia recusandae quia sequi. Molestiae adipisci officia rerum officia. Itaque eveniet natus dolores et at quae non hic. Qui odio consequatur id quia quam.
- Consequuntur possimus dolorem dignissimos beatae saepe.`,
- images: [],
- videoUrl: 'https://www.youtube.com/watch?v=bjU7QKcEUFY',
- },
-]
diff --git a/src/mocks/tags.mock.tsx b/src/mocks/tags.mock.tsx
deleted file mode 100644
index 1e55bcbd1d..0000000000
--- a/src/mocks/tags.mock.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-import type { ITag } from 'src/models/tags.model'
-import { MOCK_DB_META } from './db.mock'
-
-export const TAGS_MOCK: ITag[] = [
- // how-to
- {
- ...MOCK_DB_META('DJN99ErXz8FHy035YdMO'),
- image: '',
- label: 'extrusion',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'sheet press',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'other machine',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'collection',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'product',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'mould',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'research',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'hack',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'washing',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'HDPE',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'LDPE',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'PP',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'PS',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META('fLUiS1PS9WEKSRlTe8Cs'),
- image: '',
- label: 'shredder',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META('JVpo3tdEqbk8G787hAZH'),
- image: '',
- label: 'injection',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META('kuJqlMsnpfr5VR4BZ1ML'),
- image: '',
- label: 'compression',
- categories: ['how-to'],
- },
- {
- ...MOCK_DB_META('jUtS7pVbv7DXoQyV13RR'),
- image: '',
- label: 'sorting',
- categories: ['how-to'],
- },
- // EVENTS
- {
- ...MOCK_DB_META('1zfteiFXNDbDnlE3Incg'),
- image: '',
- label: 'cleanup',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('9RlNW5tLD3BxMhL7keFN'),
- image: '',
- label: 'workshop',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('T7bZy8OhN7K4OWJ09wSX'),
- image: '',
- label: 'exhibition',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('cd41vHdBh1M2YtPlYcYR'),
- image: '',
- label: 'presentation',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('IM8aJW5LrQDK2Mby8rYJ'),
- image: '',
- label: 'screening',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('kVSRJqFt52hi8RHW5wjb'),
- image: '',
- label: 'meet & greet',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('7yhssOmZqiihTBXK2cxU'),
- image: '',
- label: 'brainstorm session',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('5nXtB6mHdffDurEDLt6Q'),
- image: '',
- label: 'open day',
- categories: ['event'],
- },
- {
- ...MOCK_DB_META('Qr2sOd3aM4CvZsSfFkPn'),
- image: '',
- label: 'protest',
- categories: ['event'],
- },
- // PROFILE EXPERTISE
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'Electronics',
- categories: ['profile-expertise'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'Machining',
- categories: ['profile-expertise'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'Welding',
- categories: ['profile-expertise'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'Assembling',
- categories: ['profile-expertise'],
- },
- {
- ...MOCK_DB_META(),
- image: '',
- label: 'Mould making',
- categories: ['profile-expertise'],
- },
-]
diff --git a/src/mocks/user.mock.tsx b/src/mocks/user.mock.tsx
deleted file mode 100644
index dc2d2ce5cb..0000000000
--- a/src/mocks/user.mock.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention*/
-import type { IUser } from 'src/models/user.models'
-import { MOCK_DB_META } from './db.mock'
-
-export const MOCK_USER: IUser = {
- verified: true,
- badges: { verified: true },
- userName: 'chris-m-clarke',
- displayName: 'chris-m-clarke',
- moderation: 'accepted',
- ...MOCK_DB_META(),
- _authID: '123',
- DHSite_id: 70134,
- DHSite_mention_name: 'chris-m-clarke',
- country: '',
- coverImages: [],
- links: [],
- votedUsefulHowtos: {},
-}
diff --git a/src/mocks/user_pp.mock.tsx b/src/mocks/user_pp.mock.tsx
deleted file mode 100644
index bfad4a1a53..0000000000
--- a/src/mocks/user_pp.mock.tsx
+++ /dev/null
@@ -1,389 +0,0 @@
-import type {
- IUserPP,
- IWorkspaceType,
- IPlasticType,
- IMAchineBuilderXp,
-} from 'src/models/user_pp.models'
-import { MOCK_DB_META } from './db.mock'
-import { MOCK_USER } from './user.mock'
-
-// assets plasticType
-import Pet from 'src/assets/images/plastic-types/pet.svg'
-import PP from 'src/assets/images/plastic-types/pp.svg'
-import PS from 'src/assets/images/plastic-types/ps.svg'
-import Hdpe from 'src/assets/images/plastic-types/hdpe.svg'
-import Ldpe from 'src/assets/images/plastic-types/ldpe.svg'
-import Other from 'src/assets/images/plastic-types/other.svg'
-import Pvc from 'src/assets/images/plastic-types/pvc.svg'
-
-// assets profileType
-// Verified
-
-// assets workspaceType
-import Extrusion from 'src/assets/images/workspace-focus/extrusion.png'
-import Injection from 'src/assets/images/workspace-focus/injection.png'
-import Mix from 'src/assets/images/workspace-focus/mix.png'
-import Sheetpress from 'src/assets/images/workspace-focus/sheetpress.png'
-import Shredder from 'src/assets/images/workspace-focus/shredder.png'
-import { ProfileType } from 'src/modules/profile/types'
-
-export const MOCK_USER_WORKSPACE: IUserPP = {
- ...MOCK_USER,
- userName: 'workspace-username',
- about:
- "Description of user profile, it's a nice workspace where we build products out of recycled plastic",
- profileType: ProfileType.WORKSPACE,
- workspaceType: 'extrusion',
- coverImages: [
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- ],
- links: [
- {
- label: 'instagram',
- url: 'https://www.instagram.com/realpreciousplastic/',
- },
- {
- label: 'facebook',
- url: 'https://www.facebook.com/preciousplastic/',
- },
- ],
- mapPinDescription: 'This is a description to display on the map user card',
- isExpert: true,
- isV4Member: false,
- openingHours: [],
- collectedPlasticTypes: [],
- machineBuilderXp: [],
-}
-export const MOCK_USER_COLLECTION: IUserPP = {
- verified: true,
- badges: { verified: true },
- userName: 'collection-username',
- about: 'We are collecting plastic in city center',
- ...MOCK_DB_META(),
- _authID: '123',
- country: 'Netherlands',
- profileType: ProfileType.COLLECTION_POINT,
- moderation: 'accepted',
- displayName: 'collection-username',
- coverImages: [
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- ],
- links: [
- {
- label: 'instagram',
- url: 'https://www.instagram.com/realpreciousplastic/',
- },
- {
- label: 'facebook',
- url: 'https://www.facebook.com/preciousplastic/',
- },
- ],
- mapPinDescription: 'Collecting plastic',
- isExpert: false,
- isV4Member: true,
- openingHours: [],
- collectedPlasticTypes: [],
- machineBuilderXp: [],
- votedUsefulHowtos: {},
-}
-export const MOCK_USER_MEMBER: IUserPP = {
- verified: true,
- badges: { verified: false },
- userName: 'member-username',
- about: "I'm just a member of this community that share knowledge",
- ...MOCK_DB_META(),
- _authID: '123',
- country: 'Netherlands',
- profileType: ProfileType.MEMBER,
- moderation: 'accepted',
- displayName: 'member-username',
- coverImages: [
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- ],
- links: [
- {
- label: 'instagram',
- url: 'https://www.instagram.com/realpreciousplastic/',
- },
- {
- label: 'facebook',
- url: 'https://www.facebook.com/preciousplastic/',
- },
- ],
- isExpert: false,
- isV4Member: false,
- openingHours: [],
- collectedPlasticTypes: [],
- machineBuilderXp: [],
- votedUsefulHowtos: {},
-}
-export const MOCK_USER_COMMUNITY: IUserPP = {
- verified: true,
- badges: { verified: true },
- userName: 'community-username',
- about: 'We are building a local community to fight plastic waste',
- ...MOCK_DB_META(),
- _authID: '123',
- country: 'Kenya',
- profileType: ProfileType.COMMUNITY_BUILDER,
- moderation: 'accepted',
- displayName: 'community-username',
- coverImages: [
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- ],
- links: [
- {
- label: 'instagram',
- url: 'https://www.instagram.com/realpreciousplastic/',
- },
- {
- label: 'facebook',
- url: 'https://www.facebook.com/preciousplastic/',
- },
- ],
- workspaceType: 'mix',
- mapPinDescription: null,
- isExpert: false,
- isV4Member: true,
- openingHours: [],
- collectedPlasticTypes: [],
- machineBuilderXp: [],
- votedUsefulHowtos: {},
-}
-export const MOCK_USER_MACHINE: IUserPP = {
- verified: true,
- badges: { verified: true },
- userName: 'community-username',
- about: 'We are building machine to recycle plastic',
- ...MOCK_DB_META(),
- _authID: '123',
- country: 'USA',
- profileType: ProfileType.MACHINE_BUILDER,
- moderation: 'accepted',
- displayName: 'collection-username',
- coverImages: [
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- {
- contentType: 'image/jpeg',
- downloadUrl:
- 'https://firebasestorage.googleapis.com/v0/b/precious-plastics-v4-dev.appspot.com/o/uploads%2FhowtosV1%2FcWngQOnxxD3r3oI8TKx8%2FScreen%20Shot%202019-03-16%20at%2020.40.36.png?alt=media&token=51ac3516-064c-4f1d-ac2b-4460ee9f3500',
- fullPath:
- 'uploads/howtosV1/cWngQOnxxD3r3oI8TKx8/Screen Shot 2019-03-16 at 20.40.36.png',
- name: 'Screen Shot 2019-03-16 at 20.40.36.png',
- size: 209068,
- timeCreated: '2019-05-08T12:28:27.318Z',
- type: 'image/jpeg',
- updated: '2019-05-08T12:28:27.318Z',
- },
- ],
- links: [
- {
- label: 'instagram',
- url: 'https://www.instagram.com/realpreciousplastic/',
- },
- {
- label: 'facebook',
- url: 'https://www.facebook.com/preciousplastic/',
- },
- ],
- workspaceType: 'mix',
- mapPinDescription: null,
- isExpert: true,
- isV4Member: false,
- openingHours: [],
- collectedPlasticTypes: [],
- machineBuilderXp: [],
- votedUsefulHowtos: {},
-}
-
-export const PLASTIC_TYPES: IPlasticType[] = [
- {
- label: 'pet',
- number: '1',
- imageSrc: Pet,
- },
- {
- label: 'hdpe',
- number: '2',
- imageSrc: Hdpe,
- },
- {
- label: 'pvc',
- number: '3',
- imageSrc: Pvc,
- },
- {
- label: 'ldpe',
- number: '4',
- imageSrc: Ldpe,
- },
- {
- label: 'pp',
- number: '5',
- imageSrc: PP,
- },
- {
- label: 'ps',
- number: '6',
- imageSrc: PS,
- },
- {
- label: 'other',
- number: '7',
- imageSrc: Other,
- },
-]
-
-export const MACHINE_BUILDER_XP: IMAchineBuilderXp[] = [
- {
- label: 'electronics',
- },
- {
- label: 'machining',
- },
- {
- label: 'welding',
- },
- {
- label: 'assembling',
- },
- {
- label: 'mould-making',
- },
-]
-
-export const WORKSPACE_TYPES: IWorkspaceType[] = [
- {
- label: 'shredder',
- textLabel: 'Shredder',
- subText: 'Shredding plastic waste into flakes',
- imageSrc: Shredder,
- },
- {
- label: 'sheetpress',
- textLabel: 'Sheetpress',
- subText: 'Making recycled plastic sheets',
- imageSrc: Sheetpress,
- },
- {
- label: 'extrusion',
- textLabel: 'Extrusion',
- subText: 'Extruding plastic into beams or products',
- imageSrc: Extrusion,
- },
- {
- label: 'injection',
- textLabel: 'Injection',
- subText: 'Making small productions of goods',
- imageSrc: Injection,
- },
- {
- label: 'mix',
- textLabel: 'Mix',
- subText: 'Running a workspace with multiple machines and goals',
- imageSrc: Mix,
- },
-]
diff --git a/src/models/howto.models.tsx b/src/models/howto.models.tsx
index 5b74dcc713..7c3a10daad 100644
--- a/src/models/howto.models.tsx
+++ b/src/models/howto.models.tsx
@@ -23,6 +23,7 @@ export interface IHowto extends IHowtoFormInput, IModerable {
comments?: IComment[]
total_downloads?: number
mentions: UserMention[]
+ previousSlugs?: string[]
}
/**
diff --git a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx
index 5d51a95422..2993349458 100644
--- a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx
+++ b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx
@@ -173,21 +173,27 @@ export default class HowtoDescription extends PureComponent {
data-cy={'accept'}
variant={'primary'}
icon="check"
- mr={1}
onClick={() => this.props.moderateHowto(true)}
- />
+ showIconOnly={true}
+ >
+ Accept
+
)}
{/* Check if logged in user is the creator of the how-to OR a super-admin */}
{loggedInUser && isAllowToEditContent(howto, loggedInUser) && (
-