diff --git a/build/webpack.base.js b/build/webpack.base.js index a343e79cc..f34a6b066 100755 --- a/build/webpack.base.js +++ b/build/webpack.base.js @@ -36,6 +36,7 @@ const baseConfig = { }, resolve: { alias: { + // unfetch: "unfetch/dist/unfetch.js", process: "process/browser", "aelf-sdk": "aelf-sdk/dist/aelf.umd.js", "react-use": "react-use/lib", diff --git a/build/webpack.dev.js b/build/webpack.dev.js index 57121de35..0abe9e56b 100755 --- a/build/webpack.dev.js +++ b/build/webpack.dev.js @@ -71,29 +71,12 @@ const devConfig = { // inline: false, historyApiFallback: true, proxy: proxyServer, - // before(app) { - // app.all("*", (req, res, next) => { - // let mockFile = mockMapper[req.path]; - // if (isObject(mockFile)) { - // mockFile = mockFile[req.query.path]; - // } - // if (mockFile && devMode === "local") { - // res.sendFile( - // path.resolve(__dirname, mockFile), - // { - // headers: { - // "Content-Type": "application/json; charset=utf-8", - // }, - // }, - // (err) => { - // err && console.error(err); - // } - // ); - // } else { - // next(); - // } - // }); - // }, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "*", + "Access-Control-Allow-Headers": "*", + "Access-Control-Allow-Credentials": "true" + }, }, }; diff --git a/package.json b/package.json index 6b15150fa..9c96d758b 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@aelf-react/core": "^0.1.19", - "@ant-design/icons": "^4.1.0", + "@ant-design/icons": "4.8.1", "@babel/preset-typescript": "^7.21.0", "@babel/runtime": "^7.7.2", "@hot-loader/react-dom": "^17.0.2", @@ -112,6 +112,7 @@ "socket.io-client": "^2.2.0", "tslib": "^2.5.1", "uglifyjs-webpack-plugin": "^2.2.0", + "unfetch": "4.2.0", "vconsole": "^3.15.1", "webpack": "^5.74.0", "webpack-cli": "^4.10.0", diff --git a/src/App.js b/src/App.js index 71aee7709..d2d17d1d1 100644 --- a/src/App.js +++ b/src/App.js @@ -101,7 +101,7 @@ function App() { return (
- + diff --git a/src/common/request.js b/src/common/request.js index 7043a6165..7c5c0b16b 100644 --- a/src/common/request.js +++ b/src/common/request.js @@ -2,26 +2,27 @@ * @file 请求方法 * @author atom-yang */ -import axios from 'axios'; -import { omitBy } from 'lodash/fp'; -import { isObject } from 'lodash'; +import axios from "axios"; +import { omitBy } from "lodash/fp"; +import { isObject } from "lodash"; const defaultRequestOptions = { headers: { - 'Content-Type': 'application/json;charset=utf-8', + "Content-Type": "application/json;charset=utf-8", }, - withCredentials: true, - method: 'POST', + // withCredentials: true, + method: "POST", }; const http = axios.create(defaultRequestOptions); -const needPurify = (rawData) => (isObject(rawData) && !Array.isArray(rawData)); -const purify = (rawData) => (needPurify(rawData) - ? omitBy((value) => value === null - || value === undefined - || value === '')(rawData) - : rawData); +const needPurify = (rawData) => isObject(rawData) && !Array.isArray(rawData); +const purify = (rawData) => + needPurify(rawData) + ? omitBy((value) => value === null || value === undefined || value === "")( + rawData + ) + : rawData; /** * @desc 处理xhr status 200,但是数据status不为200的情况 @@ -54,12 +55,15 @@ const makeRequestConfig = (url, params, { headers = {}, ...extraOptions }) => { ...extraOptions, }; - if (config.method.toUpperCase() === 'GET') { + if (config.method.toUpperCase() === "GET") { config.params = data; - } else if (config.method.toUpperCase() === 'POST') { + } else if (config.method.toUpperCase() === "POST") { config.data = data; } else { - throw new Error(`don\'t support http method ${config.method.toUpperCase()}`); + throw new Error( + // eslint-disable-next-line no-useless-escape + `don\'t support http method ${config.method.toUpperCase()}` + ); } return config; @@ -71,5 +75,7 @@ const makeRequestConfig = (url, params, { headers = {}, ...extraOptions }) => { * @param {Object} params 参数 * @param {Object} extraOptions 额外的参数 */ -export const request = (url, params, extraOptions = {}) => http.request(makeRequestConfig(url, params, extraOptions)) - .then((res) => handleInvalidError(res), handleRequestError); +export const request = (url, params, extraOptions = {}) => + http + .request(makeRequestConfig(url, params, extraOptions)) + .then((res) => handleInvalidError(res), handleRequestError); diff --git a/src/index.js b/src/index.js index 34c8cfe71..3246a9069 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ * @author huangzongzhe,longyue,zhouminghui */ import React from "react"; -import ReactDOM from "react-dom"; +import ReactDOM, { unmountComponentAtNode } from "react-dom"; import { Provider } from "react-redux"; import Cookies from "js-cookie"; import VConsole from "vconsole"; @@ -25,7 +25,7 @@ import "./index.less"; import "./portkey.less"; import "./common/webLoginConfig"; - +import "./public-path"; import App from "./App"; import { WALLET_IMG } from "./common/constants"; import { isPhoneCheck } from "./common/utils"; @@ -59,9 +59,14 @@ getNodesInfo(); if (module.hot) { module.hot.accept(); } +window.addEventListener("unmount", () => { + const root = document.getElementById("app"); + root && unmountComponentAtNode(root); +}); const container = document.getElementById("app"); const isMobile = isPhoneCheck(); + ReactDOM.render( diff --git a/src/pages/Proposal/App.jsx b/src/pages/Proposal/App.jsx index 22568bbbf..a1f6ae575 100644 --- a/src/pages/Proposal/App.jsx +++ b/src/pages/Proposal/App.jsx @@ -60,11 +60,11 @@ const App = () => { const isLogged = useMemo(() => logStatus === LOG_STATUS.LOGGED, [logStatus]); const { loginState } = useWebLogin(); - useEffect(() => { - sendMessage({ - href, - }); - }, [href]); + // useEffect(() => { + // sendMessage({ + // href, + // }); + // }, [href]); // useEffect(() => { // walletInstance.isExist diff --git a/src/pages/Proposal/containers/OrganizationList/index.jsx b/src/pages/Proposal/containers/OrganizationList/index.jsx index 5bcd70dba..58780f137 100644 --- a/src/pages/Proposal/containers/OrganizationList/index.jsx +++ b/src/pages/Proposal/containers/OrganizationList/index.jsx @@ -5,6 +5,7 @@ import React, { useEffect, useState } from "react"; import { useSelector, useDispatch, shallowEqual } from "react-redux"; import { useNavigate, Link, useLocation } from "react-router-dom"; +import { useEffectOnce } from "react-use"; import { Tabs, Pagination, @@ -91,24 +92,52 @@ const OrganizationList = () => { const handleTabChange = (key) => { if (key === proposalTypes.PARLIAMENT) { removeHash(); + fetchList({ + ...params, + pageNum: 1, + proposalType: key, + search: "", + }); setActiveKey(proposalTypes.PARLIAMENT); } else { const index = Object.values(keyFromHash).findIndex((ele) => ele === key); window.location.hash = Object.keys(keyFromHash)[index]; } + }; + + const changeKey = () => { + const { hash } = window.location; + const key = keyFromHash[hash]; + setActiveKey(key || proposalTypes.PARLIAMENT); + return key || proposalTypes.PARLIAMENT; + }; + + useEffectOnce(() => { + const key = changeKey(); fetchList({ ...params, pageNum: 1, proposalType: key, search: "", }); - }; - window.addEventListener("hashchange", () => { - const { hash } = window.location; - const key = keyFromHash[hash]; - setActiveKey(key || proposalTypes.PARLIAMENT); }); + useEffect(() => { + const onHashChange = () => { + const key = changeKey(); + fetchList({ + ...params, + pageNum: 1, + proposalType: key, + search: "", + }); + }; + window.addEventListener("hashchange", onHashChange); + return () => { + window.removeEventListener("hashchange", onHashChange); + }; + }, []); + const editOrganization = (orgAddress) => { const org = list.filter((item) => item.orgAddress === orgAddress)[0]; Modal.confirm({ diff --git a/src/pages/Proposal/containers/ProposalList/index.jsx b/src/pages/Proposal/containers/ProposalList/index.jsx index 2022b3b2c..b08f8c970 100644 --- a/src/pages/Proposal/containers/ProposalList/index.jsx +++ b/src/pages/Proposal/containers/ProposalList/index.jsx @@ -133,6 +133,14 @@ const ProposalList = () => { const handleTabChange = (key) => { if (key === proposalTypes.PARLIAMENT) { removeHash(); + fetchList({ + ...params, + pageNum: 1, + proposalType: key, + status: proposalStatus.ALL, + isContract: 0, + search: "", + }); setActiveKey(proposalTypes.PARLIAMENT); } else { const index = Object.values(keyFromHash).findIndex((ele) => ele === key); diff --git a/src/public-path.js b/src/public-path.js new file mode 100644 index 000000000..37b72a1ab --- /dev/null +++ b/src/public-path.js @@ -0,0 +1,4 @@ +if (window.__MICRO_APP_ENVIRONMENT__) { + // eslint-disable-next-line + __webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__; +} diff --git a/src/routes/routes.js b/src/routes/routes.js index 204f53bd9..fb9764cd7 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -3,10 +3,12 @@ * @author huangzongzhe * TODO: details modified to Resource */ -import React, { lazy } from "react"; -import { Navigate, useRoutes } from "react-router"; - +import React, { lazy, useEffect } from "react"; +import { Navigate, useNavigate, useRoutes } from "react-router"; +import { useLocation } from "react-use"; +import unfetch from "unfetch"; import { ProposalRouter } from "../pages/Proposal/routes"; +import { WebLoginInstance } from "../utils/webLogin"; // Notice: we need register the route in Breadcurmb.js. // If not, we will always turn to '/' @@ -33,34 +35,80 @@ const SearchFailed = lazy(() => import("../pages/SearchFailed/SearchFailed")); const SearchInvalid = lazy(() => import("../pages/SearchInvalid/SearchInvalid") ); - +const GOVERNANCE_LIST = ["/proposal", "/vote", "/resource"]; // eslint-disable-next-line import/prefer-default-export -export const PageRouter = () => - useRoutes( - ProposalRouter.concat([ - { path: "/", element: }, - { path: "/blocks", element: }, - // { path: "/unconfirmedBlocks", element: }, - { path: "/block/:id", element: }, - { path: "/txs", element: }, - // { path: "/unconfirmedTxs", element: }, - { path: "/txs/block", element: }, - { path: "/tx/:id", element: }, - { path: "/vote", element: }, - { path: "/vote/*", element: }, - { path: "/resource", element: }, - { path: "/resourceDetail/:id", element: }, - { path: "/token", element: }, - { path: "/token/:symbol", element: }, - { path: "/search-invalid/:string", element: }, - { path: "/search-invalid/*", element: }, - { path: "/search-failed", element: }, - { path: "/accounts", element: }, - // { path: "/contract", element: }, - { path: "/address/:address", element: }, - { path: "/contract/:address", element: }, - { path: "/address/:address/:codeHash", element: }, - { path: "/contracts", element: }, - { path: "*", element: }, - ]) +export const PageRouter = () => { + const navigate = useNavigate(); + const { pathname } = useLocation(); + useEffect(() => { + // if the history entry was not pushed/replaced by app-router, it will reload in Next.js + const onRouteChange = () => { + const isGovernance = GOVERNANCE_LIST.some((ele) => + window.location.pathname.startsWith(ele) + ); + if (isGovernance) { + window.microApp.dispatch({ + pathname: window.location.pathname + window.location.hash, + }); + } + }; + const onDataListener = (data) => { + // if (data.path && data.path !== pathname) { + // navigate(data.path); + // } + if (data.type === "logoutSilently") { + WebLoginInstance.get().logoutAsync({ + noModal: true + }); + } + }; + if (window.microApp) { + window.fetch = unfetch; + window.microApp.addDataListener(onDataListener, true); + window.addEventListener("hashchange", onRouteChange); + window.addEventListener("pushstate", onRouteChange); + // window.addEventListener("popstate", onDataListener); + } + return () => { + window.microApp.removeDataListener(onDataListener); + window.removeEventListener("hashchange", onRouteChange); + window.removeEventListener("pushstate", onRouteChange); + // window.removeEventListener("pophstate", onDataListener); + }; + }, []); + const MICRO_APP_ROUTER = ProposalRouter.concat([ + { + path: "/vote", + element: , + }, + { path: "/vote/*", element: }, + { path: "/resource", element: }, + { path: "/resourceDetail/:id", element: }, + ]); + return useRoutes( + window.microApp + ? MICRO_APP_ROUTER + : MICRO_APP_ROUTER.concat([ + { path: "/", element: }, + { path: "/blocks", element: }, + // { path: "/unconfirmedBlocks", element: }, + { path: "/block/:id", element: }, + { path: "/txs", element: }, + // { path: "/unconfirmedTxs", element: }, + { path: "/txs/block", element: }, + { path: "/tx/:id", element: }, + { path: "/token", element: }, + { path: "/token/:symbol", element: }, + { path: "/search-invalid/:string", element: }, + { path: "/search-invalid/*", element: }, + { path: "/search-failed", element: }, + { path: "/accounts", element: }, + // { path: "/contract", element: }, + { path: "/address/:address", element: }, + { path: "/contract/:address", element: }, + { path: "/address/:address/:codeHash", element: }, + { path: "/contracts", element: }, + { path: "*", element: }, + ]) ); +}; diff --git a/src/utils/webLogin.js b/src/utils/webLogin.js index 155a0f0e1..cec7465d3 100644 --- a/src/utils/webLogin.js +++ b/src/utils/webLogin.js @@ -34,11 +34,11 @@ export class WebLoginInstance { }); } - async logoutAsync() { + async logoutAsync(option) { return new Promise((resolve, reject) => { this._logoutResolve = resolve; this._logoutReject = reject; - this._context.logout(); + this._context.logout(option); }); } diff --git a/template.ejs b/template.ejs index aea0fb9ba..cb5517005 100755 --- a/template.ejs +++ b/template.ejs @@ -3,7 +3,9 @@ - <%= htmlWebpackPlugin.options.title %> + + <%= htmlWebpackPlugin.options.title %> + @@ -11,13 +13,13 @@ - +
diff --git a/yarn.lock b/yarn.lock index 5b94db44b..6969b55ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -79,20 +79,21 @@ dependencies: "@ctrl/tinycolor" "^3.4.0" -"@ant-design/icons-svg@^4.2.1": +"@ant-design/icons-svg@^4.2.1", "@ant-design/icons-svg@^4.3.0": version "4.3.0" resolved "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.3.0.tgz#cd8d3624bba50975e848591cea12cb6be132cd82" integrity sha512-WOgvdH/1Wl8Z7VXigRbCa5djO14zxrNTzvrAQzhWiBQtEKT0uTc8K1ltjKZ8U1gPn/wXhMA8/jE39SJl0WNxSg== -"@ant-design/icons@^4.1.0": - version "4.7.0" - resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-4.7.0.tgz#8c3cbe0a556ba92af5dc7d1e70c0b25b5179af0f" - integrity sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g== +"@ant-design/icons@4.8.1": + version "4.8.1" + resolved "https://registry.npmjs.org/@ant-design/icons/-/icons-4.8.1.tgz#44f6c81f609811d68d48a123eb5dcc477f8fbcb7" + integrity sha512-JRAuiqllnMsiZIO8OvBOeFconprC3cnMpJ9MvXrHh+H5co9rlg8/aSHQfLf5jKKe18lUgRaIwC2pz8YxH9VuCA== dependencies: "@ant-design/colors" "^6.0.0" - "@ant-design/icons-svg" "^4.2.1" + "@ant-design/icons-svg" "^4.3.0" "@babel/runtime" "^7.11.2" classnames "^2.2.6" + lodash "^4.17.15" rc-util "^5.9.4" "@ant-design/icons@^4.7.0": @@ -15964,6 +15965,11 @@ underscore@~1.13.2: resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== +unfetch@4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"