koffing 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/Makefile +21 -0
  2. package/README.md +75 -26
  3. package/build/asset-manifest.json +22 -0
  4. package/build/favicon.png +0 -0
  5. package/build/index.html +1 -0
  6. package/build/precache-manifest.5382b78dea2866c8a94cee003da35d84.js +26 -0
  7. package/build/robots.txt +3 -0
  8. package/build/service-worker.js +39 -0
  9. package/build/static/css/main.102b9840.chunk.css +2 -0
  10. package/build/static/css/main.102b9840.chunk.css.map +1 -0
  11. package/build/static/js/2.4b3dd85a.chunk.js +3 -0
  12. package/build/static/js/2.4b3dd85a.chunk.js.LICENSE.txt +67 -0
  13. package/build/static/js/2.4b3dd85a.chunk.js.map +1 -0
  14. package/build/static/js/main.07f66bec.chunk.js +2 -0
  15. package/build/static/js/main.07f66bec.chunk.js.map +1 -0
  16. package/build/static/js/runtime-main.525bb0ff.js +2 -0
  17. package/build/static/js/runtime-main.525bb0ff.js.map +1 -0
  18. package/package.json +42 -31
  19. package/public/favicon.png +0 -0
  20. package/public/index.html +30 -0
  21. package/public/robots.txt +3 -0
  22. package/src/App.test.js +9 -0
  23. package/src/components/App.js +18 -0
  24. package/src/components/AppFooter/AppFooter.css.js +12 -0
  25. package/src/components/AppFooter/AppFooter.js +31 -0
  26. package/src/components/AppFooter/index.js +3 -0
  27. package/src/components/AppHeader/AppHeader.css.js +21 -0
  28. package/src/components/AppHeader/AppHeader.js +34 -0
  29. package/src/components/AppHeader/index.js +3 -0
  30. package/src/components/Board/Board.css.js +21 -0
  31. package/src/components/Board/Board.js +110 -0
  32. package/src/components/Board/index.js +3 -0
  33. package/src/components/BoardInput/BoardInput.css.js +14 -0
  34. package/src/components/BoardInput/BoardInput.js +36 -0
  35. package/src/components/BoardInput/index.js +3 -0
  36. package/src/components/BoardOutput/BoardOutput.css.js +17 -0
  37. package/src/components/BoardOutput/BoardOutput.js +36 -0
  38. package/src/components/BoardOutput/index.js +3 -0
  39. package/src/components/Code/Code.css.js +10 -0
  40. package/src/components/Code/Code.js +28 -0
  41. package/src/components/Code/index.js +3 -0
  42. package/src/components/StyledComponent.js +24 -0
  43. package/src/components/ThemedApp.js +25 -0
  44. package/src/core/Koffing.js +71 -0
  45. package/src/{Pokemon.js → core/Pokemon.js} +9 -2
  46. package/src/{PokemonTeam.js → core/PokemonTeam.js} +0 -2
  47. package/src/{PokemonTeamSet.js → core/PokemonTeamSet.js} +0 -2
  48. package/src/{ShowdownParser.js → core/ShowdownParser.js} +7 -8
  49. package/src/core/index.js +7 -0
  50. package/src/img/koffing-shiny.png +0 -0
  51. package/src/img/koffing.png +0 -0
  52. package/src/index.css +42 -0
  53. package/src/index.js +15 -74
  54. package/src/serviceWorker.js +141 -0
  55. package/src/setupTests.js +5 -0
  56. package/src/teams/example.koffing.js +25 -0
  57. package/src/tools/base64.js +25 -0
  58. package/src/tools/history.js +17 -0
  59. package/src/tools/index.js +4 -0
  60. package/src/variables.json +5 -0
  61. package/dist/koffing.js +0 -940
  62. package/dist/koffing.min.js +0 -1
@@ -0,0 +1,14 @@
1
+ import {makeStyles} from '@material-ui/core/styles';
2
+
3
+ export default makeStyles((theme) => ({
4
+ root: {
5
+ marginTop: 0,
6
+ overflow: 'hidden'
7
+ },
8
+ textArea: {
9
+ fontFamily: "monospace",
10
+ fontSize: "1em",
11
+ backgroundColor: theme.palette.secondary.main,
12
+ padding: theme.spacing()
13
+ }
14
+ }))
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import PropTypes from "prop-types";
3
+ import TextField from "@material-ui/core/TextField";
4
+ import useStyles from "./BoardInput.css";
5
+
6
+ function BoardInput({value, onChange}) {
7
+ const classes = useStyles();
8
+
9
+ return <TextField
10
+ autoComplete="off"
11
+ autoCorrect="off"
12
+ autoCapitalize="off"
13
+ spellCheck="false"
14
+ multiline
15
+ className={classes.root}
16
+ rows="12"
17
+ rowsMax="24"
18
+ autoFocus={true}
19
+ placeholder="Place here your Showdown teams"
20
+ // defaultValue={exampleTeam}
21
+ fullWidth
22
+ margin="normal"
23
+ value={value}
24
+ inputProps={{
25
+ className: classes.textArea
26
+ }}
27
+ onChange={onChange}
28
+ />
29
+ }
30
+
31
+ BoardInput.propTypes = {
32
+ value: PropTypes.string.isRequired,
33
+ onChange: PropTypes.func
34
+ }
35
+
36
+ export default BoardInput;
@@ -0,0 +1,3 @@
1
+ import BoardInput from './BoardInput';
2
+
3
+ export default BoardInput;
@@ -0,0 +1,17 @@
1
+ import {makeStyles} from '@material-ui/core/styles';
2
+
3
+ export default makeStyles((theme) => ({
4
+ root: {
5
+ padding: theme.spacing() * 2,
6
+ color: theme.palette.text.secondary
7
+ },
8
+ qrContainer: {
9
+ padding: theme.spacing() * 2,
10
+ textAlign: "center",
11
+ backgroundColor: "#dde0f6"
12
+ },
13
+ jsonContainer: {
14
+ padding: theme.spacing() * 2,
15
+ backgroundColor: "#fafafa"
16
+ }
17
+ }))
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import Paper from "@material-ui/core/Paper";
4
+ import QRCode from "qrcode.react";
5
+ import Code from "../Code";
6
+ import useStyles from "./BoardOutput.css";
7
+ import logo from "../../img/koffing.png";
8
+
9
+ const qrIconSettings = {
10
+ src: logo,
11
+ height: 48,
12
+ width: 48,
13
+ excavate: true
14
+ }
15
+
16
+ function BoardOutput({qrValue, jsonValue}) {
17
+ const classes = useStyles();
18
+
19
+ return (
20
+ <Paper className={classes.root} elevation={1}>
21
+ <Paper className={classes.qrContainer}>
22
+ <QRCode value={qrValue} size={320} renderAs="canvas" imageSettings={qrIconSettings}/>
23
+ </Paper>
24
+ <Paper className={classes.jsonContainer}>
25
+ <Code code={jsonValue} language={'json'}/>
26
+ </Paper>
27
+ </Paper>
28
+ );
29
+ }
30
+
31
+ BoardOutput.propTypes = {
32
+ qrValue: PropTypes.string.isRequired,
33
+ jsonValue: PropTypes.string.isRequired
34
+ }
35
+
36
+ export default BoardOutput;
@@ -0,0 +1,3 @@
1
+ import BoardOutput from './BoardOutput';
2
+
3
+ export default BoardOutput;
@@ -0,0 +1,10 @@
1
+ export default {
2
+ root: {
3
+ margin: '6px 0'
4
+ },
5
+ pre: {
6
+ margin: 0,
7
+ border: 'none !important',
8
+ color: '#008008'
9
+ }
10
+ }
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import StyledComponent from "../StyledComponent";
4
+ import styles from "./Code.css";
5
+
6
+ class Code extends StyledComponent {
7
+ static propTypes = Object.assign({}, super.propTypes, {
8
+ language: PropTypes.string.isRequired,
9
+ code: PropTypes.string.isRequired,
10
+ })
11
+
12
+ render() {
13
+ const formattedCode = this.props.code;
14
+ const codeClassName = `language-${this.props.language}`;
15
+ const {classes} = this.props;
16
+ return (
17
+ <div className={classes.root}>
18
+ <pre className={classes.pre}>
19
+ <code className={codeClassName}>
20
+ <div dangerouslySetInnerHTML={{__html: formattedCode}}/>
21
+ </code>
22
+ </pre>
23
+ </div>
24
+ );
25
+ }
26
+ }
27
+
28
+ export default Code.styled(styles);
@@ -0,0 +1,3 @@
1
+ import Code from './Code';
2
+
3
+ export default Code;
@@ -0,0 +1,24 @@
1
+ import {Component} from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import {withStyles} from '@material-ui/core/styles';
4
+ // eslint-disable-next-line no-unused-vars
5
+ import {StyledComponentProps} from '@material-ui/styles/withStyles'
6
+
7
+ /**
8
+ * @link https://material-ui.com/es/styles/basics/#higher-order-component-api
9
+ */
10
+ class StyledComponent extends Component {
11
+ static propTypes = {
12
+ classes: PropTypes.object.isRequired
13
+ }
14
+
15
+ /**
16
+ * @param {object} styles
17
+ * @returns {React.ComponentType<any & StyledComponentProps<T>>}
18
+ */
19
+ static styled(styles) {
20
+ return withStyles(styles)(this);
21
+ }
22
+ }
23
+
24
+ export default StyledComponent;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import {createMuiTheme, MuiThemeProvider} from '@material-ui/core/styles';
3
+ import App from "./App";
4
+
5
+ const theme = createMuiTheme({
6
+ typography: {
7
+ fontFamily: '"Exo 2","Helvetica Neue",Arial,sans-serif',
8
+ },
9
+ palette: {
10
+ primary: {main: '#6B71B8'},
11
+ secondary: {main: '#F6F79D'},
12
+ },
13
+ });
14
+
15
+
16
+ const ThemedApp = () => (
17
+ <div className="koffing-app-container">
18
+ {/*<CssBaseline/>*//* MUI adds the reset at the end, which is not what we want*/}
19
+ <MuiThemeProvider theme={theme}>
20
+ <App/>
21
+ </MuiThemeProvider>
22
+ </div>
23
+ );
24
+
25
+ export default ThemedApp;
@@ -0,0 +1,71 @@
1
+ import Pokemon from "./Pokemon";
2
+ import PokemonTeam from "./PokemonTeam";
3
+ import PokemonTeamSet from "./PokemonTeamSet";
4
+ import ShowdownParser from "./ShowdownParser";
5
+
6
+ class Koffing {
7
+ /**
8
+ * Converts from Showdown to a PokemonTeamSet object.
9
+ *
10
+ * @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
11
+ * @returns {PokemonTeamSet}
12
+ */
13
+ static parse(data) {
14
+ if (
15
+ data instanceof PokemonTeamSet
16
+ || data instanceof PokemonTeam
17
+ || data instanceof Pokemon
18
+ ) {
19
+ return data;
20
+ }
21
+ if (data instanceof ShowdownParser) {
22
+ return data.parse();
23
+ }
24
+ return (new ShowdownParser(data)).parse();
25
+ }
26
+
27
+ /**
28
+ * Prettifies and sanitizes the given Showdown code.
29
+ *
30
+ * @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
31
+ * @returns {String}
32
+ */
33
+ static format(data) {
34
+ return this.parse(data).toShowdown();
35
+ }
36
+
37
+ /**
38
+ * Converts from Showdown to JSON code.
39
+ *
40
+ * @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
41
+ * @returns {String}
42
+ */
43
+ static toJson(data) {
44
+ return this.parse(data).toJson();
45
+ }
46
+
47
+ /**
48
+ * Converts from JSON to Showdown code.
49
+ *
50
+ * @param {String|Object|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data JSON code or object
51
+ * @returns {String}
52
+ */
53
+ static toShowdown(data) {
54
+ if (
55
+ data instanceof PokemonTeamSet
56
+ || data instanceof PokemonTeam
57
+ || data instanceof Pokemon
58
+ ) {
59
+ return data.toShowdown();
60
+ }
61
+ if (data instanceof ShowdownParser) {
62
+ return data.parse().format();
63
+ }
64
+ if (typeof data === 'string' || data instanceof String) {
65
+ data = JSON.parse(data);
66
+ }
67
+ return PokemonTeamSet.fromObject(JSON.parse(data)).toShowdown();
68
+ }
69
+ }
70
+
71
+ export default Koffing;
@@ -1,5 +1,3 @@
1
- "use strict";
2
-
3
1
  class Pokemon {
4
2
  constructor() {
5
3
  /**
@@ -34,6 +32,10 @@ class Pokemon {
34
32
  * @type {Number}
35
33
  */
36
34
  this.happiness = undefined;
35
+ /**
36
+ * @type {String}
37
+ */
38
+ this.teratype = undefined;
37
39
  /**
38
40
  * @type {String}
39
41
  */
@@ -66,6 +68,7 @@ class Pokemon {
66
68
  p.level = obj.level;
67
69
  p.shiny = obj.shiny;
68
70
  p.happiness = obj.happiness;
71
+ p.teratype = obj.teratype;
69
72
  p.nature = obj.nature;
70
73
  p.evs = obj.evs;
71
74
  p.ivs = obj.ivs;
@@ -119,6 +122,10 @@ class Pokemon {
119
122
  if (!isNaN(this.happiness)) {
120
123
  str += `Happiness: ${this.happiness}\n`;
121
124
  }
125
+
126
+ if (this.teratype) {
127
+ str += `Tera Type: ${this.teratype}\n`;
128
+ }
122
129
 
123
130
  if (this.nature) {
124
131
  str += `${this.nature} Nature\n`;
@@ -1,5 +1,3 @@
1
- "use strict";
2
-
3
1
  import Pokemon from "./Pokemon";
4
2
 
5
3
  class PokemonTeam {
@@ -1,5 +1,3 @@
1
- "use strict";
2
-
3
1
  import PokemonTeam from "./PokemonTeam";
4
2
 
5
3
  class PokemonTeamSet {
@@ -1,8 +1,6 @@
1
- "use strict";
2
-
3
- import Pokemon from "Pokemon";
4
- import PokemonTeam from "PokemonTeam";
5
- import PokemonTeamSet from "PokemonTeamSet";
1
+ import Pokemon from "./Pokemon";
2
+ import PokemonTeam from "./PokemonTeam";
3
+ import PokemonTeamSet from "./PokemonTeamSet";
6
4
 
7
5
  /**
8
6
  * Ported from Pokemon Showdown Client's exportTeam/importTeam functions.
@@ -17,7 +15,7 @@ class ShowdownParser {
17
15
  /**
18
16
  * @type {String}
19
17
  */
20
- this.code = code + "";
18
+ this.code = code.trim() + "";
21
19
  }
22
20
 
23
21
  /**
@@ -190,7 +188,7 @@ class ShowdownParser {
190
188
  _parseKeyValuePairs(line, pokemon) {
191
189
  const rg = ShowdownParser.regexes;
192
190
 
193
- return ['ability', 'level', 'shiny', 'happiness', 'nature'].some(
191
+ return ['ability', 'level', 'shiny', 'happiness', 'teratype', 'nature'].some(
194
192
  function (key) {
195
193
  if (line.match(rg[key])) {
196
194
  pokemon[key] = rg[key].exec(line)[1].trim();
@@ -272,10 +270,11 @@ ShowdownParser.regexes = {
272
270
  level: /^Level:\s?([0-9]{1,3})$/i,
273
271
  shiny: /^Shiny:\s?(Yes|No)$/i,
274
272
  happiness: /^Happiness:\s?([0-9]{1,3})$/i,
273
+ teratype: /^Tera Type:\s?(.*)$/i,
275
274
  eivs: /^([EI]Vs):\s?(.*)$/i,
276
275
  eivs_value: /^([0-9]+)\s+(hp|atk|def|spa|spd|spe)$/i,
277
276
  nature: /^(.*)\s+Nature$/,
278
277
  move: /^[-~]\s?(.*)$/i
279
278
  };
280
279
 
281
- export default ShowdownParser;
280
+ export default ShowdownParser;
@@ -0,0 +1,7 @@
1
+ import Koffing from "./Koffing";
2
+ import ShowdownParser from "./ShowdownParser";
3
+
4
+ export {
5
+ Koffing,
6
+ ShowdownParser
7
+ };
Binary file
Binary file
package/src/index.css ADDED
@@ -0,0 +1,42 @@
1
+ html {
2
+ box-sizing: border-box;
3
+ -webkit-font-smoothing: antialiased;
4
+ -moz-osx-font-smoothing: grayscale;
5
+ }
6
+
7
+ *, *::before, *::after {
8
+ box-sizing: inherit;
9
+ }
10
+
11
+ body {
12
+ margin: 0;
13
+ background-color: #fafafa;
14
+ }
15
+
16
+ @media print {
17
+ body {
18
+ background-color: #fff;
19
+ }
20
+ }
21
+
22
+ a {
23
+ color: #6B71B8;
24
+ }
25
+
26
+ .koffing-sprite {
27
+ animation-name: koffing-animation;
28
+ animation-duration: 700ms;
29
+ animation-iteration-count: infinite;
30
+ animation-direction: alternate;
31
+ animation-timing-function: ease-in-out;
32
+ }
33
+
34
+ /* Standard syntax */
35
+ @keyframes koffing-animation {
36
+ 0% {
37
+ transform: translate(0px, 0px);
38
+ }
39
+ 100% {
40
+ transform: translate(-2px, -3px);
41
+ }
42
+ }
package/src/index.js CHANGED
@@ -1,76 +1,17 @@
1
- "use strict";
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import './index.css';
4
+ import ThemedApp from './components/ThemedApp';
5
+ import * as serviceWorker from './serviceWorker';
2
6
 
3
- import Pokemon from "Pokemon";
4
- import PokemonTeam from "PokemonTeam";
5
- import PokemonTeamSet from "PokemonTeamSet";
6
- import ShowdownParser from "ShowdownParser";
7
+ ReactDOM.render(
8
+ <React.StrictMode>
9
+ <ThemedApp/>
10
+ </React.StrictMode>,
11
+ document.getElementById('root')
12
+ );
7
13
 
8
- class Koffing {
9
- /**
10
- * Converts from Showdown to a PokemonTeamSet object.
11
- *
12
- * @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
13
- * @returns {PokemonTeamSet}
14
- */
15
- static parse(data) {
16
- if (
17
- data instanceof PokemonTeamSet
18
- || data instanceof PokemonTeam
19
- || data instanceof Pokemon
20
- ) {
21
- return data;
22
- }
23
- if (data instanceof ShowdownParser) {
24
- return data.parse();
25
- }
26
- return (new ShowdownParser(data)).parse();
27
- }
28
-
29
- /**
30
- * Prettifies and sanitizes the given Showdown code.
31
- *
32
- * @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
33
- * @returns {String}
34
- */
35
- static format(data) {
36
- return this.parse(data).toShowdown();
37
- }
38
-
39
- /**
40
- * Converts from Showdown to JSON code.
41
- *
42
- * @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
43
- * @returns {String}
44
- */
45
- static toJson(data) {
46
- return this.parse(data).toJson();
47
- }
48
-
49
- /**
50
- * Converts from JSON to Showdown code.
51
- *
52
- * @param {String|Object|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data JSON code or object
53
- * @returns {String}
54
- */
55
- static toShowdown(data) {
56
- if (
57
- data instanceof PokemonTeamSet
58
- || data instanceof PokemonTeam
59
- || data instanceof Pokemon
60
- ) {
61
- return data.toShowdown();
62
- }
63
- if (data instanceof ShowdownParser) {
64
- return data.parse().format();
65
- }
66
- if (typeof value === 'string' || value instanceof String) {
67
- data = JSON.parse(data);
68
- }
69
- return PokemonTeamSet.fromObject(JSON.parse(data)).toShowdown();
70
- }
71
- }
72
-
73
- export {
74
- Koffing,
75
- ShowdownParser
76
- };
14
+ // If you want your app to work offline and load faster, you can change
15
+ // unregister() to register() below. Note this comes with some pitfalls.
16
+ // Learn more about service workers: https://bit.ly/CRA-PWA
17
+ serviceWorker.unregister();
@@ -0,0 +1,141 @@
1
+ // This optional code is used to register a service worker.
2
+ // register() is not called by default.
3
+
4
+ // This lets the app load faster on subsequent visits in production, and gives
5
+ // it offline capabilities. However, it also means that developers (and users)
6
+ // will only see deployed updates on subsequent visits to a page, after all the
7
+ // existing tabs open on the page have been closed, since previously cached
8
+ // teams are updated in the background.
9
+
10
+ // To learn more about the benefits of this model and instructions on how to
11
+ // opt-in, read https://bit.ly/CRA-PWA
12
+
13
+ const isLocalhost = Boolean(
14
+ window.location.hostname === 'localhost' ||
15
+ // [::1] is the IPv6 localhost address.
16
+ window.location.hostname === '[::1]' ||
17
+ // 127.0.0.0/8 are considered localhost for IPv4.
18
+ window.location.hostname.match(
19
+ /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20
+ )
21
+ );
22
+
23
+ export function register(config) {
24
+ if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25
+ // The URL constructor is available in all browsers that support SW.
26
+ const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27
+ if (publicUrl.origin !== window.location.origin) {
28
+ // Our service worker won't work if PUBLIC_URL is on a different origin
29
+ // from what our page is served on. This might happen if a CDN is used to
30
+ // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31
+ return;
32
+ }
33
+
34
+ window.addEventListener('load', () => {
35
+ const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36
+
37
+ if (isLocalhost) {
38
+ // This is running on localhost. Let's check if a service worker still exists or not.
39
+ checkValidServiceWorker(swUrl, config);
40
+
41
+ // Add some additional logging to localhost, pointing developers to the
42
+ // service worker/PWA documentation.
43
+ navigator.serviceWorker.ready.then(() => {
44
+ console.log(
45
+ 'This web app is being served cache-first by a service ' +
46
+ 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47
+ );
48
+ });
49
+ } else {
50
+ // Is not localhost. Just register service worker
51
+ registerValidSW(swUrl, config);
52
+ }
53
+ });
54
+ }
55
+ }
56
+
57
+ function registerValidSW(swUrl, config) {
58
+ navigator.serviceWorker
59
+ .register(swUrl)
60
+ .then(registration => {
61
+ registration.onupdatefound = () => {
62
+ const installingWorker = registration.installing;
63
+ if (installingWorker == null) {
64
+ return;
65
+ }
66
+ installingWorker.onstatechange = () => {
67
+ if (installingWorker.state === 'installed') {
68
+ if (navigator.serviceWorker.controller) {
69
+ // At this point, the updated precached content has been fetched,
70
+ // but the previous service worker will still serve the older
71
+ // content until all client tabs are closed.
72
+ console.log(
73
+ 'New content is available and will be used when all ' +
74
+ 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75
+ );
76
+
77
+ // Execute callback
78
+ if (config && config.onUpdate) {
79
+ config.onUpdate(registration);
80
+ }
81
+ } else {
82
+ // At this point, everything has been precached.
83
+ // It's the perfect time to display a
84
+ // "Content is cached for offline use." message.
85
+ console.log('Content is cached for offline use.');
86
+
87
+ // Execute callback
88
+ if (config && config.onSuccess) {
89
+ config.onSuccess(registration);
90
+ }
91
+ }
92
+ }
93
+ };
94
+ };
95
+ })
96
+ .catch(error => {
97
+ console.error('Error during service worker registration:', error);
98
+ });
99
+ }
100
+
101
+ function checkValidServiceWorker(swUrl, config) {
102
+ // Check if the service worker can be found. If it can't reload the page.
103
+ fetch(swUrl, {
104
+ headers: { 'Service-Worker': 'script' },
105
+ })
106
+ .then(response => {
107
+ // Ensure service worker exists, and that we really are getting a JS file.
108
+ const contentType = response.headers.get('content-type');
109
+ if (
110
+ response.status === 404 ||
111
+ (contentType != null && contentType.indexOf('javascript') === -1)
112
+ ) {
113
+ // No service worker found. Probably a different app. Reload the page.
114
+ navigator.serviceWorker.ready.then(registration => {
115
+ registration.unregister().then(() => {
116
+ window.location.reload();
117
+ });
118
+ });
119
+ } else {
120
+ // Service worker found. Proceed as normal.
121
+ registerValidSW(swUrl, config);
122
+ }
123
+ })
124
+ .catch(() => {
125
+ console.log(
126
+ 'No internet connection found. App is running in offline mode.'
127
+ );
128
+ });
129
+ }
130
+
131
+ export function unregister() {
132
+ if ('serviceWorker' in navigator) {
133
+ navigator.serviceWorker.ready
134
+ .then(registration => {
135
+ registration.unregister();
136
+ })
137
+ .catch(error => {
138
+ console.error(error.message);
139
+ });
140
+ }
141
+ }
@@ -0,0 +1,5 @@
1
+ // jest-dom adds custom jest matchers for asserting on DOM nodes.
2
+ // allows you to do things like:
3
+ // expect(element).toHaveTextContent(/react/i)
4
+ // learn more: https://github.com/testing-library/jest-dom
5
+ import '@testing-library/jest-dom/extend-expect';