mirror of
https://github.com/Haiti-Distributed-Healthcare-System/hdhs.git
synced 2026-10-26 17:35:23 +00:00
Merge pull request #74 from Haiti-Distributed-Healthcare-System/update-linting-config
Attempt 2: Linting Config + Action
This commit is contained in:
29 files changed
+14763
-6153
No files matched your search
@@ -17,6 +17,7 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: docker-compose -f dev-docker-compose.yml up --detach
|
||||
- run: docker exec haiti_pwa npm run lint
|
||||
- run: docker exec haiti_pwa npm run test:cov
|
||||
- run: docker exec haiti_pwa npm run cy:run
|
||||
- run: docker exec haiti_pwa npm run build
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
parser: "@typescript-eslint/parser", // Specifies the ESLint parser
|
||||
extends: [
|
||||
"plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react
|
||||
"plugin:@typescript-eslint/recommended", // Uses the recommended rules from the @typescript-eslint/eslint-plugin
|
||||
"prettier/@typescript-eslint", // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
|
||||
"plugin:prettier/recommended", // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
|
||||
sourceType: "module", // Allows for the use of imports
|
||||
ecmaFeatures: {
|
||||
jsx: true, // Allows for the parsing of JSX
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-empty-interface": "off",
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect", // Tells eslint-plugin-react to automatically detect the version of React to use
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
semi: false,
|
||||
trailingComma: 'all',
|
||||
singleQuote: true,
|
||||
printWidth: 80,
|
||||
tabWidth: 4,
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
|
||||
}
|
||||
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"eslint.autoFixOnSave": true,
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
{
|
||||
"language": "typescript",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "typescriptreact",
|
||||
"autoFix": true
|
||||
}
|
||||
],
|
||||
"editor.formatOnSave": true,
|
||||
"[javascript]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('Homepage', () => {
|
||||
it('shows login button', function () {
|
||||
cy.visit('http://localhost:3000')
|
||||
cy.get('.am-button').contains('Login')
|
||||
})
|
||||
it('shows login button', function () {
|
||||
cy.visit('http://localhost:3000')
|
||||
cy.get('.am-button').contains('Login')
|
||||
})
|
||||
})
|
||||
|
||||
export {};
|
||||
export {}
|
||||
Generated
+110
-48
@@ -1840,42 +1840,42 @@
|
||||
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.19.0.tgz",
|
||||
"integrity": "sha512-u7IcQ9qwsB6U806LupZmINRnQjC+RJyv36sV/ugaFWMHTbFm/hlLTRx3gGYJgHisxcGSTnf+I/fPDieRMhPSQQ==",
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.28.0.tgz",
|
||||
"integrity": "sha512-w0Ugcq2iatloEabQP56BRWJowliXUP5Wv6f9fKzjJmDW81hOTBxRoJ4LoEOxRpz9gcY51Libytd2ba3yLmSOfg==",
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "2.19.0",
|
||||
"eslint-utils": "^1.4.3",
|
||||
"@typescript-eslint/experimental-utils": "2.28.0",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"regexpp": "^3.0.0",
|
||||
"tsutils": "^3.17.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.19.0.tgz",
|
||||
"integrity": "sha512-zwpg6zEOPbhB3+GaQfufzlMUOO6GXCNZq6skk+b2ZkZAIoBhVoanWK255BS1g5x9bMwHpLhX0Rpn5Fc3NdCZdg==",
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.28.0.tgz",
|
||||
"integrity": "sha512-4SL9OWjvFbHumM/Zh/ZeEjUFxrYKtdCi7At4GyKTbQlrj1HcphIDXlje4Uu4cY+qzszR5NdVin4CCm6AXCjd6w==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.3",
|
||||
"@typescript-eslint/typescript-estree": "2.19.0",
|
||||
"eslint-scope": "^5.0.0"
|
||||
"@typescript-eslint/typescript-estree": "2.28.0",
|
||||
"eslint-scope": "^5.0.0",
|
||||
"eslint-utils": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.19.0.tgz",
|
||||
"integrity": "sha512-s0jZoxAWjHnuidbbN7aA+BFVXn4TCcxEVGPV8lWMxZglSs3NRnFFAlL+aIENNmzB2/1jUJuySi6GiM6uACPmpg==",
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.28.0.tgz",
|
||||
"integrity": "sha512-RqPybRDquui9d+K86lL7iPqH6Dfp9461oyqvlXMNtap+PyqYbkY5dB7LawQjDzot99fqzvS0ZLZdfe+1Bt3Jgw==",
|
||||
"requires": {
|
||||
"@types/eslint-visitor-keys": "^1.0.0",
|
||||
"@typescript-eslint/experimental-utils": "2.19.0",
|
||||
"@typescript-eslint/typescript-estree": "2.19.0",
|
||||
"@typescript-eslint/experimental-utils": "2.28.0",
|
||||
"@typescript-eslint/typescript-estree": "2.28.0",
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.19.0.tgz",
|
||||
"integrity": "sha512-n6/Xa37k0jQdwpUszffi19AlNbVCR0sdvCs3DmSKMD7wBttKY31lhD2fug5kMD91B2qW4mQldaTEc1PEzvGu8w==",
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.28.0.tgz",
|
||||
"integrity": "sha512-HDr8MP9wfwkiuqzRVkuM3BeDrOC4cKbO5a6BymZBHUt5y/2pL0BXD6I/C/ceq2IZoHWhcASk+5/zo+dwgu9V8Q==",
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
"eslint-visitor-keys": "^1.1.0",
|
||||
@@ -2091,9 +2091,9 @@
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
|
||||
"integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ=="
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
|
||||
"integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg=="
|
||||
},
|
||||
"acorn-globals": {
|
||||
"version": "4.3.4",
|
||||
@@ -2112,9 +2112,9 @@
|
||||
}
|
||||
},
|
||||
"acorn-jsx": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz",
|
||||
"integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw=="
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
|
||||
"integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ=="
|
||||
},
|
||||
"acorn-walk": {
|
||||
"version": "6.2.0",
|
||||
@@ -5200,10 +5200,18 @@
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-utils": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
|
||||
"integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"version": "12.3.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz",
|
||||
"integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==",
|
||||
"version": "12.4.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
|
||||
"integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
|
||||
"requires": {
|
||||
"type-fest": "^0.8.1"
|
||||
}
|
||||
@@ -5229,6 +5237,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"version": "6.10.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.1.tgz",
|
||||
"integrity": "sha512-svTy6zh1ecQojvpbJSgH3aei/Rt7C6i090l5f2WQ4aB05lYHeZIR1qL4wZyyILTbtmnbHP5Yn8MrsOJMGa8RkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"get-stdin": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"get-stdin": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
|
||||
"integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-react-app": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.0.tgz",
|
||||
@@ -5506,6 +5531,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-prettier": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz",
|
||||
"integrity": "sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"prettier-linter-helpers": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz",
|
||||
@@ -5547,9 +5581,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-utils": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
|
||||
"integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==",
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
@@ -5560,12 +5594,12 @@
|
||||
"integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A=="
|
||||
},
|
||||
"espree": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz",
|
||||
"integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
|
||||
"integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
|
||||
"requires": {
|
||||
"acorn": "^7.1.0",
|
||||
"acorn-jsx": "^5.1.0",
|
||||
"acorn": "^7.1.1",
|
||||
"acorn-jsx": "^5.2.0",
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -5575,11 +5609,18 @@
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"esquery": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
|
||||
"integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
|
||||
"integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
|
||||
"requires": {
|
||||
"estraverse": "^4.0.0"
|
||||
"estraverse": "^5.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"estraverse": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz",
|
||||
"integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"esrecurse": {
|
||||
@@ -5971,6 +6012,12 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
|
||||
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
|
||||
},
|
||||
"fast-diff": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
|
||||
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
|
||||
@@ -6189,9 +6236,9 @@
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
|
||||
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg=="
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
|
||||
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA=="
|
||||
},
|
||||
"flatten": {
|
||||
"version": "1.0.3",
|
||||
@@ -11753,6 +11800,21 @@
|
||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.4.tgz",
|
||||
"integrity": "sha512-SVJIQ51spzFDvh4fIbCLvciiDMCrRhlN3mbZvv/+ycjvmF5E73bKdGfU8QDLNmjYJf+lsGnDBC4UUnvTe5OO0w==",
|
||||
"dev": true
|
||||
},
|
||||
"prettier-linter-helpers": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
|
||||
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-diff": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"pretty-bytes": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz",
|
||||
@@ -12863,9 +12925,9 @@
|
||||
}
|
||||
},
|
||||
"regexpp": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz",
|
||||
"integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g=="
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
|
||||
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q=="
|
||||
},
|
||||
"regexpu-core": {
|
||||
"version": "4.6.0",
|
||||
@@ -14598,9 +14660,9 @@
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
|
||||
"integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw=="
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz",
|
||||
"integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w=="
|
||||
},
|
||||
"style-loader": {
|
||||
"version": "1.1.3",
|
||||
|
||||
+72
-66
@@ -1,69 +1,75 @@
|
||||
{
|
||||
"name": "hdhs",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.0.5",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.4.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"@types/jest": "^24.9.1",
|
||||
"@types/node": "^12.12.26",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/react-router-dom": "^5.1.4",
|
||||
"antd-mobile": "^2.3.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-scripts": "3.3.1",
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"cy:open": "cypress open",
|
||||
"cy:run": "cypress run",
|
||||
"test:cov": "react-scripts test --coverage --watchAll=false",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
},
|
||||
"jest": {
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"statements": 90
|
||||
}
|
||||
"name": "hdhs",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.0.5",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.4.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"@types/jest": "^24.9.1",
|
||||
"@types/node": "^12.12.26",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/react-router-dom": "^5.1.4",
|
||||
"antd-mobile": "^2.3.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-scripts": "3.3.1",
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"coverageReporters": [
|
||||
"lcov"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/webpack-preprocessor": "^4.1.3",
|
||||
"@testing-library/react-hooks": "^3.2.1",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"cypress": "^4.2.0",
|
||||
"react-test-renderer": "^16.13.1",
|
||||
"svg-url-loader": "^5.0.0",
|
||||
"ts-loader": "^6.2.2",
|
||||
"webpack": "^4.42.1"
|
||||
}
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"cy:open": "cypress open",
|
||||
"cy:run": "cypress run",
|
||||
"lint": "tsc --noEmit && eslint 'src/*.{js,ts,tsx}' --fix",
|
||||
"test:cov": "react-scripts test --coverage --watchAll=false"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
},
|
||||
"jest": {
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"statements": 90
|
||||
}
|
||||
},
|
||||
"coverageReporters": [
|
||||
"lcov"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/webpack-preprocessor": "^4.1.3",
|
||||
"@testing-library/react-hooks": "^3.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^2.28.0",
|
||||
"@typescript-eslint/parser": "^2.28.0",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"cypress": "^4.2.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.10.1",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"prettier": "^2.0.4",
|
||||
"react-test-renderer": "^16.13.1",
|
||||
"svg-url-loader": "^5.0.0",
|
||||
"ts-loader": "^6.2.2",
|
||||
"webpack": "^4.42.1"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import App from './App';
|
||||
import React from 'react'
|
||||
import { render } from '@testing-library/react'
|
||||
import App from './App'
|
||||
|
||||
test('renders learn react link', () => {
|
||||
const { getByText } = render(<App />);
|
||||
const linkElement = getByText(/Login/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
const { getByText } = render(<App />)
|
||||
const linkElement = getByText(/Login/i)
|
||||
expect(linkElement).toBeInTheDocument()
|
||||
})
|
||||
+35
-35
@@ -1,39 +1,39 @@
|
||||
import React from "react";
|
||||
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
|
||||
import React from 'react'
|
||||
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
|
||||
|
||||
import Login from "./components/Login";
|
||||
import LandingPage from "./components/LandingPage";
|
||||
import PatientInfoPlaceholder from "./components/PatientInfoPlaceholder";
|
||||
import Wrapper from "./Wrapper";
|
||||
import Login from './components/Login'
|
||||
import LandingPage from './components/LandingPage'
|
||||
import PatientInfoPlaceholder from './components/PatientInfoPlaceholder'
|
||||
import Wrapper from './Wrapper'
|
||||
|
||||
import "./scss/App.scss";
|
||||
import "./antd-mobile.css";
|
||||
import './scss/App.scss'
|
||||
import './antd-mobile.css'
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route path="/login">
|
||||
<Login />
|
||||
</Route>
|
||||
<Route path="/landing">
|
||||
<LandingPage />
|
||||
</Route>
|
||||
<Route path="/patientinfo">
|
||||
<Wrapper
|
||||
navTitle="Patient Information"
|
||||
leftArrowText="Home"
|
||||
leftArrowRoute="/"
|
||||
>
|
||||
<PatientInfoPlaceholder />
|
||||
</Wrapper>
|
||||
</Route>
|
||||
<Route path="/">
|
||||
<Login />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
const App: React.FunctionComponent = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route path="/login">
|
||||
<Login />
|
||||
</Route>
|
||||
<Route path="/landing">
|
||||
<LandingPage />
|
||||
</Route>
|
||||
<Route path="/patientinfo">
|
||||
<Wrapper
|
||||
navTitle="Patient Information"
|
||||
leftArrowText="Home"
|
||||
leftArrowRoute="/"
|
||||
>
|
||||
<PatientInfoPlaceholder />
|
||||
</Wrapper>
|
||||
</Route>
|
||||
<Route path="/">
|
||||
<Login />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
)
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App
|
||||
+60
-59
@@ -1,74 +1,75 @@
|
||||
import React from "react";
|
||||
import { render, queryByAttribute, fireEvent } from "@testing-library/react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import Wrapper from "./Wrapper";
|
||||
import React from 'react'
|
||||
import { render, queryByAttribute, fireEvent } from '@testing-library/react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import Wrapper from './Wrapper'
|
||||
|
||||
const mockHistoryPush = jest.fn();
|
||||
jest.mock("react-router-dom", () => ({
|
||||
useHistory: () => ({
|
||||
push: mockHistoryPush,
|
||||
}),
|
||||
}));
|
||||
const mockHistoryPush = jest.fn()
|
||||
jest.mock('react-router-dom', () => ({
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
useHistory: () => ({
|
||||
push: mockHistoryPush,
|
||||
}),
|
||||
}))
|
||||
|
||||
test("renders it's inner contents", () => {
|
||||
const dom = render(
|
||||
<Wrapper leftArrowText="back">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>
|
||||
);
|
||||
const dom = render(
|
||||
<Wrapper leftArrowText="back">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>,
|
||||
)
|
||||
|
||||
const textContents = dom.getByText("Hello!");
|
||||
const textContents = dom.getByText('Hello!')
|
||||
|
||||
expect(textContents).toBeInTheDocument();
|
||||
});
|
||||
expect(textContents).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test("renders navBar when given navTitle", () => {
|
||||
const dom = render(
|
||||
<Wrapper navTitle="CHI">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>
|
||||
);
|
||||
test('renders navBar when given navTitle', () => {
|
||||
const dom = render(
|
||||
<Wrapper navTitle="CHI">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>,
|
||||
)
|
||||
|
||||
const getById = queryByAttribute.bind(null, "id");
|
||||
const renderedNavBar = getById(dom.container, "nav-bar");
|
||||
const navTitle = dom.getByText("CHI");
|
||||
const getById = queryByAttribute.bind(null, 'id')
|
||||
const renderedNavBar = getById(dom.container, 'nav-bar')
|
||||
const navTitle = dom.getByText('CHI')
|
||||
|
||||
expect(renderedNavBar).toBeTruthy();
|
||||
expect(navTitle).toBeInTheDocument();
|
||||
});
|
||||
expect(renderedNavBar).toBeTruthy()
|
||||
expect(navTitle).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test("renders no navBar when not given props", () => {
|
||||
const dom = render(
|
||||
<Wrapper>
|
||||
<div>Hello!</div>
|
||||
</Wrapper>
|
||||
);
|
||||
const getById = queryByAttribute.bind(null, "id");
|
||||
const renderedNavBar = getById(dom.container, "nav-bar");
|
||||
expect(renderedNavBar).toBeFalsy();
|
||||
});
|
||||
test('renders no navBar when not given props', () => {
|
||||
const dom = render(
|
||||
<Wrapper>
|
||||
<div>Hello!</div>
|
||||
</Wrapper>,
|
||||
)
|
||||
const getById = queryByAttribute.bind(null, 'id')
|
||||
const renderedNavBar = getById(dom.container, 'nav-bar')
|
||||
expect(renderedNavBar).toBeFalsy()
|
||||
})
|
||||
|
||||
test("renders leftArrowText", () => {
|
||||
const dom = render(
|
||||
<Wrapper leftArrowText="back">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>
|
||||
);
|
||||
test('renders leftArrowText', () => {
|
||||
const dom = render(
|
||||
<Wrapper leftArrowText="back">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>,
|
||||
)
|
||||
|
||||
const leftArrowText = dom.getByText("back");
|
||||
const leftArrowText = dom.getByText('back')
|
||||
|
||||
expect(leftArrowText).toBeInTheDocument();
|
||||
});
|
||||
expect(leftArrowText).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test("redirects on left arrow click ", () => {
|
||||
const dom = render(
|
||||
<Wrapper leftArrowText="back" leftArrowRoute="/">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>
|
||||
);
|
||||
test('redirects on left arrow click ', () => {
|
||||
const dom = render(
|
||||
<Wrapper leftArrowText="back" leftArrowRoute="/">
|
||||
<div>Hello!</div>
|
||||
</Wrapper>,
|
||||
)
|
||||
|
||||
const leftArrowText = dom.getByText("back");
|
||||
fireEvent.click(leftArrowText);
|
||||
const leftArrowText = dom.getByText('back')
|
||||
fireEvent.click(leftArrowText)
|
||||
|
||||
expect(useHistory().push).toBeCalledWith("/");
|
||||
});
|
||||
expect(useHistory().push).toBeCalledWith('/')
|
||||
})
|
||||
+39
-37
@@ -1,42 +1,44 @@
|
||||
import React from "react";
|
||||
import { NavBar, Icon } from "antd-mobile";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import React from 'react'
|
||||
import { NavBar, Icon } from 'antd-mobile'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
import "./scss/Wrapper.scss";
|
||||
import './scss/Wrapper.scss'
|
||||
|
||||
type props = {
|
||||
navTitle?: string;
|
||||
leftArrowText?: string;
|
||||
leftArrowRoute?: string;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
type WrapperProps = {
|
||||
navTitle?: string
|
||||
leftArrowText?: string
|
||||
leftArrowRoute?: string
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const Wrapper = (props: props) => {
|
||||
const { navTitle, leftArrowText, leftArrowRoute } = props;
|
||||
const hist = useHistory();
|
||||
const needNavBar = navTitle || leftArrowText || leftArrowRoute;
|
||||
const leftContentArr = leftArrowText
|
||||
? [<Icon type="left" />, `${leftArrowText}`]
|
||||
: [];
|
||||
const leftRoute = leftArrowRoute ? `${leftArrowRoute}` : "/";
|
||||
const Wrapper: React.FunctionComponent<WrapperProps> = (
|
||||
props: WrapperProps,
|
||||
) => {
|
||||
const { navTitle, leftArrowText, leftArrowRoute } = props
|
||||
const hist = useHistory()
|
||||
const needNavBar = navTitle || leftArrowText || leftArrowRoute
|
||||
const leftContentArr = leftArrowText
|
||||
? [<Icon key={1} type="left" />, `${leftArrowText}`]
|
||||
: []
|
||||
const leftRoute = leftArrowRoute ? `${leftArrowRoute}` : '/'
|
||||
|
||||
return (
|
||||
<div id="primary-wrapper">
|
||||
<div id="wrapper-contents">
|
||||
{needNavBar && (
|
||||
<NavBar
|
||||
id="nav-bar"
|
||||
mode="light"
|
||||
onLeftClick={() => hist.push(leftRoute)}
|
||||
leftContent={leftContentArr}
|
||||
>
|
||||
{`${navTitle}`}
|
||||
</NavBar>
|
||||
)}
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div id="primary-wrapper">
|
||||
<div id="wrapper-contents">
|
||||
{needNavBar && (
|
||||
<NavBar
|
||||
id="nav-bar"
|
||||
mode="light"
|
||||
onLeftClick={(): void => hist.push(leftRoute)}
|
||||
leftContent={leftContentArr}
|
||||
>
|
||||
{`${navTitle}`}
|
||||
</NavBar>
|
||||
)}
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Wrapper;
|
||||
export default Wrapper
|
||||
+5949
-5380
File diff suppressed because it is too large.
Load diff
Vendored
+7875
-2
File diff suppressed because it is too large.
Load diff
@@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
import LandingPage from "./LandingPage";
|
||||
import React from 'react'
|
||||
import { render } from '@testing-library/react'
|
||||
import LandingPage from './LandingPage'
|
||||
|
||||
test("renders learn react link", () => {
|
||||
const { getByText } = render(<LandingPage />);
|
||||
const lookupButtonElement = getByText(/Patient Lookup/i);
|
||||
const newPatientButtonElement = getByText(/New Patient/i);
|
||||
expect(lookupButtonElement).toBeInTheDocument();
|
||||
expect(newPatientButtonElement).toBeInTheDocument();
|
||||
});
|
||||
test('renders learn react link', () => {
|
||||
const { getByText } = render(<LandingPage />)
|
||||
const lookupButtonElement = getByText(/Patient Lookup/i)
|
||||
const newPatientButtonElement = getByText(/New Patient/i)
|
||||
expect(lookupButtonElement).toBeInTheDocument()
|
||||
expect(newPatientButtonElement).toBeInTheDocument()
|
||||
})
|
||||
@@ -1,35 +1,35 @@
|
||||
import React, { ReactElement } from "react";
|
||||
import { WhiteSpace, Button } from "antd-mobile";
|
||||
import { UserAddOutlined } from "@ant-design/icons";
|
||||
import React, { ReactElement } from 'react'
|
||||
import { WhiteSpace, Button } from 'antd-mobile'
|
||||
import { UserAddOutlined } from '@ant-design/icons'
|
||||
|
||||
import "../scss/LandingPage.scss";
|
||||
import '../scss/LandingPage.scss'
|
||||
|
||||
export default function LandingPage(): ReactElement {
|
||||
/* istanbul ignore next */
|
||||
// TODO: these onClick functions could be mocked in a unit test
|
||||
const patientLookup = () => {
|
||||
console.log("Clicked Patient Lookup");
|
||||
};
|
||||
/* istanbul ignore next */
|
||||
// TODO: these onClick functions could be mocked in a unit test
|
||||
const patientLookup = () => {
|
||||
console.log('Clicked Patient Lookup')
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
const newPatient = () => {
|
||||
console.log("Clicked New Patient");
|
||||
};
|
||||
return (
|
||||
<div id="landing-wrapper">
|
||||
<div className="button-flex">
|
||||
<Button onClick={patientLookup} icon="search">
|
||||
Patient Lookup
|
||||
</Button>
|
||||
<WhiteSpace />
|
||||
</div>
|
||||
<br />
|
||||
<div className="button-flex">
|
||||
<Button icon={<UserAddOutlined />} onClick={newPatient}>
|
||||
New Patient
|
||||
</Button>
|
||||
<WhiteSpace />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
/* istanbul ignore next */
|
||||
const newPatient = () => {
|
||||
console.log('Clicked New Patient')
|
||||
}
|
||||
return (
|
||||
<div id="landing-wrapper">
|
||||
<div className="button-flex">
|
||||
<Button onClick={patientLookup} icon="search">
|
||||
Patient Lookup
|
||||
</Button>
|
||||
<WhiteSpace />
|
||||
</div>
|
||||
<br />
|
||||
<div className="button-flex">
|
||||
<Button icon={<UserAddOutlined />} onClick={newPatient}>
|
||||
New Patient
|
||||
</Button>
|
||||
<WhiteSpace />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
import React, { ReactElement } from "react";
|
||||
import useApi from "../hooks/useApi";
|
||||
import { InputItem, Button } from "antd-mobile";
|
||||
import "../scss/Login.scss";
|
||||
import React, { ReactElement } from 'react'
|
||||
import useApi from '../hooks/useApi'
|
||||
import { InputItem, Button } from 'antd-mobile'
|
||||
import '../scss/Login.scss'
|
||||
|
||||
export default function Login(): ReactElement {
|
||||
const { response, isLoading } = useApi("");
|
||||
const { response, isLoading } = useApi('')
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="loginWrapper">
|
||||
<div id="loginGrid">
|
||||
<div id="iconCard">
|
||||
<div id="imgWrap">
|
||||
<img src="/logoIcon512.jpg" alt="CHI Logo"></img>
|
||||
return (
|
||||
<>
|
||||
<div id="loginWrapper">
|
||||
<div id="loginGrid">
|
||||
<div id="iconCard">
|
||||
<div id="imgWrap">
|
||||
<img src="/logoIcon512.jpg" alt="CHI Logo"></img>
|
||||
</div>
|
||||
</div>
|
||||
<InputItem placeholder="username" />
|
||||
<InputItem placeholder="password" type="password" />
|
||||
<div id="buttonFlex">
|
||||
<Button>Login</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<InputItem placeholder="username" />
|
||||
<InputItem placeholder="password" type="password" />
|
||||
<div id="buttonFlex">
|
||||
<Button>Login</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>Loading API Fetch: {isLoading.toString()}</p>
|
||||
{response && <p>API Fetch Result: {JSON.stringify(response)}</p>}
|
||||
</>
|
||||
);
|
||||
<p>Loading API Fetch: {isLoading.toString()}</p>
|
||||
{response && <p>API Fetch Result: {JSON.stringify(response)}</p>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
/* istanbul ignore file */
|
||||
import React, { ReactElement } from "react";
|
||||
import React, { ReactElement } from 'react'
|
||||
|
||||
export default function PatientInfoPlaceholder(): ReactElement {
|
||||
return (
|
||||
<img
|
||||
src="https://i.imgur.com/K5pR07w.png"
|
||||
alt="placeholder"
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
></img>
|
||||
);
|
||||
return (
|
||||
<img
|
||||
src="https://i.imgur.com/K5pR07w.png"
|
||||
alt="placeholder"
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
></img>
|
||||
)
|
||||
}
|
||||
@@ -1,28 +1,28 @@
|
||||
import { renderHook } from "@testing-library/react-hooks";
|
||||
import useApi from "./useApi";
|
||||
import { renderHook } from '@testing-library/react-hooks'
|
||||
import useApi from './useApi'
|
||||
|
||||
test("should return loading and then a response", async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useApi(""));
|
||||
test('should return loading and then a response', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useApi(''))
|
||||
|
||||
expect(result.current.response).toBeNull();
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.isLoading).toBeTruthy();
|
||||
expect(result.current.response).toBeNull()
|
||||
expect(result.current.error).toBeNull()
|
||||
expect(result.current.isLoading).toBeTruthy()
|
||||
|
||||
await waitForNextUpdate();
|
||||
await waitForNextUpdate()
|
||||
|
||||
expect(result.current.response).toBeTruthy();
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.isLoading).toBeFalsy();
|
||||
});
|
||||
expect(result.current.response).toBeTruthy()
|
||||
expect(result.current.error).toBeNull()
|
||||
expect(result.current.isLoading).toBeFalsy()
|
||||
})
|
||||
|
||||
test("should return an error on a non existent route", async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useApi("/404"));
|
||||
test('should return an error on a non existent route', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useApi('/404'))
|
||||
|
||||
expect(result.current.response).toBeNull();
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.response).toBeNull()
|
||||
expect(result.current.error).toBeNull()
|
||||
|
||||
await waitForNextUpdate();
|
||||
await waitForNextUpdate()
|
||||
|
||||
expect(result.current.response).toBeFalsy();
|
||||
expect(result.current.error).toBeTruthy();
|
||||
});
|
||||
expect(result.current.response).toBeFalsy()
|
||||
expect(result.current.error).toBeTruthy()
|
||||
})
|
||||
+29
-29
@@ -1,35 +1,35 @@
|
||||
import React from "react";
|
||||
import React from 'react'
|
||||
|
||||
const useApi = (route: string) => {
|
||||
const [response, setResponse] = React.useState(null);
|
||||
const [error, setError] = React.useState(null);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [response, setResponse] = React.useState(null)
|
||||
const [error, setError] = React.useState(null)
|
||||
const [isLoading, setIsLoading] = React.useState(false)
|
||||
|
||||
/* istanbul ignore next */
|
||||
const getUrl = () => {
|
||||
if (process.env.environment === "docker") {
|
||||
return "http://api:4000/";
|
||||
} else {
|
||||
return "http://localhost:4000/";
|
||||
/* istanbul ignore next */
|
||||
const getUrl = () => {
|
||||
if (process.env.environment === 'docker') {
|
||||
return 'http://api:4000/'
|
||||
} else {
|
||||
return 'http://localhost:4000/'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const res = await fetch(getUrl() + route);
|
||||
const json = await res.json();
|
||||
setResponse(json);
|
||||
setIsLoading(false);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
return { response, error, isLoading };
|
||||
};
|
||||
React.useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const res = await fetch(getUrl() + route)
|
||||
const json = await res.json()
|
||||
setResponse(json)
|
||||
setIsLoading(false)
|
||||
} catch (error) {
|
||||
setError(error)
|
||||
}
|
||||
}
|
||||
fetchData()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
return { response, error, isLoading }
|
||||
}
|
||||
|
||||
export default useApi;
|
||||
export default useApi
|
||||
+7
-7
@@ -1,13 +1,13 @@
|
||||
/* istanbul ignore file */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './scss/index.scss';
|
||||
import App from './App';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import './scss/index.scss'
|
||||
import App from './App'
|
||||
import * as serviceWorker from './serviceWorker'
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
ReactDOM.render(<App />, document.getElementById('root'))
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||
serviceWorker.register();
|
||||
serviceWorker.register()
|
||||
@@ -1,7 +1,7 @@
|
||||
.am-button:hover {
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100vh;
|
||||
height: 100vh;
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
.button-flex {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 2em 0;
|
||||
.am-button {
|
||||
background-color: #9bd7ff;
|
||||
width: 40%;
|
||||
&.am-button-active {
|
||||
background-color: #ccebff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 2em 0;
|
||||
.am-button {
|
||||
background-color: #9bd7ff;
|
||||
width: 40%;
|
||||
&.am-button-active {
|
||||
background-color: #ccebff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#landing-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
+66
-66
@@ -2,78 +2,78 @@
|
||||
// @include media("<desktop") {
|
||||
|
||||
#loginWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
height: 100%;
|
||||
padding: 0 2rem;
|
||||
#loginGrid {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 45%;
|
||||
#iconCard {
|
||||
animation-name: fade-in-from-up;
|
||||
animation-duration: 1.5s;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
#imgWrap {
|
||||
width: 28%;
|
||||
margin: auto;
|
||||
padding: 0.2rem;
|
||||
background-color: #eee;
|
||||
border-radius: 5px;
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 512px;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
height: 100%;
|
||||
padding: 0 2rem;
|
||||
#loginGrid {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 45%;
|
||||
#iconCard {
|
||||
animation-name: fade-in-from-up;
|
||||
animation-duration: 1.5s;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
#imgWrap {
|
||||
width: 28%;
|
||||
margin: auto;
|
||||
padding: 0.2rem;
|
||||
background-color: #eee;
|
||||
border-radius: 5px;
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 512px;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
input {
|
||||
animation-name: fade-in;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
#buttonFlex {
|
||||
animation-name: fade-in;
|
||||
animation-duration: 2s;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.am-button {
|
||||
background-color: #9bd7ff;
|
||||
width: 40%;
|
||||
&.am-button-active {
|
||||
background-color: #ccebff;
|
||||
input {
|
||||
animation-name: fade-in;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
#buttonFlex {
|
||||
animation-name: fade-in;
|
||||
animation-duration: 2s;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.am-button {
|
||||
background-color: #9bd7ff;
|
||||
width: 40%;
|
||||
&.am-button-active {
|
||||
background-color: #ccebff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$animationDelay: 1;
|
||||
@for $i from 1 through 15 {
|
||||
.loginGrid :nth-child(#{$i}) {
|
||||
animation-delay: #{0.3+ ($i)/30}s;
|
||||
$animationDelay: 1;
|
||||
@for $i from 1 through 15 {
|
||||
.loginGrid :nth-child(#{$i}) {
|
||||
animation-delay: #{0.3+ ($i)/30}s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in-from-up {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-100px);
|
||||
@keyframes fade-in-from-up {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-100px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
#primary-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
#wrapper-contents {
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
max-width: 50em;
|
||||
max-height: 94.6vh;
|
||||
}
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
#wrapper-contents {
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2),
|
||||
0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
max-width: 50em;
|
||||
max-height: 94.6vh;
|
||||
}
|
||||
}
|
||||
+200
-170
@@ -22,7 +22,6 @@
|
||||
/// @access public
|
||||
////
|
||||
|
||||
|
||||
///
|
||||
/// Creates a list of global breakpoints
|
||||
///
|
||||
@@ -30,12 +29,11 @@
|
||||
/// $breakpoints: ('phone': 320px);
|
||||
///
|
||||
$breakpoints: (
|
||||
'phone': 320px,
|
||||
'tablet': 768px,
|
||||
'desktop': 1024px
|
||||
'phone': 320px,
|
||||
'tablet': 768px,
|
||||
'desktop': 1024px,
|
||||
) !default;
|
||||
|
||||
|
||||
///
|
||||
/// Creates a list of static expressions or media types
|
||||
///
|
||||
@@ -48,16 +46,17 @@ $breakpoints: (
|
||||
/// );
|
||||
///
|
||||
$media-expressions: (
|
||||
'screen': 'screen',
|
||||
'print': 'print',
|
||||
'handheld': 'handheld',
|
||||
'landscape': '(orientation: landscape)',
|
||||
'portrait': '(orientation: portrait)',
|
||||
'retina2x': '(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi), (min-resolution: 2dppx)',
|
||||
'retina3x': '(-webkit-min-device-pixel-ratio: 3), (min-resolution: 350dpi), (min-resolution: 3dppx)'
|
||||
'screen': 'screen',
|
||||
'print': 'print',
|
||||
'handheld': 'handheld',
|
||||
'landscape': '(orientation: landscape)',
|
||||
'portrait': '(orientation: portrait)',
|
||||
'retina2x':
|
||||
'(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi), (min-resolution: 2dppx)',
|
||||
'retina3x':
|
||||
'(-webkit-min-device-pixel-ratio: 3), (min-resolution: 350dpi), (min-resolution: 3dppx)',
|
||||
) !default;
|
||||
|
||||
|
||||
///
|
||||
/// Defines a number to be added or subtracted from each unit when declaring breakpoints with exclusive intervals
|
||||
///
|
||||
@@ -80,10 +79,10 @@ $media-expressions: (
|
||||
/// @media (min-width: 2.1rem) {}
|
||||
///
|
||||
$unit-intervals: (
|
||||
'px': 1,
|
||||
'em': 0.01,
|
||||
'rem': 0.1,
|
||||
'': 0
|
||||
'px': 1,
|
||||
'em': 0.01,
|
||||
'rem': 0.1,
|
||||
'': 0,
|
||||
) !default;
|
||||
|
||||
///
|
||||
@@ -175,7 +174,6 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @access private
|
||||
////
|
||||
|
||||
|
||||
///
|
||||
/// Log a message either with `@error` if supported
|
||||
/// else with `@warn`, using `feature-exists('at-error')`
|
||||
@@ -184,17 +182,16 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @param {String} $message - Message to log
|
||||
///
|
||||
@function im-log($message) {
|
||||
@if feature-exists('at-error') {
|
||||
@error $message;
|
||||
} @else {
|
||||
@warn $message;
|
||||
$_: noop();
|
||||
}
|
||||
@if feature-exists('at-error') {
|
||||
@error $message;
|
||||
} @else {
|
||||
@warn $message;
|
||||
$_: noop();
|
||||
}
|
||||
|
||||
@return $message;
|
||||
@return $message;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Wrapper mixin for the log function so it can be used with a more friendly
|
||||
/// API than `@if im-log('..') {}` or `$_: im-log('..')`. Basically, use the function
|
||||
@@ -204,15 +201,16 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @param {String} $message - Message to log
|
||||
///
|
||||
@mixin log($message) {
|
||||
@if im-log($message) {}
|
||||
@if im-log($message) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Function with no `@return` called next to `@warn` in Sass 3.3
|
||||
/// to trigger a compiling error and stop the process.
|
||||
///
|
||||
@function noop() {}
|
||||
@function noop() {
|
||||
}
|
||||
|
||||
///
|
||||
/// Determines whether a list of conditions is intercepted by the static breakpoint.
|
||||
@@ -222,28 +220,30 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {Boolean} - Returns true if the conditions are intercepted by the static breakpoint
|
||||
///
|
||||
@function im-intercepts-static-breakpoint($conditions...) {
|
||||
$no-media-breakpoint-value: map-get($breakpoints, $im-no-media-breakpoint);
|
||||
$no-media-breakpoint-value: map-get($breakpoints, $im-no-media-breakpoint);
|
||||
|
||||
@if not $no-media-breakpoint-value {
|
||||
@if im-log('`#{$im-no-media-breakpoint}` is not a valid breakpoint.') {}
|
||||
}
|
||||
|
||||
@each $condition in $conditions {
|
||||
@if not map-has-key($media-expressions, $condition) {
|
||||
$operator: get-expression-operator($condition);
|
||||
$prefix: get-expression-prefix($operator);
|
||||
$value: get-expression-value($condition, $operator);
|
||||
|
||||
@if ($prefix == 'max' and $value <= $no-media-breakpoint-value) or
|
||||
($prefix == 'min' and $value > $no-media-breakpoint-value) {
|
||||
@return false;
|
||||
}
|
||||
} @else if not index($im-no-media-expressions, $condition) {
|
||||
@return false;
|
||||
@if not $no-media-breakpoint-value {
|
||||
@if im-log('`#{$im-no-media-breakpoint}` is not a valid breakpoint.') {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@return true;
|
||||
@each $condition in $conditions {
|
||||
@if not map-has-key($media-expressions, $condition) {
|
||||
$operator: get-expression-operator($condition);
|
||||
$prefix: get-expression-prefix($operator);
|
||||
$value: get-expression-value($condition, $operator);
|
||||
|
||||
@if ($prefix == 'max' and $value <= $no-media-breakpoint-value) or
|
||||
($prefix == 'min' and $value > $no-media-breakpoint-value)
|
||||
{
|
||||
@return false;
|
||||
}
|
||||
} @else if not index($im-no-media-expressions, $condition) {
|
||||
@return false;
|
||||
}
|
||||
}
|
||||
|
||||
@return true;
|
||||
}
|
||||
|
||||
////
|
||||
@@ -252,7 +252,6 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @access private
|
||||
////
|
||||
|
||||
|
||||
///
|
||||
/// Get operator of an expression
|
||||
///
|
||||
@@ -261,21 +260,20 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {String} - Any of `>=`, `>`, `<=`, `<`, `≥`, `≤`
|
||||
///
|
||||
@function get-expression-operator($expression) {
|
||||
@each $operator in ('>=', '>', '<=', '<', '≥', '≤') {
|
||||
@if str-index($expression, $operator) {
|
||||
@return $operator;
|
||||
@each $operator in ('>=', '>', '<=', '<', '≥', '≤') {
|
||||
@if str-index($expression, $operator) {
|
||||
@return $operator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It is not possible to include a mixin inside a function, so we have to
|
||||
// rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
|
||||
// functions cannot be called anywhere in Sass, we need to hack the call in
|
||||
// a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
|
||||
// Sass 3.3, change this line in `@if im-log(..) {}` instead.
|
||||
$_: im-log('No operator found in `#{$expression}`.');
|
||||
// It is not possible to include a mixin inside a function, so we have to
|
||||
// rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
|
||||
// functions cannot be called anywhere in Sass, we need to hack the call in
|
||||
// a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
|
||||
// Sass 3.3, change this line in `@if im-log(..) {}` instead.
|
||||
$_: im-log('No operator found in `#{$expression}`.');
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Get dimension of an expression, based on a found operator
|
||||
///
|
||||
@@ -285,18 +283,17 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {String} - `width` or `height` (or potentially anything else)
|
||||
///
|
||||
@function get-expression-dimension($expression, $operator) {
|
||||
$operator-index: str-index($expression, $operator);
|
||||
$parsed-dimension: str-slice($expression, 0, $operator-index - 1);
|
||||
$dimension: 'width';
|
||||
$operator-index: str-index($expression, $operator);
|
||||
$parsed-dimension: str-slice($expression, 0, $operator-index - 1);
|
||||
$dimension: 'width';
|
||||
|
||||
@if str-length($parsed-dimension) > 0 {
|
||||
$dimension: $parsed-dimension;
|
||||
}
|
||||
@if str-length($parsed-dimension) > 0 {
|
||||
$dimension: $parsed-dimension;
|
||||
}
|
||||
|
||||
@return $dimension;
|
||||
@return $dimension;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Get dimension prefix based on an operator
|
||||
///
|
||||
@@ -305,10 +302,9 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {String} - `min` or `max`
|
||||
///
|
||||
@function get-expression-prefix($operator) {
|
||||
@return if(index(('<', '<=', '≤'), $operator), 'max', 'min');
|
||||
@return if(index(('<', '<=', '≤'), $operator), 'max', 'min');
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Get value of an expression, based on a found operator
|
||||
///
|
||||
@@ -318,36 +314,35 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {Number} - A numeric value
|
||||
///
|
||||
@function get-expression-value($expression, $operator) {
|
||||
$operator-index: str-index($expression, $operator);
|
||||
$value: str-slice($expression, $operator-index + str-length($operator));
|
||||
$operator-index: str-index($expression, $operator);
|
||||
$value: str-slice($expression, $operator-index + str-length($operator));
|
||||
|
||||
@if map-has-key($breakpoints, $value) {
|
||||
$value: map-get($breakpoints, $value);
|
||||
} @else {
|
||||
$value: to-number($value);
|
||||
}
|
||||
@if map-has-key($breakpoints, $value) {
|
||||
$value: map-get($breakpoints, $value);
|
||||
} @else {
|
||||
$value: to-number($value);
|
||||
}
|
||||
|
||||
$interval: map-get($unit-intervals, unit($value));
|
||||
$interval: map-get($unit-intervals, unit($value));
|
||||
|
||||
@if not $interval {
|
||||
// It is not possible to include a mixin inside a function, so we have to
|
||||
// rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
|
||||
// functions cannot be called anywhere in Sass, we need to hack the call in
|
||||
// a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
|
||||
// Sass 3.3, change this line in `@if im-log(..) {}` instead.
|
||||
$_: im-log('Unknown unit `#{unit($value)}`.');
|
||||
}
|
||||
@if not $interval {
|
||||
// It is not possible to include a mixin inside a function, so we have to
|
||||
// rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
|
||||
// functions cannot be called anywhere in Sass, we need to hack the call in
|
||||
// a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
|
||||
// Sass 3.3, change this line in `@if im-log(..) {}` instead.
|
||||
$_: im-log('Unknown unit `#{unit($value)}`.');
|
||||
}
|
||||
|
||||
@if $operator == '>' {
|
||||
$value: $value + $interval;
|
||||
} @else if $operator == '<' {
|
||||
$value: $value - $interval;
|
||||
}
|
||||
@if $operator == '>' {
|
||||
$value: $value + $interval;
|
||||
} @else if $operator == '<' {
|
||||
$value: $value - $interval;
|
||||
}
|
||||
|
||||
@return $value;
|
||||
@return $value;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Parse an expression to return a valid media-query expression
|
||||
///
|
||||
@@ -356,18 +351,18 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {String} - Valid media query
|
||||
///
|
||||
@function parse-expression($expression) {
|
||||
// If it is part of $media-expressions, it has no operator
|
||||
// then there is no need to go any further, just return the value
|
||||
@if map-has-key($media-expressions, $expression) {
|
||||
@return map-get($media-expressions, $expression);
|
||||
}
|
||||
// If it is part of $media-expressions, it has no operator
|
||||
// then there is no need to go any further, just return the value
|
||||
@if map-has-key($media-expressions, $expression) {
|
||||
@return map-get($media-expressions, $expression);
|
||||
}
|
||||
|
||||
$operator: get-expression-operator($expression);
|
||||
$dimension: get-expression-dimension($expression, $operator);
|
||||
$prefix: get-expression-prefix($operator);
|
||||
$value: get-expression-value($expression, $operator);
|
||||
$operator: get-expression-operator($expression);
|
||||
$dimension: get-expression-dimension($expression, $operator);
|
||||
$prefix: get-expression-prefix($operator);
|
||||
$value: get-expression-value($expression, $operator);
|
||||
|
||||
@return '(#{$prefix}-#{$dimension}: #{$value})';
|
||||
@return '(#{$prefix}-#{$dimension}: #{$value})';
|
||||
}
|
||||
|
||||
///
|
||||
@@ -382,17 +377,17 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {List} Sliced list
|
||||
///
|
||||
@function slice($list, $start: 1, $end: length($list)) {
|
||||
@if length($list) < 1 or $start > $end {
|
||||
@return ();
|
||||
}
|
||||
@if length($list) < 1 or $start > $end {
|
||||
@return ();
|
||||
}
|
||||
|
||||
$result: ();
|
||||
$result: ();
|
||||
|
||||
@for $i from $start through $end {
|
||||
$result: append($result, nth($list, $i));
|
||||
}
|
||||
@for $i from $start through $end {
|
||||
$result: append($result, nth($list, $i));
|
||||
}
|
||||
|
||||
@return $result;
|
||||
@return $result;
|
||||
}
|
||||
|
||||
////
|
||||
@@ -401,7 +396,6 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @access private
|
||||
////
|
||||
|
||||
|
||||
///
|
||||
/// Casts a string into a number
|
||||
///
|
||||
@@ -410,44 +404,57 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {Number}
|
||||
///
|
||||
@function to-number($value) {
|
||||
@if type-of($value) == 'number' {
|
||||
@return $value;
|
||||
} @else if type-of($value) != 'string' {
|
||||
$_: im-log('Value for `to-number` should be a number or a string.');
|
||||
}
|
||||
|
||||
$first-character: str-slice($value, 1, 1);
|
||||
$result: 0;
|
||||
$digits: 0;
|
||||
$minus: ($first-character == '-');
|
||||
$numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);
|
||||
|
||||
// Remove +/- sign if present at first character
|
||||
@if ($first-character == '+' or $first-character == '-') {
|
||||
$value: str-slice($value, 2);
|
||||
}
|
||||
|
||||
@for $i from 1 through str-length($value) {
|
||||
$character: str-slice($value, $i, $i);
|
||||
|
||||
@if not (index(map-keys($numbers), $character) or $character == '.') {
|
||||
@return to-length(if($minus, -$result, $result), str-slice($value, $i))
|
||||
@if type-of($value) == 'number' {
|
||||
@return $value;
|
||||
} @else if type-of($value) != 'string' {
|
||||
$_: im-log('Value for `to-number` should be a number or a string.');
|
||||
}
|
||||
|
||||
@if $character == '.' {
|
||||
$digits: 1;
|
||||
} @else if $digits == 0 {
|
||||
$result: $result * 10 + map-get($numbers, $character);
|
||||
} @else {
|
||||
$digits: $digits * 10;
|
||||
$result: $result + map-get($numbers, $character) / $digits;
|
||||
}
|
||||
}
|
||||
$first-character: str-slice($value, 1, 1);
|
||||
$result: 0;
|
||||
$digits: 0;
|
||||
$minus: ($first-character == '-');
|
||||
$numbers: (
|
||||
'0': 0,
|
||||
'1': 1,
|
||||
'2': 2,
|
||||
'3': 3,
|
||||
'4': 4,
|
||||
'5': 5,
|
||||
'6': 6,
|
||||
'7': 7,
|
||||
'8': 8,
|
||||
'9': 9,
|
||||
);
|
||||
|
||||
@return if($minus, -$result, $result);
|
||||
// Remove +/- sign if present at first character
|
||||
@if ($first-character == '+' or $first-character == '-') {
|
||||
$value: str-slice($value, 2);
|
||||
}
|
||||
|
||||
@for $i from 1 through str-length($value) {
|
||||
$character: str-slice($value, $i, $i);
|
||||
|
||||
@if not(index(map-keys($numbers), $character) or $character == '.') {
|
||||
@return to-length(
|
||||
if($minus, -$result, $result),
|
||||
str-slice($value, $i)
|
||||
);
|
||||
}
|
||||
|
||||
@if $character == '.' {
|
||||
$digits: 1;
|
||||
} @else if $digits == 0 {
|
||||
$result: $result * 10 + map-get($numbers, $character);
|
||||
} @else {
|
||||
$digits: $digits * 10;
|
||||
$result: $result + map-get($numbers, $character) / $digits;
|
||||
}
|
||||
}
|
||||
|
||||
@return if($minus, -$result, $result);
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Add `$unit` to `$value`
|
||||
///
|
||||
@@ -457,13 +464,29 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @return {Number} - `$value` expressed in `$unit`
|
||||
///
|
||||
@function to-length($value, $unit) {
|
||||
$units: ('px': 1px, 'cm': 1cm, 'mm': 1mm, '%': 1%, 'ch': 1ch, 'pc': 1pc, 'in': 1in, 'em': 1em, 'rem': 1rem, 'pt': 1pt, 'ex': 1ex, 'vw': 1vw, 'vh': 1vh, 'vmin': 1vmin, 'vmax': 1vmax);
|
||||
$units: (
|
||||
'px': 1px,
|
||||
'cm': 1cm,
|
||||
'mm': 1mm,
|
||||
'%': 1%,
|
||||
'ch': 1ch,
|
||||
'pc': 1pc,
|
||||
'in': 1in,
|
||||
'em': 1em,
|
||||
'rem': 1rem,
|
||||
'pt': 1pt,
|
||||
'ex': 1ex,
|
||||
'vw': 1vw,
|
||||
'vh': 1vh,
|
||||
'vmin': 1vmin,
|
||||
'vmax': 1vmax,
|
||||
);
|
||||
|
||||
@if not index(map-keys($units), $unit) {
|
||||
$_: im-log('Invalid unit `#{$unit}`.');
|
||||
}
|
||||
@if not index(map-keys($units), $unit) {
|
||||
$_: im-log('Invalid unit `#{$unit}`.');
|
||||
}
|
||||
|
||||
@return $value * map-get($units, $unit);
|
||||
@return $value * map-get($units, $unit);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -505,19 +528,22 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// }
|
||||
///
|
||||
@mixin media-context($tweakpoints: (), $tweak-media-expressions: ()) {
|
||||
// Save global configuration
|
||||
$global-breakpoints: $breakpoints;
|
||||
$global-media-expressions: $media-expressions;
|
||||
// Save global configuration
|
||||
$global-breakpoints: $breakpoints;
|
||||
$global-media-expressions: $media-expressions;
|
||||
|
||||
// Update global configuration
|
||||
$breakpoints: map-merge($breakpoints, $tweakpoints) !global;
|
||||
$media-expressions: map-merge($media-expressions, $tweak-media-expressions) !global;
|
||||
// Update global configuration
|
||||
$breakpoints: map-merge($breakpoints, $tweakpoints) !global;
|
||||
$media-expressions: map-merge(
|
||||
$media-expressions,
|
||||
$tweak-media-expressions
|
||||
) !global;
|
||||
|
||||
@content;
|
||||
@content;
|
||||
|
||||
// Restore global configuration
|
||||
$breakpoints: $global-breakpoints !global;
|
||||
$media-expressions: $global-media-expressions !global;
|
||||
// Restore global configuration
|
||||
$breakpoints: $global-breakpoints !global;
|
||||
$media-expressions: $global-media-expressions !global;
|
||||
}
|
||||
|
||||
////
|
||||
@@ -526,7 +552,6 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @access public
|
||||
////
|
||||
|
||||
|
||||
///
|
||||
/// Generates a media query based on a list of conditions
|
||||
///
|
||||
@@ -551,15 +576,20 @@ $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
|
||||
/// @include media('>=350px', '<tablet', 'retina3x') { }
|
||||
///
|
||||
@mixin media($conditions...) {
|
||||
@if ($im-media-support and length($conditions) == 0) or
|
||||
(not $im-media-support and im-intercepts-static-breakpoint($conditions...)) {
|
||||
@content;
|
||||
} @else if ($im-media-support and length($conditions) > 0) {
|
||||
@media #{unquote(parse-expression(nth($conditions, 1)))} {
|
||||
// Recursive call
|
||||
@include media(slice($conditions, 2)...) {
|
||||
@if ($im-media-support and length($conditions) == 0) or
|
||||
(
|
||||
not
|
||||
$im-media-support and
|
||||
im-intercepts-static-breakpoint($conditions...)
|
||||
)
|
||||
{
|
||||
@content;
|
||||
}
|
||||
} @else if ($im-media-support and length($conditions) > 0) {
|
||||
@media #{unquote(parse-expression(nth($conditions, 1)))} {
|
||||
// Recursive call
|
||||
@include media(slice($conditions, 2) ...) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -1,16 +1,16 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-color: #e8ffd9;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
|
||||
'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
|
||||
'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-color: #e8ffd9;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
+112
-113
@@ -1,4 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
// This optional code is used to register a service worker.
|
||||
// register() is not called by default.
|
||||
|
||||
@@ -12,135 +13,133 @@
|
||||
// opt-in, read https://bit.ly/CRA-PWA
|
||||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
|
||||
),
|
||||
)
|
||||
|
||||
type Config = {
|
||||
onSuccess?: (registration: ServiceWorkerRegistration) => void;
|
||||
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
||||
};
|
||||
onSuccess?: (registration: ServiceWorkerRegistration) => void
|
||||
onUpdate?: (registration: ServiceWorkerRegistration) => void
|
||||
}
|
||||
|
||||
export function register(config?: Config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(
|
||||
process.env.PUBLIC_URL,
|
||||
window.location.href
|
||||
);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config)
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA',
|
||||
)
|
||||
})
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl: string, config?: Config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||
);
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing
|
||||
if (installingWorker == null) {
|
||||
return
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
|
||||
)
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration)
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.')
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error during service worker registration:', error)
|
||||
})
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { 'Service-Worker': 'script' }
|
||||
})
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { 'Service-Worker': 'script' },
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
);
|
||||
});
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type')
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null &&
|
||||
contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.',
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,4 @@
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import '@testing-library/jest-dom/extend-expect'
|
||||
Reference in new issue
Block a user