From a6f9509a757f36733c38e09fb97a9092504294fb Mon Sep 17 00:00:00 2001 From: Piers Gillingham Date: Wed, 5 Jul 2023 20:17:48 +0900 Subject: [PATCH] Implement React Structure. --- .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/php.xml | 19 + .idea/vcs.xml | 6 + package-lock.json | 536 ++++++++++++++++++ package.json | 12 +- src/App.test.tsx | 9 - src/App.tsx | 78 ++- src/StoreProvider.ts | 11 + src/index.tsx | 38 +- src/state/ducks/front/entry/actions.ts | 41 ++ src/state/ducks/front/entry/api.ts | 14 + src/state/ducks/front/entry/constants.ts | 1 + src/state/ducks/front/entry/forms.ts | 0 src/state/ducks/front/entry/index.ts | 18 + src/state/ducks/front/entry/operations.ts | 19 + src/state/ducks/front/entry/reducers.ts | 45 ++ src/state/ducks/front/entry/sagas.ts | 28 + src/state/ducks/front/entry/selectors.ts | 8 + src/state/ducks/front/entry/types.ts | 23 + src/state/ducks/front/entry/validation.ts | 0 src/state/ducks/front/entry/watchersSagas.ts | 19 + src/state/ducks/index.ts | 58 ++ src/state/store.ts | 38 ++ src/translations/en/common.json | 3 + src/translations/jp/common.json | 3 + src/utils/ApiUtils.ts | 88 +++ src/views/App.tsx | 45 ++ src/views/atoms/Page.tsx | 29 + src/views/components/front/EntryComponent.tsx | 26 + src/views/components/share/Contents.tsx | 15 + src/views/containers/front/EntryContainer.tsx | 52 ++ src/views/containers/share/RouteContainer.tsx | 22 + src/views/layout/front/Footer.tsx | 19 + src/views/layout/front/Header.tsx | 34 ++ src/views/layout/front/Layout.tsx | 30 + tsconfig.json | 4 +- 36 files changed, 1344 insertions(+), 53 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/php.xml create mode 100644 .idea/vcs.xml delete mode 100644 src/App.test.tsx create mode 100644 src/StoreProvider.ts create mode 100644 src/state/ducks/front/entry/actions.ts create mode 100644 src/state/ducks/front/entry/api.ts create mode 100644 src/state/ducks/front/entry/constants.ts create mode 100644 src/state/ducks/front/entry/forms.ts create mode 100644 src/state/ducks/front/entry/index.ts create mode 100644 src/state/ducks/front/entry/operations.ts create mode 100644 src/state/ducks/front/entry/reducers.ts create mode 100644 src/state/ducks/front/entry/sagas.ts create mode 100644 src/state/ducks/front/entry/selectors.ts create mode 100644 src/state/ducks/front/entry/types.ts create mode 100644 src/state/ducks/front/entry/validation.ts create mode 100644 src/state/ducks/front/entry/watchersSagas.ts create mode 100644 src/state/ducks/index.ts create mode 100644 src/state/store.ts create mode 100644 src/translations/en/common.json create mode 100644 src/translations/jp/common.json create mode 100644 src/utils/ApiUtils.ts create mode 100644 src/views/App.tsx create mode 100644 src/views/atoms/Page.tsx create mode 100644 src/views/components/front/EntryComponent.tsx create mode 100644 src/views/components/share/Contents.tsx create mode 100644 src/views/containers/front/EntryContainer.tsx create mode 100644 src/views/containers/share/RouteContainer.tsx create mode 100644 src/views/layout/front/Footer.tsx create mode 100644 src/views/layout/front/Header.tsx create mode 100644 src/views/layout/front/Layout.tsx diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000..f324872 --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d8ab291..0038d8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,18 @@ "@types/node": "^16.18.38", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", + "axios": "^1.4.0", + "bootstrap": "^5.3.0", "react": "^18.2.0", + "react-bootstrap": "^2.8.0", "react-dom": "^18.2.0", + "react-helmet": "^6.1.0", + "react-i18next": "^13.0.1", + "react-redux": "^8.1.1", + "react-router": "^6.14.1", + "react-router-dom": "^6.14.1", "react-scripts": "5.0.1", + "redux-saga": "^1.2.3", "typescript": "^4.9.5", "web-vitals": "^2.1.4" } @@ -3200,6 +3209,124 @@ } } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.0.tgz", + "integrity": "sha512-bfufjg4ESE5giN+Fxj1XIzS5f/YIhqcGc+Ve+vUUKU8xZ8t/Xtjlv8F3kjqDBQdk//n3mluFY7xG1wQVB9rMLQ==", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@redux-saga/core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.2.3.tgz", + "integrity": "sha512-U1JO6ncFBAklFTwoQ3mjAeQZ6QGutsJzwNBjgVLSWDpZTRhobUzuVDS1qH3SKGJD8fvqoaYOjp6XJ3gCmeZWgA==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@redux-saga/deferred": "^1.2.1", + "@redux-saga/delay-p": "^1.2.1", + "@redux-saga/is": "^1.1.3", + "@redux-saga/symbols": "^1.1.3", + "@redux-saga/types": "^1.2.1", + "redux": "^4.0.4", + "typescript-tuple": "^2.2.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/redux-saga" + } + }, + "node_modules/@redux-saga/deferred": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz", + "integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g==" + }, + "node_modules/@redux-saga/delay-p": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz", + "integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==", + "dependencies": { + "@redux-saga/symbols": "^1.1.3" + } + }, + "node_modules/@redux-saga/is": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz", + "integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==", + "dependencies": { + "@redux-saga/symbols": "^1.1.3", + "@redux-saga/types": "^1.2.1" + } + }, + "node_modules/@redux-saga/symbols": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz", + "integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg==" + }, + "node_modules/@redux-saga/types": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz", + "integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA==" + }, + "node_modules/@remix-run/router": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.1.tgz", + "integrity": "sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@restart/hooks": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.9.tgz", + "integrity": "sha512-3BekqcwB6Umeya+16XPooARn4qEPW6vNvwYnlofIYe6h9qG1/VeD7UvShCWx11eFz5ELYmwIEshz+MkPX3wjcQ==", + "dependencies": { + "dequal": "^2.0.2" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz", + "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@popperjs/core": "^2.11.6", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.4.9", + "@types/warning": "^3.0.0", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.2.tgz", + "integrity": "sha512-/GDx+K1STGtpgTsj5Dj3J51YaKxZDblbCQHTH1zHLuoBEWodj6MjtRVv3TUijj1JYLRLSFsFzN8NV4M3QV4d9w==", + "peerDependencies": { + "react": ">=16.14.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -3518,6 +3645,14 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@swc/helpers": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", @@ -3965,6 +4100,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -4081,6 +4225,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", + "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -4157,6 +4309,16 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "node_modules/@types/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" + }, "node_modules/@types/ws": { "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", @@ -4967,6 +5129,29 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -5363,6 +5548,24 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, + "node_modules/bootstrap": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz", + "integrity": "sha512-UnBV3E3v4STVNQdms6jSGO2CvOkjUMdDAVR2V5N4uCMdaIkaQjbcEAMqRimDHIs4uqBYzDAKCQwCB+97tJgHQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.7" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5627,6 +5830,11 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/clean-css": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", @@ -6575,6 +6783,15 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -8535,6 +8752,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -8637,6 +8867,14 @@ "node": ">=12" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", @@ -8771,6 +9009,29 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "23.2.7", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.2.7.tgz", + "integrity": "sha512-EsbHHvF6b+p+B6Cht5fYWY7VE/WYOrqB1+DNwa1UpLTw6mG5g4tc8KCEjUUOSMUA2yqCsdYQP+PqVq5nBMtOtQ==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "peer": true, + "dependencies": { + "@babel/runtime": "^7.22.5" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -8915,6 +9176,14 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -13889,6 +14158,23 @@ "react-is": "^16.13.1" } }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, + "node_modules/prop-types-extra/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -13914,6 +14200,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -14058,6 +14349,35 @@ "node": ">=14" } }, + "node_modules/react-bootstrap": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz", + "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.3", + "@types/react-transition-group": "^4.4.5", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -14192,11 +14512,99 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-helmet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "dependencies": { + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/react-i18next": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.0.1.tgz", + "integrity": "sha512-gMO6N2GfSfuH7xlHSsZ/mZf+Py9bLm/+EDKIn5fNTuDTjcCcwmMU5UEuGCDk5mdfivbo7ySyYXBN7B9tbGUxiA==", + "dependencies": { + "@babel/runtime": "^7.22.5", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-redux": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.1.tgz", + "integrity": "sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4 || ^5.0.0-beta.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -14205,6 +14613,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.1.tgz", + "integrity": "sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g==", + "dependencies": { + "@remix-run/router": "1.7.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.1.tgz", + "integrity": "sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw==", + "dependencies": { + "@remix-run/router": "1.7.1", + "react-router": "6.14.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -14277,6 +14715,29 @@ } } }, + "node_modules/react-side-effect": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", + "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -14332,6 +14793,22 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-saga": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.2.3.tgz", + "integrity": "sha512-HDe0wTR5nhd8Xr5xjGzoyTbdAw6rjy1GDplFt3JKtKN8/MnkQSRqK/n6aQQhpw5NI4ekDVOaW+w4sdxPBaCoTQ==", + "dependencies": { + "@redux-saga/core": "^1.2.3" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -16010,6 +16487,27 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-compare": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", + "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==", + "dependencies": { + "typescript-logic": "^0.0.0" + } + }, + "node_modules/typescript-logic": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", + "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==" + }, + "node_modules/typescript-tuple": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", + "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", + "dependencies": { + "typescript-compare": "^0.0.2" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -16024,6 +16522,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -16147,6 +16659,14 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -16208,6 +16728,14 @@ "node": ">= 0.8" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -16236,6 +16764,14 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/package.json b/package.json index b773754..b69eef1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,17 @@ "react-dom": "^18.2.0", "react-scripts": "5.0.1", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "react-bootstrap": "^2.8.0", + "react-dom": "^18.2.0", + "react-helmet": "^6.1.0", + "react-i18next": "^13.0.1", + "react-redux": "^8.1.1", + "react-router": "^6.14.1", + "react-router-dom": "^6.14.1", + "redux-saga": "^1.2.3", + "bootstrap": "^5.3.0", + "axios": "^1.4.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/App.test.tsx b/src/App.test.tsx deleted file mode 100644 index 2a68616..0000000 --- a/src/App.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/App.tsx b/src/App.tsx index a53698a..1fe0507 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,26 +1,60 @@ import React from 'react'; -import logo from './logo.svg'; -import './App.css'; +import {render} from 'react-dom'; +import {Provider as ReduxProvider} from "react-redux"; +import {App} from './views/App'; +import configureStore from "./state/store"; +import {BrowserRouter} from "react-router-dom"; +import common_jp from "./translations/jp/common.json"; +import common_en from "./translations/en/common.json"; +import i18next from "i18next"; +import {I18nextProvider} from "react-i18next"; +import storeProvider from "./StoreProvider"; +/*** + * ///////////////////////////////////// + * コアREACTファイル + * ------------------ + * + * reactアプリケーションフローの始まり + * すべての初期ライブラリがここで読み込まれます。 + * ここで読み込まれるライブラリは + * * dotenv (環境変数について) + * * i18next (翻訳について) + * * Redux (グローバルなステート管理のために) + * //////////////////////////////////// + */ -function App() { - return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
-
- ); +declare global { + interface Window { + REDUX_INITIAL_DATA?: typeof store; + } } -export default App; +// 翻訳機能も追加。※ デフォルトは日本語 +i18next.init({ + interpolation: {escapeValue: false}, + lng: 'jp', + resources: { + en: { + common: common_en + }, + jp: { + common: common_jp + }, + }, +}); + +const configureStores = () => configureStore(window.REDUX_INITIAL_DATA); +storeProvider.init(configureStores) +const store = storeProvider.getStore(); + +// reactの最初表示を開始する。 +render( + + + + + + + , + document.getElementById('root') +); diff --git a/src/StoreProvider.ts b/src/StoreProvider.ts new file mode 100644 index 0000000..8e4314c --- /dev/null +++ b/src/StoreProvider.ts @@ -0,0 +1,11 @@ +let store = undefined; +// Jest/Emzymeのテストに支障をきたさないようにreduxStoreをグローバル化しています。 +const storeProvider = { + init(configureStore) { + store = configureStore(); + }, + getStore() { + return store; + } +}; +export default storeProvider; diff --git a/src/index.tsx b/src/index.tsx index 032464f..6ebeb9d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,19 +1,19 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; - -const root = ReactDOM.createRoot( - document.getElementById('root') as HTMLElement -); -root.render( - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); +// import React from 'react'; +// import ReactDOM from 'react-dom/client'; +// import './index.css'; +// import App from './App'; +// import reportWebVitals from './reportWebVitals'; +// +// const root = ReactDOM.createRoot( +// document.getElementById('root') as HTMLElement +// ); +// root.render( +// +// +// +// ); +// +// // If you want to start measuring performance in your app, pass a function +// // to log results (for example: reportWebVitals(console.log)) +// // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +// reportWebVitals(); diff --git a/src/state/ducks/front/entry/actions.ts b/src/state/ducks/front/entry/actions.ts new file mode 100644 index 0000000..d73b444 --- /dev/null +++ b/src/state/ducks/front/entry/actions.ts @@ -0,0 +1,41 @@ +import types from "./types"; + +export function sendEntryRequest(formData) { + return { + type: types.FRONT_ENTRY_REQUEST, + payload: { + formData: formData + } + } +} + +export function sendEntryLoading() { + return { + type: types.FRONT_ENTRY_LOADING + } +} + +export function sendEntrySuccess() { + return { + type: types.FRONT_ENTRY_SUCCESS + } +} + +export function sendEntryFailure(errorData) { + return { + type: types.FRONT_ENTRY_FAILURE, + payload: { + errorData: errorData + } + } +} + + +const actions = { + sendEntryRequest, + sendEntryLoading, + sendEntrySuccess, + sendEntryFailure +}; + +export default actions; diff --git a/src/state/ducks/front/entry/api.ts b/src/state/ducks/front/entry/api.ts new file mode 100644 index 0000000..37f893a --- /dev/null +++ b/src/state/ducks/front/entry/api.ts @@ -0,0 +1,14 @@ +import {POST_CUSTOMERS_PATH} from "./constants"; +import ApiUtils from "../../../../utils/ApiUtils"; +/** + * @param accessToken + * @param params + * @param account_id + * @returns {AxiosPromise} + */ +export function callRequests(params) { + return new ApiUtils().post( + POST_CUSTOMERS_PATH, + params, + ) +} diff --git a/src/state/ducks/front/entry/constants.ts b/src/state/ducks/front/entry/constants.ts new file mode 100644 index 0000000..00f6da4 --- /dev/null +++ b/src/state/ducks/front/entry/constants.ts @@ -0,0 +1 @@ +export const POST_CUSTOMERS_PATH = "/api/customers/"; diff --git a/src/state/ducks/front/entry/forms.ts b/src/state/ducks/front/entry/forms.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/state/ducks/front/entry/index.ts b/src/state/ducks/front/entry/index.ts new file mode 100644 index 0000000..3bb4c1d --- /dev/null +++ b/src/state/ducks/front/entry/index.ts @@ -0,0 +1,18 @@ +/** + * ////////////////////////////////////////////////// + * REDUCKSメインファイル + * -------------------------- + * + * セレクタ、オペレーション、サガ、リデューサを束ねるメインファイル。 + * Reducksの他のコンポーネント(requests)と結合するために、主にducks/index.jsファイルにエクスポートされます。 + * /////////////////////////////////////////////////// + */ + +import * as watchersSagas from './watchersSagas'; + +export const entryWatcherSagas = Object.values(watchersSagas); +// export {default as requestSelectors} from "./selectors"; +export {default as requestOperations} from "./operations"; +export {default as requestTypes} from "./types"; +// export {default as requestForms} from "./forms" +export {entryState, default as entryReducer} from './reducers'; diff --git a/src/state/ducks/front/entry/operations.ts b/src/state/ducks/front/entry/operations.ts new file mode 100644 index 0000000..96ca3fe --- /dev/null +++ b/src/state/ducks/front/entry/operations.ts @@ -0,0 +1,19 @@ +import actions from "./actions"; + +/*** + * ///////////////////////////////////////////////////////// + * OPERATIONS オペレーション + * -------------------- + * + * ミドルウェアを必要とするすべてのアクションまたはアクションのためのバインドで、一緒にバインドされます。 + * このファイルでは、ミドルウェアのインジェクションを必要とするアクションはありませんが、その例がここにあります。 + * 例: https://github.com/alexnm/re-ducks#operations (英語) + * //////////////////////////////////////////////////////// + */ +const sendEntryRequest = actions.sendEntryRequest; + +const operations = { + sendEntryRequest +} + +export default operations; diff --git a/src/state/ducks/front/entry/reducers.ts b/src/state/ducks/front/entry/reducers.ts new file mode 100644 index 0000000..b7a80e0 --- /dev/null +++ b/src/state/ducks/front/entry/reducers.ts @@ -0,0 +1,45 @@ +/*** + * ///////////////////////////////////////// + * REDUCERS (リデューサー) + * ------------------- + * + * すべてのリアクトのマネージャーアカウントの一時的なデータが保存される領域。 + * アプリケーションのどこでもデータを使用することができます。 + * + * Reducerイベントは、ステートへのセッター命令のみを **実行すべき** です。 + * + * このReducerのステートは、/src/state/ducks/index.jsに設定されているrequestsグループに束縛されています。 + * ////////////////////////////////////////// + */ + +export const entryState = { + entryForm: {}, + entryFormLoading: false, + entryFormError: null +} + +export default function entryReducer(state = entryState, action) { + switch (action.type) { + case 'ENTRY_FORM_UPDATE': + return { + ...state, + entryForm: { + ...state.entryForm, + ...action.payload + } + } + case 'ENTRY_FORM_LOADING': + return { + ...state, + entryFormLoading: true + } + case 'ENTRY_FORM_ERROR': + return { + ...state, + entryFormError: action.payload, + entryFormLoading: false + } + default: + return state; + } +} diff --git a/src/state/ducks/front/entry/sagas.ts b/src/state/ducks/front/entry/sagas.ts new file mode 100644 index 0000000..de9dc7a --- /dev/null +++ b/src/state/ducks/front/entry/sagas.ts @@ -0,0 +1,28 @@ +/*** + * //////////////// + * SAGA MIDDLEWARE (SAGAミドルウェア) + * --------------- + * + * SAGAミドルウェアは、アクションとリデューサ間のアクションを解析し、アクションのTYPEに基づいてAPI関数を処理します。 + * すべてのSAGAミドルウェアは、watchersSagas.jsから呼び出されます。 + * //////////////// + */ + + +import {call, put} from "redux-saga/effects"; +import actions from "./actions"; +import {callRequests } from "./api"; + +/** + * アカウント取得リクエスト + * @param data + */ +export function* entryRequest(data) { + yield put(actions.sendEntryLoading()) + try { + const requests = yield call(callRequests, data.payload.form); + yield put(actions.sendEntrySuccess()); + } catch (e) { + yield put(actions.sendEntryFailure(e)); + } +} diff --git a/src/state/ducks/front/entry/selectors.ts b/src/state/ducks/front/entry/selectors.ts new file mode 100644 index 0000000..145e8ae --- /dev/null +++ b/src/state/ducks/front/entry/selectors.ts @@ -0,0 +1,8 @@ +/** + * //////////////////////////////////////// + * SELECTORS (セレクタ) + * ----------------- + * + * リデューサーの生データをフィルタリングして、ビューにきれいな結果を提供するために使用されます。 + * /////////////////////////////////////// + */ diff --git a/src/state/ducks/front/entry/types.ts b/src/state/ducks/front/entry/types.ts new file mode 100644 index 0000000..a31249f --- /dev/null +++ b/src/state/ducks/front/entry/types.ts @@ -0,0 +1,23 @@ +/*** + * ////////////////////////////////////////////////////////////// + * TYPES (タイプ) + * ---------------------- + * + * タイプは、アクション、リデューサ、saga(または他の)ミドルウェアで使用するための定数です。 + * Typeはアクションの中で、ミドルウェアやリデューサーに命令を伝えるために使われます。 + * 全てのアクションタイプは、グループ化しやすいように以下の配列に格納され、選択されます。 + * ////////////////////////////////////////////////////////////// + */ +export const FRONT_ENTRY_REQUEST = 'FRONT_ENTRY_REQUEST'; +export const FRONT_ENTRY_SUCCESS = 'FRONT_ENTRY_SUCCESS'; +export const FRONT_ENTRY_FAILURE = 'FRONT_ENTRY_FAILURE'; +export const FRONT_ENTRY_LOADING = 'FRONT_ENTRY_LOADING'; + +const types = { + FRONT_ENTRY_REQUEST, + FRONT_ENTRY_SUCCESS, + FRONT_ENTRY_FAILURE, + FRONT_ENTRY_LOADING +} + +export default types; diff --git a/src/state/ducks/front/entry/validation.ts b/src/state/ducks/front/entry/validation.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/state/ducks/front/entry/watchersSagas.ts b/src/state/ducks/front/entry/watchersSagas.ts new file mode 100644 index 0000000..f4db64c --- /dev/null +++ b/src/state/ducks/front/entry/watchersSagas.ts @@ -0,0 +1,19 @@ +import { takeLeading } from "redux-saga/effects"; +import {default as types} from "./types"; +import { + entryRequest +} from "./sagas"; + +/** + * ////////////////////////////////////////// + * SAGA WATCHERS (サガ・ウォッチャー) + * -------------------- + * actions.jsからのすべてのアクションは、ここで読み込まれてからreducerに送られます。 + * イベントタイプが一致した場合、下記の第2パラメータの関数が呼び出され、任意のアクションデータを使用することができます。 + * //////////////////////////////////////////// + */ + +export function* fetchRequests() { + yield takeLeading(types.FRONT_ENTRY_REQUEST, entryRequest); +} + diff --git a/src/state/ducks/index.ts b/src/state/ducks/index.ts new file mode 100644 index 0000000..3e5bfd0 --- /dev/null +++ b/src/state/ducks/index.ts @@ -0,0 +1,58 @@ +import { + entryReducer, + entryState, + entryWatcherSagas +} from './front/entry' + +/*** + * /////////////////////////////////////////////// + * REDUCKSメインファイル 🦆 + * --------------------------- + * + * これは、reduxの子グループを束ねるreducksのメインファイルです。 + * これで、ステイツ、リデューサー、レドゥーサガが結ばれる。 + * + * reducksの詳細と、新しいreduxグループの追加については、以下のリンクをご参照ください。 + * reducksのテンプレート化の例 : https://github.com/alexnm/re-ducks#enter-re-ducks + * ////////////////////////////////////////////// + */ +import {all, call, spawn} from 'redux-saga/effects'; + + +/** + * すべての子のreduxステートを束ねる + */ +export const StoreState = { + entryState: entryState, +}; + +/** + * すべてのリデューサーイベントを束ねる + */ +export const reducers = { + entryReducer +}; + +/** + * すべてのサガ・ウォッチャーを束ね、束ねられたウォッチャーの呼び出しに成功した場合、グローバル・キャッチを設定します。 + */ +export function* rootSaga() { + const watchers = [ + ...entryWatcherSagas + ]; + + yield all( + watchers.map((saga) => + spawn(function* () { + while (true) { + try { + yield call(saga); + break; + } catch (ex) { + console.log(ex); + } + } + }), + ), + ); +} diff --git a/src/state/store.ts b/src/state/store.ts new file mode 100644 index 0000000..db4a95c --- /dev/null +++ b/src/state/store.ts @@ -0,0 +1,38 @@ +import {applyMiddleware, combineReducers, compose, createStore} from "redux"; +import {reducers, rootSaga} from './ducks'; +import createSagaMiddleware from 'redux-saga'; + +declare global { + interface Window { + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose; + } +} + +/*** + * //////////////////////////////////////////// + * コアREDUX作成ファイル + * -------------------------- + * + * 他の redux MIDDLEWARE および STORES|REDUCERS をここにバインドします。 + * SAGA MIDDLEWAREとREDUCERSのみがここに読み込まれます。 + * //////////////////////////////////////////// + */ + +const sagaMiddleware = createSagaMiddleware(); + +export default function configureStore(REDUX_INITIAL_DATA: any | undefined) { + const middlewares = []; + middlewares.push(sagaMiddleware); + const rootReducer = combineReducers(reducers); + const composeEnhancer = (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ + trace: true, + traceLimit: 25 + })) || compose; + const store = createStore( + rootReducer, + composeEnhancer(applyMiddleware(...middlewares)) + ); + sagaMiddleware.run(rootSaga) + return store; +} diff --git a/src/translations/en/common.json b/src/translations/en/common.json new file mode 100644 index 0000000..0db3279 --- /dev/null +++ b/src/translations/en/common.json @@ -0,0 +1,3 @@ +{ + +} diff --git a/src/translations/jp/common.json b/src/translations/jp/common.json new file mode 100644 index 0000000..0db3279 --- /dev/null +++ b/src/translations/jp/common.json @@ -0,0 +1,3 @@ +{ + +} diff --git a/src/utils/ApiUtils.ts b/src/utils/ApiUtils.ts new file mode 100644 index 0000000..17464a1 --- /dev/null +++ b/src/utils/ApiUtils.ts @@ -0,0 +1,88 @@ +import axios from "axios"; + +export default class ApiUtils { + /** + * constructor + * @param {string|null} accessToken auth0 アクセストークン + * @param {number|null} timeout タイムアウト + * @param {string|null} baseurl カスタムURL + * @param {boolean} forceNoMock ロカール環境でモック設定を有効にしても、モックサーバーに送信しない。 + */ + constructor(accessToken = null, timeout = null, baseurl = null, forceNoMock = false,) { + let accessTokens = ""; + accessTokens = accessToken; + axios.defaults.baseURL = baseurl || process.env.REACT_APP_MANAGEMENT_API_DOMAIN; + axios.defaults.headers.post['Content-Type'] = 'application/json'; + axios.defaults.headers.post['Accept'] = 'application/json'; + + if (accessToken !== null) { + axios.defaults.headers.common['Authorization'] = "Bearer " + accessToken; + } + axios.defaults.timeout = timeout || process.env.REACT_APP_MANGEMENT_API_TIMEOUT; + } + + /** + * GET リクエスト + * @param uri API アクセスポイント + * @param parameters Get クエリーパラメーター + * @param responseSchema + * @param additionalParams + * @returns {Promise> | *} (API|Network) リクエスト + */ + get(uri, parameters, responseSchema = null, additionalParams = {}) { + return axios({ + ...additionalParams, + method: 'GET', + url: uri, + params: { + ...parameters, + } + }) + } + + /** + * POST リクエスト + * @param {string} uri API アクセスポイント + * @param {Object} body Post データ + * @param responseSchema + * @returns {Promise> | *} (API|Network) リスポンス + */ + post(uri, body, responseSchema = null) { + return axios({ + method: 'POST', + url: uri, + data: JSON.stringify(body) + }); + } + + /** + * DELETE リクエスト + * @param {string} uri API アクセスポイント + * @param {string} id ID + * @returns {Promise> | *} (API|Network) リスポンス + */ + delete(uri, id) { + return axios({ + method: 'DELETE', + url: uri + id, + }); + } + + /** + * UPDATE リクエスト + * @param uri API アクセスポイント + * @param id Unique ID + * @param body 更新データ + * @param responseSchema + * @returns {Promise> | *} (API|Network) リスポンス + */ + put(uri, id, body, responseSchema = null) { + return axios({ + method: 'PUT', + url: uri + id, + data: body + }); + } +} + +export {axios}; diff --git a/src/views/App.tsx b/src/views/App.tsx new file mode 100644 index 0000000..8434cf5 --- /dev/null +++ b/src/views/App.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import {Route} from "react-router-dom"; +import {compose} from "redux"; +import {connect} from "react-redux"; +import {withTranslation} from "react-i18next"; +import {ThemeProvider} from "react-bootstrap"; +import FrontLayout from "./layout/front/Layout"; + +/** + * メインビューコンポーネント、すべてのビューはここからロードされます。 + */ +const mapStateToProps = state => { + return { + + } +} + +/** + * Reduxアクション(これもコンポーネントのパラメータに挿入されます。) + */ +const mapEventToProps = { + +} + +const AppContainer = () => { + + return ( +
+ + + + + +
+ ) +} + +/** + * ロードされたreduxのステートとプロップを上記のコンポーネントにプッシュします。 + * 注:翻訳ライブラリとルーターライブラリもここで呼ばれます。 + */ + +export const App = compose( + connect(mapStateToProps, mapEventToProps), + withTranslation('common'))(AppContainer) as React.ElementType diff --git a/src/views/atoms/Page.tsx b/src/views/atoms/Page.tsx new file mode 100644 index 0000000..d6b5aa6 --- /dev/null +++ b/src/views/atoms/Page.tsx @@ -0,0 +1,29 @@ +import React, {forwardRef} from 'react'; +import {Helmet} from 'react-helmet'; +import PropTypes from 'prop-types'; + + +const Page = forwardRef(({ + children, + title = '', + ...rest + }, ref) => { + return ( +
+ + {title} + + {children} +
+ ); +}); + +Page.propTypes = { + children: PropTypes.node.isRequired, + title: PropTypes.string +}; + +export default Page; diff --git a/src/views/components/front/EntryComponent.tsx b/src/views/components/front/EntryComponent.tsx new file mode 100644 index 0000000..3e46c13 --- /dev/null +++ b/src/views/components/front/EntryComponent.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import Page from "../../atoms/Page"; +import {Container} from "react-bootstrap"; + +/** + * + * @param {*} t - 翻訳 + * @returns {JSX.Element} + * @constructor + */ +const EntryComponent = ( + { + t + }) => { + return ( + + + Hello World + + + ); +} + +export default EntryComponent; diff --git a/src/views/components/share/Contents.tsx b/src/views/components/share/Contents.tsx new file mode 100644 index 0000000..203533f --- /dev/null +++ b/src/views/components/share/Contents.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import RouteContainer from "../../containers/share/RouteContainer"; + +/** + * @returns {JSX.Element} + * @constructor + */ +const Contents = () => { + return ( +
+ +
+ ) +} +export default Contents diff --git a/src/views/containers/front/EntryContainer.tsx b/src/views/containers/front/EntryContainer.tsx new file mode 100644 index 0000000..74d67e2 --- /dev/null +++ b/src/views/containers/front/EntryContainer.tsx @@ -0,0 +1,52 @@ +import React, {useEffect} from "react"; +import {connect} from "react-redux"; +import {withTranslation} from "react-i18next"; +import EntryComponent from "../../components/front/EntryComponent"; +import {compose} from "redux"; + +/** + * Reduxステート(これはコンポーネントのパラメータに挿入されます。) + * @param state - reduxルートクラス + */ +const mapStateToProps = state => { + return { + + } +} + +/** + * Reduxアクション(これもコンポーネントのパラメータに挿入されます。) + */ +const mapEventToProps = { + +} + +/** + * + * @param {Object} managerProfile + * @param t + * @returns {JSX.Element} + * @constructor + */ +const _entryContainer = ( + { + t + }) => { + + return ( + + ) +}; + + +/** + * Redux + * i18next Translations + */ +const EntryContainer = compose( + connect(mapStateToProps, mapEventToProps), + withTranslation('common'))(_entryContainer) + +export default EntryContainer; diff --git a/src/views/containers/share/RouteContainer.tsx b/src/views/containers/share/RouteContainer.tsx new file mode 100644 index 0000000..9c0e29f --- /dev/null +++ b/src/views/containers/share/RouteContainer.tsx @@ -0,0 +1,22 @@ +import { Route, Routes } from "react-router-dom"; +import React from "react"; +import EntryContainer from "../front/EntryContainer"; + +/** + * urlに基づいてコンテナをロードする + * @returns {JSX.Element} + * @constructor + */ +const RouteContainer = () => { + return ( +
+ + {/** ログイン不要URLマッピング**/} + + + + +
+ ) +} +export default RouteContainer diff --git a/src/views/layout/front/Footer.tsx b/src/views/layout/front/Footer.tsx new file mode 100644 index 0000000..a185bd4 --- /dev/null +++ b/src/views/layout/front/Footer.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import {withTranslation} from "react-i18next"; + +/** + * @param {*} t - 翻訳ファイル + * @returns {JSX.Element} + * @constructor + */ +const Footer = ({ + t, + }) => { + return ( +
+ +
+ ); +}; + +export default withTranslation('common')(Footer); diff --git a/src/views/layout/front/Header.tsx b/src/views/layout/front/Header.tsx new file mode 100644 index 0000000..e4e39e5 --- /dev/null +++ b/src/views/layout/front/Header.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {withTranslation} from "react-i18next"; + +/** + * @param {string} className - 親からのクラス名 + * @param {boolean} onMobileNavOpen - スマートフォンのナビメニュー開閉 + * @param {*} t - 翻訳ファイル + * @param {Object} managerProfile - ログインユーザープロフィールデータ + * @param {*} i18n - 翻訳ファイル + * @param {*} rest - 他の変数 + */ +const TopBar = ({ + className, + onMobileNavOpen, + t, + managerProfile, + i18n, + ...rest + }) => { + + return ( +
+ +
+ ); +}; + +TopBar.propTypes = { + className: PropTypes.string, + onMobileNavOpen: PropTypes.func +}; + +export default withTranslation('common')(TopBar); diff --git a/src/views/layout/front/Layout.tsx b/src/views/layout/front/Layout.tsx new file mode 100644 index 0000000..f994b6f --- /dev/null +++ b/src/views/layout/front/Layout.tsx @@ -0,0 +1,30 @@ +import React, {useState} from 'react'; +import Footer from "./Footer"; +import Header from "./Header"; +import Contents from "../../components/share/Contents"; + +/** + * + * @param getProfile + * @param managerProfile + * @param sidebarLinks + * @returns {JSX.Element} + * @constructor + */ +const FrontLayout = ({}) => { + return ( +
+
+
+
+
+ +
+
+
+
+ ); +}; + +export default FrontLayout; diff --git a/tsconfig.json b/tsconfig.json index a273b0c..048d448 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,13 +10,13 @@ "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, - "strict": true, + "strict": false, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, - "isolatedModules": true, + "isolatedModules": false, "noEmit": true, "jsx": "react-jsx" },