diff --git a/web/cashtab/package-lock.json b/web/cashtab/package-lock.json --- a/web/cashtab/package-lock.json +++ b/web/cashtab/package-lock.json @@ -25,6 +25,7 @@ "qrcode.react": "^1.0.0", "react": "^17.0.1", "react-app-polyfill": "^2.0.0", + "react-beautiful-dnd": "^13.1.0", "react-copy-to-clipboard": "^5.0.3", "react-dev-utils": "^11.0.4", "react-device-detect": "^1.15.0", @@ -1463,10 +1464,14 @@ } }, "node_modules/@babel/runtime": { - "version": "7.13.10", - "license": "MIT", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", "dependencies": { "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/runtime-corejs3": { @@ -2853,6 +2858,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/html-minifier-terser": { "version": "5.1.1", "dev": true, @@ -2915,7 +2929,6 @@ }, "node_modules/@types/prop-types": { "version": "15.7.3", - "dev": true, "license": "MIT" }, "node_modules/@types/q": { @@ -2925,7 +2938,6 @@ }, "node_modules/@types/react": { "version": "17.0.3", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -2933,6 +2945,17 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-redux": { + "version": "7.1.21", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.21.tgz", + "integrity": "sha512-bLdglUiBSQNzWVVbmNPKGYYjrzp3/YDPwfOH3nLEz99I4awLlaRAPWjo6bZ2POpxztFWtDDXIPxBLVykXqBt+w==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, "node_modules/@types/react-test-renderer": { "version": "17.0.1", "dev": true, @@ -2943,7 +2966,6 @@ }, "node_modules/@types/scheduler": { "version": "0.16.1", - "dev": true, "license": "MIT" }, "node_modules/@types/source-list-map": { @@ -6741,6 +6763,14 @@ "node": ">=6" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, "node_modules/css-color-keywords": { "version": "1.0.0", "license": "ISC", @@ -7386,7 +7416,6 @@ }, "node_modules/csstype": { "version": "3.0.7", - "dev": true, "license": "MIT" }, "node_modules/cuid": { @@ -21263,6 +21292,11 @@ "performance-now": "^2.1.0" } }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "node_modules/random-bytes": { "version": "1.0.0", "license": "MIT", @@ -21912,6 +21946,24 @@ "asap": "~2.0.6" } }, + "node_modules/react-beautiful-dnd": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", + "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==", + "dependencies": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0", + "react-dom": "^16.8.5 || ^17.0.0" + } + }, "node_modules/react-copy-to-clipboard": { "version": "5.0.3", "license": "MIT", @@ -22078,9 +22130,33 @@ } }, "node_modules/react-is": { - "version": "17.0.1", - "dev": true, - "license": "MIT" + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-redux": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", + "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } }, "node_modules/react-router": { "version": "5.2.0", @@ -22285,6 +22361,14 @@ "node": ">=0.10.0" } }, + "node_modules/redux": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/regenerate": { "version": "1.4.2", "dev": true, @@ -26362,6 +26446,14 @@ "node": ">=0.10.0" } }, + "node_modules/use-memo-one": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", + "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" @@ -29533,7 +29625,9 @@ } }, "@babel/runtime": { - "version": "7.13.10", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -30466,6 +30560,15 @@ "@types/node": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/html-minifier-terser": { "version": "5.1.1", "dev": true @@ -30516,8 +30619,7 @@ "dev": true }, "@types/prop-types": { - "version": "15.7.3", - "dev": true + "version": "15.7.3" }, "@types/q": { "version": "1.5.4", @@ -30525,13 +30627,23 @@ }, "@types/react": { "version": "17.0.3", - "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "@types/react-redux": { + "version": "7.1.21", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.21.tgz", + "integrity": "sha512-bLdglUiBSQNzWVVbmNPKGYYjrzp3/YDPwfOH3nLEz99I4awLlaRAPWjo6bZ2POpxztFWtDDXIPxBLVykXqBt+w==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, "@types/react-test-renderer": { "version": "17.0.1", "dev": true, @@ -30540,8 +30652,7 @@ } }, "@types/scheduler": { - "version": "0.16.1", - "dev": true + "version": "0.16.1" }, "@types/source-list-map": { "version": "0.1.2", @@ -33268,6 +33379,14 @@ } } }, + "css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "requires": { + "tiny-invariant": "^1.0.6" + } + }, "css-color-keywords": { "version": "1.0.0" }, @@ -33674,8 +33793,7 @@ } }, "csstype": { - "version": "3.0.7", - "dev": true + "version": "3.0.7" }, "cuid": { "version": "2.1.8" @@ -42942,6 +43060,11 @@ "performance-now": "^2.1.0" } }, + "raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "random-bytes": { "version": "1.0.0" }, @@ -43349,6 +43472,20 @@ } } }, + "react-beautiful-dnd": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", + "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==", + "requires": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + } + }, "react-copy-to-clipboard": { "version": "5.0.3", "requires": { @@ -43461,8 +43598,22 @@ "requires": {} }, "react-is": { - "version": "17.0.1", - "dev": true + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "react-redux": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", + "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + } }, "react-router": { "version": "5.2.0", @@ -43600,6 +43751,14 @@ "minimatch": "3.0.4" } }, + "redux": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, "regenerate": { "version": "1.4.2", "dev": true @@ -46404,6 +46563,12 @@ "use": { "version": "3.1.1" }, + "use-memo-one": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", + "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2" }, diff --git a/web/cashtab/package.json b/web/cashtab/package.json --- a/web/cashtab/package.json +++ b/web/cashtab/package.json @@ -21,6 +21,7 @@ "qrcode.react": "^1.0.0", "react": "^17.0.1", "react-app-polyfill": "^2.0.0", + "react-beautiful-dnd": "^13.1.0", "react-copy-to-clipboard": "^5.0.3", "react-dev-utils": "^11.0.4", "react-device-detect": "^1.15.0", diff --git a/web/cashtab/src/components/Wallet/TokenList.js b/web/cashtab/src/components/Wallet/TokenList.js --- a/web/cashtab/src/components/Wallet/TokenList.js +++ b/web/cashtab/src/components/Wallet/TokenList.js @@ -1,22 +1,73 @@ -import React from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import TokenListItem from './TokenListItem'; import { Link } from 'react-router-dom'; import { formatBalance } from '@utils/formatting'; +import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; const TokenList = ({ tokens }) => { + const [sortedTokenList, setSortedTokenList] = useState([...tokens]); + // remaining steps are: + // set the latest sorted list with setLocalStorage to stringified list + // getLocalStorage and parse it + // if localDataArray exists, map it, if not use the default token list + + const reorder = (list, startIndex, endIndex) => { + const result = Array.from(list); + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + return result; + }; + + const handleDragEnd = result => { + setSortedTokenList( + reorder( + sortedTokenList, + result.source.index, + result.destination.index, + ), + ); + console.log(sortedTokenList); + }; + return ( -
- {tokens.map(token => ( - - - - ))} -
+ + + {(provided, snapshot) => ( +
+ {sortedTokenList.map((token, index) => ( + + {(provided, snapshot) => ( +
+ + + +
+ )} +
+ ))} + {provided.placeholder} +
+ )} +
+
); };