diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a1366ba34..d9a15d5af 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,4 +6,3 @@ updates: interval: 'daily' allow: - dependency-name: '@zero-tech/zapp-*' - - dependency-type: 'indirect' diff --git a/README.md b/README.md index 2faeee8dc..0228b25ab 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ The [zOS Feed app](https://github.com/zer0-os/zOS-feed) is the first core app, a There is always work to be done on the core platform, so if you've noticed a bug or want to get involved at a deeper level, feel free to open a PR, or get in touch with the core team. Be sure to check out the [contributing guidelines](CONTRIBUTING.md) and [style guide](STYLE_GUIDE.md) before opening a PR. +### Architecture + +A high level overview of the Component, Connected Component, Redux Saga, Normalizr, Redux architecture: https://miro.com/app/board/uXjVPL_sxFI=/ + ### Deployment #### Production diff --git a/package-lock.json b/package-lock.json index b16480f6f..ee57cfedf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "zOS", - "version": "0.11.0", + "version": "0.12.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "zOS", - "version": "0.11.0", + "version": "0.12.0", "dependencies": { "@craco/craco": "^6.4.3", "@giphy/js-fetch-api": "^4.7.1", @@ -28,10 +28,10 @@ "@zer0-os/zos-component-library": "0.18.9", "@zer0-os/zos-feed": "^1.29.2", "@zer0-os/zos-zns": "2.3.3", - "@zero-tech/zapp-buy-domains": "^0.2.1", - "@zero-tech/zapp-daos": "^0.4.0", - "@zero-tech/zapp-nfts": "^0.7.5", - "@zero-tech/zapp-staking": "0.4.8", + "@zero-tech/zapp-buy-domains": "*", + "@zero-tech/zapp-daos": "*", + "@zero-tech/zapp-nfts": "latest", + "@zero-tech/zapp-staking": "*", "@zero-tech/zui": "^0.16.0", "audio-react-recorder-fixed": "^1.0.3", "classnames": "^2.3.1", @@ -2118,7 +2118,8 @@ }, "node_modules/@ensdomains/eth-ens-namehash": { "version": "2.0.15", - "license": "ISC" + "resolved": "https://registry.npmjs.org/@ensdomains/eth-ens-namehash/-/eth-ens-namehash-2.0.15.tgz", + "integrity": "sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw==" }, "node_modules/@enzoferey/ethers-error-parser": { "version": "0.2.2", @@ -3416,54 +3417,6 @@ "node": ">=10" } }, - "node_modules/@gnosis.pm/safe-react-gateway-sdk": { - "version": "2.10.1", - "license": "MIT", - "dependencies": { - "cross-fetch": "^3.1.5" - } - }, - "node_modules/@gnosis.pm/safe-react-gateway-sdk/node_modules/cross-fetch": { - "version": "3.1.5", - "license": "MIT", - "dependencies": { - "node-fetch": "2.6.7" - } - }, - "node_modules/@gnosis.pm/safe-react-gateway-sdk/node_modules/node-fetch": { - "version": "2.6.7", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/@gnosis.pm/safe-react-gateway-sdk/node_modules/tr46": { - "version": "0.0.3", - "license": "MIT" - }, - "node_modules/@gnosis.pm/safe-react-gateway-sdk/node_modules/webidl-conversions": { - "version": "3.0.1", - "license": "BSD-2-Clause" - }, - "node_modules/@gnosis.pm/safe-react-gateway-sdk/node_modules/whatwg-url": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/@graphql-typed-document-node/core": { "version": "3.1.1", "license": "MIT", @@ -6352,6 +6305,60 @@ "rollup": "^1.20.0||^2.0.0" } }, + "node_modules/@safe-global/safe-gateway-typescript-sdk": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.7.0.tgz", + "integrity": "sha512-3BvlUgp0oZ1Zkn7nG3wY1jvCEE4t530BjKcaa3r0qsf0whf/ez/0gmQwk7DTOGmVmvOfjj6HHikxnrUCCX+/3Q==", + "dependencies": { + "cross-fetch": "^3.1.5" + } + }, + "node_modules/@safe-global/safe-gateway-typescript-sdk/node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/@safe-global/safe-gateway-typescript-sdk/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@safe-global/safe-gateway-typescript-sdk/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/@safe-global/safe-gateway-typescript-sdk/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/@safe-global/safe-gateway-typescript-sdk/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/@sentry/browser": { "version": "7.13.0", "license": "BSD-3-Clause", @@ -6471,29 +6478,87 @@ } }, "node_modules/@snapshot-labs/snapshot.js": { - "version": "0.3.56", - "license": "MIT", + "version": "0.4.58", + "resolved": "https://registry.npmjs.org/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.58.tgz", + "integrity": "sha512-dtfeiB0kEtpkQXKtc/MXrCj2cy3/CbbtNKMKudm/aLCTyK3DzYtQyvPLxQ1LwEvFcmf+1w3F6LAPENtmuj9obQ==", "dependencies": { "@ensdomains/eth-ens-namehash": "^2.0.15", - "@ethersproject/abi": "^5.0.4", - "@ethersproject/bytes": "^5.0.8", - "@ethersproject/contracts": "^5.0.3", - "@ethersproject/hash": "^5.0.9", - "@ethersproject/providers": "^5.3.1", - "@ethersproject/wallet": "^5.4.0", - "ajv": "^8.6.0", - "ajv-formats": "^2.1.0", - "cross-fetch": "^3.0.6", - "json-to-graphql-query": "^2.0.0", + "@ethersproject/abi": "^5.6.4", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/contracts": "^5.6.2", + "@ethersproject/hash": "^5.6.1", + "@ethersproject/providers": "^5.6.8", + "@ethersproject/wallet": "^5.6.2", + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "cross-fetch": "^3.1.5", + "json-to-graphql-query": "^2.2.4", "lodash.set": "^4.3.2" }, "engines": { "node": ">=14" } }, + "node_modules/@snapshot-labs/snapshot.js/node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@snapshot-labs/snapshot.js/node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, "node_modules/@snapshot-labs/snapshot.js/node_modules/ajv": { - "version": "8.11.2", - "license": "MIT", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -6505,9 +6570,56 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@snapshot-labs/snapshot.js/node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, "node_modules/@snapshot-labs/snapshot.js/node_modules/json-schema-traverse": { "version": "1.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/@snapshot-labs/snapshot.js/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@snapshot-labs/snapshot.js/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/@snapshot-labs/snapshot.js/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/@snapshot-labs/snapshot.js/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } }, "node_modules/@stitches/react": { "version": "1.2.8", @@ -7530,7 +7642,8 @@ }, "node_modules/@types/shortid": { "version": "0.0.29", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", + "integrity": "sha512-9BCYD9btg2CY4kPcpMQ+vCR8U6V8f/KvixYD5ZbxoWlkhddNF5IeZMVL3p+QFUkg+Hb+kPAG9Jgk4bnnF1v/Fw==" }, "node_modules/@types/source-list-map": { "version": "0.1.2", @@ -8449,177 +8562,6 @@ "react-router-dom": "5.3.0" } }, - "node_modules/@zer0-os/zos-feed/node_modules/@ethersproject/abi": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.1.tgz", - "integrity": "sha512-9mhbjUk76BiSluiiW4BaYyI58KSbDMMQpCLdsAR+RsT2GyATiNYxVv+pGWRrekmsIdY3I+hOqsYQSTkc8L/mcg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.4.0", - "@ethersproject/bignumber": "^5.4.0", - "@ethersproject/bytes": "^5.4.0", - "@ethersproject/constants": "^5.4.0", - "@ethersproject/hash": "^5.4.0", - "@ethersproject/keccak256": "^5.4.0", - "@ethersproject/logger": "^5.4.0", - "@ethersproject/properties": "^5.4.0", - "@ethersproject/strings": "^5.4.0" - } - }, - "node_modules/@zer0-os/zos-feed/node_modules/@ethersproject/bytes": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz", - "integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.4.0" - } - }, - "node_modules/@zer0-os/zos-feed/node_modules/@remix-run/router": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz", - "integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==", - "peer": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@zer0-os/zos-feed/node_modules/@zero-tech/zapp-utils": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.5.tgz", - "integrity": "sha512-djydYDIu5GP5+y84K2aOL71ho5PBprfsZJO75Jy9zlHA47Co8nn3WK59D7yTO/Oyu0FJYZSAvBehYQ5VWFHwUQ==", - "dependencies": { - "@cloudinary/url-gen": "^1.8.6", - "@enzoferey/ethers-error-parser": "^0.2.2", - "@ethersproject/units": "^5.6.1", - "@zero-tech/zfi-sdk": "0.2.1", - "@zero-tech/zns-sdk": "0.6.1", - "classnames": "^2.3.1", - "cloudinary-build-url": "^0.2.4", - "lodash": "^4.17.21", - "react-query": "^3.39.1" - }, - "peerDependencies": { - "@testing-library/react": "^11.2.6", - "@zero-tech/zui": "0.15.0", - "ethers": "^5.4.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-redux": "^7.2.6", - "react-router-dom": "^5.3.0" - } - }, - "node_modules/@zer0-os/zos-feed/node_modules/@zero-tech/zns-sdk": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.6.1.tgz", - "integrity": "sha512-nuZLWoJn3h9+aleHVdASkwb7G7h1gomLemju4yGIiZPUhWHnhnjtjk4rfPxvE5VLApdGF9fCV4gk9yOyQ6OwxA==", - "dependencies": { - "@apollo/client": "3.4.10", - "@ethersproject/abi": "5.4.1", - "@ethersproject/bytes": "5.4.0", - "@ethersproject/providers": "5.4.5", - "coingecko-api": "1.0.10", - "consola": "2.15.3", - "cross-fetch": "3.1.4", - "graphql": "15.5.3", - "lolex": "6.0.0" - }, - "peerDependencies": { - "@zero-tech/zauction-sdk": ">=0.1.4", - "ethers": "^5.4.6" - } - }, - "node_modules/@zer0-os/zos-feed/node_modules/@zero-tech/zui": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.15.0.tgz", - "integrity": "sha512-8cWXVMJ+76egw2xCDO5QonAILG8aHGYHSmSpVozaAGWHmcIzOOZcGW7xIan2Oj8JkpN+1tljvjrO5HpUbk7IFg==", - "peer": true, - "dependencies": { - "@radix-ui/react-accessible-icon": "^1.0.0", - "@radix-ui/react-accordion": "^1.0.1", - "@radix-ui/react-aspect-ratio": "^1.0.0", - "@radix-ui/react-avatar": "^1.0.1", - "@radix-ui/react-checkbox": "^1.0.1", - "@radix-ui/react-dialog": "^0.1.7", - "@radix-ui/react-dropdown-menu": "^0.1.6", - "@radix-ui/react-slider": "^1.1.0", - "@radix-ui/react-tabs": "^0.1.5", - "@radix-ui/react-toggle": "^1.0.0", - "@radix-ui/react-toggle-group": "^1.0.0", - "@radix-ui/react-tooltip": "^1.0.0", - "@react-aria/button": "^3.5.0", - "@react-aria/i18n": "^3.4.1", - "@react-aria/numberfield": "^3.2.1", - "@react-aria/textfield": "^3.6.1", - "@react-stately/numberfield": "^3.1.1", - "@stitches/react": "^1.2.8", - "@storybook/preset-scss": "^1.0.3", - "@uiw/react-md-editor": "^3.12.3", - "classnames": "^2.3.2", - "ethers": "^5.6.9", - "focus-visible": "^5.2.0", - "react-infinite-scroll-component": "^6.1.0", - "react-loading-skeleton": "^3.1.0", - "react-router-dom": "^6.3.0", - "remark-emoji": "^3.0.2", - "remark-gemoji": "^7.0.1", - "sass": "^1.52.2" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@zer0-os/zos-feed/node_modules/@zero-tech/zui/node_modules/react-router-dom": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz", - "integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==", - "peer": true, - "dependencies": { - "@remix-run/router": "1.4.0", - "react-router": "6.9.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/@zer0-os/zos-feed/node_modules/react-router": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz", - "integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==", - "peer": true, - "dependencies": { - "@remix-run/router": "1.4.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, "node_modules/@zer0-os/zos-zns": { "version": "2.3.3", "license": "ISC", @@ -8736,7 +8678,8 @@ }, "node_modules/@zero-tech/zapp-buy-domains": { "version": "0.2.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-buy-domains/-/zapp-buy-domains-0.2.1.tgz", + "integrity": "sha512-vYYN02Jx+M2MVCjjQYsY/NJrGousc9+WY0Z/6UxCtsk19SKQ7RshuxJxIUDcQ0IyxwOFWI/ssMQ1u82UB7rkGQ==", "dependencies": { "@zero-tech/zns-sdk": "0.8.9", "@zero-tech/zui": "0.11.4", @@ -8893,15 +8836,16 @@ } }, "node_modules/@zero-tech/zapp-daos": { - "version": "0.4.0", - "license": "ISC", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-daos/-/zapp-daos-0.8.0.tgz", + "integrity": "sha512-xDtUgyvrteuH9m8D3eeBuEcmm9mZq2Z1IP6cPY3Z9mm7QV5eNTIJ7ZLfgqyWwPsMiDlUrYpBAVHSE3pQb4xjJQ==", "dependencies": { "@babel/plugin-proposal-class-properties": "^7.18.6", "@ethersproject/units": "^5.6.1", - "@zero-tech/zapp-utils": "^0.5.0", - "@zero-tech/zdao-sdk": "0.13.0", - "@zero-tech/zns-sdk": "0.8.13", - "@zero-tech/zui": "^0.11.4", + "@zero-tech/zapp-utils": "0.5.5", + "@zero-tech/zdao-sdk": "0.14.1", + "@zero-tech/zns-sdk": "0.10.2", + "@zero-tech/zui": "0.15.0", "classnames": "^2.3.1", "formik": "^2.2.9", "markdown-to-text": "^0.1.1", @@ -8964,15 +8908,17 @@ } }, "node_modules/@zero-tech/zapp-daos/node_modules/@remix-run/router": { - "version": "1.3.0", - "license": "MIT", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz", + "integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==", "engines": { "node": ">=14" } }, "node_modules/@zero-tech/zapp-daos/node_modules/@types/lodash": { "version": "4.14.180", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.180.tgz", + "integrity": "sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==" }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zapp-utils": { "version": "0.5.5", @@ -9041,8 +8987,9 @@ } }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zdao-sdk": { - "version": "0.13.0", - "license": "MIT", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zdao-sdk/-/zdao-sdk-0.14.1.tgz", + "integrity": "sha512-IofAMYPEd/hpLI4A9/pqdJmsPUEh2/7OfZgtyVHkD5wsyijFOJ59OExliHI/EINg0UpbSQpoi+Oy9T+/B/0Jrg==", "dependencies": { "@ethersproject/abstract-signer": "^5.4.1", "@ethersproject/address": "^5.4.0", @@ -9050,8 +8997,8 @@ "@ethersproject/contracts": "^5.4.1", "@ethersproject/providers": "^5.4.5", "@ethersproject/wallet": "^5.4.0", - "@gnosis.pm/safe-react-gateway-sdk": "2.10.1", - "@snapshot-labs/snapshot.js": "0.3.56", + "@safe-global/safe-gateway-typescript-sdk": "3.7.0", + "@snapshot-labs/snapshot.js": "0.4.58", "@types/lodash": "4.14.180", "@types/shortid": "0.0.29", "cross-fetch": "3.1.5", @@ -9072,21 +9019,24 @@ }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zdao-sdk/node_modules/cross-fetch": { "version": "3.1.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", "dependencies": { "node-fetch": "2.6.7" } }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zdao-sdk/node_modules/graphql": { "version": "16.3.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.3.0.tgz", + "integrity": "sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==", "engines": { "node": "^12.22.0 || ^14.16.0 || >=16.0.0" } }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zdao-sdk/node_modules/graphql-request": { "version": "4.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-4.1.0.tgz", + "integrity": "sha512-CBFcO6LP7cg+aBMc+x9C1dZEQsKTBZKR2J+HzuB0cR/6aaU4K4/tRXTQu8CDMp5195ZU+DTNKZZOSK1WRbTeAg==", "dependencies": { "cross-fetch": "^3.0.6", "extract-files": "^9.0.0", @@ -9097,13 +9047,15 @@ } }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zns-sdk": { - "version": "0.8.13", - "license": "MIT", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.10.2.tgz", + "integrity": "sha512-gwUOkOWKfZvpwMOFUyJ+fAKBnKmW/HrOo7T+YJjFG3xPcfjCrXfc81qbay4dZRA3BYZXLVUNgBRu46Ix+daRcw==", "dependencies": { "@apollo/client": "3.4.10", "@ethersproject/abi": "5.4.1", "@ethersproject/bytes": "5.4.0", "@ethersproject/providers": "5.4.5", + "@zero-tech/zero-contracts": "^0.0.4", "coingecko-api": "1.0.10", "consola": "2.15.3", "cross-fetch": "3.1.4", @@ -9119,19 +9071,25 @@ }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zns-sdk/node_modules/dotenv": { "version": "16.0.1", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", "engines": { "node": ">=12" } }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zui": { - "version": "0.11.6", - "license": "ISC", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.15.0.tgz", + "integrity": "sha512-8cWXVMJ+76egw2xCDO5QonAILG8aHGYHSmSpVozaAGWHmcIzOOZcGW7xIan2Oj8JkpN+1tljvjrO5HpUbk7IFg==", "dependencies": { "@radix-ui/react-accessible-icon": "^1.0.0", + "@radix-ui/react-accordion": "^1.0.1", "@radix-ui/react-aspect-ratio": "^1.0.0", + "@radix-ui/react-avatar": "^1.0.1", + "@radix-ui/react-checkbox": "^1.0.1", "@radix-ui/react-dialog": "^0.1.7", "@radix-ui/react-dropdown-menu": "^0.1.6", + "@radix-ui/react-slider": "^1.1.0", "@radix-ui/react-tabs": "^0.1.5", "@radix-ui/react-toggle": "^1.0.0", "@radix-ui/react-toggle-group": "^1.0.0", @@ -9144,7 +9102,7 @@ "@stitches/react": "^1.2.8", "@storybook/preset-scss": "^1.0.3", "@uiw/react-md-editor": "^3.12.3", - "classnames": "^2.3.1", + "classnames": "^2.3.2", "ethers": "^5.6.9", "focus-visible": "^5.2.0", "react-infinite-scroll-component": "^6.1.0", @@ -9160,11 +9118,12 @@ } }, "node_modules/@zero-tech/zapp-daos/node_modules/@zero-tech/zui/node_modules/react-router-dom": { - "version": "6.7.0", - "license": "MIT", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz", + "integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==", "dependencies": { - "@remix-run/router": "1.3.0", - "react-router": "6.7.0" + "@remix-run/router": "1.4.0", + "react-router": "6.9.0" }, "engines": { "node": ">=14" @@ -9176,14 +9135,16 @@ }, "node_modules/@zero-tech/zapp-daos/node_modules/dotenv": { "version": "16.0.0", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", "engines": { "node": ">=12" } }, "node_modules/@zero-tech/zapp-daos/node_modules/node-fetch": { "version": "2.6.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -9200,10 +9161,11 @@ } }, "node_modules/@zero-tech/zapp-daos/node_modules/react-router": { - "version": "6.7.0", - "license": "MIT", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz", + "integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==", "dependencies": { - "@remix-run/router": "1.3.0" + "@remix-run/router": "1.4.0" }, "engines": { "node": ">=14" @@ -9214,37 +9176,42 @@ }, "node_modules/@zero-tech/zapp-daos/node_modules/tr46": { "version": "0.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/@zero-tech/zapp-daos/node_modules/webidl-conversions": { "version": "3.0.1", - "license": "BSD-2-Clause" + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/@zero-tech/zapp-daos/node_modules/whatwg-url": { "version": "5.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "node_modules/@zero-tech/zapp-nfts": { - "version": "0.7.5", - "license": "ISC", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-nfts/-/zapp-nfts-0.11.0.tgz", + "integrity": "sha512-SC9/aqA/PYsO5ZDgNzCx4Vp9aVAFN+qyHHWwcktrKCf6lVH3AiX23/3aoh4raN63+NYdv2eeY6E0+9fNZ+uv/Q==", "dependencies": { "@ethersproject/units": "^5.6.1", "@testing-library/jest-dom": "^5.16.5", "@testing-library/user-event": "^14.4.3", "@zer0-os/zapp-scripts": "^0.0.3", - "@zero-tech/zapp-utils": "0.5.4", + "@zero-tech/zapp-utils": "0.5.6", "@zero-tech/zero-contracts": "^0.0.7", - "@zero-tech/zns-sdk": "0.9.1", + "@zero-tech/zns-sdk": "0.10.1", "@zero-tech/ztoken-sdk": "^0.0.3", - "@zero-tech/zui": "0.12.0", + "@zero-tech/zui": "0.16.1", "classnames": "^2.3.1", "formik": "^2.2.9", "moment": "^2.29.4", "react-query": "^3.39.1", + "react-resize-detector": "7.0.0", "yup": "^0.32.11" }, "peerDependencies": { @@ -9259,6 +9226,8 @@ }, "node_modules/@zero-tech/zapp-nfts/node_modules/@ethersproject/abi": { "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.1.tgz", + "integrity": "sha512-9mhbjUk76BiSluiiW4BaYyI58KSbDMMQpCLdsAR+RsT2GyATiNYxVv+pGWRrekmsIdY3I+hOqsYQSTkc8L/mcg==", "funding": [ { "type": "individual", @@ -9269,7 +9238,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/address": "^5.4.0", "@ethersproject/bignumber": "^5.4.0", @@ -9300,66 +9268,14 @@ "@ethersproject/logger": "^5.4.0" } }, - "node_modules/@zero-tech/zapp-nfts/node_modules/@remix-run/router": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz", - "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w==", - "engines": { - "node": ">=14" - } - }, - "node_modules/@zero-tech/zapp-nfts/node_modules/@zero-tech/zapp-utils": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.4.tgz", - "integrity": "sha512-jtYH8Zws0OTDXjCy0aco4VjZcj3pFBAljc3LCyeDNNgU0FFxOlFP7jC+vv57sgrWDhTbVtgjeIIEK7lXe2TIaA==", - "dependencies": { - "@cloudinary/url-gen": "^1.8.6", - "@enzoferey/ethers-error-parser": "^0.2.2", - "@ethersproject/units": "^5.6.1", - "@zero-tech/zfi-sdk": "0.2.1", - "@zero-tech/zns-sdk": "0.6.1", - "classnames": "^2.3.1", - "cloudinary-build-url": "^0.2.4", - "lodash": "^4.17.21", - "react-query": "^3.39.1" - }, - "peerDependencies": { - "@testing-library/react": "^11.2.6", - "@zero-tech/zui": "0.12.0", - "ethers": "^5.4.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-redux": "^7.2.6", - "react-router-dom": "^5.3.0" - } - }, - "node_modules/@zero-tech/zapp-nfts/node_modules/@zero-tech/zapp-utils/node_modules/@zero-tech/zns-sdk": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.6.1.tgz", - "integrity": "sha512-nuZLWoJn3h9+aleHVdASkwb7G7h1gomLemju4yGIiZPUhWHnhnjtjk4rfPxvE5VLApdGF9fCV4gk9yOyQ6OwxA==", - "dependencies": { - "@apollo/client": "3.4.10", - "@ethersproject/abi": "5.4.1", - "@ethersproject/bytes": "5.4.0", - "@ethersproject/providers": "5.4.5", - "coingecko-api": "1.0.10", - "consola": "2.15.3", - "cross-fetch": "3.1.4", - "graphql": "15.5.3", - "lolex": "6.0.0" - }, - "peerDependencies": { - "@zero-tech/zauction-sdk": ">=0.1.4", - "ethers": "^5.4.6" - } - }, "node_modules/@zero-tech/zapp-nfts/node_modules/@zero-tech/zero-contracts": { "version": "0.0.7", "license": "MIT" }, "node_modules/@zero-tech/zapp-nfts/node_modules/@zero-tech/zns-sdk": { - "version": "0.9.1", - "license": "MIT", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.10.1.tgz", + "integrity": "sha512-180P+EpN1qlL7Mk63ZDGx6AicxWNkGXZEMsi1zIQfULMn++xlTvbD0W6LNQ7TIJP1hNnuF4hh14tzk3KJU5V5Q==", "dependencies": { "@apollo/client": "3.4.10", "@ethersproject/abi": "5.4.1", @@ -9381,86 +9297,21 @@ }, "node_modules/@zero-tech/zapp-nfts/node_modules/@zero-tech/zns-sdk/node_modules/@zero-tech/zero-contracts": { "version": "0.0.4", - "license": "MIT" - }, - "node_modules/@zero-tech/zapp-nfts/node_modules/@zero-tech/zui": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.12.0.tgz", - "integrity": "sha512-FErCZIuEeSKk1ukUt9v81YsCo+qq/0aAtVzE27d0FrHcN6yoa9e6zYcjsr3hKBCjf92GQxsgOxw8rMQqUqmhZA==", - "dependencies": { - "@radix-ui/react-accessible-icon": "^1.0.0", - "@radix-ui/react-aspect-ratio": "^1.0.0", - "@radix-ui/react-checkbox": "^1.0.1", - "@radix-ui/react-dialog": "^0.1.7", - "@radix-ui/react-dropdown-menu": "^0.1.6", - "@radix-ui/react-slider": "^1.1.0", - "@radix-ui/react-tabs": "^0.1.5", - "@radix-ui/react-toggle": "^1.0.0", - "@radix-ui/react-toggle-group": "^1.0.0", - "@radix-ui/react-tooltip": "^1.0.0", - "@react-aria/button": "^3.5.0", - "@react-aria/i18n": "^3.4.1", - "@react-aria/numberfield": "^3.2.1", - "@react-aria/textfield": "^3.6.1", - "@react-stately/numberfield": "^3.1.1", - "@stitches/react": "^1.2.8", - "@storybook/preset-scss": "^1.0.3", - "@uiw/react-md-editor": "^3.12.3", - "classnames": "^2.3.1", - "ethers": "^5.6.9", - "focus-visible": "^5.2.0", - "react-infinite-scroll-component": "^6.1.0", - "react-loading-skeleton": "^3.1.0", - "react-router-dom": "^6.3.0", - "remark-emoji": "^3.0.2", - "remark-gemoji": "^7.0.1", - "sass": "^1.52.2" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@zero-tech/zapp-nfts/node_modules/@zero-tech/zui/node_modules/react-router-dom": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.2.tgz", - "integrity": "sha512-N/oAF1Shd7g4tWy+75IIufCGsHBqT74tnzHQhbiUTYILYF0Blk65cg+HPZqwC+6SqEyx033nKqU7by38v3lBZg==", - "dependencies": { - "@remix-run/router": "1.3.3", - "react-router": "6.8.2" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } + "resolved": "https://registry.npmjs.org/@zero-tech/zero-contracts/-/zero-contracts-0.0.4.tgz", + "integrity": "sha512-nqDoLsUlTf7shanR9mzi8E7OzfSWzlaZtLrpwgCIojYnDjf/oUJ4N3iF00vCt1jmDRzP61EoNo3I0yQFg6m60Q==" }, "node_modules/@zero-tech/zapp-nfts/node_modules/dotenv": { "version": "16.0.1", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", "engines": { "node": ">=12" } }, - "node_modules/@zero-tech/zapp-nfts/node_modules/react-router": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz", - "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==", - "dependencies": { - "@remix-run/router": "1.3.3" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, "node_modules/@zero-tech/zapp-staking": { - "version": "0.4.8", - "license": "ISC", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-staking/-/zapp-staking-0.4.9.tgz", + "integrity": "sha512-je+4K0BXqUCx6s7NDby9ppk2li6aMpwF2/lO1DawE47hoQbd09AcR0xTnr/prFCRhRU3mVNlz36tgSmEyutQBw==", "dependencies": { "@babel/plugin-proposal-class-properties": "^7.18.6", "@enzoferey/ethers-error-parser": "^0.2.2", @@ -9534,31 +9385,6 @@ "node": ">=14" } }, - "node_modules/@zero-tech/zapp-staking/node_modules/@zero-tech/zapp-utils": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.5.tgz", - "integrity": "sha512-djydYDIu5GP5+y84K2aOL71ho5PBprfsZJO75Jy9zlHA47Co8nn3WK59D7yTO/Oyu0FJYZSAvBehYQ5VWFHwUQ==", - "dependencies": { - "@cloudinary/url-gen": "^1.8.6", - "@enzoferey/ethers-error-parser": "^0.2.2", - "@ethersproject/units": "^5.6.1", - "@zero-tech/zfi-sdk": "0.2.1", - "@zero-tech/zns-sdk": "0.6.1", - "classnames": "^2.3.1", - "cloudinary-build-url": "^0.2.4", - "lodash": "^4.17.21", - "react-query": "^3.39.1" - }, - "peerDependencies": { - "@testing-library/react": "^11.2.6", - "@zero-tech/zui": "0.15.0", - "ethers": "^5.4.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-redux": "^7.2.6", - "react-router-dom": "^5.3.0" - } - }, "node_modules/@zero-tech/zapp-staking/node_modules/@zero-tech/zns-sdk": { "version": "0.6.1", "license": "MIT", @@ -9735,6 +9561,95 @@ "node": ">=12" } }, + "node_modules/@zero-tech/zapp-utils": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.6.tgz", + "integrity": "sha512-uxbEJQk24AFzW9LUNZkmQpe7k6z4MEIY5DC0NDHpH53jb02dl557wIPNnpxTMiNI/WkTzlsudZuuQ4I5+1Bdcg==", + "dependencies": { + "@cloudinary/url-gen": "^1.8.6", + "@enzoferey/ethers-error-parser": "^0.2.2", + "@ethersproject/units": "^5.6.1", + "@zero-tech/zfi-sdk": "0.2.1", + "@zero-tech/zns-sdk": "0.6.1", + "classnames": "^2.3.1", + "cloudinary-build-url": "^0.2.4", + "lodash": "^4.17.21", + "react-query": "^3.39.1" + }, + "peerDependencies": { + "@testing-library/react": "^11.2.6", + "@zero-tech/zui": "^0.16.0", + "ethers": "^5.4.0", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-redux": "^7.2.6", + "react-router-dom": "^5.3.0" + } + }, + "node_modules/@zero-tech/zapp-utils/node_modules/@ethersproject/abi": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.1.tgz", + "integrity": "sha512-9mhbjUk76BiSluiiW4BaYyI58KSbDMMQpCLdsAR+RsT2GyATiNYxVv+pGWRrekmsIdY3I+hOqsYQSTkc8L/mcg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/hash": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/strings": "^5.4.0" + } + }, + "node_modules/@zero-tech/zapp-utils/node_modules/@ethersproject/bytes": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz", + "integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.4.0" + } + }, + "node_modules/@zero-tech/zapp-utils/node_modules/@zero-tech/zns-sdk": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.6.1.tgz", + "integrity": "sha512-nuZLWoJn3h9+aleHVdASkwb7G7h1gomLemju4yGIiZPUhWHnhnjtjk4rfPxvE5VLApdGF9fCV4gk9yOyQ6OwxA==", + "dependencies": { + "@apollo/client": "3.4.10", + "@ethersproject/abi": "5.4.1", + "@ethersproject/bytes": "5.4.0", + "@ethersproject/providers": "5.4.5", + "coingecko-api": "1.0.10", + "consola": "2.15.3", + "cross-fetch": "3.1.4", + "graphql": "15.5.3", + "lolex": "6.0.0" + }, + "peerDependencies": { + "@zero-tech/zauction-sdk": ">=0.1.4", + "ethers": "^5.4.6" + } + }, "node_modules/@zero-tech/zauction-sdk": { "version": "0.1.4", "license": "MIT", @@ -10661,9 +10576,9 @@ } }, "node_modules/@zero-tech/zui": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.16.0.tgz", - "integrity": "sha512-DBDkNRBiW6Scln0rQZeJMAQ6dfICPIi1iYZLERPuasSQzDyIfhrrNZS9J6yRA3AXZEdh45x96elBJNxw0IrzKw==", + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.16.1.tgz", + "integrity": "sha512-c236KUX2UdRvFfFbE6KeJM1EgtKS6+zcszCY/Tv3xRpNqTNyV2Tp2+1HFptgkh4rn6YfW6p8KvDETzmuRnzF+w==", "dependencies": { "@radix-ui/react-accessible-icon": "^1.0.0", "@radix-ui/react-accordion": "^1.0.1", @@ -10866,7 +10781,8 @@ }, "node_modules/ajv-formats": { "version": "2.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dependencies": { "ajv": "^8.0.0" }, @@ -10880,8 +10796,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.11.2", - "license": "MIT", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -10895,7 +10812,8 @@ }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/ajv-keywords": { "version": "3.5.2", @@ -18080,7 +17998,8 @@ }, "node_modules/extract-files": { "version": "9.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz", + "integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==", "engines": { "node": "^10.17.0 || ^12.0.0 || >= 13.7.0" }, @@ -23078,8 +22997,9 @@ "license": "ISC" }, "node_modules/json-to-graphql-query": { - "version": "2.2.4", - "license": "MIT" + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/json-to-graphql-query/-/json-to-graphql-query-2.2.5.tgz", + "integrity": "sha512-5Nom9inkIMrtY992LMBBG1Zaekrc10JaRhyZgprwHBVMDtRgllTvzl0oBbg13wJsVZoSoFNNMaeIVQs0P04vsA==" }, "node_modules/json3": { "version": "3.3.3", @@ -23458,7 +23378,8 @@ }, "node_modules/lodash.set": { "version": "4.3.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==" }, "node_modules/lodash.template": { "version": "4.5.0", @@ -30684,14 +30605,16 @@ }, "node_modules/shortid": { "version": "2.2.16", - "license": "MIT", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", + "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", "dependencies": { "nanoid": "^2.1.0" } }, "node_modules/shortid/node_modules/nanoid": { "version": "2.1.11", - "license": "MIT" + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" }, "node_modules/side-channel": { "version": "1.0.4", @@ -36610,7 +36533,9 @@ "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, "@ensdomains/eth-ens-namehash": { - "version": "2.0.15" + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@ensdomains/eth-ens-namehash/-/eth-ens-namehash-2.0.15.tgz", + "integrity": "sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw==" }, "@enzoferey/ethers-error-parser": { "version": "0.2.2", @@ -37318,39 +37243,6 @@ } } }, - "@gnosis.pm/safe-react-gateway-sdk": { - "version": "2.10.1", - "requires": { - "cross-fetch": "^3.1.5" - }, - "dependencies": { - "cross-fetch": { - "version": "3.1.5", - "requires": { - "node-fetch": "2.6.7" - } - }, - "node-fetch": { - "version": "2.6.7", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "tr46": { - "version": "0.0.3" - }, - "webidl-conversions": { - "version": "3.0.1" - }, - "whatwg-url": { - "version": "5.0.0", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } - }, "@graphql-typed-document-node/core": { "version": "3.1.1", "requires": {} @@ -39314,6 +39206,51 @@ "picomatch": "^2.2.2" } }, + "@safe-global/safe-gateway-typescript-sdk": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.7.0.tgz", + "integrity": "sha512-3BvlUgp0oZ1Zkn7nG3wY1jvCEE4t530BjKcaa3r0qsf0whf/ez/0gmQwk7DTOGmVmvOfjj6HHikxnrUCCX+/3Q==", + "requires": { + "cross-fetch": "^3.1.5" + }, + "dependencies": { + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "@sentry/browser": { "version": "7.13.0", "requires": { @@ -39398,24 +39335,64 @@ } }, "@snapshot-labs/snapshot.js": { - "version": "0.3.56", + "version": "0.4.58", + "resolved": "https://registry.npmjs.org/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.58.tgz", + "integrity": "sha512-dtfeiB0kEtpkQXKtc/MXrCj2cy3/CbbtNKMKudm/aLCTyK3DzYtQyvPLxQ1LwEvFcmf+1w3F6LAPENtmuj9obQ==", "requires": { "@ensdomains/eth-ens-namehash": "^2.0.15", - "@ethersproject/abi": "^5.0.4", - "@ethersproject/bytes": "^5.0.8", - "@ethersproject/contracts": "^5.0.3", - "@ethersproject/hash": "^5.0.9", - "@ethersproject/providers": "^5.3.1", - "@ethersproject/wallet": "^5.4.0", - "ajv": "^8.6.0", - "ajv-formats": "^2.1.0", - "cross-fetch": "^3.0.6", - "json-to-graphql-query": "^2.0.0", + "@ethersproject/abi": "^5.6.4", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/contracts": "^5.6.2", + "@ethersproject/hash": "^5.6.1", + "@ethersproject/providers": "^5.6.8", + "@ethersproject/wallet": "^5.6.2", + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "cross-fetch": "^3.1.5", + "json-to-graphql-query": "^2.2.4", "lodash.set": "^4.3.2" }, "dependencies": { + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, "ajv": { - "version": "8.11.2", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -39423,8 +39400,45 @@ "uri-js": "^4.2.2" } }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + } + }, "json-schema-traverse": { - "version": "1.0.0" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } } } }, @@ -40142,7 +40156,9 @@ } }, "@types/shortid": { - "version": "0.0.29" + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", + "integrity": "sha512-9BCYD9btg2CY4kPcpMQ+vCR8U6V8f/KvixYD5ZbxoWlkhddNF5IeZMVL3p+QFUkg+Hb+kPAG9Jgk4bnnF1v/Fw==" }, "@types/source-list-map": { "version": "0.1.2" @@ -40824,128 +40840,6 @@ "lodash.get": "^4.4.2", "lodash.isequalwith": "^4.4.0", "react-infinite-scroll-component": "^6.1.0" - }, - "dependencies": { - "@ethersproject/abi": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.1.tgz", - "integrity": "sha512-9mhbjUk76BiSluiiW4BaYyI58KSbDMMQpCLdsAR+RsT2GyATiNYxVv+pGWRrekmsIdY3I+hOqsYQSTkc8L/mcg==", - "requires": { - "@ethersproject/address": "^5.4.0", - "@ethersproject/bignumber": "^5.4.0", - "@ethersproject/bytes": "^5.4.0", - "@ethersproject/constants": "^5.4.0", - "@ethersproject/hash": "^5.4.0", - "@ethersproject/keccak256": "^5.4.0", - "@ethersproject/logger": "^5.4.0", - "@ethersproject/properties": "^5.4.0", - "@ethersproject/strings": "^5.4.0" - } - }, - "@ethersproject/bytes": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz", - "integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==", - "requires": { - "@ethersproject/logger": "^5.4.0" - } - }, - "@remix-run/router": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz", - "integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==", - "peer": true - }, - "@zero-tech/zapp-utils": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.5.tgz", - "integrity": "sha512-djydYDIu5GP5+y84K2aOL71ho5PBprfsZJO75Jy9zlHA47Co8nn3WK59D7yTO/Oyu0FJYZSAvBehYQ5VWFHwUQ==", - "requires": { - "@cloudinary/url-gen": "^1.8.6", - "@enzoferey/ethers-error-parser": "^0.2.2", - "@ethersproject/units": "^5.6.1", - "@zero-tech/zfi-sdk": "0.2.1", - "@zero-tech/zns-sdk": "0.6.1", - "classnames": "^2.3.1", - "cloudinary-build-url": "^0.2.4", - "lodash": "^4.17.21", - "react-query": "^3.39.1" - } - }, - "@zero-tech/zns-sdk": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.6.1.tgz", - "integrity": "sha512-nuZLWoJn3h9+aleHVdASkwb7G7h1gomLemju4yGIiZPUhWHnhnjtjk4rfPxvE5VLApdGF9fCV4gk9yOyQ6OwxA==", - "requires": { - "@apollo/client": "3.4.10", - "@ethersproject/abi": "5.4.1", - "@ethersproject/bytes": "5.4.0", - "@ethersproject/providers": "5.4.5", - "coingecko-api": "1.0.10", - "consola": "2.15.3", - "cross-fetch": "3.1.4", - "graphql": "15.5.3", - "lolex": "6.0.0" - } - }, - "@zero-tech/zui": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.15.0.tgz", - "integrity": "sha512-8cWXVMJ+76egw2xCDO5QonAILG8aHGYHSmSpVozaAGWHmcIzOOZcGW7xIan2Oj8JkpN+1tljvjrO5HpUbk7IFg==", - "peer": true, - "requires": { - "@radix-ui/react-accessible-icon": "^1.0.0", - "@radix-ui/react-accordion": "^1.0.1", - "@radix-ui/react-aspect-ratio": "^1.0.0", - "@radix-ui/react-avatar": "^1.0.1", - "@radix-ui/react-checkbox": "^1.0.1", - "@radix-ui/react-dialog": "^0.1.7", - "@radix-ui/react-dropdown-menu": "^0.1.6", - "@radix-ui/react-slider": "^1.1.0", - "@radix-ui/react-tabs": "^0.1.5", - "@radix-ui/react-toggle": "^1.0.0", - "@radix-ui/react-toggle-group": "^1.0.0", - "@radix-ui/react-tooltip": "^1.0.0", - "@react-aria/button": "^3.5.0", - "@react-aria/i18n": "^3.4.1", - "@react-aria/numberfield": "^3.2.1", - "@react-aria/textfield": "^3.6.1", - "@react-stately/numberfield": "^3.1.1", - "@stitches/react": "^1.2.8", - "@storybook/preset-scss": "^1.0.3", - "@uiw/react-md-editor": "^3.12.3", - "classnames": "^2.3.2", - "ethers": "^5.6.9", - "focus-visible": "^5.2.0", - "react-infinite-scroll-component": "^6.1.0", - "react-loading-skeleton": "^3.1.0", - "react-router-dom": "^6.3.0", - "remark-emoji": "^3.0.2", - "remark-gemoji": "^7.0.1", - "sass": "^1.52.2" - }, - "dependencies": { - "react-router-dom": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz", - "integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==", - "peer": true, - "requires": { - "@remix-run/router": "1.4.0", - "react-router": "6.9.0" - } - } - } - }, - "react-router": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz", - "integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==", - "peer": true, - "requires": { - "@remix-run/router": "1.4.0" - } - } } }, "@zer0-os/zos-zns": { @@ -41023,6 +40917,8 @@ }, "@zero-tech/zapp-buy-domains": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-buy-domains/-/zapp-buy-domains-0.2.1.tgz", + "integrity": "sha512-vYYN02Jx+M2MVCjjQYsY/NJrGousc9+WY0Z/6UxCtsk19SKQ7RshuxJxIUDcQ0IyxwOFWI/ssMQ1u82UB7rkGQ==", "requires": { "@zero-tech/zns-sdk": "0.8.9", "@zero-tech/zui": "0.11.4", @@ -41109,259 +41005,34 @@ } }, "dotenv": { - "version": "16.0.1" - }, - "react-router": { - "version": "6.7.0", - "requires": { - "@remix-run/router": "1.3.0" - } - } - } - }, - "@zero-tech/zapp-daos": { - "version": "0.4.0", - "requires": { - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@ethersproject/units": "^5.6.1", - "@zero-tech/zapp-utils": "^0.5.0", - "@zero-tech/zdao-sdk": "0.13.0", - "@zero-tech/zns-sdk": "0.8.13", - "@zero-tech/zui": "^0.11.4", - "classnames": "^2.3.1", - "formik": "^2.2.9", - "markdown-to-text": "^0.1.1", - "millify": "^4.0.0", - "moment": "^2.29.1", - "react-query": "^3.39.1", - "react-resize-detector": "7.0.0", - "yup": "^0.32.11" - }, - "dependencies": { - "@ethersproject/abi": { - "version": "5.4.1", - "requires": { - "@ethersproject/address": "^5.4.0", - "@ethersproject/bignumber": "^5.4.0", - "@ethersproject/bytes": "^5.4.0", - "@ethersproject/constants": "^5.4.0", - "@ethersproject/hash": "^5.4.0", - "@ethersproject/keccak256": "^5.4.0", - "@ethersproject/logger": "^5.4.0", - "@ethersproject/properties": "^5.4.0", - "@ethersproject/strings": "^5.4.0" - } - }, - "@ethersproject/bytes": { - "version": "5.4.0", - "requires": { - "@ethersproject/logger": "^5.4.0" - } - }, - "@remix-run/router": { - "version": "1.3.0" - }, - "@types/lodash": { - "version": "4.14.180" - }, - "@zero-tech/zapp-utils": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.5.tgz", - "integrity": "sha512-djydYDIu5GP5+y84K2aOL71ho5PBprfsZJO75Jy9zlHA47Co8nn3WK59D7yTO/Oyu0FJYZSAvBehYQ5VWFHwUQ==", - "requires": { - "@cloudinary/url-gen": "^1.8.6", - "@enzoferey/ethers-error-parser": "^0.2.2", - "@ethersproject/units": "^5.6.1", - "@zero-tech/zfi-sdk": "0.2.1", - "@zero-tech/zns-sdk": "0.6.1", - "classnames": "^2.3.1", - "cloudinary-build-url": "^0.2.4", - "lodash": "^4.17.21", - "react-query": "^3.39.1" - }, - "dependencies": { - "@zero-tech/zns-sdk": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.6.1.tgz", - "integrity": "sha512-nuZLWoJn3h9+aleHVdASkwb7G7h1gomLemju4yGIiZPUhWHnhnjtjk4rfPxvE5VLApdGF9fCV4gk9yOyQ6OwxA==", - "requires": { - "@apollo/client": "3.4.10", - "@ethersproject/abi": "5.4.1", - "@ethersproject/bytes": "5.4.0", - "@ethersproject/providers": "5.4.5", - "coingecko-api": "1.0.10", - "consola": "2.15.3", - "cross-fetch": "3.1.4", - "graphql": "15.5.3", - "lolex": "6.0.0" - } - } - } - }, - "@zero-tech/zauction-sdk": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@zero-tech/zauction-sdk/-/zauction-sdk-0.2.12.tgz", - "integrity": "sha512-7bwToIhNLrEOdlS5PfYNOyneVZV/imEc28oWcKMNp3IDHfzMfB4L/loi+R5NLeQZQs4kdaf98X1qSvAZLLj8fg==", - "peer": true, - "requires": { - "@apollo/client": "3.4.10", - "@ethersproject/abi": "5.4.1", - "@ethersproject/bytes": "5.4.0", - "@ethersproject/providers": "5.4.5", - "consola": "2.15.3", - "cross-fetch": "3.1.4", - "graphql": "15.5.3" - } - }, - "@zero-tech/zdao-sdk": { - "version": "0.13.0", - "requires": { - "@ethersproject/abstract-signer": "^5.4.1", - "@ethersproject/address": "^5.4.0", - "@ethersproject/bignumber": "^5.4.2", - "@ethersproject/contracts": "^5.4.1", - "@ethersproject/providers": "^5.4.5", - "@ethersproject/wallet": "^5.4.0", - "@gnosis.pm/safe-react-gateway-sdk": "2.10.1", - "@snapshot-labs/snapshot.js": "0.3.56", - "@types/lodash": "4.14.180", - "@types/shortid": "0.0.29", - "cross-fetch": "3.1.5", - "date-fns": "2.28.0", - "dotenv": "16.0.0", - "graphql": "16.3.0", - "graphql-request": "4.1.0", - "graphql-tag": "2.12.6", - "lodash": "4.17.21", - "shortid": "2.2.16", - "typescript": "4.6.2" - }, - "dependencies": { - "cross-fetch": { - "version": "3.1.5", - "requires": { - "node-fetch": "2.6.7" - } - }, - "graphql": { - "version": "16.3.0" - }, - "graphql-request": { - "version": "4.1.0", - "requires": { - "cross-fetch": "^3.0.6", - "extract-files": "^9.0.0", - "form-data": "^3.0.0" - } - } - } - }, - "@zero-tech/zns-sdk": { - "version": "0.8.13", - "requires": { - "@apollo/client": "3.4.10", - "@ethersproject/abi": "5.4.1", - "@ethersproject/bytes": "5.4.0", - "@ethersproject/providers": "5.4.5", - "coingecko-api": "1.0.10", - "consola": "2.15.3", - "cross-fetch": "3.1.4", - "dotenv": "16.0.1", - "env-var": "7.1.1", - "graphql": "15.5.3", - "lolex": "6.0.0" - }, - "dependencies": { - "dotenv": { - "version": "16.0.1" - } - } - }, - "@zero-tech/zui": { - "version": "0.11.6", - "requires": { - "@radix-ui/react-accessible-icon": "^1.0.0", - "@radix-ui/react-aspect-ratio": "^1.0.0", - "@radix-ui/react-dialog": "^0.1.7", - "@radix-ui/react-dropdown-menu": "^0.1.6", - "@radix-ui/react-tabs": "^0.1.5", - "@radix-ui/react-toggle": "^1.0.0", - "@radix-ui/react-toggle-group": "^1.0.0", - "@radix-ui/react-tooltip": "^1.0.0", - "@react-aria/button": "^3.5.0", - "@react-aria/i18n": "^3.4.1", - "@react-aria/numberfield": "^3.2.1", - "@react-aria/textfield": "^3.6.1", - "@react-stately/numberfield": "^3.1.1", - "@stitches/react": "^1.2.8", - "@storybook/preset-scss": "^1.0.3", - "@uiw/react-md-editor": "^3.12.3", - "classnames": "^2.3.1", - "ethers": "^5.6.9", - "focus-visible": "^5.2.0", - "react-infinite-scroll-component": "^6.1.0", - "react-loading-skeleton": "^3.1.0", - "react-router-dom": "^6.3.0", - "remark-emoji": "^3.0.2", - "remark-gemoji": "^7.0.1", - "sass": "^1.52.2" - }, - "dependencies": { - "react-router-dom": { - "version": "6.7.0", - "requires": { - "@remix-run/router": "1.3.0", - "react-router": "6.7.0" - } - } - } - }, - "dotenv": { - "version": "16.0.0" - }, - "node-fetch": { - "version": "2.6.7", - "requires": { - "whatwg-url": "^5.0.0" - } + "version": "16.0.1" }, "react-router": { "version": "6.7.0", "requires": { "@remix-run/router": "1.3.0" } - }, - "tr46": { - "version": "0.0.3" - }, - "webidl-conversions": { - "version": "3.0.1" - }, - "whatwg-url": { - "version": "5.0.0", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } } } }, - "@zero-tech/zapp-nfts": { - "version": "0.7.5", + "@zero-tech/zapp-daos": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-daos/-/zapp-daos-0.8.0.tgz", + "integrity": "sha512-xDtUgyvrteuH9m8D3eeBuEcmm9mZq2Z1IP6cPY3Z9mm7QV5eNTIJ7ZLfgqyWwPsMiDlUrYpBAVHSE3pQb4xjJQ==", "requires": { + "@babel/plugin-proposal-class-properties": "^7.18.6", "@ethersproject/units": "^5.6.1", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/user-event": "^14.4.3", - "@zer0-os/zapp-scripts": "^0.0.3", - "@zero-tech/zapp-utils": "0.5.4", - "@zero-tech/zero-contracts": "^0.0.7", - "@zero-tech/zns-sdk": "0.9.1", - "@zero-tech/ztoken-sdk": "^0.0.3", - "@zero-tech/zui": "0.12.0", + "@zero-tech/zapp-utils": "0.5.5", + "@zero-tech/zdao-sdk": "0.14.1", + "@zero-tech/zns-sdk": "0.10.2", + "@zero-tech/zui": "0.15.0", "classnames": "^2.3.1", "formik": "^2.2.9", - "moment": "^2.29.4", + "markdown-to-text": "^0.1.1", + "millify": "^4.0.0", + "moment": "^2.29.1", "react-query": "^3.39.1", + "react-resize-detector": "7.0.0", "yup": "^0.32.11" }, "dependencies": { @@ -41381,21 +41052,24 @@ }, "@ethersproject/bytes": { "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz", - "integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==", "requires": { "@ethersproject/logger": "^5.4.0" } }, "@remix-run/router": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz", - "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz", + "integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==" + }, + "@types/lodash": { + "version": "4.14.180", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.180.tgz", + "integrity": "sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==" }, "@zero-tech/zapp-utils": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.4.tgz", - "integrity": "sha512-jtYH8Zws0OTDXjCy0aco4VjZcj3pFBAljc3LCyeDNNgU0FFxOlFP7jC+vv57sgrWDhTbVtgjeIIEK7lXe2TIaA==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.5.tgz", + "integrity": "sha512-djydYDIu5GP5+y84K2aOL71ho5PBprfsZJO75Jy9zlHA47Co8nn3WK59D7yTO/Oyu0FJYZSAvBehYQ5VWFHwUQ==", "requires": { "@cloudinary/url-gen": "^1.8.6", "@enzoferey/ethers-error-parser": "^0.2.2", @@ -41426,11 +41100,76 @@ } } }, - "@zero-tech/zero-contracts": { - "version": "0.0.7" + "@zero-tech/zauction-sdk": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@zero-tech/zauction-sdk/-/zauction-sdk-0.2.12.tgz", + "integrity": "sha512-7bwToIhNLrEOdlS5PfYNOyneVZV/imEc28oWcKMNp3IDHfzMfB4L/loi+R5NLeQZQs4kdaf98X1qSvAZLLj8fg==", + "peer": true, + "requires": { + "@apollo/client": "3.4.10", + "@ethersproject/abi": "5.4.1", + "@ethersproject/bytes": "5.4.0", + "@ethersproject/providers": "5.4.5", + "consola": "2.15.3", + "cross-fetch": "3.1.4", + "graphql": "15.5.3" + } + }, + "@zero-tech/zdao-sdk": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zdao-sdk/-/zdao-sdk-0.14.1.tgz", + "integrity": "sha512-IofAMYPEd/hpLI4A9/pqdJmsPUEh2/7OfZgtyVHkD5wsyijFOJ59OExliHI/EINg0UpbSQpoi+Oy9T+/B/0Jrg==", + "requires": { + "@ethersproject/abstract-signer": "^5.4.1", + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.2", + "@ethersproject/contracts": "^5.4.1", + "@ethersproject/providers": "^5.4.5", + "@ethersproject/wallet": "^5.4.0", + "@safe-global/safe-gateway-typescript-sdk": "3.7.0", + "@snapshot-labs/snapshot.js": "0.4.58", + "@types/lodash": "4.14.180", + "@types/shortid": "0.0.29", + "cross-fetch": "3.1.5", + "date-fns": "2.28.0", + "dotenv": "16.0.0", + "graphql": "16.3.0", + "graphql-request": "4.1.0", + "graphql-tag": "2.12.6", + "lodash": "4.17.21", + "shortid": "2.2.16", + "typescript": "4.6.2" + }, + "dependencies": { + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + } + }, + "graphql": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.3.0.tgz", + "integrity": "sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==" + }, + "graphql-request": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-4.1.0.tgz", + "integrity": "sha512-CBFcO6LP7cg+aBMc+x9C1dZEQsKTBZKR2J+HzuB0cR/6aaU4K4/tRXTQu8CDMp5195ZU+DTNKZZOSK1WRbTeAg==", + "requires": { + "cross-fetch": "^3.0.6", + "extract-files": "^9.0.0", + "form-data": "^3.0.0" + } + } + } }, "@zero-tech/zns-sdk": { - "version": "0.9.1", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.10.2.tgz", + "integrity": "sha512-gwUOkOWKfZvpwMOFUyJ+fAKBnKmW/HrOo7T+YJjFG3xPcfjCrXfc81qbay4dZRA3BYZXLVUNgBRu46Ix+daRcw==", "requires": { "@apollo/client": "3.4.10", "@ethersproject/abi": "5.4.1", @@ -41446,18 +41185,22 @@ "lolex": "6.0.0" }, "dependencies": { - "@zero-tech/zero-contracts": { - "version": "0.0.4" + "dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" } } }, "@zero-tech/zui": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.12.0.tgz", - "integrity": "sha512-FErCZIuEeSKk1ukUt9v81YsCo+qq/0aAtVzE27d0FrHcN6yoa9e6zYcjsr3hKBCjf92GQxsgOxw8rMQqUqmhZA==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.15.0.tgz", + "integrity": "sha512-8cWXVMJ+76egw2xCDO5QonAILG8aHGYHSmSpVozaAGWHmcIzOOZcGW7xIan2Oj8JkpN+1tljvjrO5HpUbk7IFg==", "requires": { "@radix-ui/react-accessible-icon": "^1.0.0", + "@radix-ui/react-accordion": "^1.0.1", "@radix-ui/react-aspect-ratio": "^1.0.0", + "@radix-ui/react-avatar": "^1.0.1", "@radix-ui/react-checkbox": "^1.0.1", "@radix-ui/react-dialog": "^0.1.7", "@radix-ui/react-dropdown-menu": "^0.1.6", @@ -41474,7 +41217,7 @@ "@stitches/react": "^1.2.8", "@storybook/preset-scss": "^1.0.3", "@uiw/react-md-editor": "^3.12.3", - "classnames": "^2.3.1", + "classnames": "^2.3.2", "ethers": "^5.6.9", "focus-visible": "^5.2.0", "react-infinite-scroll-component": "^6.1.0", @@ -41486,31 +41229,144 @@ }, "dependencies": { "react-router-dom": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.2.tgz", - "integrity": "sha512-N/oAF1Shd7g4tWy+75IIufCGsHBqT74tnzHQhbiUTYILYF0Blk65cg+HPZqwC+6SqEyx033nKqU7by38v3lBZg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz", + "integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==", "requires": { - "@remix-run/router": "1.3.3", - "react-router": "6.8.2" + "@remix-run/router": "1.4.0", + "react-router": "6.9.0" } } } }, "dotenv": { - "version": "16.0.1" + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } }, "react-router": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz", - "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz", + "integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==", "requires": { - "@remix-run/router": "1.3.3" + "@remix-run/router": "1.4.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } } } }, + "@zero-tech/zapp-nfts": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-nfts/-/zapp-nfts-0.11.0.tgz", + "integrity": "sha512-SC9/aqA/PYsO5ZDgNzCx4Vp9aVAFN+qyHHWwcktrKCf6lVH3AiX23/3aoh4raN63+NYdv2eeY6E0+9fNZ+uv/Q==", + "requires": { + "@ethersproject/units": "^5.6.1", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/user-event": "^14.4.3", + "@zer0-os/zapp-scripts": "^0.0.3", + "@zero-tech/zapp-utils": "0.5.6", + "@zero-tech/zero-contracts": "^0.0.7", + "@zero-tech/zns-sdk": "0.10.1", + "@zero-tech/ztoken-sdk": "^0.0.3", + "@zero-tech/zui": "0.16.1", + "classnames": "^2.3.1", + "formik": "^2.2.9", + "moment": "^2.29.4", + "react-query": "^3.39.1", + "react-resize-detector": "7.0.0", + "yup": "^0.32.11" + }, + "dependencies": { + "@ethersproject/abi": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.1.tgz", + "integrity": "sha512-9mhbjUk76BiSluiiW4BaYyI58KSbDMMQpCLdsAR+RsT2GyATiNYxVv+pGWRrekmsIdY3I+hOqsYQSTkc8L/mcg==", + "requires": { + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/hash": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/strings": "^5.4.0" + } + }, + "@ethersproject/bytes": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz", + "integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==", + "requires": { + "@ethersproject/logger": "^5.4.0" + } + }, + "@zero-tech/zero-contracts": { + "version": "0.0.7" + }, + "@zero-tech/zns-sdk": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.10.1.tgz", + "integrity": "sha512-180P+EpN1qlL7Mk63ZDGx6AicxWNkGXZEMsi1zIQfULMn++xlTvbD0W6LNQ7TIJP1hNnuF4hh14tzk3KJU5V5Q==", + "requires": { + "@apollo/client": "3.4.10", + "@ethersproject/abi": "5.4.1", + "@ethersproject/bytes": "5.4.0", + "@ethersproject/providers": "5.4.5", + "@zero-tech/zero-contracts": "^0.0.4", + "coingecko-api": "1.0.10", + "consola": "2.15.3", + "cross-fetch": "3.1.4", + "dotenv": "16.0.1", + "env-var": "7.1.1", + "graphql": "15.5.3", + "lolex": "6.0.0" + }, + "dependencies": { + "@zero-tech/zero-contracts": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@zero-tech/zero-contracts/-/zero-contracts-0.0.4.tgz", + "integrity": "sha512-nqDoLsUlTf7shanR9mzi8E7OzfSWzlaZtLrpwgCIojYnDjf/oUJ4N3iF00vCt1jmDRzP61EoNo3I0yQFg6m60Q==" + } + } + }, + "dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" + } + } + }, "@zero-tech/zapp-staking": { - "version": "0.4.8", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-staking/-/zapp-staking-0.4.9.tgz", + "integrity": "sha512-je+4K0BXqUCx6s7NDby9ppk2li6aMpwF2/lO1DawE47hoQbd09AcR0xTnr/prFCRhRU3mVNlz36tgSmEyutQBw==", "requires": { "@babel/plugin-proposal-class-properties": "^7.18.6", "@enzoferey/ethers-error-parser": "^0.2.2", @@ -41549,22 +41405,6 @@ "@remix-run/router": { "version": "1.3.0" }, - "@zero-tech/zapp-utils": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.5.tgz", - "integrity": "sha512-djydYDIu5GP5+y84K2aOL71ho5PBprfsZJO75Jy9zlHA47Co8nn3WK59D7yTO/Oyu0FJYZSAvBehYQ5VWFHwUQ==", - "requires": { - "@cloudinary/url-gen": "^1.8.6", - "@enzoferey/ethers-error-parser": "^0.2.2", - "@ethersproject/units": "^5.6.1", - "@zero-tech/zfi-sdk": "0.2.1", - "@zero-tech/zns-sdk": "0.6.1", - "classnames": "^2.3.1", - "cloudinary-build-url": "^0.2.4", - "lodash": "^4.17.21", - "react-query": "^3.39.1" - } - }, "@zero-tech/zns-sdk": { "version": "0.6.1", "requires": { @@ -41681,6 +41521,64 @@ } } }, + "@zero-tech/zapp-utils": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@zero-tech/zapp-utils/-/zapp-utils-0.5.6.tgz", + "integrity": "sha512-uxbEJQk24AFzW9LUNZkmQpe7k6z4MEIY5DC0NDHpH53jb02dl557wIPNnpxTMiNI/WkTzlsudZuuQ4I5+1Bdcg==", + "requires": { + "@cloudinary/url-gen": "^1.8.6", + "@enzoferey/ethers-error-parser": "^0.2.2", + "@ethersproject/units": "^5.6.1", + "@zero-tech/zfi-sdk": "0.2.1", + "@zero-tech/zns-sdk": "0.6.1", + "classnames": "^2.3.1", + "cloudinary-build-url": "^0.2.4", + "lodash": "^4.17.21", + "react-query": "^3.39.1" + }, + "dependencies": { + "@ethersproject/abi": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.1.tgz", + "integrity": "sha512-9mhbjUk76BiSluiiW4BaYyI58KSbDMMQpCLdsAR+RsT2GyATiNYxVv+pGWRrekmsIdY3I+hOqsYQSTkc8L/mcg==", + "requires": { + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/hash": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/strings": "^5.4.0" + } + }, + "@ethersproject/bytes": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz", + "integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==", + "requires": { + "@ethersproject/logger": "^5.4.0" + } + }, + "@zero-tech/zns-sdk": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zns-sdk/-/zns-sdk-0.6.1.tgz", + "integrity": "sha512-nuZLWoJn3h9+aleHVdASkwb7G7h1gomLemju4yGIiZPUhWHnhnjtjk4rfPxvE5VLApdGF9fCV4gk9yOyQ6OwxA==", + "requires": { + "@apollo/client": "3.4.10", + "@ethersproject/abi": "5.4.1", + "@ethersproject/bytes": "5.4.0", + "@ethersproject/providers": "5.4.5", + "coingecko-api": "1.0.10", + "consola": "2.15.3", + "cross-fetch": "3.1.4", + "graphql": "15.5.3", + "lolex": "6.0.0" + } + } + } + }, "@zero-tech/zauction-sdk": { "version": "0.1.4", "requires": { @@ -42173,9 +42071,9 @@ } }, "@zero-tech/zui": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.16.0.tgz", - "integrity": "sha512-DBDkNRBiW6Scln0rQZeJMAQ6dfICPIi1iYZLERPuasSQzDyIfhrrNZS9J6yRA3AXZEdh45x96elBJNxw0IrzKw==", + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@zero-tech/zui/-/zui-0.16.1.tgz", + "integrity": "sha512-c236KUX2UdRvFfFbE6KeJM1EgtKS6+zcszCY/Tv3xRpNqTNyV2Tp2+1HFptgkh4rn6YfW6p8KvDETzmuRnzF+w==", "requires": { "@radix-ui/react-accessible-icon": "^1.0.0", "@radix-ui/react-accordion": "^1.0.1", @@ -42310,12 +42208,16 @@ }, "ajv-formats": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "requires": { "ajv": "^8.0.0" }, "dependencies": { "ajv": { - "version": "8.11.2", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -42324,7 +42226,9 @@ } }, "json-schema-traverse": { - "version": "1.0.0" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" } } }, @@ -47142,7 +47046,9 @@ } }, "extract-files": { - "version": "9.0.0" + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz", + "integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==" }, "extract-zip": { "version": "1.7.0", @@ -50312,7 +50218,9 @@ "version": "5.0.1" }, "json-to-graphql-query": { - "version": "2.2.4" + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/json-to-graphql-query/-/json-to-graphql-query-2.2.5.tgz", + "integrity": "sha512-5Nom9inkIMrtY992LMBBG1Zaekrc10JaRhyZgprwHBVMDtRgllTvzl0oBbg13wJsVZoSoFNNMaeIVQs0P04vsA==" }, "json3": { "version": "3.3.3" @@ -50583,7 +50491,9 @@ "version": "4.6.2" }, "lodash.set": { - "version": "4.3.2" + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==" }, "lodash.template": { "version": "4.5.0", @@ -55308,12 +55218,16 @@ }, "shortid": { "version": "2.2.16", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", + "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", "requires": { "nanoid": "^2.1.0" }, "dependencies": { "nanoid": { - "version": "2.1.11" + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" } } }, diff --git a/package.json b/package.json index 44506ba81..31789b34f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zOS", - "version": "0.11.0", + "version": "0.12.0", "private": true, "main": "./public/electron.js", "engines": { @@ -28,10 +28,10 @@ "@zer0-os/zos-component-library": "0.18.9", "@zer0-os/zos-feed": "^1.29.2", "@zer0-os/zos-zns": "2.3.3", - "@zero-tech/zapp-buy-domains": "^0.2.1", - "@zero-tech/zapp-daos": "^0.4.0", - "@zero-tech/zapp-nfts": "^0.7.5", - "@zero-tech/zapp-staking": "0.4.8", + "@zero-tech/zapp-buy-domains": "latest", + "@zero-tech/zapp-daos": "latest", + "@zero-tech/zapp-nfts": "latest", + "@zero-tech/zapp-staking": "latest", "@zero-tech/zui": "^0.16.0", "audio-react-recorder-fixed": "^1.0.3", "classnames": "^2.3.1", diff --git a/src/components/message-audio-recorder/index.tsx b/src/components/message-audio-recorder/index.tsx index 6deb62313..7d2caaa72 100644 --- a/src/components/message-audio-recorder/index.tsx +++ b/src/components/message-audio-recorder/index.tsx @@ -1,25 +1,27 @@ import React from 'react'; -import AudioReactRecorder, { RecordState } from 'audio-react-recorder-fixed'; +import { RecordState } from 'audio-react-recorder-fixed'; import { IconCheck, IconTrash4 } from '@zero-tech/zui/icons'; import { IconButton } from '../icon-button'; import { Media } from '../message-input/utils'; import './styles.scss'; +const AudioReactRecorder = require('audio-react-recorder-fixed').default; + export interface Properties { onMediaSelected: (file: Media) => void; onClose: () => void; } export interface State { - isMicRecording: boolean; + isMicRecording: RecordState; } export default class MessageAudioRecorder extends React.Component { constructor(props) { super(props); this.state = { - isMicRecording: false, + isMicRecording: null, }; } diff --git a/src/components/message/index.tsx b/src/components/message/index.tsx index 3a5cdfde5..53c798683 100644 --- a/src/components/message/index.tsx +++ b/src/components/message/index.tsx @@ -170,7 +170,7 @@ export class Message extends React.Component { const match = part.match(/@\[(.*?)\]\(([a-z]+):([A-Za-z0-9_-]+)\)/i); if (!match) { - return textToPlainEmojis(message); + return textToPlainEmojis(part); } if (match[2] === 'user') { diff --git a/src/components/messenger/list/index.test.tsx b/src/components/messenger/list/index.test.tsx index 92a552dbd..140e476fd 100644 --- a/src/components/messenger/list/index.test.tsx +++ b/src/components/messenger/list/index.test.tsx @@ -4,9 +4,12 @@ import { Container as DirectMessageChat, Properties } from '.'; import directMessagesFixture from './direct-messages-fixture.json'; import Tooltip from '../../tooltip'; import { Channel } from '../../../store/channels'; +import { normalize } from '../../../store/channels-list'; import { Dialog } from '@zer0-os/zos-component-library'; import { SearchConversations } from '../search-conversations'; import { AutocompleteMembers } from '../autocomplete-members'; +import { RootState } from '../../../store'; +import moment from 'moment'; export const DIRECT_MESSAGES_TEST = directMessagesFixture as unknown as Channel[]; @@ -189,4 +192,45 @@ describe('messenger-list', () => { ]); }); }); + + describe('mapState', () => { + const subject = (channels) => { + return DirectMessageChat.mapState(getState(channels)); + }; + + const getState = (channels) => { + const channelData = normalize(channels); + return { + channelsList: { value: channelData.result }, + normalized: channelData.entities, + } as RootState; + }; + + test('gets sorted conversations', () => { + const state = subject([ + { id: 'convo-1', lastMessage: { createdAt: moment('2023-03-01').valueOf() }, isChannel: true }, + { id: 'convo-2', lastMessage: { createdAt: moment('2023-03-02').valueOf() }, isChannel: true }, + ]); + + expect(state.directMessages.map((c) => c.id)).toEqual([ + 'convo-2', + 'convo-1', + ]); + }); + + test('gets only conversations', () => { + // Note: There's currently a bug where we're labelling channels as isChannel: false + // and Conversations as true. + const state = subject([ + { id: 'convo-1', isChannel: true }, + { id: 'convo-2', isChannel: false }, + { id: 'convo-3', isChannel: true }, + ]); + + expect(state.directMessages.map((c) => c.id)).toEqual([ + 'convo-1', + 'convo-3', + ]); + }); + }); }); diff --git a/src/components/messenger/list/index.tsx b/src/components/messenger/list/index.tsx index ff8e79862..559485931 100644 --- a/src/components/messenger/list/index.tsx +++ b/src/components/messenger/list/index.tsx @@ -15,12 +15,13 @@ import { createDirectMessage } from '../../../store/channels-list'; import { AutocompleteMembers } from '../autocomplete-members'; import { CreateMessengerConversation } from '../../../store/channels-list/types'; -import './styles.scss'; import { Button } from '@zer0-os/zos-component-library'; import { IconMessagePlusSquare, IconMessageQuestionSquare } from '@zero-tech/zui/icons'; import { IconButton } from '../../icon-button'; import { SearchConversations } from '../search-conversations'; +import './styles.scss'; + export interface PublicProperties { className?: string; onSubmit?: (userIds: string[]) => void; @@ -63,6 +64,7 @@ export class Container extends React.Component { componentDidMount(): void { this.props.fetchDirectMessages(); + this.setState({ directMessagesList: this.props.directMessages }); } componentDidUpdate(prevProps: Properties): void { diff --git a/src/components/notification/index.tsx b/src/components/notification/index.tsx new file mode 100644 index 000000000..5a9bb212a --- /dev/null +++ b/src/components/notification/index.tsx @@ -0,0 +1 @@ +export { NotificationPopup as NotificationList } from './popup'; diff --git a/src/components/notification/item/index.test.tsx b/src/components/notification/item/index.test.tsx new file mode 100644 index 000000000..a16ac5d89 --- /dev/null +++ b/src/components/notification/item/index.test.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { NotificationItem, Properties } from '.'; +import moment from 'moment'; + +describe('NotificationItem', () => { + const subject = (props: Partial = {}) => { + const allProps = { + body: '', + createdAt: '', + ...props, + }; + + return shallow(); + }; + + it('renders the message', () => { + const wrapper = subject({ + body: 'Here is the description', + }); + + expect(wrapper.find('p').text()).toEqual('Here is the description'); + }); + + it('renders created timestamp', () => { + const wrapper = subject({ + createdAt: '2023-03-10T22:33:34.945Z', + }); + + const expectedTimeDescription = moment('2023-03-10T22:33:34.945Z').fromNow(); + + expect(wrapper.find('.notification-item__timestamp').text()).toEqual(expectedTimeDescription); + }); + + it('renders Avatar', () => { + const wrapper = subject({ + originatingName: 'Originating Name', + originatingImageUrl: 'image-url', + }); + + const avatar = wrapper.find('Avatar'); + + expect(avatar.prop('userFriendlyName')).toEqual('Originating Name'); + expect(avatar.prop('imageURL')).toEqual('image-url'); + }); +}); diff --git a/src/components/notification/item/index.tsx b/src/components/notification/item/index.tsx new file mode 100644 index 000000000..226b7c0e3 --- /dev/null +++ b/src/components/notification/item/index.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import classNames from 'classnames'; +import { Avatar } from '@zero-tech/zui/components/Avatar'; + +import './style.scss'; +import moment from 'moment'; + +export interface Properties { + body: string; + createdAt: string; + originatingName?: string; + originatingImageUrl?: string; + notRead?: boolean; +} + +export class NotificationItem extends React.Component { + get time() { + return moment(this.props.createdAt).fromNow(); + } + + render() { + return ( +
+
+ +
+
+

{this.props.body}

+ {this.time} +
+
+ ); + } +} diff --git a/src/components/notification/item/style.scss b/src/components/notification/item/style.scss new file mode 100644 index 000000000..6d3b09a27 --- /dev/null +++ b/src/components/notification/item/style.scss @@ -0,0 +1,33 @@ +@use '~@zero-tech/zui/styles/theme' as theme; + +.notification-item { + &__wrapper { + display: flex; + padding: 16px 16px; + } + + &__avatar { + margin-right: 16px; + } + + &__content { + p { + color: theme.$color-greyscale-12; + + margin: 0px; + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 17px; + } + } + + &__timestamp { + color: theme.$color-greyscale-11; + + font-style: normal; + font-weight: 400; + font-size: 12px; + line-height: 15px; + } +} diff --git a/src/components/notification/list/container.test.tsx b/src/components/notification/list/container.test.tsx new file mode 100644 index 000000000..ab98630c7 --- /dev/null +++ b/src/components/notification/list/container.test.tsx @@ -0,0 +1,175 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { RootState } from '../../../store'; +import { AsyncListStatus } from '../../../store/normalized'; + +import { Container, Properties } from './container'; + +describe('NotificationsListContainer', () => { + const subject = (props: Partial = {}) => { + const allProps = { + notifications: [], + userId: '', + fetchNotifications: () => undefined, + ...props, + }; + + return shallow(); + }; + + it('passes notifications to the NotificationList', () => { + const notifications = [ + { a: 'notification' }, + { b: 'notification' }, + ]; + const wrapper = subject({ notifications }); + + expect(wrapper.find('NotificationList').prop('list')).toEqual(notifications); + }); + + it('fetches the notifications when rendered', () => { + const fetchNotifications = jest.fn(); + + subject({ fetchNotifications }); + + expect(fetchNotifications).toHaveBeenCalledOnce(); + }); + + describe('mapState', () => { + const subject = (state: Partial) => { + return Container.mapState({ + authentication: { user: { data: { id: 'user-id' } as any } }, + notificationsList: { value: [] }, + ...state, + } as RootState); + }; + + test('notifications', () => { + const state = subject({ + notificationsList: { + status: AsyncListStatus.Idle, + value: [ + 'id-1', + 'id-2', + ], + }, + normalized: { + notifications: { + 'id-1': { id: 'id-1', notificationType: 'chat_channel_mention' }, + 'id-2': { id: 'id-2', notificationType: 'chat_channel_mention' }, + }, + }, + }); + + expect(state.notifications).toIncludeAllPartialMembers([ + { id: 'id-1' }, + { id: 'id-2' }, + ]); + }); + + test('userId', () => { + const state = subject({ + authentication: { user: { data: { id: 'user-id' } as any } }, + }); + + expect(state.userId).toEqual('user-id'); + }); + }); + + describe('mapNotification', () => { + const subject = (notification = {}, state: Partial) => { + return Container.mapNotification(notification, state as RootState); + }; + + describe('unknown type', () => { + it('maps body with a known channel', () => { + const mappedNotification = subject({ notificationType: 'unknown_type' }, {}); + + expect(mappedNotification).toBeNull(); + }); + }); + + describe('chat_channel_mention', () => { + it('maps body with a known channel', () => { + const mappedNotification = subject( + { + notificationType: 'chat_channel_mention', + data: { chatId: 'chat-id' }, + originUser: { + profileSummary: { + firstName: 'Johnny', + lastName: 'Chatter', + profileImage: 'image-url', + }, + }, + }, + { + normalized: { + channels: { + 'chat-id': { id: 'chat-id', name: 'TestingChannel' }, + }, + }, + } + ); + + expect(mappedNotification.body).toEqual('Johnny Chatter mentioned you in #TestingChannel'); + }); + + it('maps body with unknown info', () => { + const mappedNotification = subject( + { + notificationType: 'chat_channel_mention', + data: { chatId: 'chat-id' }, + }, + { + normalized: { + channels: {}, + }, + } + ); + + expect(mappedNotification.body).toEqual('Someone mentioned you in a channel'); + }); + + it('maps default properties', () => { + const mappedNotification = subject( + { + id: 'notification-id', + notificationType: 'chat_channel_mention', + data: { chatId: 'chat-id' }, + createdAt: '2023-01-20T22:33:34.945Z', + }, + { + normalized: { channels: {} }, + } + ); + + expect(mappedNotification.id).toEqual('notification-id'); + expect(mappedNotification.createdAt).toEqual('2023-01-20T22:33:34.945Z'); + }); + + it('maps sender', () => { + const mappedNotification = subject( + { + notificationType: 'chat_channel_mention', + data: {}, + originUser: { + profileSummary: { + firstName: 'first', + lastName: 'Last', + profileImage: 'image-url', + }, + }, + }, + { + normalized: { channels: {} }, + } + ); + + expect(mappedNotification.originatingName).toEqual('first Last'); + expect(mappedNotification.originatingImageUrl).toEqual('image-url'); + }); + }); + }); +}); diff --git a/src/components/notification/list/container.tsx b/src/components/notification/list/container.tsx new file mode 100644 index 000000000..7b3b2ee98 --- /dev/null +++ b/src/components/notification/list/container.tsx @@ -0,0 +1,73 @@ +import React from 'react'; + +import { connectContainer } from '../../../store/redux-container'; +import { RootState } from '../../../store'; +import { fetch as fetchNotifications, denormalize } from '../../../store/notifications'; +import { denormalize as denormalizeChannel } from '../../../store/channels'; + +import { NotificationList } from '.'; + +export interface Properties { + notifications: any[]; + userId: string; + fetchNotifications: (payload: { userId: string }) => void; +} + +export class Container extends React.Component { + static mapState(state: RootState): Partial { + const { + authentication: { user }, + } = state; + const notifications = denormalize(state.notificationsList.value, state) + .map((n) => Container.mapNotification(n, state)) + .filter((n) => !!n); + + return { + notifications, + userId: user?.data?.id, + }; + } + + static mapActions(_props: Properties): Partial { + return { + fetchNotifications, + }; + } + + static mapNotification(notification, state: RootState) { + if (notification.notificationType === 'chat_channel_mention') { + const channelId = notification.data?.chatId; + const { name: channelName } = denormalizeChannel(channelId, state) || {}; + const channelText = channelName ? `#${channelName}` : 'a channel'; + + // This should probably be extracted to a display utility or added + // to the domain model + let displayName = [ + notification.originUser?.profileSummary?.firstName, + notification.originUser?.profileSummary?.lastName, + ] + .filter((e) => e) + .join(' '); + displayName = displayName || 'Someone'; + + return { + id: notification.id, + createdAt: notification.createdAt, + body: `${displayName} mentioned you in ${channelText}`, + originatingName: displayName, + originatingImageUrl: notification.originUser?.profileSummary?.profileImage, + }; + } + return null; + } + + componentDidMount() { + this.props.fetchNotifications({ userId: this.props.userId }); + } + + render() { + return ; + } +} + +export const NotificationListContainer = connectContainer<{}>(Container); diff --git a/src/components/notification/list/index.test.tsx b/src/components/notification/list/index.test.tsx new file mode 100644 index 000000000..ad8d78401 --- /dev/null +++ b/src/components/notification/list/index.test.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { NotificationList, Properties } from '.'; + +describe('NotificationList', () => { + const subject = (props: Partial = {}) => { + const allProps = { + list: [], + ...props, + }; + + return shallow(); + }; + + it('renders the list', () => { + const wrapper = subject({ + list: [ + { id: 'id-1', body: 'body-1', createdAt: '2023-03-13T22:33:34.945Z' }, + { id: 'id-2', body: 'body-2', createdAt: '2023-01-20T22:33:34.945Z' }, + ], + }); + + expect(wrapper.find('NotificationItem').map((n) => n.props())).toEqual([ + { body: 'body-1', createdAt: '2023-03-13T22:33:34.945Z' }, + { body: 'body-2', createdAt: '2023-01-20T22:33:34.945Z' }, + ]); + }); + + it('renders the empyt state when empty', () => { + const wrapper = subject({ + list: [], + }); + + expect(wrapper.find('NotificationItem').exists()).toBeFalse(); + expect(wrapper.find('.notification-empty-list').exists()).toBeTrue(); + }); +}); diff --git a/src/components/notification/list/index.tsx b/src/components/notification/list/index.tsx new file mode 100644 index 000000000..9d6a14521 --- /dev/null +++ b/src/components/notification/list/index.tsx @@ -0,0 +1,47 @@ +import { IconBellRinging1 } from '@zero-tech/zui/icons'; +import React from 'react'; + +import { NotificationItem } from '../item'; + +import './style.scss'; + +interface Notification { + id: string; + body: string; + createdAt: string; + originatingName?: string; + originatingImageUrl?: string; +} + +export interface Properties { + list?: Notification[]; +} + +export class NotificationList extends React.Component { + render() { + return ( +
+ {this.props.list.length > 0 && ( +
+ {this.props.list.map((n) => ( + + ))} +
+ )} + {this.props.list.length <= 0 && ( +
+ +
Clear.
+
You'll be notified about important things here.
+
+ )} +
+ ); + } +} diff --git a/src/components/notification/list/style.scss b/src/components/notification/list/style.scss new file mode 100644 index 000000000..b729a81a5 --- /dev/null +++ b/src/components/notification/list/style.scss @@ -0,0 +1,26 @@ +@use '~@zero-tech/zui/styles/theme' as theme; + +.notification-empty-list { + width: 210px; + margin: auto; + padding-bottom: 32px; + color: theme.$color-greyscale-11; + text-align: center; + font-weight: 400; + font-size: 14px; + line-height: 150%; + + > *:first-child { + color: theme.$color-primary-transparency-11; + width: 50%; + margin: auto; + } + + &__title { + color: theme.$color-greyscale-12; + font-weight: 400; + font-size: 16px; + line-height: 24px; + margin: 3px; + } +} diff --git a/src/components/notification/popup/index.tsx b/src/components/notification/popup/index.tsx new file mode 100644 index 000000000..6f8a9a1d3 --- /dev/null +++ b/src/components/notification/popup/index.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { createPortal } from 'react-dom'; + +import { NotificationListContainer } from '../list/container'; + +import './style.scss'; + +export interface Properties {} + +export class NotificationPopup extends React.Component { + render() { + return <>{createPortal(this.renderPopup(), document.body)}; + } + + renderPopup() { + return ( +
+
+

Notifications

+
+ +
+ ); + } +} diff --git a/src/components/notification/popup/style.scss b/src/components/notification/popup/style.scss new file mode 100644 index 000000000..1fa909289 --- /dev/null +++ b/src/components/notification/popup/style.scss @@ -0,0 +1,27 @@ +@use '~@zero-tech/zui/styles/theme' as theme; + +.notification-popup { + position: absolute; + top: 75px; + right: 20px; + z-index: 500; + background-color: theme.$color-primary-2; + width: 360px; + padding: 0px 16px; + + // Elevation 3 + box-shadow: 12px 11px 54px #040304; + border-radius: 16px 0px 16px 16px; + + font-family: 'Inter'; + + h3 { + color: theme.$color-white; + margin: 20px 0px; + + font-style: normal; + font-weight: 700; + font-size: 16px; + line-height: 24px; + } +} diff --git a/src/components/sidekick/index.test.tsx b/src/components/sidekick/index.test.tsx index b036502a3..5a3701534 100644 --- a/src/components/sidekick/index.test.tsx +++ b/src/components/sidekick/index.test.tsx @@ -4,7 +4,6 @@ import { shallow } from 'enzyme'; import { Container } from '.'; import { IfAuthenticated } from '../authentication/if-authenticated'; import { MessengerList } from '../messenger/list'; -import { SidekickTabs } from './types'; describe('Sidekick', () => { const subject = (props: any = {}) => { @@ -34,90 +33,26 @@ describe('Sidekick', () => { expect(ifAuthenticated.find('.todo').exists()).toBe(true); }); - it('renders sidekick with class animation in', () => { + it('renders sidekick state when open', () => { const wrapper = subject({ isOpen: true }); const sidekick = wrapper.find('.sidekick'); - expect(sidekick.hasClass('sidekick--slide-in')).toBe(true); + expect(sidekick.hasClass('sidekick--open')).toBe(true); }); - it('it should not render out class animation', () => { + it('renders sidekick state when closed', () => { const wrapper = subject({ isOpen: false }); const sidekick = wrapper.find('.sidekick'); - expect(sidekick.hasClass('sidekick--slide-out')).toBe(false); - }); - - it('renders sidekick panel', () => { - const wrapper = subject(); - - const ifAuthenticated = wrapper.find(IfAuthenticated).find({ showChildren: true }); - - expect(ifAuthenticated.find('.app-sidekick-panel__target').exists()).toBe(true); - }); - - it('renders sidekick when panel tab is clicked', () => { - const updateSidekick = jest.fn(); - const wrapper = subject({ updateSidekick, isOpen: false }); - - expect(wrapper.find('.sidekick').hasClass('sidekick--slide-out')).toBe(false); - - wrapper.find('.app-sidekick-panel__target').simulate('click'); - - expect(updateSidekick).toHaveBeenCalledWith({ isOpen: true }); - }); - - it('handle network tab content', () => { - const setActiveSidekickTab = jest.fn(); - const wrapper = subject({ setActiveSidekickTab }); - wrapper.find('.sidekick__tabs-network').simulate('click'); - - expect(setActiveSidekickTab).toHaveBeenCalledWith({ activeTab: SidekickTabs.NETWORK }); - }); - - it('handle messages tab content', () => { - const setActiveSidekickTab = jest.fn(); - const wrapper = subject({ setActiveSidekickTab }); - wrapper.find('.sidekick__tabs-messages').simulate('click'); - - expect(setActiveSidekickTab).toHaveBeenCalledWith({ activeTab: SidekickTabs.MESSAGES }); - }); - - it('handle notifications tab content', () => { - const setActiveSidekickTab = jest.fn(); - const wrapper = subject({ setActiveSidekickTab }); - wrapper.find('.sidekick__tabs-notifications').simulate('click'); - - expect(setActiveSidekickTab).toHaveBeenCalledWith({ activeTab: SidekickTabs.NOTIFICATIONS }); - }); - - it('render notifications tab content', () => { - const wrapper = subject({ activeTab: SidekickTabs.NOTIFICATIONS }); - wrapper.find('.sidekick__tabs-notifications').simulate('click'); - - expect(wrapper.find('.sidekick__tab-content--notifications').exists()).toBe(true); + expect(sidekick.hasClass('sidekick--open')).toBe(false); }); it('render messages tab content', () => { - const wrapper = subject({ activeTab: SidekickTabs.MESSAGES }); - wrapper.find('.sidekick__tabs-messages').simulate('click'); + const wrapper = subject(); expect(wrapper.find(MessengerList).exists()).toBe(true); expect(wrapper.find('.sidekick__tab-content--messages').exists()).toBe(true); }); - - it('render network tab content', () => { - const wrapper = subject({ activeTab: SidekickTabs.NETWORK }); - wrapper.find('.sidekick__tabs-network').simulate('click'); - - expect(wrapper.find('.sidekick__tab-content--network').exists()).toBe(true); - }); - - it('renders total unread messages', () => { - const wrapper = subject({ countAllUnreadMessages: 10 }); - - expect(wrapper.find('.sidekick__tab-notifications--unread-messages').exists()).toBe(true); - }); }); diff --git a/src/components/sidekick/index.tsx b/src/components/sidekick/index.tsx index 5c512824b..8fae2f5b7 100644 --- a/src/components/sidekick/index.tsx +++ b/src/components/sidekick/index.tsx @@ -2,19 +2,9 @@ import React from 'react'; import { RootState } from '../../store'; import { connectContainer } from '../../store/redux-container'; import { IfAuthenticated } from '../authentication/if-authenticated'; -import { IconButton, Icons } from '@zer0-os/zos-component-library'; import classNames from 'classnames'; -import { AuthenticationState } from '../../store/authentication/types'; -import { - UpdateSidekickPayload, - updateSidekick, - setActiveSidekickTab, - SetActiveSidekickTabPayload, - syncSidekickState, -} from '../../store/layout'; +import { syncSidekickState } from '../../store/layout'; import { MessengerList } from '../messenger/list'; -import { denormalize } from '../../store/channels'; -import { SidekickTabs as Tabs } from './types'; import './styles.scss'; @@ -23,48 +13,23 @@ interface PublicProperties { } export interface Properties extends PublicProperties { - user: AuthenticationState['user']; - updateSidekick: (action: UpdateSidekickPayload) => void; - setActiveSidekickTab: (action: SetActiveSidekickTabPayload) => void; syncSidekickState: () => void; - countAllUnreadMessages: number; isOpen: boolean; - activeTab: Tabs; } -export interface State { - canStartAnimation: boolean; -} - -export class Container extends React.Component { - state = { canStartAnimation: false }; - defaultProps: { - activeTab: Tabs.MESSAGES; - }; - +export class Container extends React.Component { static mapState(state: RootState): Partial { - const directMessages = denormalize(state.channelsList.value, state).filter((channel) => Boolean(channel.isChannel)); - - const countAllUnreadMessages = directMessages.reduce( - (count, directMessage) => count + directMessage.unreadCount, - 0 - ); - const { - authentication: { user }, layout: { value }, } = state; return { - user, - countAllUnreadMessages, isOpen: value.isSidekickOpen, - activeTab: value.activeSidekickTab, }; } static mapActions(_props: Properties): Partial { - return { updateSidekick, setActiveSidekickTab, syncSidekickState }; + return { syncSidekickState }; } componentDidMount() { @@ -75,109 +40,18 @@ export class Container extends React.Component { return this.props.isOpen; } - clickTab(tab: Tabs): void { - this.props.setActiveSidekickTab({ - activeTab: tab, - }); - } - - toggleSidekickPanel = (): void => { - this.setState({ canStartAnimation: true }); - this.props.updateSidekick({ isOpen: !this.isOpen }); - }; - - renderSidekickPanel(): JSX.Element { - return ( -
- - - -
- - - -
-
- ); - } - - renderMessageTab() { - if (this.props.countAllUnreadMessages > 0) { - return ( -
- {this.props.countAllUnreadMessages} -
- ); - } else { - return ( - - ); - } - } - - renderTabs(): JSX.Element { + renderTabContent(): JSX.Element { return ( -
- - {this.renderMessageTab()} - +
+
); } - renderTabContent(): JSX.Element { - switch (this.props.activeTab) { - case Tabs.NETWORK: - return
NETWORK
; - case Tabs.MESSAGES: - return ( -
- -
- ); - case Tabs.NOTIFICATIONS: - return
NOTIFICATIONS
; - default: - return null; - } - } - render() { return ( -
- {this.renderSidekickPanel()} -
{this.renderTabs()}
+
{this.renderTabContent()}
diff --git a/src/components/sidekick/styles.scss b/src/components/sidekick/styles.scss index 4203e3e2b..6a8188e05 100644 --- a/src/components/sidekick/styles.scss +++ b/src/components/sidekick/styles.scss @@ -9,43 +9,10 @@ width: $width-sidekick; height: 100%; margin-right: -$width-sidekick; + transition: margin animation.$animation-duration-double var(--sidekick-transition-easing-function); - &--slide-in { - animation: sidekick-slide-in animation.$animation-duration-double ease-in forwards; - } - &--slide-out { - animation: sidekick-slide-out animation.$animation-duration-double ease-out forwards; - } - - &__tabs { - position: absolute; - top: 0; - right: 0; - left: 0; - width: 100%; - - font-size: 16px; - height: 48px; - display: flex; - justify-content: space-evenly; - align-items: center; - - .icon-button { - padding: 7px; - &__icon { - vertical-align: middle; - height: 16px; - width: 16px; - } - & PATH { - fill: theme.$font-color-primary; - } - &:hover { - background-color: theme.$background-color-app-panel-hover; - border-radius: 9999px; - transition-duration: animation.$animation-duration-double; - } - } + &--open { + margin-right: 0; } .scroll-container__gradient { @@ -55,21 +22,6 @@ background: linear-gradient(to top, transparent, theme.$background-color-tertiary-hover 100%); } - &__invitation-button { - .button-component { - position: absolute; - bottom: 22px; - left: 40px; - - .button-component__label { - min-height: 36px; - line-height: 36px; - vertical-align: middle; - text-transform: capitalize; - } - } - } - &__tab-content { width: 100%; padding-top: 56px; @@ -78,75 +30,4 @@ height: 100%; } } - - &__tab-notifications { - display: flex; - align-items: center; - justify-content: center; - background-color: theme.$accent-color; - color: theme.$font-color-primary; - height: 34px; - width: 34px; - border-radius: 50%; - cursor: pointer; - } -} - -.app-sidekick-panel__target { - position: absolute; - left: -16px; - top: 0; - cursor: pointer; -} - -.sidekick-panel-tab__tab { - height: 104px; - width: 16px; - transform: rotate(180deg); -} - -.sidekick-panel-tab__tab PATH { - fill: theme.$background-color-tertiary-hover; -} - -.sidekick-panel-tab__opacity-gradient-first-stop { - stop-color: theme.$background-color-app-panel; -} - -.sidekick-panel-tab__opacity-gradient-second-stop, -.sidekick-panel-tab__opacity-gradient-third-stop { - stop-color: theme.$actionable-hover-background; -} - -.sidekick-panel-tab__icon { - position: absolute; - top: 44px; - left: 0px; - width: 14px; -} - -.sidekick-panel-tab__icon-item { - background: theme.$actionable-color; - height: 2px; - display: block; - border-radius: 3px; - margin-bottom: 2px; -} - -@keyframes sidekick-slide-in { - 0% { - margin-right: -$width-sidekick; - } - 100% { - margin-right: 0; - } -} - -@keyframes sidekick-slide-out { - 0% { - margin-right: 0; - } - 100% { - margin-right: -$width-sidekick; - } } diff --git a/src/components/sidekick/types.ts b/src/components/sidekick/types.ts deleted file mode 100644 index 3e0bc790c..000000000 --- a/src/components/sidekick/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum SidekickTabs { - NETWORK = 'network', - MESSAGES = 'messages', - NOTIFICATIONS = 'notifications', -} diff --git a/src/components/user-actions/index.test.tsx b/src/components/user-actions/index.test.tsx new file mode 100644 index 000000000..6aa3e52d3 --- /dev/null +++ b/src/components/user-actions/index.test.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Properties, UserActions } from '.'; + +describe('UserActions', () => { + const subject = (props: Partial = {}) => { + const allProps = { + userImageUrl: '', + userIsOnline: false, + isConversationListOpen: false, + updateConversationState: (_) => undefined, + ...props, + }; + + return shallow(); + }; + + it('renders user avatar', () => { + const wrapper = subject({ userImageUrl: 'image-url' }); + + expect(wrapper.find('Avatar').props()).toContainEntries([ + [ + 'type', + 'circle', + ], + [ + 'size', + 'regular', + ], + [ + 'imageURL', + 'image-url', + ], + ]); + }); + + it('renders user status when online', () => { + const wrapper = subject({ userIsOnline: true }); + + expect(wrapper.find('Avatar').prop('statusType')).toEqual('active'); + }); + + it('renders user status when offline', () => { + const wrapper = subject({ userIsOnline: false }); + + expect(wrapper.find('Avatar').prop('statusType')).toEqual('offline'); + }); + + it('opens and closes the notification list', () => { + const wrapper = subject(); + + notificationButton(wrapper).simulate('click'); + + expect(wrapper.find('IconBell1').prop('isFilled')).toBeTrue(); + expect(wrapper.find('NotificationPopup').exists()).toBeTrue(); + + notificationButton(wrapper).simulate('click'); + + expect(wrapper.find('IconBell1').prop('isFilled')).toBeFalse(); + expect(wrapper.find('NotificationPopup').exists()).toBeFalse(); + }); + + it('opens the conversation list', () => { + const updateConversationState = jest.fn(); + const wrapper = subject({ updateConversationState, isConversationListOpen: false }); + + conversationButton(wrapper).simulate('click'); + + expect(updateConversationState).toBeCalledWith(true); + }); + + it('closes the conversation list', () => { + const updateConversationState = jest.fn(); + const wrapper = subject({ updateConversationState, isConversationListOpen: true }); + + conversationButton(wrapper).simulate('click'); + + expect(updateConversationState).toBeCalledWith(false); + }); + + it('renders conversation list closed', () => { + const wrapper = subject({ isConversationListOpen: false }); + + expect(wrapper.find('IconMessageSquare2').prop('isFilled')).toBeFalse(); + }); + + it('renders conversation list open', () => { + const wrapper = subject({ isConversationListOpen: true }); + + expect(wrapper.find('IconMessageSquare2').prop('isFilled')).toBeTrue(); + }); +}); + +function notificationButton(wrapper) { + return wrapper.find('button').at(1); +} + +function conversationButton(wrapper) { + return wrapper.find('button').at(0); +} diff --git a/src/components/user-actions/index.tsx b/src/components/user-actions/index.tsx new file mode 100644 index 000000000..4fa09954a --- /dev/null +++ b/src/components/user-actions/index.tsx @@ -0,0 +1,62 @@ +import React from 'react'; + +import { Avatar } from '@zero-tech/zui/components'; + +import './styles.scss'; +import { IconBell1, IconMessageSquare2 } from '@zero-tech/zui/icons'; +import { NotificationPopup } from '../notification/popup'; + +export interface Properties { + userImageUrl?: string; + userIsOnline: boolean; + isConversationListOpen: boolean; + updateConversationState: (isOpen: boolean) => void; +} + +interface State { + isNotificationPopupOpen: boolean; +} + +export class UserActions extends React.Component { + state = { isNotificationPopupOpen: false }; + + get userStatus(): 'active' | 'offline' { + return this.props.userIsOnline ? 'active' : 'offline'; + } + + toggleNotificationState = () => { + this.setState({ isNotificationPopupOpen: !this.state.isNotificationPopupOpen }); + }; + + toggleConversationListState = () => { + this.props.updateConversationState(!this.props.isConversationListOpen); + }; + + render() { + return ( + <> +
+ + + +
+ {this.state.isNotificationPopupOpen && } + + ); + } +} diff --git a/src/components/user-actions/styles.scss b/src/components/user-actions/styles.scss new file mode 100644 index 000000000..b975f2585 --- /dev/null +++ b/src/components/user-actions/styles.scss @@ -0,0 +1,24 @@ +@use '~@zero-tech/zui/styles/theme' as theme; + +.user-actions { + display: flex; + gap: 15px; + + color: theme.$color-primary-transparency-11; + + button { + border-radius: 50%; + height: 40px; + width: 40px; + line-height: 0px; + margin: 0px; + + > * { + margin: auto; // Center the icon + } + + &:hover { + background-color: theme.$color-primary-4; + } + } +} diff --git a/src/components/wallet-manager/index.test.tsx b/src/components/wallet-manager/index.test.tsx index 5e74213e8..f9f8d983a 100644 --- a/src/components/wallet-manager/index.test.tsx +++ b/src/components/wallet-manager/index.test.tsx @@ -49,6 +49,25 @@ describe('WalletManager', () => { expect(wrapper.find(Button).exists()).toBe(false); }); + it('renders user actions address when set', () => { + const currentAddress = '0x0000000000000000000000000000000000000001'; + + const wrapper = subject({ + currentAddress, + userIsOnline: true, + userImageUrl: 'image-url', + isConversationListOpen: true, + }); + const ifAuthenticated = wrapper.find(IfAuthenticated).find({ showChildren: true }); + + expect(ifAuthenticated.find('UserActions').props()).toEqual({ + userImageUrl: 'image-url', + userIsOnline: true, + isConversationListOpen: true, + updateConversationState: undefined, + }); + }); + it('renders wallet address when set', () => { const currentAddress = '0x0000000000000000000000000000000000000001'; @@ -271,5 +290,60 @@ describe('WalletManager', () => { expect(state.isWalletModalOpen).toEqual(isWalletModalOpenMock); }); + + test('userImageUrl', () => { + const state = subject( + getState({ + authentication: { + user: { + data: { + id: 'user-id', + profileSummary: { + profileImage: 'user-url', + }, + }, + }, + }, + }) + ); + + expect(state.userImageUrl).toEqual('user-url'); + }); + + test('userImageUrl', () => { + const state = subject( + getState({ + authentication: { + user: { data: { profileSummary: { profileImage: 'user-url' } } }, + }, + }) + ); + + expect(state.userImageUrl).toEqual('user-url'); + }); + + test('userIsOnline', () => { + const state = subject( + getState({ + authentication: { + user: { data: { isOnline: true } }, + }, + }) + ); + + expect(state.userIsOnline).toEqual(true); + }); + + test('isConversationListOpen', () => { + const state = subject( + getState({ + layout: { + value: { isSidekickOpen: true }, + }, + }) + ); + + expect(state.isConversationListOpen).toEqual(true); + }); }); }); diff --git a/src/components/wallet-manager/index.tsx b/src/components/wallet-manager/index.tsx index bb0578441..34fde6d28 100644 --- a/src/components/wallet-manager/index.tsx +++ b/src/components/wallet-manager/index.tsx @@ -11,6 +11,8 @@ import { isElectron } from '../../utils'; import { Button as ConnectButton } from '../../components/authentication/button'; import './styles.scss'; import { IfAuthenticated } from '../authentication/if-authenticated'; +import { UserActions } from '../user-actions'; +import { updateSidekick } from '../../store/layout'; interface PublicProperties { className?: string; @@ -23,6 +25,10 @@ export interface Properties extends PublicProperties { updateConnector: (connector: WalletType | Connectors.None) => void; setWalletModalOpen: (isWalletModalOpen: boolean) => void; isWalletModalOpen: Web3State['isWalletModalOpen']; + userImageUrl: string; + userIsOnline: boolean; + updateConversationState: (isOpen: boolean) => void; + isConversationListOpen: boolean; } export interface State { @@ -33,6 +39,10 @@ export class Container extends React.Component { static mapState(state: RootState): Partial { const { web3: { status, value, isWalletModalOpen }, + authentication: { + user: { data: userData }, + }, + layout, } = state; return { @@ -40,6 +50,9 @@ export class Container extends React.Component { currentAddress: value.address, connectionStatus: status, isWalletModalOpen, + userImageUrl: userData?.profileSummary?.profileImage || '', + userIsOnline: !!userData?.isOnline, + isConversationListOpen: !!layout?.value?.isSidekickOpen, }; } @@ -47,6 +60,7 @@ export class Container extends React.Component { return { updateConnector, setWalletModalOpen, + updateConversationState: (isOpen: boolean) => updateSidekick({ isOpen }), }; } @@ -121,10 +135,18 @@ export class Container extends React.Component { return (
- +
+ + +
diff --git a/src/lib/api/rest.ts b/src/lib/api/rest.ts index 365c4f2c7..cf7c94b26 100644 --- a/src/lib/api/rest.ts +++ b/src/lib/api/rest.ts @@ -24,7 +24,7 @@ function apiUrl(path: string): string { */ const xPlatFormHeader = { 'X-APP-PLATFORM': 'zos' }; -export function get(path: string, filter?: RequestFilter | string) { +export function get(path: string, filter?: RequestFilter | string, query?: any) { let queryData; if (filter) { if (typeof filter === 'string') { @@ -36,6 +36,10 @@ export function get(path: string, filter?: RequestFilter | string) { } } + if (query) { + queryData = { ...queryData, ...query }; + } + return Request.get(apiUrl(path)).set(xPlatFormHeader).withCredentials().query(queryData); } diff --git a/src/platform-apps/channels/container.test.tsx b/src/platform-apps/channels/container.test.tsx index 862d1ec38..4599bd4ed 100644 --- a/src/platform-apps/channels/container.test.tsx +++ b/src/platform-apps/channels/container.test.tsx @@ -175,20 +175,24 @@ describe('ChannelsContainer', () => { value: [ 'the-id', 'the-second-id', + 'the-conversation-id', ], }, normalized: { + // Note: There's currently a bug where we're labelling channels as isChannel: false + // and Conversations as true. channels: { - 'the-id': { id: 'the-id', name: 'the channel' }, - 'the-second-id': { id: 'the-second-id', name: 'the second channel' }, - 'the-third-id': { id: 'the-third-id', name: 'the third channel' }, + 'the-id': { id: 'the-id', name: 'the channel', isChannel: false }, + 'the-second-id': { id: 'the-second-id', name: 'the second channel', isChannel: false }, + 'the-third-id': { id: 'the-third-id', name: 'the third channel', isChannel: false }, + 'the-conversation-id': { id: 'the-conversation-id', name: 'the conversation', isChannel: true }, }, }, }); - expect(state.channels).toIncludeAllPartialMembers([ - { id: 'the-id', name: 'the channel' }, - { id: 'the-second-id', name: 'the second channel' }, + expect(state.channels.map((c) => c.id)).toEqual([ + 'the-id', + 'the-second-id', ]); }); diff --git a/src/platform-apps/channels/container.tsx b/src/platform-apps/channels/container.tsx index 52550d28e..3ff923aab 100644 --- a/src/platform-apps/channels/container.tsx +++ b/src/platform-apps/channels/container.tsx @@ -124,4 +124,4 @@ export class Container extends React.Component { } } -export const ChannelsContainer = withAuthenticationContext<{}>(connectContainer(Container)); +export const ChannelsContainer = withAuthenticationContext(connectContainer<{}>(Container)); diff --git a/src/store/index.ts b/src/store/index.ts index f04307c17..f42e0e8a0 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -13,6 +13,7 @@ import { reducer as apps } from './apps'; import { reducer as normalized } from './normalized'; import { reducer as authentication } from './authentication'; import { reducer as chat } from './chat'; +import { reducer as notificationsList } from './notifications'; const sagaMiddleware = createSagaMiddleware({ onError: (e) => { @@ -30,6 +31,7 @@ export const rootReducer = combineReducers({ normalized, authentication, chat, + notificationsList, }); export type RootState = ReturnType; diff --git a/src/store/layout/constants.ts b/src/store/layout/constants.ts index 85e569faa..f7f374713 100644 --- a/src/store/layout/constants.ts +++ b/src/store/layout/constants.ts @@ -1,7 +1 @@ -import { SidekickTabs } from './../../components/sidekick/types'; - export const SIDEKICK_OPEN_STORAGE = 'isSidekickOpen'; - -export const SIDEKICK_TAB_KEY = 'sidekick-tab'; - -export const DEFAULT_ACTIVE_TAB = SidekickTabs.MESSAGES; diff --git a/src/store/layout/index.test.ts b/src/store/layout/index.test.ts index cf6171895..9b22fbd78 100644 --- a/src/store/layout/index.test.ts +++ b/src/store/layout/index.test.ts @@ -6,7 +6,6 @@ describe('layout reducer', () => { isContextPanelOpen: false, isSidekickOpen: false, hasContextPanel: false, - activeSidekickTab: null, }, }; @@ -16,7 +15,6 @@ describe('layout reducer', () => { isContextPanelOpen: false, isSidekickOpen: false, hasContextPanel: false, - activeSidekickTab: null, }, }); }); diff --git a/src/store/layout/index.ts b/src/store/layout/index.ts index 09376577d..15c7b6614 100644 --- a/src/store/layout/index.ts +++ b/src/store/layout/index.ts @@ -1,14 +1,12 @@ import { createSlice, PayloadAction, createAction } from '@reduxjs/toolkit'; -import type { AppLayout, LayoutState, UpdateSidekickPayload, SetActiveSidekickTabPayload } from './types'; +import type { AppLayout, LayoutState, UpdateSidekickPayload } from './types'; export enum SagaActionTypes { updateSidekick = 'layout/saga/updateSidekick', - setActiveSidekickTab = 'layout/saga/setActiveSidekickTab', syncSidekickState = 'layout/saga/syncSidekickState', } export const updateSidekick = createAction(SagaActionTypes.updateSidekick); -export const setActiveSidekickTab = createAction(SagaActionTypes.setActiveSidekickTab); export const syncSidekickState = createAction(SagaActionTypes.syncSidekickState); const initialState: LayoutState = { @@ -16,7 +14,6 @@ const initialState: LayoutState = { isContextPanelOpen: false, hasContextPanel: false, isSidekickOpen: false, - activeSidekickTab: null, }, }; @@ -35,4 +32,4 @@ const slice = createSlice({ export const { update } = slice.actions; export const { reducer } = slice; -export { AppLayout, LayoutState, UpdateSidekickPayload, SetActiveSidekickTabPayload }; +export { AppLayout, LayoutState, UpdateSidekickPayload }; diff --git a/src/store/layout/saga.test.ts b/src/store/layout/saga.test.ts index 405d7a483..d65bc14f8 100644 --- a/src/store/layout/saga.test.ts +++ b/src/store/layout/saga.test.ts @@ -1,6 +1,5 @@ -import { SidekickTabs } from './../../components/sidekick/types'; import { expectSaga } from 'redux-saga-test-plan'; -import { updateSidekick as updateSidekickSaga, updateActiveSidekickTab, syncSidekickState } from './saga'; +import { updateSidekick as updateSidekickSaga, syncSidekickState } from './saga'; import { reducer } from '.'; @@ -28,20 +27,6 @@ describe('layout saga', () => { expect(global.localStorage.setItem).toHaveBeenCalled(); }); - it('should store active tab', async () => { - const { storeState } = await expectSaga(updateActiveSidekickTab, { payload: { activeTab: SidekickTabs.MESSAGES } }) - .withReducer(reducer, state as any) - .run(); - - expect(storeState).toMatchObject({ - value: { - activeSidekickTab: SidekickTabs.MESSAGES, - }, - }); - - expect(global.localStorage.setItem).toHaveBeenCalledWith('user-id-sidekick-tab', 'messages'); - }); - it('should sync sidekick state', async () => { global.localStorage.getItem = jest.fn().mockReturnValue('true'); @@ -51,12 +36,10 @@ describe('layout saga', () => { expect(storeState).toMatchObject({ value: { - activeSidekickTab: SidekickTabs.MESSAGES, isSidekickOpen: true, }, }); expect(global.localStorage.getItem).toHaveBeenNthCalledWith(1, 'user-id-isSidekickOpen'); - expect(global.localStorage.getItem).toHaveBeenNthCalledWith(2, 'user-id-sidekick-tab'); }); }); diff --git a/src/store/layout/saga.ts b/src/store/layout/saga.ts index c258309e4..e54d66b63 100644 --- a/src/store/layout/saga.ts +++ b/src/store/layout/saga.ts @@ -1,9 +1,8 @@ import getDeepProperty from 'lodash.get'; -import { SIDEKICK_OPEN_STORAGE, SIDEKICK_TAB_KEY } from './constants'; +import { SIDEKICK_OPEN_STORAGE } from './constants'; import { put, takeLatest, select } from 'redux-saga/effects'; import { update, SagaActionTypes } from './'; import { resolveFromLocalStorageAsBoolean } from '../../lib/storage'; -import { resolveActiveTab } from './utils'; export const getKeyWithUserId = (key: string) => (state) => { const user = getDeepProperty(state, 'authentication.user.data', null); @@ -29,34 +28,15 @@ export function* updateSidekick(action) { } } -export function* updateActiveSidekickTab(action) { - const { activeTab } = action.payload; - - const sidekickTabKeyWithUserId = yield select(getKeyWithUserId(SIDEKICK_TAB_KEY)); - - if (sidekickTabKeyWithUserId) { - localStorage.setItem(sidekickTabKeyWithUserId, activeTab); - - yield put( - update({ - activeSidekickTab: activeTab, - }) - ); - } -} - export function* syncSidekickState() { - const sidekickTabKeyWithUserId = yield select(getKeyWithUserId(SIDEKICK_TAB_KEY)); const sidekickOpenStorageWithUserId = yield select(getKeyWithUserId(SIDEKICK_OPEN_STORAGE)); - if (sidekickTabKeyWithUserId && sidekickOpenStorageWithUserId) { + if (sidekickOpenStorageWithUserId) { const isSidekickOpen = resolveFromLocalStorageAsBoolean(sidekickOpenStorageWithUserId); - const activeSidekickTab = resolveActiveTab(sidekickTabKeyWithUserId); yield put( update({ isSidekickOpen, - activeSidekickTab, }) ); } @@ -64,6 +44,5 @@ export function* syncSidekickState() { export function* saga() { yield takeLatest(SagaActionTypes.updateSidekick, updateSidekick); - yield takeLatest(SagaActionTypes.setActiveSidekickTab, updateActiveSidekickTab); yield takeLatest(SagaActionTypes.syncSidekickState, syncSidekickState); } diff --git a/src/store/layout/types.ts b/src/store/layout/types.ts index 021d5c0a9..92ad14319 100644 --- a/src/store/layout/types.ts +++ b/src/store/layout/types.ts @@ -1,10 +1,7 @@ -import { SidekickTabs } from './../../components/sidekick/types'; - export interface AppLayout { hasContextPanel: boolean; isContextPanelOpen: boolean; isSidekickOpen: boolean; - activeSidekickTab: SidekickTabs; } export interface LayoutState { @@ -14,7 +11,3 @@ export interface LayoutState { export interface UpdateSidekickPayload { isOpen: boolean; } - -export interface SetActiveSidekickTabPayload { - activeTab: SidekickTabs; -} diff --git a/src/store/layout/utils.test.ts b/src/store/layout/utils.test.ts deleted file mode 100644 index 213b12eb1..000000000 --- a/src/store/layout/utils.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { SidekickTabs } from './../../components/sidekick/types'; -import { resolveActiveTab } from './utils'; - -describe('layout.utils', () => { - describe('resolveActiveTab', () => { - it('should use the key to get the data', () => { - const key = 'key'; - resolveActiveTab(key); - expect(global.localStorage.getItem).toHaveBeenCalledWith(key); - }); - - it('returns default active tab', () => { - const key = 'key'; - const activeTab = resolveActiveTab(key); - expect(activeTab).toEqual(SidekickTabs.MESSAGES); - }); - - it('returns stored active tab', () => { - const key = 'key'; - global.localStorage.getItem = jest.fn().mockReturnValue('notifications'); - - const activeTab = resolveActiveTab(key); - expect(activeTab).toEqual(SidekickTabs.NOTIFICATIONS); - }); - - it('returns default in case stored tab is not matching any tab', () => { - const key = 'key'; - global.localStorage.getItem = jest.fn().mockReturnValue('data here'); - - const activeTab = resolveActiveTab(key); - expect(activeTab).toEqual(SidekickTabs.MESSAGES); - }); - }); -}); diff --git a/src/store/layout/utils.ts b/src/store/layout/utils.ts deleted file mode 100644 index 347819505..000000000 --- a/src/store/layout/utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SidekickTabs } from '../../components/sidekick/types'; -import { DEFAULT_ACTIVE_TAB } from './constants'; - -export function resolveActiveTab(key: string) { - const activeTab = localStorage.getItem(key) as SidekickTabs; - - if (Object.values(SidekickTabs).includes(activeTab)) { - return activeTab; - } - - return DEFAULT_ACTIVE_TAB; -} diff --git a/src/store/messages/saga.test.ts b/src/store/messages/saga.test.ts index 7c765f9e2..fe3644cef 100644 --- a/src/store/messages/saga.test.ts +++ b/src/store/messages/saga.test.ts @@ -7,6 +7,7 @@ import { deleteMessageApi, editMessageApi, uploadFileMessage as uploadFileMessageApi, + getLinkPreviews, } from './api'; import { fetch, @@ -17,6 +18,7 @@ import { receiveDelete, editMessage, uploadFileMessage, + receiveNewMessage, } from './saga'; import { rootReducer } from '..'; @@ -85,6 +87,113 @@ describe('messages saga', () => { expect(channels[channelId].messageIdsCache).not.toStrictEqual([]); }); + it('send message with link preview', async () => { + const channelId = '0x000000000000000000000000000000000000000A'; + const message = 'www.google.com'; + const mentionedUserIds = ['ef698a51-1cea-42f8-a078-c0f96ed03c9e']; + const parentMessage = null; + + const initialState = { + authentication: { + user: { + data: { + id: 1, + profileId: '2', + profileSummary: { + firstName: 'Johnn', + lastName: 'Doe', + profileImage: '/image.jpg', + }, + }, + }, + }, + }; + + const { + storeState: { + normalized: { channels, messages }, + }, + } = await expectSaga(send, { payload: { channelId, message, mentionedUserIds, parentMessage } }) + .provide([ + [ + matchers.call.fn(sendMessagesByChannelId), + { status: 200, body: { id: 'message 1', message } }, + ], + [ + matchers.call.fn(getLinkPreviews), + { + status: 200, + body: { + id: 'fdf2ce2b-062e-4a83-9c27-03f36c81c0c0', + url: 'http://www.google.com', + type: 'link', + title: 'Google', + description: 'Search the world information, including webpages.', + }, + }, + ], + ]) + .withReducer(rootReducer, initialState as any) + .call(sendMessagesByChannelId, channelId, message, mentionedUserIds, parentMessage) + .run(); + + const messageId = channels[channelId]['messages'][0]; + expect(messages[messageId].preview).not.toBeNull(); + }); + + it('receive new message with link preview', async () => { + const channelId = '0x000000000000000000000000000000000000000A'; + const message = { + id: 8667728016, + message: 'www.google.com', + parentMessageText: null, + createdAt: 1678861267433, + updatedAt: 0, + }; + + const initialState = { + authentication: { + user: { + data: { + id: 1, + profileId: '2', + profileSummary: { + firstName: 'Johnn', + lastName: 'Doe', + profileImage: '/image.jpg', + }, + }, + }, + }, + }; + + const { + storeState: { + normalized: { channels, messages }, + }, + } = await expectSaga(receiveNewMessage, { payload: { channelId, message } }) + .provide([ + [ + matchers.call.fn(getLinkPreviews), + { + status: 200, + body: { + id: 'fdf2ce2b-062e-4a83-9c27-03f36c81c0c0', + url: 'http://www.google.com', + type: 'link', + title: 'Google', + description: 'Search the world information, including webpages.', + }, + }, + ], + ]) + .withReducer(rootReducer, initialState as any) + .run(); + + const messageId = channels[channelId]['messages'][0]; + expect(messages[messageId].preview).not.toBeNull(); + }); + it('reply message', async () => { const channelId = '0x000000000000000000000000000000000000000A'; const message = 'reply'; diff --git a/src/store/messages/saga.ts b/src/store/messages/saga.ts index b4f3d5772..3d04830f1 100644 --- a/src/store/messages/saga.ts +++ b/src/store/messages/saga.ts @@ -293,10 +293,15 @@ export function* stopSyncChannels(action) { } export function* receiveNewMessage(action) { - const { channelId, message } = action.payload; + let { channelId, message } = action.payload; const cachedMessageIds = [...(yield select(getCachedMessageIds(channelId)))]; const currentMessages = yield select(rawMessagesSelector(channelId)); + const preview = yield getPreview(message?.message); + + if (preview) { + message = { ...message, preview }; + } let messages = []; if (cachedMessageIds.length) { diff --git a/src/store/notifications/api.ts b/src/store/notifications/api.ts new file mode 100644 index 000000000..19d97b88b --- /dev/null +++ b/src/store/notifications/api.ts @@ -0,0 +1,6 @@ +import { get } from '../../lib/api/rest'; + +export async function fetchNotifications(userId: string) { + const response = await get('/api/notifications/filter', { limit: 15 }, { userId }); + return response.body; +} diff --git a/src/store/notifications/index.test.ts b/src/store/notifications/index.test.ts new file mode 100644 index 000000000..829d72d33 --- /dev/null +++ b/src/store/notifications/index.test.ts @@ -0,0 +1,31 @@ +import { reducer, receiveNormalized, setStatus } from '.'; +import { AsyncListStatus, AsyncNormalizedListState } from '../normalized'; + +describe('notificationsList reducer', () => { + const initialExistingState: AsyncNormalizedListState = { + status: AsyncListStatus.Idle, + value: [], + }; + + it('should handle initial state', () => { + expect(reducer(undefined, { type: 'unknown' })).toEqual({ + status: AsyncListStatus.Idle, + value: [], + }); + }); + + it('should replace existing state with new state', () => { + const actual = reducer(initialExistingState, receiveNormalized(['the-id'])); + + expect(actual).toStrictEqual({ + value: ['the-id'], + status: AsyncListStatus.Idle, + }); + }); + + it('should replace existing status with new status', () => { + const actual = reducer(initialExistingState, setStatus(AsyncListStatus.Fetching)); + + expect(actual.status).toEqual(AsyncListStatus.Fetching); + }); +}); diff --git a/src/store/notifications/index.ts b/src/store/notifications/index.ts new file mode 100644 index 000000000..cea4a1a41 --- /dev/null +++ b/src/store/notifications/index.ts @@ -0,0 +1,26 @@ +import { createAction } from '@reduxjs/toolkit'; + +import { createNormalizedListSlice, createNormalizedSlice } from '../normalized'; + +import { Payload } from './saga'; + +export enum SagaActionTypes { + Fetch = 'notifications/saga/fetch', +} + +const fetch = createAction(SagaActionTypes.Fetch); + +const slice = createNormalizedSlice({ + name: 'notifications', +}); +const { schema } = slice; + +const listSlice = createNormalizedListSlice({ + name: 'notificationsList', + schema, +}); + +export const { receiveNormalized, setStatus, receive } = listSlice.actions; +export const { reducer, normalize, denormalize } = listSlice; + +export { fetch }; diff --git a/src/store/notifications/saga.test.ts b/src/store/notifications/saga.test.ts new file mode 100644 index 000000000..f46ea461d --- /dev/null +++ b/src/store/notifications/saga.test.ts @@ -0,0 +1,100 @@ +import { expectSaga } from 'redux-saga-test-plan'; +import * as matchers from 'redux-saga-test-plan/matchers'; + +import { AsyncListStatus } from '../normalized'; +import { rootReducer } from '..'; + +import { fetch } from './saga'; +import { setStatus } from '.'; +import { fetchNotifications } from './api'; + +describe('notifications list saga', () => { + it('sets status to fetching', async () => { + await expectSaga(fetch, { payload: {} }) + .put(setStatus(AsyncListStatus.Fetching)) + .provide([ + [ + matchers.call.fn(fetchNotifications), + [], + ], + ]) + .run(); + }); + + it('fetches notifications', async () => { + await expectSaga(fetch, { payload: { userId: 'user-id' } }) + .provide([ + [ + matchers.call.fn(fetchNotifications), + [], + ], + ]) + .call(fetchNotifications, 'user-id') + .run(); + }); + + it('sets status to Idle', async () => { + const { + storeState: { notificationsList }, + } = await expectSaga(fetch, { payload: {} }) + .withReducer(rootReducer) + .provide([ + [ + matchers.call.fn(fetchNotifications), + [], + ], + ]) + .run(); + + expect(notificationsList.status).toBe(AsyncListStatus.Idle); + }); + + it('adds notification ids to notificationsList state', async () => { + const ids = [ + 'id-1', + 'id-2', + 'id-3', + ]; + const { + storeState: { notificationsList }, + } = await expectSaga(fetch, { payload: {} }) + .withReducer(rootReducer) + .provide([ + [ + matchers.call.fn(fetchNotifications), + [ + { id: 'id-1', notificationType: 'type-1' }, + { id: 'id-2', notificationType: 'type-2' }, + { id: 'id-3', notificationType: 'type-3' }, + ], + ], + ]) + .run(); + + expect(notificationsList.value).toStrictEqual(ids); + }); + + it('adds notifications to normalized state', async () => { + const { + storeState: { normalized }, + } = await expectSaga(fetch, { payload: {} }) + .provide([ + [ + matchers.call.fn(fetchNotifications), + [ + { id: 'id-1', notificationType: 'type-1' }, + { id: 'id-2', notificationType: 'type-2' }, + { id: 'id-3', notificationType: 'type-3' }, + ], + ], + ]) + .withReducer(rootReducer) + .run(); + + expect(normalized.notifications).toStrictEqual({ + 'id-1': { id: 'id-1', notificationType: 'type-1' }, + 'id-2': { id: 'id-2', notificationType: 'type-2' }, + 'id-3': { id: 'id-3', notificationType: 'type-3' }, + }); + }); +}); diff --git a/src/store/notifications/saga.ts b/src/store/notifications/saga.ts new file mode 100644 index 000000000..dcac3dfe3 --- /dev/null +++ b/src/store/notifications/saga.ts @@ -0,0 +1,26 @@ +import { takeLatest, put, call } from 'redux-saga/effects'; + +import { AsyncListStatus } from '../normalized'; + +import { SagaActionTypes, receive, setStatus } from '.'; +import { fetchNotifications } from './api'; + +export interface Payload { + userId: string; +} + +export function* fetch(action) { + const { userId } = action.payload; + + yield put(setStatus(AsyncListStatus.Fetching)); + + const notifications = yield call(fetchNotifications, userId); + + yield put(receive(notifications)); + + yield put(setStatus(AsyncListStatus.Idle)); +} + +export function* saga() { + yield takeLatest(SagaActionTypes.Fetch, fetch); +} diff --git a/src/store/notifications/types.ts b/src/store/notifications/types.ts new file mode 100644 index 000000000..a8d773bd6 --- /dev/null +++ b/src/store/notifications/types.ts @@ -0,0 +1,18 @@ +import { Channel, User } from '../channels'; + +export interface Payload { + channelId: string; +} + +export enum ChannelType { + Channel, + DirectMessage, +} + +export interface DirectMessage extends Channel { + otherMembers: User[]; +} + +export interface CreateMessengerConversation { + userIds: string[]; +} diff --git a/src/store/saga.ts b/src/store/saga.ts index 6ec49fe9f..eeb603561 100644 --- a/src/store/saga.ts +++ b/src/store/saga.ts @@ -10,6 +10,7 @@ import { saga as authentication } from './authentication/saga'; import { saga as chat } from './chat/saga'; import { saga as theme } from './theme/saga'; import { saga as layout } from './layout/saga'; +import { saga as notificationsList } from './notifications/saga'; export function* rootSaga() { const allSagas = { @@ -23,6 +24,7 @@ export function* rootSaga() { chat, theme, layout, + notificationsList, }; yield all(