mirror of
https://github.com/valitydev/wallet-utils.git
synced 2024-11-06 00:45:17 +00:00
FE-603: init with config (#5)
This commit is contained in:
parent
24d58cc71b
commit
b534080593
@ -44,7 +44,8 @@ module.exports = {
|
||||
}),
|
||||
new CopyWebpackPlugin(
|
||||
[
|
||||
{from: './src/app/assets/icons', to: './assets/icons'}
|
||||
{from: './src/app/assets/icons', to: './assets/icons'},
|
||||
{from: './src/appConfig.json', to: '..'}
|
||||
],
|
||||
{debug: 'warning'}
|
||||
)
|
||||
|
218
package-lock.json
generated
218
package-lock.json
generated
@ -43,6 +43,12 @@
|
||||
"integrity": "sha512-NOLEgsT6UiDTjnWG5Hd2Mg25LRyz/oe8ql3wbjzgSFeRzRROhPmtlsvIrei4B46UjERF0td9SZ1ZXPLOdcrBHg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/query-string": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/query-string/-/query-string-5.1.0.tgz",
|
||||
"integrity": "sha512-9/sJK+T04pNq7uwReR0CLxqXj1dhxiTapZ1tIxA0trEsT6FRS0bz09YMcMb7tsVBTm4RJ0NEBYGsAjoEmqoFXg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/ramda": {
|
||||
"version": "0.25.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.25.24.tgz",
|
||||
@ -87,6 +93,75 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-redux": {
|
||||
"version": "5.0.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-5.0.20.tgz",
|
||||
"integrity": "sha512-WeiE+bcA/6JaPIFpOJ75rvtM2/+Yu41k0YMgIXLnjRbyL55vG7B22HzFrVkyoIQNbCZFBz+pWdRDWRmNG4USBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"redux": "^3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"redux": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
|
||||
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.2.1",
|
||||
"lodash-es": "^4.2.1",
|
||||
"loose-envify": "^1.1.0",
|
||||
"symbol-observable": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/redux": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/redux/-/redux-3.6.0.tgz",
|
||||
"integrity": "sha1-8evh5UEVGAcuT9/KXHbhbnTBOZo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"redux": "*"
|
||||
}
|
||||
},
|
||||
"@types/redux-form": {
|
||||
"version": "7.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/redux-form/-/redux-form-7.2.5.tgz",
|
||||
"integrity": "sha512-R4FHhJyB6P5zxbvtVp4C9qH3MYobxXwBMqf8bTL4j57w8qiDjMV+NiH1MEn/8n8zX0x5djRueqxeL0pVUyWQog==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"redux": "^3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"redux": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
|
||||
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.2.1",
|
||||
"lodash-es": "^4.2.1",
|
||||
"loose-envify": "^1.1.0",
|
||||
"symbol-observable": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
@ -2651,8 +2726,7 @@
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
|
||||
},
|
||||
"decompress-response": {
|
||||
"version": "3.3.0",
|
||||
@ -2666,8 +2740,7 @@
|
||||
"deep-equal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
||||
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.4.2",
|
||||
@ -3136,6 +3209,11 @@
|
||||
"is-symbol": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"es6-error": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
|
||||
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="
|
||||
},
|
||||
"escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
@ -5391,6 +5469,11 @@
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
|
||||
"dev": true
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz",
|
||||
"integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w=="
|
||||
},
|
||||
"home-or-tmp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
|
||||
@ -5828,7 +5911,6 @@
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
@ -6123,8 +6205,7 @@
|
||||
"is-promise": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
|
||||
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
|
||||
"dev": true
|
||||
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
|
||||
},
|
||||
"is-property": {
|
||||
"version": "1.0.2",
|
||||
@ -6499,23 +6580,6 @@
|
||||
"invert-kv": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"libphonenumber-js": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.1.11.tgz",
|
||||
"integrity": "sha512-ofIEkWyZaPvZLVP3QyOtEAY/Ie630VuV+rLIgLQ6OSV1wQtzjhG3mXabivbHPZlqV2lWEo2C8qnluBc8fdbDig==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.0",
|
||||
"semver-compare": "^1.0.0",
|
||||
"xml2js": "^0.4.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||
}
|
||||
}
|
||||
},
|
||||
"listr": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/listr/-/listr-0.13.0.tgz",
|
||||
@ -6795,8 +6859,7 @@
|
||||
"lodash": {
|
||||
"version": "4.17.5",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
|
||||
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.8",
|
||||
@ -7769,6 +7832,18 @@
|
||||
"prepend-http": "^1.0.0",
|
||||
"query-string": "^4.1.0",
|
||||
"sort-keys": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"npm-run-path": {
|
||||
@ -9041,13 +9116,19 @@
|
||||
"dev": true
|
||||
},
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"dev": true,
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.1.0.tgz",
|
||||
"integrity": "sha512-pNB/Gr8SA8ff8KpUFM36o/WFAlthgaThka5bV19AD9PNTH20Pwq5Zxodif2YyHwrctp6SkL4GqlOot0qR/wGaw==",
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||
}
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
@ -9201,6 +9282,19 @@
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "5.0.7",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
|
||||
"integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==",
|
||||
"requires": {
|
||||
"hoist-non-react-statics": "^2.5.0",
|
||||
"invariant": "^2.0.0",
|
||||
"lodash": "^4.17.5",
|
||||
"lodash-es": "^4.17.5",
|
||||
"loose-envify": "^1.1.0",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"read-chunk": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz",
|
||||
@ -9334,6 +9428,44 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"redux": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
|
||||
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
|
||||
"requires": {
|
||||
"lodash": "^4.2.1",
|
||||
"lodash-es": "^4.2.1",
|
||||
"loose-envify": "^1.1.0",
|
||||
"symbol-observable": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"redux-devtools-extension": {
|
||||
"version": "2.13.2",
|
||||
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz",
|
||||
"integrity": "sha1-4Pmo6N/KfBe+kscSSVijuU6ykR0="
|
||||
},
|
||||
"redux-form": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-form/-/redux-form-7.3.0.tgz",
|
||||
"integrity": "sha512-WcZRsRsVG25l8Cih3bEeeoZFxSIvoHqTpBRe5Ifl1ob7xvEpYLXyYYHAFER1DpTfMZPgTPHZ4UkR4ILFP3hzkw==",
|
||||
"requires": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"es6-error": "^4.1.1",
|
||||
"hoist-non-react-statics": "^2.5.0",
|
||||
"invariant": "^2.2.3",
|
||||
"is-promise": "^2.1.0",
|
||||
"lodash": "^4.17.5",
|
||||
"lodash-es": "^4.17.5",
|
||||
"prop-types": "^15.6.1"
|
||||
}
|
||||
},
|
||||
"redux-saga": {
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-0.16.0.tgz",
|
||||
@ -9850,7 +9982,8 @@
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "0.4.5",
|
||||
@ -9910,11 +10043,6 @@
|
||||
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
|
||||
"dev": true
|
||||
},
|
||||
"semver-compare": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
|
||||
"integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
|
||||
},
|
||||
"send": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
|
||||
@ -12008,20 +12136,6 @@
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"xml2js": {
|
||||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~9.0.1"
|
||||
}
|
||||
},
|
||||
"xmlbuilder": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
|
||||
|
@ -26,6 +26,9 @@
|
||||
"@types/react": "~16.3.11",
|
||||
"@types/react-addons-css-transition-group": "~15.0.4",
|
||||
"@types/react-dom": "~16.0.5",
|
||||
"@types/react-redux": "~5.0.14",
|
||||
"@types/redux": "~3.6.0",
|
||||
"@types/redux-form": "~7.2.5",
|
||||
"cache-loader": "~1.2.2",
|
||||
"copy-webpack-plugin": "~4.5.1",
|
||||
"css-loader": "~0.28.11",
|
||||
@ -59,6 +62,10 @@
|
||||
"react": "~16.3.2",
|
||||
"react-addons-css-transition-group": "~15.6.2",
|
||||
"react-dom": "~16.3.2",
|
||||
"react-redux": "~5.0.5",
|
||||
"redux": "~3.7.2",
|
||||
"redux-devtools-extension": "~2.13.2",
|
||||
"redux-form": "~7.3.0",
|
||||
"redux-saga": "~0.16.0"
|
||||
}
|
||||
}
|
||||
|
6
src/app/actions/abstract-action.ts
Normal file
6
src/app/actions/abstract-action.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Action } from 'redux';
|
||||
|
||||
export interface AbstractAction<P = null, M = null> extends Action {
|
||||
payload?: P;
|
||||
meta?: M;
|
||||
}
|
11
src/app/actions/config-actions/app-config-received.ts
Normal file
11
src/app/actions/config-actions/app-config-received.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { AppConfig } from 'app/backend';
|
||||
import { AbstractAction, TypeKeys } from 'app/actions';
|
||||
|
||||
export interface Config {
|
||||
appConfig: AppConfig;
|
||||
}
|
||||
|
||||
export interface AppConfigReceived extends AbstractAction<Config> {
|
||||
type: TypeKeys.APP_CONFIG_RECEIVED;
|
||||
payload: Config;
|
||||
}
|
1
src/app/actions/config-actions/index.ts
Normal file
1
src/app/actions/config-actions/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './app-config-received';
|
5
src/app/actions/index.ts
Normal file
5
src/app/actions/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export * from './type-keys';
|
||||
export * from './abstract-action';
|
||||
export * from './initialize-actions';
|
||||
export * from './config-actions';
|
||||
export * from './model-actions';
|
1
src/app/actions/initialize-actions/index.ts
Normal file
1
src/app/actions/initialize-actions/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './initialize-actions';
|
21
src/app/actions/initialize-actions/initialize-actions.ts
Normal file
21
src/app/actions/initialize-actions/initialize-actions.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { AbstractAction, TypeKeys } from 'app/actions';
|
||||
import { InitConfig } from 'app/config';
|
||||
import { LogicError } from 'app/backend';
|
||||
|
||||
export interface InitializeAppRequested extends AbstractAction<InitConfig> {
|
||||
type: TypeKeys.INITIALIZE_APP_REQUESTED;
|
||||
payload: InitConfig;
|
||||
}
|
||||
|
||||
export interface InitializeAppCompleted extends AbstractAction {
|
||||
type: TypeKeys.INITIALIZE_APP_COMPLETED;
|
||||
}
|
||||
|
||||
export interface InitializeAppFailed extends AbstractAction<LogicError> {
|
||||
type: TypeKeys.INITIALIZE_APP_FAILED;
|
||||
payload: LogicError;
|
||||
}
|
||||
|
||||
export const initializeApp = () => ({
|
||||
type: TypeKeys.INITIALIZE_APP_REQUESTED
|
||||
});
|
1
src/app/actions/model-actions/index.ts
Normal file
1
src/app/actions/model-actions/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './initialize-action';
|
7
src/app/actions/model-actions/initialize-action.ts
Normal file
7
src/app/actions/model-actions/initialize-action.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { AbstractAction, TypeKeys } from 'app/actions';
|
||||
import { ModelState } from 'app/state';
|
||||
|
||||
export interface InitializeModelCompleted extends AbstractAction<ModelState> {
|
||||
type: TypeKeys.INITIALIZE_MODEL_COMPLETED;
|
||||
payload: ModelState;
|
||||
}
|
7
src/app/actions/type-keys.ts
Normal file
7
src/app/actions/type-keys.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export enum TypeKeys {
|
||||
INITIALIZE_APP_REQUESTED = 'INITIALIZE_APP_REQUESTED',
|
||||
INITIALIZE_APP_COMPLETED = 'INITIALIZE_APP_COMPLETED',
|
||||
INITIALIZE_APP_FAILED = 'INITIALIZE_APP_FAILED',
|
||||
APP_CONFIG_RECEIVED = 'APP_CONFIG_RECEIVED',
|
||||
INITIALIZE_MODEL_COMPLETED = 'INITIALIZE_MODEL_COMPLETED'
|
||||
}
|
3
src/app/backend/app-config.ts
Normal file
3
src/app/backend/app-config.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export class AppConfig {
|
||||
wapiEndpoint: string;
|
||||
}
|
36
src/app/backend/fetch-wapi.ts
Normal file
36
src/app/backend/fetch-wapi.ts
Normal file
@ -0,0 +1,36 @@
|
||||
function s4(): string {
|
||||
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
|
||||
}
|
||||
|
||||
function guid(): string {
|
||||
return `${s4()}${s4()}-${s4()}${s4()}`;
|
||||
}
|
||||
|
||||
export class FetchWapiParams {
|
||||
endpoint: string;
|
||||
accessToken: string;
|
||||
method?: 'GET' | 'POST' | 'PUT';
|
||||
body?: any;
|
||||
}
|
||||
|
||||
export function fetchWapi<T>(param: FetchWapiParams): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(param.endpoint, {
|
||||
method: param.method || 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
'Authorization': `Bearer ${param.accessToken}`,
|
||||
'X-Request-ID': guid()
|
||||
},
|
||||
body: param.body ? JSON.stringify(param.body) : undefined
|
||||
}).then((res) =>
|
||||
res.status >= 200 && res.status <= 300
|
||||
? resolve(res.json())
|
||||
: res.json()
|
||||
.then((ex) => reject(ex))
|
||||
.catch(() => reject({
|
||||
message: `${res.status}: ${res.statusText}`
|
||||
}))
|
||||
).catch((ex) => reject({message: `${ex}`}));
|
||||
});
|
||||
}
|
11
src/app/backend/get-app-config.ts
Normal file
11
src/app/backend/get-app-config.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { AppConfig } from './app-config';
|
||||
import { getNocacheValue } from 'app/utils/get-nocache-value';
|
||||
|
||||
export const getAppConfig = (): Promise<AppConfig> => (
|
||||
fetch(`../appConfig.json?nocache=${getNocacheValue()}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'GET'
|
||||
}).then((response) => response.json())
|
||||
);
|
7
src/app/backend/get-identity.ts
Normal file
7
src/app/backend/get-identity.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Identity, fetchWapi } from 'app/backend';
|
||||
|
||||
export const getIdentityByID = (wapiEndpoint: string, accessToken: string, identityID: string): Promise<Identity> =>
|
||||
fetchWapi({
|
||||
endpoint: `${wapiEndpoint}/identities/${identityID}`,
|
||||
accessToken
|
||||
});
|
5
src/app/backend/index.ts
Normal file
5
src/app/backend/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export * from './model';
|
||||
export * from './fetch-wapi';
|
||||
export * from './app-config';
|
||||
export * from './get-app-config';
|
||||
export * from './get-identity';
|
11
src/app/backend/model/identity.ts
Normal file
11
src/app/backend/model/identity.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export class Identity {
|
||||
id: string;
|
||||
name: string;
|
||||
createdAt: string;
|
||||
provider: string;
|
||||
class: string;
|
||||
level: string;
|
||||
effectiveChallenge: string;
|
||||
isBlocked: boolean;
|
||||
metadata: {};
|
||||
}
|
2
src/app/backend/model/index.ts
Normal file
2
src/app/backend/model/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './logic-error';
|
||||
export * from './identity';
|
4
src/app/backend/model/logic-error.ts
Normal file
4
src/app/backend/model/logic-error.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export class LogicError {
|
||||
code: string;
|
||||
message: string;
|
||||
}
|
23
src/app/components/app/app-loader/app-loader.scss
Normal file
23
src/app/components/app/app-loader/app-loader.scss
Normal file
@ -0,0 +1,23 @@
|
||||
@import "../../../styles/animations";
|
||||
|
||||
.loader {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
@include responsive(sm) {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: translate(0, 0);
|
||||
animation: growth .75s;
|
||||
}
|
||||
}
|
11
src/app/components/app/app-loader/app-loader.scss.d.ts
vendored
Normal file
11
src/app/components/app/app-loader/app-loader.scss.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
export const loader: string;
|
||||
export const growth: string;
|
||||
export const fadein: string;
|
||||
export const fadeout: string;
|
||||
export const slidedown: string;
|
||||
export const slideup: string;
|
||||
export const popup: string;
|
||||
export const popout: string;
|
||||
export const rotatein: string;
|
||||
export const rotateout: string;
|
||||
export const shake: string;
|
11
src/app/components/app/app-loader/app-loader.tsx
Normal file
11
src/app/components/app/app-loader/app-loader.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import * as styles from './app-loader.scss';
|
||||
import { Loader } from '../../ui/loader';
|
||||
|
||||
const AppLoaderDef: React.SFC = () => (
|
||||
<div className={styles.loader}>
|
||||
<Loader/>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const AppLoader = AppLoaderDef;
|
1
src/app/components/app/app-loader/index.ts
Normal file
1
src/app/components/app/app-loader/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './app-loader';
|
6
src/app/components/app/app-props.ts
Normal file
6
src/app/components/app/app-props.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { InitializeAppState } from 'app/state';
|
||||
|
||||
export interface AppProps {
|
||||
initializeApp: InitializeAppState;
|
||||
initApp: () => any;
|
||||
}
|
40
src/app/components/app/app.tsx
Normal file
40
src/app/components/app/app.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { layout } from './app.scss';
|
||||
|
||||
import { Overlay } from './overlay';
|
||||
import { ModalContainer } from './modal-container';
|
||||
import { initializeApp } from 'app/actions';
|
||||
import { State } from 'app/state';
|
||||
import { AppProps } from './app-props';
|
||||
import { AppLoader } from './app-loader';
|
||||
|
||||
class AppDef extends React.Component<AppProps> {
|
||||
|
||||
componentWillMount() {
|
||||
this.props.initApp();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {initialized, error} = this.props.initializeApp;
|
||||
return (
|
||||
<div className={layout}>
|
||||
<Overlay/>
|
||||
{error ? <div>{error.message}</div> : false}
|
||||
{!initialized && !error ? <AppLoader/> : false}
|
||||
{initialized ? <ModalContainer/> : false}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State) => ({
|
||||
initializeApp: state.initializeApp
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch<State>) => ({
|
||||
initApp: bindActionCreators(initializeApp, dispatch),
|
||||
});
|
||||
|
||||
export const App = connect(mapStateToProps, mapDispatchToProps)(AppDef);
|
@ -1 +1 @@
|
||||
export * from './layout';
|
||||
export * from './app';
|
||||
|
@ -1,12 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { layout } from './layout.scss';
|
||||
|
||||
import { Overlay } from './overlay';
|
||||
import { ModalContainer } from './modal-container';
|
||||
|
||||
export const App: React.SFC = () => (
|
||||
<div className={layout}>
|
||||
<Overlay/>
|
||||
<ModalContainer/>
|
||||
</div>
|
||||
);
|
@ -5,7 +5,7 @@ import { header, text, _center } from './mobile-header.scss';
|
||||
export const MobileHeader: React.SFC = () => (
|
||||
<header className={header}>
|
||||
<div className={cx(text, {[_center]: true})}>
|
||||
[props.initConfig.name]
|
||||
Процедура идентификации
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
@ -42,10 +42,6 @@
|
||||
padding: 30px;
|
||||
box-sizing: border-box;
|
||||
background-image: linear-gradient(90deg, $deep-blue 0%, $blue 39%, $lightest-blue 100%);
|
||||
|
||||
footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.with_shadow {
|
||||
|
@ -1,13 +1,19 @@
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import * as cx from 'classnames';
|
||||
import * as ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
||||
import { appear, leave, overlay, img, bg1, bg2, bg3, bg4, bg5, bg6, bg7, bg8 } from './overlay.scss';
|
||||
import { State } from 'app/state';
|
||||
|
||||
const backgrounds: ReadonlyArray<string> = [bg1, bg2, bg3, bg4, bg5, bg6, bg7, bg8];
|
||||
|
||||
const getRandom = (): number => Math.floor(Math.random() * 7);
|
||||
|
||||
export const Overlay: React.SFC = () => (
|
||||
interface OverlayDefProps {
|
||||
inFrame: boolean;
|
||||
}
|
||||
|
||||
const OverlayDef: React.SFC<OverlayDefProps> = (props) => (
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName={{enter: null, appear, leave}}
|
||||
transitionEnter={false}
|
||||
@ -15,8 +21,14 @@ export const Overlay: React.SFC = () => (
|
||||
transitionAppearTimeout={500}
|
||||
transitionLeaveTimeout={500}>
|
||||
<div key='overlay' className={cx(overlay, {
|
||||
[img]: true,
|
||||
[backgrounds[getRandom()]]: true
|
||||
[img]: !props.inFrame,
|
||||
[backgrounds[getRandom()]]: !props.inFrame
|
||||
})} />
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
|
||||
const mapStateToProps = (state: State) => ({
|
||||
inFrame: state.config.inFrame
|
||||
});
|
||||
|
||||
export const Overlay = connect(mapStateToProps)(OverlayDef);
|
||||
|
1
src/app/config/config-resolver/index.ts
Normal file
1
src/app/config/config-resolver/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './resolve-config';
|
23
src/app/config/config-resolver/resolve-config.ts
Normal file
23
src/app/config/config-resolver/resolve-config.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { PossibleEvents, Transport } from '../../../communication';
|
||||
import { Config } from '../config';
|
||||
import { getOrigin } from '../../../get-origin';
|
||||
import { UserConfig } from './user-config';
|
||||
import { resolveInitConfig } from './resolve-init-config';
|
||||
import { isInFrame } from '../../../is-in-iframe';
|
||||
import { deserialize } from 'app/utils/uri-serializer';
|
||||
|
||||
const isUriContext = !!location.search;
|
||||
|
||||
const resolveUserConfig = (transport: Transport): Promise<UserConfig> => {
|
||||
return new Promise((resolve) =>
|
||||
isUriContext
|
||||
? resolve(deserialize(location.search))
|
||||
: transport.on(PossibleEvents.init, (config) => resolve(config)));
|
||||
};
|
||||
|
||||
export const resolveConfig = (transport: Transport): Promise<Config> =>
|
||||
resolveUserConfig(transport).then((userConfig) => ({
|
||||
origin: getOrigin(),
|
||||
inFrame: isInFrame(),
|
||||
initConfig: resolveInitConfig(userConfig)
|
||||
}));
|
9
src/app/config/config-resolver/resolve-init-config.ts
Normal file
9
src/app/config/config-resolver/resolve-init-config.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { InitConfig } from 'app/config';
|
||||
import { UserConfig } from './user-config';
|
||||
|
||||
export const resolveInitConfig = (userConfig: UserConfig): InitConfig => {
|
||||
return {
|
||||
...new InitConfig(),
|
||||
...userConfig
|
||||
};
|
||||
};
|
1
src/app/config/config-resolver/user-config.ts
Normal file
1
src/app/config/config-resolver/user-config.ts
Normal file
@ -0,0 +1 @@
|
||||
export type UserConfig = any;
|
9
src/app/config/config.ts
Normal file
9
src/app/config/config.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { AppConfig } from 'app/backend';
|
||||
import { InitConfig } from './init-config';
|
||||
|
||||
export class Config {
|
||||
origin: string;
|
||||
inFrame: boolean;
|
||||
initConfig: InitConfig;
|
||||
appConfig?: AppConfig;
|
||||
}
|
6
src/app/config/identity-challenge-init-config.ts
Normal file
6
src/app/config/identity-challenge-init-config.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { InitConfig } from 'app/config/init-config';
|
||||
import { StartIdentityChallengeParams } from '../../initializer/model';
|
||||
|
||||
export class IdentityChallengeInitConfig extends InitConfig {
|
||||
params: StartIdentityChallengeParams;
|
||||
}
|
4
src/app/config/index.ts
Normal file
4
src/app/config/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './config';
|
||||
export * from './config-resolver';
|
||||
export * from './init-config';
|
||||
export * from './identity-challenge-init-config';
|
6
src/app/config/init-config.ts
Normal file
6
src/app/config/init-config.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { ActionType } from '../../communication/model';
|
||||
|
||||
export class InitConfig {
|
||||
token: string;
|
||||
type: ActionType;
|
||||
}
|
19
src/app/configure-store.ts
Normal file
19
src/app/configure-store.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { applyMiddleware, combineReducers, createStore, Store } from 'redux';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
import { State } from './state';
|
||||
import rootSaga from 'app/sagas/root-saga';
|
||||
import { configReducer, initializeAppReducer, modelReducer } from 'app/reducers';
|
||||
|
||||
export function configureStore(initState: any): Store<State> {
|
||||
const sagaMiddleware = createSagaMiddleware();
|
||||
const store = createStore(combineReducers({
|
||||
initializeApp: initializeAppReducer,
|
||||
config: configReducer,
|
||||
model: modelReducer,
|
||||
form: formReducer
|
||||
}), initState, composeWithDevTools(applyMiddleware(sagaMiddleware)));
|
||||
sagaMiddleware.run(rootSaga);
|
||||
return store;
|
||||
}
|
@ -4,13 +4,21 @@ import * as ReactDOM from 'react-dom';
|
||||
import './styles/main.scss';
|
||||
import { Child } from '../communication';
|
||||
import { App } from './components/app';
|
||||
import { resolveConfig } from './config';
|
||||
import { configureStore } from 'app/configure-store';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
const app = document.getElementById('app');
|
||||
|
||||
Child.resolve()
|
||||
.then(() => {
|
||||
ReactDOM.render(
|
||||
<App/>,
|
||||
app
|
||||
);
|
||||
.then((transport) => {
|
||||
resolveConfig(transport).then((config) => {
|
||||
const store = configureStore({config});
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App/>
|
||||
</Provider>,
|
||||
app
|
||||
);
|
||||
});
|
||||
});
|
||||
|
4
src/app/log-messages.ts
Normal file
4
src/app/log-messages.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const logPrefix = '[RbkmoneyWallet]';
|
||||
export const sadnessMessage = 'Param will not be applied.';
|
||||
export const getMessageInvalidValue = (fieldName: string, value: string, reason: string): string =>
|
||||
`${logPrefix} Invalid value of param '${fieldName}':'${value}'. ${reason} ${sadnessMessage}`;
|
16
src/app/reducers/config-reducer.ts
Normal file
16
src/app/reducers/config-reducer.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ConfigState } from 'app/state';
|
||||
import { AppConfigReceived, TypeKeys } from 'app/actions';
|
||||
|
||||
type ConfigReducerAction = AppConfigReceived;
|
||||
|
||||
export const configReducer = (s: ConfigState = null, action: ConfigReducerAction) => {
|
||||
switch (action.type) {
|
||||
case TypeKeys.APP_CONFIG_RECEIVED:
|
||||
return {
|
||||
...s,
|
||||
...action.payload
|
||||
};
|
||||
|
||||
}
|
||||
return s;
|
||||
};
|
3
src/app/reducers/index.ts
Normal file
3
src/app/reducers/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './initialize-app-reducer';
|
||||
export * from './config-reducer';
|
||||
export * from './model-reducer';
|
27
src/app/reducers/initialize-app-reducer.ts
Normal file
27
src/app/reducers/initialize-app-reducer.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { InitializeAppCompleted, InitializeAppFailed, InitializeAppRequested, TypeKeys } from 'app/actions';
|
||||
import { InitializeAppState } from 'app/state';
|
||||
|
||||
type InitializeAppAction =
|
||||
InitializeAppFailed |
|
||||
InitializeAppRequested |
|
||||
InitializeAppCompleted;
|
||||
|
||||
const initState = {
|
||||
initialized: false
|
||||
};
|
||||
|
||||
export const initializeAppReducer = (s: InitializeAppState = initState, action: InitializeAppAction) => {
|
||||
switch (action.type) {
|
||||
case TypeKeys.INITIALIZE_APP_COMPLETED:
|
||||
return {
|
||||
...s,
|
||||
initialized: true
|
||||
};
|
||||
case TypeKeys.INITIALIZE_APP_FAILED:
|
||||
return {
|
||||
...s,
|
||||
error: action.payload
|
||||
};
|
||||
}
|
||||
return s;
|
||||
};
|
17
src/app/reducers/model-reducer.ts
Normal file
17
src/app/reducers/model-reducer.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { ModelState } from 'app/state';
|
||||
import { TypeKeys } from 'app/actions';
|
||||
import { InitializeModelCompleted } from 'app/actions/model-actions/initialize-action';
|
||||
|
||||
type ModelReducerAction =
|
||||
InitializeModelCompleted;
|
||||
|
||||
export function modelReducer(s: ModelState = null, action: ModelReducerAction): ModelState {
|
||||
switch (action.type) {
|
||||
case TypeKeys.INITIALIZE_MODEL_COMPLETED:
|
||||
return {
|
||||
...s,
|
||||
...action.payload
|
||||
};
|
||||
}
|
||||
return s;
|
||||
}
|
1
src/app/sagas/initialize-app/index.ts
Normal file
1
src/app/sagas/initialize-app/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './initialize-app';
|
39
src/app/sagas/initialize-app/initialize-app.ts
Normal file
39
src/app/sagas/initialize-app/initialize-app.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { call, CallEffect, ForkEffect, put, PutEffect, select, SelectEffect, takeLatest } from 'redux-saga/effects';
|
||||
import { loadAppConfig } from './load-app-config';
|
||||
import {
|
||||
InitializeAppCompleted,
|
||||
InitializeAppFailed,
|
||||
TypeKeys
|
||||
} from 'app/actions';
|
||||
import { State } from 'app/state';
|
||||
import { initializeModel } from './initialize-model';
|
||||
|
||||
type InitializeAppPutEffect =
|
||||
InitializeAppCompleted |
|
||||
InitializeAppFailed;
|
||||
|
||||
export type InitializeAppEffect =
|
||||
CallEffect |
|
||||
PutEffect<InitializeAppPutEffect> |
|
||||
SelectEffect;
|
||||
|
||||
export function* initializeApp(): Iterator<InitializeAppEffect> {
|
||||
try {
|
||||
yield call(loadAppConfig);
|
||||
const config = yield select((state: State) => state.config);
|
||||
const {appConfig: {endpoint}, initConfig} = config;
|
||||
yield call(initializeModel, endpoint, initConfig);
|
||||
yield put({
|
||||
type: TypeKeys.INITIALIZE_APP_COMPLETED
|
||||
} as InitializeAppCompleted);
|
||||
} catch (error) {
|
||||
yield put({
|
||||
type: TypeKeys.INITIALIZE_APP_FAILED,
|
||||
payload: error
|
||||
} as InitializeAppFailed);
|
||||
}
|
||||
}
|
||||
|
||||
export function* watchInitializeApp(): Iterator<ForkEffect> {
|
||||
yield takeLatest(TypeKeys.INITIALIZE_APP_REQUESTED, initializeApp);
|
||||
}
|
31
src/app/sagas/initialize-app/initialize-model.ts
Normal file
31
src/app/sagas/initialize-app/initialize-model.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { call, CallEffect, put, PutEffect } from 'redux-saga/effects';
|
||||
import { InitConfig, IdentityChallengeInitConfig } from 'src/app/config/index';
|
||||
import { ActionType } from '../../../communication/model';
|
||||
import { getIdentityByID, Identity } from 'app/backend/index';
|
||||
import { InitializeModelCompleted, TypeKeys } from 'app/actions';
|
||||
import { ModelState } from 'app/state';
|
||||
|
||||
export function* resolveIdentity(endpoint: string, config: IdentityChallengeInitConfig): Iterator<CallEffect | Identity> {
|
||||
const token = config.token;
|
||||
const id = config.params.identityID;
|
||||
return yield call(getIdentityByID, endpoint, token, id);
|
||||
}
|
||||
|
||||
interface ResolvedActionType {
|
||||
identity?: Identity;
|
||||
}
|
||||
|
||||
export function* resolveActionType(endpoint: string, config: InitConfig): Iterator<CallEffect | ResolvedActionType | ModelState> {
|
||||
switch (config.type) {
|
||||
case ActionType.userIdentity:
|
||||
const identity = yield call(resolveIdentity, endpoint, config);
|
||||
return {identity};
|
||||
}
|
||||
}
|
||||
|
||||
export type InitializeEffect = CallEffect | PutEffect<InitializeModelCompleted>;
|
||||
|
||||
export function* initializeModel(endpoint: string, config: InitConfig): Iterator<InitializeEffect> {
|
||||
const modelChunk = yield call(resolveActionType, endpoint, config);
|
||||
yield put({type: TypeKeys.INITIALIZE_MODEL_COMPLETED, payload: modelChunk} as InitializeModelCompleted);
|
||||
}
|
15
src/app/sagas/initialize-app/load-app-config.ts
Normal file
15
src/app/sagas/initialize-app/load-app-config.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { call, CallEffect, put, PutEffect } from 'redux-saga/effects';
|
||||
import { AppConfigReceived, TypeKeys } from 'app/actions';
|
||||
import { getAppConfig } from 'app/backend';
|
||||
|
||||
type LoadConfigEffect = CallEffect | PutEffect<AppConfigReceived>;
|
||||
|
||||
export function* loadAppConfig(): IterableIterator<LoadConfigEffect> {
|
||||
const appConfig = yield call(getAppConfig);
|
||||
yield put({
|
||||
type: TypeKeys.APP_CONFIG_RECEIVED,
|
||||
payload: {
|
||||
appConfig
|
||||
}
|
||||
} as AppConfigReceived);
|
||||
}
|
8
src/app/sagas/root-saga.ts
Normal file
8
src/app/sagas/root-saga.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { all } from 'redux-saga/effects';
|
||||
import { watchInitializeApp } from './initialize-app';
|
||||
|
||||
export default function* rootSaga(): any {
|
||||
yield all([
|
||||
watchInitializeApp()
|
||||
]);
|
||||
}
|
9
src/app/state/config-state.ts
Normal file
9
src/app/state/config-state.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { InitConfig } from 'app/config';
|
||||
import { AppConfig } from 'app/backend';
|
||||
|
||||
export class ConfigState {
|
||||
origin: string;
|
||||
inFrame: boolean;
|
||||
initConfig: InitConfig;
|
||||
appConfig?: AppConfig;
|
||||
}
|
4
src/app/state/index.ts
Normal file
4
src/app/state/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './state';
|
||||
export * from './initialize-app-state';
|
||||
export * from './config-state';
|
||||
export * from './model-state';
|
8
src/app/state/initialize-app-state.ts
Normal file
8
src/app/state/initialize-app-state.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { LogicError } from 'app/backend';
|
||||
|
||||
type Error = LogicError;
|
||||
|
||||
export interface InitializeAppState {
|
||||
initialized: boolean;
|
||||
error?: Error;
|
||||
}
|
5
src/app/state/model-state.ts
Normal file
5
src/app/state/model-state.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Identity } from 'app/backend';
|
||||
|
||||
export class ModelState {
|
||||
identity?: Identity;
|
||||
}
|
11
src/app/state/state.ts
Normal file
11
src/app/state/state.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import {
|
||||
InitializeAppState,
|
||||
ConfigState,
|
||||
ModelState
|
||||
} from '.';
|
||||
|
||||
export interface State {
|
||||
readonly initializeApp: InitializeAppState;
|
||||
readonly config: ConfigState;
|
||||
readonly model: ModelState;
|
||||
}
|
1
src/app/utils/get-nocache-value.ts
Normal file
1
src/app/utils/get-nocache-value.ts
Normal file
@ -0,0 +1 @@
|
||||
export const getNocacheValue = () => new Date().getTime();
|
35
src/app/utils/uri-serializer.ts
Normal file
35
src/app/utils/uri-serializer.ts
Normal file
@ -0,0 +1,35 @@
|
||||
const parseStringOrObject = (value: any) => {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (e) {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
export const deserialize = (url: string): any => {
|
||||
const split = (typeof url === 'string' && url !== '') && url.split('?');
|
||||
if (!split) {
|
||||
return {};
|
||||
}
|
||||
const params = split.length > 1 ? split[1] : split[0];
|
||||
const result = JSON.parse(`{"${decodeURI(params).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"')}"}`);
|
||||
for (const prop in result) {
|
||||
if (result.hasOwnProperty(prop)) {
|
||||
const value = decodeURIComponent(result[prop]);
|
||||
if (value === 'true') {
|
||||
result[prop] = true;
|
||||
} else if (value === 'false') {
|
||||
result[prop] = false;
|
||||
} else if (value === 'undefined') {
|
||||
result[prop] = undefined;
|
||||
} else if (value === 'null') {
|
||||
result[prop] = null;
|
||||
} else if (value !== '' && !isNaN(value as any)) {
|
||||
result[prop] = parseFloat(value);
|
||||
} else {
|
||||
result[prop] = parseStringOrObject(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
3
src/appConfig.json
Normal file
3
src/appConfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"wapiEndpoint": "<wapi endpoint>"
|
||||
}
|
@ -9,7 +9,7 @@ export class Child {
|
||||
const target = window.opener;
|
||||
const context = ContextResolver.get();
|
||||
return resolve(new RealTransport(target, context.parentOrigin, window));
|
||||
} else if (isInFrame() && !window.opener) {
|
||||
} else if (!isInFrame() && !window.opener) {
|
||||
return resolve(new StubTransport());
|
||||
} else {
|
||||
const shake = (e: MessageEvent) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { RealTransport } from './real-transport';
|
||||
import { Transport } from './transport';
|
||||
import { TransportInfo } from './model/transport-info';
|
||||
import { TransportInfo } from './model';
|
||||
|
||||
export class Parent {
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PossibleEvents } from './model/index';
|
||||
import { PossibleEvents } from './model';
|
||||
|
||||
export interface Transport {
|
||||
emit(name: PossibleEvents, data?: any): void;
|
||||
|
@ -18,7 +18,7 @@ export class IframeInitializer extends Initializer {
|
||||
const parent = new Parent(target, this.origin);
|
||||
return new Promise((resolve) => {
|
||||
return parent.sendHandshake().then((transport) => {
|
||||
transport.emit(PossibleEvents.init, {data});
|
||||
transport.emit(PossibleEvents.init, data);
|
||||
resolve(transport);
|
||||
});
|
||||
});
|
||||
|
@ -1,15 +1,19 @@
|
||||
import { Parent, Transport } from '../communication';
|
||||
import { Initializer } from './initializer';
|
||||
import { InitializerData } from '../communication/model';
|
||||
import isObject from 'lodash-es/isObject';
|
||||
|
||||
const serialize = (params: any): string => {
|
||||
let urlParams = '';
|
||||
for (const prop in params) {
|
||||
if (params.hasOwnProperty(prop)) {
|
||||
const value = params[prop];
|
||||
let value = params[prop];
|
||||
if ((typeof value === 'function') || (value === undefined) || (value === null)) {
|
||||
continue;
|
||||
}
|
||||
if (isObject(value)) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
if (urlParams !== '') {
|
||||
urlParams += '&';
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export const isInFrame = (): boolean => {
|
||||
try {
|
||||
return window.self === window.top;
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
"no-var-keyword": true,
|
||||
"no-parameter-reassignment": true,
|
||||
"typedef": [true, "call-signature"],
|
||||
"typedef": false,
|
||||
|
||||
"readonly-keyword": false,
|
||||
"readonly-array": true,
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
"no-this": false,
|
||||
"no-class": false,
|
||||
"no-mixed-interface": true,
|
||||
"no-mixed-interface": false,
|
||||
"no-expression-statement": false,
|
||||
"no-if-statement": false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user