fix: soft rework Customers pages
|
|
@ -1,7 +1,7 @@
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
function getBackwardsCompatibleTriggers (triggers) {
|
function getBackwardsCompatibleTriggers (triggers) {
|
||||||
const filtered = _.filter(_.matches({ triggerType: 'amount', cashDirection: 'both' }))(triggers)
|
const filtered = _.filter(_.matches({ triggerType: 'txAmount', cashDirection: 'both' }))(triggers)
|
||||||
const grouped = _.groupBy(_.prop('requirement'))(filtered)
|
const grouped = _.groupBy(_.prop('requirement'))(filtered)
|
||||||
return _.mapValues(_.compose(_.get('threshold'), _.minBy('threshold')))(grouped)
|
return _.mapValues(_.compose(_.get('threshold'), _.minBy('threshold')))(grouped)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ function getCustomerById (id) {
|
||||||
c.id_card_data, c.id_card_data_override, c.id_card_data_expiration, c.id_card_photo_path,
|
c.id_card_data, c.id_card_data_override, c.id_card_data_expiration, c.id_card_photo_path,
|
||||||
c.id_card_photo_override, t.tx_class, t.fiat, t.fiat_code, t.created,
|
c.id_card_photo_override, t.tx_class, t.fiat, t.fiat_code, t.created,
|
||||||
row_number() over (partition by c.id order by t.created desc) as rn,
|
row_number() over (partition by c.id order by t.created desc) as rn,
|
||||||
count(0) over (partition by c.id) as total_txs,
|
sum(case when t.id is not null then 1 else 0 end) over (partition by c.id) as total_txs,
|
||||||
sum(t.fiat) over (partition by c.id) as total_spent
|
sum(t.fiat) over (partition by c.id) as total_spent
|
||||||
from customers c left outer join (
|
from customers c left outer join (
|
||||||
select 'cashIn' as tx_class, id, fiat, fiat_code, created, customer_id
|
select 'cashIn' as tx_class, id, fiat, fiat_code, created, customer_id
|
||||||
|
|
|
||||||
335
new-lamassu-admin/package-lock.json
generated
|
|
@ -3828,6 +3828,12 @@
|
||||||
"@babel/types": "^7.3.0"
|
"@babel/types": "^7.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/color-name": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/eslint-visitor-keys": {
|
"@types/eslint-visitor-keys": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||||
|
|
@ -6619,6 +6625,12 @@
|
||||||
"node-int64": "^0.4.0"
|
"node-int64": "^0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"btoa": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"buffer": {
|
"buffer": {
|
||||||
"version": "4.9.1",
|
"version": "4.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||||
|
|
@ -11101,6 +11113,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"filelist": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"filesize": {
|
"filesize": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
|
||||||
|
|
@ -12719,6 +12740,12 @@
|
||||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
|
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"is-docker": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"is-dom": {
|
"is-dom": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz",
|
||||||
|
|
@ -13152,6 +13179,26 @@
|
||||||
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
|
||||||
"integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA=="
|
"integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA=="
|
||||||
},
|
},
|
||||||
|
"jake": {
|
||||||
|
"version": "10.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
|
||||||
|
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"async": "0.9.x",
|
||||||
|
"chalk": "^2.4.2",
|
||||||
|
"filelist": "^1.0.1",
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"async": {
|
||||||
|
"version": "0.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
|
||||||
|
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"version": "24.9.0",
|
"version": "24.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz",
|
||||||
|
|
@ -23640,6 +23687,285 @@
|
||||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"source-map-explorer": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-explorer/-/source-map-explorer-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-3ECQLffCFV8QgrTqcmddLkWL4/aQs6ljYfgWCLselo5QtizOfOeUCKnS4rFn7MIrdeZLM6TZrseOtsrWZhWKoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"btoa": "^1.2.1",
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"convert-source-map": "^1.7.0",
|
||||||
|
"ejs": "^3.0.2",
|
||||||
|
"escape-html": "^1.0.3",
|
||||||
|
"glob": "^7.1.6",
|
||||||
|
"gzip-size": "^5.1.1",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"open": "^7.0.3",
|
||||||
|
"source-map": "^0.7.3",
|
||||||
|
"temp": "^0.9.1",
|
||||||
|
"yargs": "^15.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/color-name": "^1.1.1",
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cliui": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.0",
|
||||||
|
"wrap-ansi": "^6.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"convert-source-map": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ejs": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"jake": "^10.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"find-up": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"locate-path": "^5.0.0",
|
||||||
|
"path-exists": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"glob": {
|
||||||
|
"version": "7.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||||
|
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"fs.realpath": "^1.0.0",
|
||||||
|
"inflight": "^1.0.4",
|
||||||
|
"inherits": "2",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"path-is-absolute": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"is-wsl": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"is-docker": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"locate-path": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"p-locate": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"open": {
|
||||||
|
"version": "7.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/open/-/open-7.0.4.tgz",
|
||||||
|
"integrity": "sha512-brSA+/yq+b08Hsr4c8fsEW2CRzk1BmfN3SAK/5VCHQ9bdoZJ4qa/+AfR0xHjlbbZUyPkUHs1b8x1RqdyZdkVqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"is-docker": "^2.0.0",
|
||||||
|
"is-wsl": "^2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-limit": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"p-try": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-locate": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"p-limit": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-try": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"path-exists": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wrap-ansi": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"y18n": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"yargs": {
|
||||||
|
"version": "15.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
|
||||||
|
"integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"cliui": "^6.0.0",
|
||||||
|
"decamelize": "^1.2.0",
|
||||||
|
"find-up": "^4.1.0",
|
||||||
|
"get-caller-file": "^2.0.1",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"require-main-filename": "^2.0.0",
|
||||||
|
"set-blocking": "^2.0.0",
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"which-module": "^2.0.0",
|
||||||
|
"y18n": "^4.0.0",
|
||||||
|
"yargs-parser": "^18.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yargs-parser": {
|
||||||
|
"version": "18.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||||
|
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"camelcase": "^5.0.0",
|
||||||
|
"decamelize": "^1.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"source-map-resolve": {
|
"source-map-resolve": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
|
||||||
|
|
@ -24323,6 +24649,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"temp": {
|
||||||
|
"version": "0.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/temp/-/temp-0.9.1.tgz",
|
||||||
|
"integrity": "sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"rimraf": "~2.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"term-size": {
|
"term-size": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,8 @@
|
||||||
"prettier": "1.19.1",
|
"prettier": "1.19.1",
|
||||||
"prettier-config-standard": "^1.0.1",
|
"prettier-config-standard": "^1.0.1",
|
||||||
"react-scripts": "^3.3.0",
|
"react-scripts": "^3.3.0",
|
||||||
"serve": "^11.2.0"
|
"serve": "^11.2.0",
|
||||||
|
"source-map-explorer": "^2.4.2"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
|
@ -78,6 +79,7 @@
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
"fix": "eslint --fix --ext .js,.md,.json src/",
|
"fix": "eslint --fix --ext .js,.md,.json src/",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
|
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"storybook": "start-storybook -p 9009 -s public",
|
"storybook": "start-storybook -p 9009 -s public",
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const ActionButton = memo(
|
const ActionButton = memo(
|
||||||
({ className, Icon, InverseIcon, color, children, ...props }) => {
|
({ className, Icon, InverseIcon, color, children, ...props }) => {
|
||||||
const classes = useStyles({ color })
|
const classes = useStyles()
|
||||||
const classNames = {
|
const classNames = {
|
||||||
[classes.actionButton]: true,
|
[classes.actionButton]: true,
|
||||||
[classes.primary]: color === 'primary',
|
[classes.primary]: color === 'primary',
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { makeStyles } from '@material-ui/core'
|
import { makeStyles, Box } from '@material-ui/core'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import ErrorMessage from 'src/components/ErrorMessage'
|
import ErrorMessage from 'src/components/ErrorMessage'
|
||||||
import Title from 'src/components/Title'
|
import Title from 'src/components/Title'
|
||||||
|
import { Label1 } from 'src/components/typography'
|
||||||
|
|
||||||
import styles from './TitleSection.styles'
|
import styles from './TitleSection.styles'
|
||||||
|
|
||||||
|
|
@ -19,7 +20,14 @@ const TitleSection = ({ className, title, error, labels, children }) => {
|
||||||
<ErrorMessage className={classes.error}>Failed to save</ErrorMessage>
|
<ErrorMessage className={classes.error}>Failed to save</ErrorMessage>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.headerLabels}>{labels}</div>
|
<Box display="flex" flexDirection="row">
|
||||||
|
{(labels ?? []).map(({ icon, label }, idx) => (
|
||||||
|
<Box key={idx} display="flex" alignItems="center">
|
||||||
|
<div className={classes.icon}>{icon}</div>
|
||||||
|
<Label1 className={classes.label}>{label}</Label1>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { mainStyles } from 'src/pages/Transactions/Transactions.styles'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
titleWrapper: {
|
titleWrapper: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
@ -13,5 +11,10 @@ export default {
|
||||||
error: {
|
error: {
|
||||||
marginLeft: 12
|
marginLeft: 12
|
||||||
},
|
},
|
||||||
headerLabels: mainStyles.headerLabels
|
icon: {
|
||||||
|
marginRight: 6
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
marginRight: 24
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const Row = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={classes.rowWrapper}>
|
||||||
<div className={classnames({ [classes.before]: expanded })}>
|
<div className={classnames({ [classes.before]: expanded })}>
|
||||||
<Tr
|
<Tr
|
||||||
className={classnames(trClasses)}
|
className={classnames(trClasses)}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@ export default {
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
padding: 4
|
padding: 4
|
||||||
},
|
},
|
||||||
|
rowWrapper: {
|
||||||
|
// workaround to shadows cut by r-virtualized when scroll is visible
|
||||||
|
padding: 1
|
||||||
|
},
|
||||||
row: {
|
row: {
|
||||||
borderRadius: 0
|
borderRadius: 0
|
||||||
},
|
},
|
||||||
|
|
@ -27,6 +31,8 @@ export default {
|
||||||
flex: [[1, 1, 'auto']]
|
flex: [[1, 1, 'auto']]
|
||||||
},
|
},
|
||||||
table: ({ width }) => ({
|
table: ({ width }) => ({
|
||||||
|
marginBottom: 30,
|
||||||
|
minHeight: 200,
|
||||||
width,
|
width,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ function H3({ children, noMargin, className, ...props }) {
|
||||||
|
|
||||||
function H4({ children, noMargin, className, ...props }) {
|
function H4({ children, noMargin, className, ...props }) {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
console.log(className)
|
|
||||||
const classNames = {
|
const classNames = {
|
||||||
[classes.h4]: true,
|
[classes.h4]: true,
|
||||||
[classes.noMargin]: noMargin,
|
[classes.noMargin]: noMargin,
|
||||||
|
|
|
||||||
|
|
@ -112,9 +112,9 @@ const CustomerProfile = memo(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const customerData = R.path(['customer'])(customerResponse) ?? []
|
const customerData = R.path(['customer'])(customerResponse) ?? []
|
||||||
|
const rawTransactions = R.path(['transactions'])(customerData) ?? []
|
||||||
const transactionsData = R.sortWith([R.descend('created')])(
|
const sortedTransactions = R.sort(R.descend(R.prop('cryptoAtoms')))(
|
||||||
R.path(['transactions'])(customerData) ?? []
|
rawTransactions
|
||||||
)
|
)
|
||||||
|
|
||||||
const blocked =
|
const blocked =
|
||||||
|
|
@ -133,7 +133,7 @@ const CustomerProfile = memo(() => {
|
||||||
Customers
|
Customers
|
||||||
</Label1>
|
</Label1>
|
||||||
<Label2 noMargin className={classes.labelLink}>
|
<Label2 noMargin className={classes.labelLink}>
|
||||||
Rafael{R.path(['name'])(customerData)}
|
{R.path(['name'])(customerData) ?? R.path(['phone'])(customerData)}
|
||||||
</Label2>
|
</Label2>
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -171,7 +171,7 @@ const CustomerProfile = memo(() => {
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
<TransactionsList data={transactionsData} />
|
<TransactionsList data={sortedTransactions} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ import moment from 'moment'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import Title from 'src/components/Title'
|
import TitleSection from 'src/components/layout/TitleSection'
|
||||||
import DataTable from 'src/components/tables/DataTable'
|
import DataTable from 'src/components/tables/DataTable'
|
||||||
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
||||||
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||||
|
import { ifNotNull } from 'src/utils/nullCheck'
|
||||||
|
|
||||||
import styles from './CustomersList.styles'
|
import styles from './CustomersList.styles'
|
||||||
|
|
||||||
|
|
@ -17,16 +18,16 @@ const CustomersList = ({ data, onClick }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
const elements = [
|
const elements = [
|
||||||
{
|
|
||||||
header: 'Name',
|
|
||||||
width: 277,
|
|
||||||
view: R.path(['name'])
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
header: 'Phone',
|
header: 'Phone',
|
||||||
width: 186,
|
width: 186,
|
||||||
view: it => parsePhoneNumberFromString(it.phone).formatInternational()
|
view: it => parsePhoneNumberFromString(it.phone).formatInternational()
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: 'Name',
|
||||||
|
width: 277,
|
||||||
|
view: R.path(['name'])
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: 'Total TXs',
|
header: 'Total TXs',
|
||||||
width: 154,
|
width: 154,
|
||||||
|
|
@ -37,47 +38,43 @@ const CustomersList = ({ data, onClick }) => {
|
||||||
header: 'Total spent',
|
header: 'Total spent',
|
||||||
width: 188,
|
width: 188,
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
view: it => `${Number.parseFloat(it.totalSpent)} ${it.lastTxFiatCode}`
|
view: it =>
|
||||||
|
`${Number.parseFloat(it.totalSpent)} ${it.lastTxFiatCode ?? ''}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Last active',
|
header: 'Last active',
|
||||||
width: 197,
|
width: 197,
|
||||||
view: it => moment.utc(it.lastActive).format('YYYY-MM-D')
|
view: it =>
|
||||||
|
ifNotNull(it.lastActive, moment.utc(it.lastActive).format('YYYY-MM-D'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Last transaction',
|
header: 'Last transaction',
|
||||||
width: 198,
|
width: 198,
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
view: it => (
|
view: it => {
|
||||||
|
const hasLastTx = !R.isNil(it.lastTxFiatCode)
|
||||||
|
const LastTxIcon = it.lastTxClass === 'cashOut' ? TxOutIcon : TxInIcon
|
||||||
|
const lastIcon = <LastTxIcon className={classes.txClassIconRight} />
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
{`${Number.parseFloat(it.lastTxFiat)} ${it.lastTxFiatCode}`}
|
{hasLastTx &&
|
||||||
{it.lastTxClass === 'cashOut' ? (
|
`${parseFloat(it.lastTxFiat)} ${it.lastTxFiatCode ?? ''}`}
|
||||||
<TxOutIcon className={classes.txClassIconRight} />
|
{hasLastTx && lastIcon}
|
||||||
) : (
|
|
||||||
<TxInIcon className={classes.txClassIconRight} />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classes.titleWrapper}>
|
<TitleSection
|
||||||
<div className={classes.titleAndButtonsContainer}>
|
title="Customers"
|
||||||
<Title>Customers</Title>
|
labels={[
|
||||||
</div>
|
{ label: 'Cash-in', icon: <TxInIcon /> },
|
||||||
<div className={classes.headerLabels}>
|
{ label: 'Cash-out', icon: <TxOutIcon /> }
|
||||||
<div>
|
]}
|
||||||
<TxOutIcon />
|
/>
|
||||||
<span>Cash-out</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<TxInIcon />
|
|
||||||
<span>Cash-in</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<DataTable elements={elements} data={data} onClick={onClick} />
|
<DataTable elements={elements} data={data} onClick={onClick} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -75,47 +75,7 @@ export default {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between'
|
justifyContent: 'space-between'
|
||||||
},
|
},
|
||||||
idDataCard: {
|
|
||||||
width: 544,
|
|
||||||
height: 240
|
|
||||||
},
|
|
||||||
phoneCard: {
|
|
||||||
width: 253,
|
|
||||||
height: 240
|
|
||||||
},
|
|
||||||
idCardPhotoCard: {
|
|
||||||
width: 378,
|
|
||||||
height: 240,
|
|
||||||
margin: [[32, 0, 0, 0]]
|
|
||||||
},
|
|
||||||
field: {
|
|
||||||
position: 'relative',
|
|
||||||
width: 144,
|
|
||||||
height: 46,
|
|
||||||
padding: [[0, 4, 4, 0]],
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
'& > p:first-child': {
|
|
||||||
height: 16,
|
|
||||||
lineHeight: '16px',
|
|
||||||
paddingLeft: 3,
|
|
||||||
margin: [[0, 0, 5, 0]]
|
|
||||||
},
|
|
||||||
'& > p:last-child': {
|
|
||||||
margin: 0,
|
|
||||||
paddingLeft: 4
|
|
||||||
}
|
|
||||||
},
|
|
||||||
customerName: {
|
customerName: {
|
||||||
marginBottom: 32
|
marginBottom: 32
|
||||||
},
|
|
||||||
fieldDisplay: {
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis'
|
|
||||||
},
|
|
||||||
idCardPhoto: {
|
|
||||||
maxWidth: 171,
|
|
||||||
maxHeight: 97
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,35 @@ import moment from 'moment'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { memo } from 'react'
|
import React, { memo } from 'react'
|
||||||
|
|
||||||
import { H2 } from 'src/components/typography'
|
import { H2, Label1, P } from 'src/components/typography'
|
||||||
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
||||||
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||||
|
import { comet } from 'src/styling/variables'
|
||||||
import { ifNotNull } from '../../../utils/nullCheck'
|
import { ifNotNull } from 'src/utils/nullCheck'
|
||||||
import styles from '../CustomersList.styles'
|
|
||||||
|
|
||||||
import FrontCameraPhoto from './FrontCameraPhoto'
|
import FrontCameraPhoto from './FrontCameraPhoto'
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
icon: {
|
||||||
|
marginRight: 11
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
marginTop: 6
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
height: 16
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
marginBottom: 4,
|
||||||
|
color: comet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const CustomerDetails = memo(({ customer }) => {
|
const CustomerDetails = memo(({ customer }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
const LastTxIcon = customer.lastTxClass === 'cashOut' ? TxOutIcon : TxInIcon
|
||||||
|
|
||||||
const elements = [
|
const elements = [
|
||||||
{
|
{
|
||||||
|
|
@ -48,13 +64,9 @@ const CustomerDetails = memo(({ customer }) => {
|
||||||
value: ifNotNull(
|
value: ifNotNull(
|
||||||
customer.lastTxFiat,
|
customer.lastTxFiat,
|
||||||
<>
|
<>
|
||||||
|
<LastTxIcon className={classes.icon} />
|
||||||
{`${Number.parseFloat(customer.lastTxFiat)}
|
{`${Number.parseFloat(customer.lastTxFiat)}
|
||||||
${customer.lastTxFiatCode}`}
|
${customer.lastTxFiatCode}`}
|
||||||
{customer.lastTxClass === 'cashOut' ? (
|
|
||||||
<TxOutIcon className={classes.txClassIconRight} />
|
|
||||||
) : (
|
|
||||||
<TxInIcon className={classes.txClassIconRight} />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -65,25 +77,35 @@ const CustomerDetails = memo(({ customer }) => {
|
||||||
<FrontCameraPhoto
|
<FrontCameraPhoto
|
||||||
frontCameraPath={R.path(['frontCameraPath'])(customer)}
|
frontCameraPath={R.path(['frontCameraPath'])(customer)}
|
||||||
/>
|
/>
|
||||||
<div>
|
<Box display="flex" flexDirection="column">
|
||||||
<Box display="flex">
|
<div className={classes.name}>
|
||||||
<H2 noMargin>Rafael{R.path(['name'])(customer)}</H2>
|
<H2 noMargin>
|
||||||
</Box>
|
{R.path(['name'])(customer) ?? R.path(['phone'])(customer)}
|
||||||
<Box display="flex">
|
</H2>
|
||||||
{elements.map(({ size, header }, idx) => (
|
|
||||||
<div key={idx} className={classes.label1} style={{ width: size }}>
|
|
||||||
{header}
|
|
||||||
</div>
|
</div>
|
||||||
|
<Box display="flex" mt="auto">
|
||||||
|
{elements.map(({ size, header }, idx) => (
|
||||||
|
<Label1
|
||||||
|
noMargin
|
||||||
|
key={idx}
|
||||||
|
className={classes.label}
|
||||||
|
style={{ width: size }}>
|
||||||
|
{header}
|
||||||
|
</Label1>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
<Box display="flex">
|
<Box display="flex">
|
||||||
{elements.map(({ size, value }, idx) => (
|
{elements.map(({ size, value }, idx) => (
|
||||||
<div key={idx} className={classes.p} style={{ width: size }}>
|
<P
|
||||||
|
noMargin
|
||||||
|
key={idx}
|
||||||
|
className={classes.value}
|
||||||
|
style={{ width: size }}>
|
||||||
{value}
|
{value}
|
||||||
</div>
|
</P>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,35 @@
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import classnames from 'classnames'
|
||||||
import React, { memo } from 'react'
|
import React, { memo } from 'react'
|
||||||
|
|
||||||
import { Info3, Label1 } from 'src/components/typography'
|
import { Info3, Label1 } from 'src/components/typography'
|
||||||
|
import { comet } from 'src/styling/variables'
|
||||||
|
|
||||||
import mainStyles from '../CustomersList.styles'
|
const useStyles = makeStyles({
|
||||||
|
field: {
|
||||||
|
width: 144,
|
||||||
|
height: 46
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
color: comet,
|
||||||
|
margin: [[0, 3]]
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
margin: 0,
|
||||||
|
paddingLeft: 4
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const useStyles = makeStyles(mainStyles)
|
const Field = memo(({ label, display, className }) => {
|
||||||
|
|
||||||
const Field = memo(({ label, display }) => {
|
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.field}>
|
<div className={classnames(classes.field, className)}>
|
||||||
<Label1>{label}</Label1>
|
<Label1 className={classes.label}>{label}</Label1>
|
||||||
<Info3 className={classes.fieldDisplay}>{display}</Info3>
|
<Info3 className={classes.value}>{display}</Info3>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles, Box } from '@material-ui/core'
|
||||||
import moment from 'moment'
|
// import moment from 'moment'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { memo } from 'react'
|
import React, { memo } from 'react'
|
||||||
|
|
||||||
|
|
@ -11,11 +11,21 @@ import {
|
||||||
import { ReactComponent as CrossedCameraIcon } from 'src/styling/icons/ID/photo/crossed-camera.svg'
|
import { ReactComponent as CrossedCameraIcon } from 'src/styling/icons/ID/photo/crossed-camera.svg'
|
||||||
import { URI } from 'src/utils/apollo'
|
import { URI } from 'src/utils/apollo'
|
||||||
|
|
||||||
import mainStyles from '../CustomersList.styles'
|
// import Field from './Field'
|
||||||
|
|
||||||
import Field from './Field'
|
const useStyles = makeStyles({
|
||||||
|
idCardPhotoCard: {
|
||||||
const useStyles = makeStyles(mainStyles)
|
width: 325,
|
||||||
|
height: 240,
|
||||||
|
margin: [[32, 0, 0, 0]]
|
||||||
|
},
|
||||||
|
idCardPhoto: {
|
||||||
|
maxHeight: 130
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
marginLeft: 14
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const IdCardPhotoCard = memo(({ customerData, updateCustomer }) => {
|
const IdCardPhotoCard = memo(({ customerData, updateCustomer }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
@ -29,7 +39,7 @@ const IdCardPhotoCard = memo(({ customerData, updateCustomer }) => {
|
||||||
updateCustomer({ idCardPhotoOverride: OVERRIDE_AUTHORIZED })
|
updateCustomer({ idCardPhotoOverride: OVERRIDE_AUTHORIZED })
|
||||||
}
|
}
|
||||||
reject={() => updateCustomer({ idCardPhotoOverride: OVERRIDE_REJECTED })}>
|
reject={() => updateCustomer({ idCardPhotoOverride: OVERRIDE_REJECTED })}>
|
||||||
<div className={classes.row}>
|
<Box display="flex" flex="1" justifyContent="center" alignItems="center">
|
||||||
{customerData.idCardPhotoPath ? (
|
{customerData.idCardPhotoPath ? (
|
||||||
<img
|
<img
|
||||||
className={classes.idCardPhoto}
|
className={classes.idCardPhoto}
|
||||||
|
|
@ -41,13 +51,14 @@ const IdCardPhotoCard = memo(({ customerData, updateCustomer }) => {
|
||||||
) : (
|
) : (
|
||||||
<CrossedCameraIcon />
|
<CrossedCameraIcon />
|
||||||
)}
|
)}
|
||||||
<Field
|
{/* <Field
|
||||||
|
className={classes.field}
|
||||||
label={'Expiration date'}
|
label={'Expiration date'}
|
||||||
display={moment
|
display={moment
|
||||||
.utc(R.path(['idCardDataExpiration'])(customerData))
|
.utc(R.path(['idCardDataExpiration'])(customerData))
|
||||||
.format('YYYY-MM-D')}
|
.format('YYYY-MM-D')}
|
||||||
/>
|
/> */}
|
||||||
</div>
|
</Box>
|
||||||
</PropertyCard>
|
</PropertyCard>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles, Box } from '@material-ui/core'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { memo } from 'react'
|
import React, { memo } from 'react'
|
||||||
|
|
@ -8,16 +8,44 @@ import {
|
||||||
OVERRIDE_AUTHORIZED,
|
OVERRIDE_AUTHORIZED,
|
||||||
OVERRIDE_REJECTED
|
OVERRIDE_REJECTED
|
||||||
} from 'src/pages/Customers/components/propertyCard'
|
} from 'src/pages/Customers/components/propertyCard'
|
||||||
|
import { ifNotNull } from 'src/utils/nullCheck'
|
||||||
import mainStyles from '../CustomersList.styles'
|
|
||||||
|
|
||||||
import Field from './Field'
|
import Field from './Field'
|
||||||
|
|
||||||
const useStyles = makeStyles(mainStyles)
|
const useStyles = makeStyles({
|
||||||
|
idDataCard: {
|
||||||
|
width: 550,
|
||||||
|
height: 240
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
marginBottom: 7
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const IdDataCard = memo(({ customerData, updateCustomer }) => {
|
const IdDataCard = memo(({ customerData, updateCustomer }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const idData = R.path(['idCardData'])(customerData)
|
||||||
|
|
||||||
|
const name = R.path(['firstName'])(idData) ?? ''
|
||||||
|
const lastName = R.path(['lastName'])(idData) ?? ''
|
||||||
|
|
||||||
|
const gender = R.path(['gender'])(idData)
|
||||||
|
const idNumber = R.path(['documentNumber'])(idData)
|
||||||
|
const country = R.path(['country'])(idData)
|
||||||
|
|
||||||
|
const rawExpirationDate = R.path(['expirationDate'])(idData)
|
||||||
|
const expirationDate = ifNotNull(
|
||||||
|
rawExpirationDate,
|
||||||
|
moment.utc(rawExpirationDate).format('YYYY-MM-D')
|
||||||
|
)
|
||||||
|
|
||||||
|
const rawDob = R.path(['dateOfBirth'])(idData)
|
||||||
|
const age = ifNotNull(
|
||||||
|
rawDob,
|
||||||
|
moment.utc().diff(moment.utc(rawDob).format('YYYY-MM-D'), 'years')
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PropertyCard
|
<PropertyCard
|
||||||
className={classes.idDataCard}
|
className={classes.idDataCard}
|
||||||
|
|
@ -27,48 +55,21 @@ const IdDataCard = memo(({ customerData, updateCustomer }) => {
|
||||||
updateCustomer({ idCardDataOverride: OVERRIDE_AUTHORIZED })
|
updateCustomer({ idCardDataOverride: OVERRIDE_AUTHORIZED })
|
||||||
}
|
}
|
||||||
reject={() => updateCustomer({ idCardDataOverride: OVERRIDE_REJECTED })}>
|
reject={() => updateCustomer({ idCardDataOverride: OVERRIDE_REJECTED })}>
|
||||||
<div className={classes.rowSpaceBetween}>
|
<div>
|
||||||
<div className={classes.column}>
|
<Box
|
||||||
<Field
|
display="flex"
|
||||||
label={'Name'}
|
alignItems="center"
|
||||||
display={`${R.path(['idCardData', 'firstName'])(
|
justifyContent="space-between"
|
||||||
customerData
|
mb={1}>
|
||||||
)} ${R.path(['idCardData', 'lastName'])(customerData)}`}
|
<Field label={'Name'} display={`${name} ${lastName}`} />
|
||||||
/>
|
<Field label={'ID number'} display={idNumber} />
|
||||||
<Field
|
<Field label={'Age'} display={age} />
|
||||||
label={'Gender'}
|
</Box>
|
||||||
display={R.path(['idCardData', 'gender'])(customerData)}
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
/>
|
<Field label={'Gender'} display={gender} />
|
||||||
</div>
|
<Field label={'Country'} display={country} />
|
||||||
<div className={classes.column}>
|
<Field label={'Expiration date'} display={expirationDate} />
|
||||||
<Field
|
</Box>
|
||||||
label={'ID number'}
|
|
||||||
display={R.path(['idCardData', 'documentNumber'])(customerData)}
|
|
||||||
/>
|
|
||||||
<Field
|
|
||||||
label={'Country'}
|
|
||||||
display={R.path(['idCardData', 'country'])(customerData)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={classes.column}>
|
|
||||||
<Field
|
|
||||||
label={'Age'}
|
|
||||||
display={moment
|
|
||||||
.utc()
|
|
||||||
.diff(
|
|
||||||
moment
|
|
||||||
.utc(R.path(['idCardData', 'dateOfBirth'])(customerData))
|
|
||||||
.format('YYYY-MM-D'),
|
|
||||||
'years'
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Field
|
|
||||||
label={'Expiration date'}
|
|
||||||
display={moment
|
|
||||||
.utc(R.path(['idCardData', 'expirationDate'])(customerData))
|
|
||||||
.format('YYYY-MM-D')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</PropertyCard>
|
</PropertyCard>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,14 @@ import {
|
||||||
OVERRIDE_REJECTED
|
OVERRIDE_REJECTED
|
||||||
} from 'src/pages/Customers/components/propertyCard'
|
} from 'src/pages/Customers/components/propertyCard'
|
||||||
|
|
||||||
import mainStyles from '../CustomersList.styles'
|
|
||||||
|
|
||||||
import Field from './Field'
|
import Field from './Field'
|
||||||
|
|
||||||
const useStyles = makeStyles(mainStyles)
|
const useStyles = makeStyles({
|
||||||
|
phoneCard: {
|
||||||
|
width: 300,
|
||||||
|
height: 240
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const PhoneCard = memo(({ customerData, updateCustomer }) => {
|
const PhoneCard = memo(({ customerData, updateCustomer }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import * as R from 'ramda'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import DataTable from 'src/components/tables/DataTable'
|
import DataTable from 'src/components/tables/DataTable'
|
||||||
|
|
@ -16,6 +17,7 @@ const useStyles = makeStyles(mainStyles)
|
||||||
|
|
||||||
const TransactionsList = ({ data }) => {
|
const TransactionsList = ({ data }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
const hasData = !(R.isEmpty(data) || R.isNil(data))
|
||||||
|
|
||||||
const elements = [
|
const elements = [
|
||||||
{
|
{
|
||||||
|
|
@ -77,10 +79,14 @@ const TransactionsList = ({ data }) => {
|
||||||
<>
|
<>
|
||||||
<div className={classes.titleWrapper}>
|
<div className={classes.titleWrapper}>
|
||||||
<div className={classes.titleAndButtonsContainer}>
|
<div className={classes.titleAndButtonsContainer}>
|
||||||
<H4>All transactions from this customer</H4>
|
<H4>
|
||||||
|
{hasData
|
||||||
|
? 'All transactions from this customer'
|
||||||
|
: 'No transactions so far'}
|
||||||
|
</H4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DataTable elements={elements} data={data} />
|
{hasData && <DataTable elements={elements} data={data} />}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ import { makeStyles } from '@material-ui/core/styles'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import React, { memo } from 'react'
|
import React, { memo } from 'react'
|
||||||
|
|
||||||
import { ActionButton } from 'src/components/buttons'
|
// import { ActionButton } from 'src/components/buttons'
|
||||||
import { H3 } from 'src/components/typography'
|
import { H3 } from 'src/components/typography'
|
||||||
import { ReactComponent as AuthorizeReversedIcon } from 'src/styling/icons/button/authorize/white.svg'
|
// import { ReactComponent as AuthorizeReversedIcon } from 'src/styling/icons/button/authorize/white.svg'
|
||||||
import { ReactComponent as AuthorizeIcon } from 'src/styling/icons/button/authorize/zodiac.svg'
|
// import { ReactComponent as AuthorizeIcon } from 'src/styling/icons/button/authorize/zodiac.svg'
|
||||||
import { ReactComponent as RejectReversedIcon } from 'src/styling/icons/button/cancel/white.svg'
|
// import { ReactComponent as RejectReversedIcon } from 'src/styling/icons/button/cancel/white.svg'
|
||||||
import { ReactComponent as RejectIcon } from 'src/styling/icons/button/cancel/zodiac.svg'
|
// import { ReactComponent as RejectIcon } from 'src/styling/icons/button/cancel/zodiac.svg'
|
||||||
|
|
||||||
import { propertyCardStyles } from './PropertyCard.styles'
|
import { propertyCardStyles } from './PropertyCard.styles'
|
||||||
|
|
||||||
|
|
@ -24,46 +24,48 @@ const PropertyCard = memo(
|
||||||
|
|
||||||
const propertyCardClassNames = {
|
const propertyCardClassNames = {
|
||||||
[classes.propertyCard]: true,
|
[classes.propertyCard]: true,
|
||||||
[classes.propertyCardPending]: state === OVERRIDE_PENDING,
|
[classes.propertyCardPending]: true
|
||||||
[classes.propertyCardRejected]: state === OVERRIDE_REJECTED,
|
// [classes.propertyCardPending]: state === OVERRIDE_PENDING
|
||||||
[classes.propertyCardAccepted]: state === OVERRIDE_AUTHORIZED
|
// [classes.propertyCardRejected]: state === OVERRIDE_REJECTED,
|
||||||
|
// [classes.propertyCardAccepted]: state === OVERRIDE_AUTHORIZED
|
||||||
}
|
}
|
||||||
|
|
||||||
const label1ClassNames = {
|
// const label1ClassNames = {
|
||||||
[classes.label1]: true,
|
// [classes.label1]: true,
|
||||||
[classes.label1Pending]: state === OVERRIDE_PENDING,
|
// [classes.label1Pending]: true
|
||||||
[classes.label1Rejected]: state === OVERRIDE_REJECTED,
|
// [classes.label1Pending]: state === OVERRIDE_PENDING
|
||||||
[classes.label1Accepted]: state === OVERRIDE_AUTHORIZED
|
// [classes.label1Rejected]: state === OVERRIDE_REJECTED,
|
||||||
}
|
// [classes.label1Accepted]: state === OVERRIDE_AUTHORIZED
|
||||||
|
// }
|
||||||
|
|
||||||
const AuthorizeButton = () => (
|
// const AuthorizeButton = () => (
|
||||||
<ActionButton
|
// <ActionButton
|
||||||
className={classes.cardActionButton}
|
// className={classes.cardActionButton}
|
||||||
color="secondary"
|
// color="secondary"
|
||||||
Icon={AuthorizeIcon}
|
// Icon={AuthorizeIcon}
|
||||||
InverseIcon={AuthorizeReversedIcon}
|
// InverseIcon={AuthorizeReversedIcon}
|
||||||
onClick={() => authorize()}>
|
// onClick={() => authorize()}>
|
||||||
Authorize
|
// Authorize
|
||||||
</ActionButton>
|
// </ActionButton>
|
||||||
)
|
// )
|
||||||
|
|
||||||
const RejectButton = () => (
|
// const RejectButton = () => (
|
||||||
<ActionButton
|
// <ActionButton
|
||||||
className={classes.cardActionButton}
|
// className={classes.cardActionButton}
|
||||||
color="secondary"
|
// color="secondary"
|
||||||
Icon={RejectIcon}
|
// Icon={RejectIcon}
|
||||||
InverseIcon={RejectReversedIcon}
|
// InverseIcon={RejectReversedIcon}
|
||||||
onClick={() => reject()}>
|
// onClick={() => reject()}>
|
||||||
Reject
|
// Reject
|
||||||
</ActionButton>
|
// </ActionButton>
|
||||||
)
|
// )
|
||||||
|
|
||||||
const authorizedAsString =
|
// const authorizedAsString =
|
||||||
state === OVERRIDE_PENDING
|
// state === OVERRIDE_PENDING
|
||||||
? 'Pending'
|
// ? 'Pending'
|
||||||
: state === OVERRIDE_REJECTED
|
// : state === OVERRIDE_REJECTED
|
||||||
? 'Rejected'
|
// ? 'Rejected'
|
||||||
: 'Accepted'
|
// : 'Accepted'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
|
|
@ -71,17 +73,18 @@ const PropertyCard = memo(
|
||||||
elevation={0}>
|
elevation={0}>
|
||||||
<div className={classes.rowSpaceBetween}>
|
<div className={classes.rowSpaceBetween}>
|
||||||
<H3>{title}</H3>
|
<H3>{title}</H3>
|
||||||
<div className={classnames(label1ClassNames)}>
|
{/* <div className={classnames(label1ClassNames)}>
|
||||||
{authorizedAsString}
|
{authorizedAsString}
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
<Paper className={classes.cardProperties} elevation={0}>
|
<Paper className={classes.cardProperties} elevation={0}>
|
||||||
{children}
|
{children}
|
||||||
</Paper>
|
</Paper>
|
||||||
<div className={classes.buttonsWrapper}>
|
{/* V2 */}
|
||||||
|
{/* <div className={classes.buttonsWrapper}>
|
||||||
{state !== OVERRIDE_AUTHORIZED && AuthorizeButton()}
|
{state !== OVERRIDE_AUTHORIZED && AuthorizeButton()}
|
||||||
{state !== OVERRIDE_REJECTED && RejectButton()}
|
{state !== OVERRIDE_REJECTED && RejectButton()}
|
||||||
</div>
|
</div> */}
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,10 @@ const propertyCardStyles = {
|
||||||
marginLeft: 12
|
marginLeft: 12
|
||||||
},
|
},
|
||||||
cardProperties: {
|
cardProperties: {
|
||||||
|
display: 'flex',
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: 'calc(100% - 100px)',
|
height: 'calc(100% - 75px)',
|
||||||
padding: [[20]],
|
padding: [[20]],
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
boxShadow: '0 0 8px 0 rgba(0, 0, 0, 0.04)',
|
boxShadow: '0 0 8px 0 rgba(0, 0, 0, 0.04)',
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
<svg viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
||||||
<desc>Created with Sketch.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<g id="icon/button/authorize/white" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
<g id="icon/button/authorize/white" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
<circle id="Oval" stroke="#FFFFFF" cx="6" cy="6" r="6"></circle>
|
<circle id="Oval" stroke="#FFFFFF" cx="6" cy="6" r="5"></circle>
|
||||||
<polyline id="Stroke-13" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" points="4 6.66666667 5 8 8 4"></polyline>
|
<polyline id="Stroke-13" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" points="4 6.66666667 5 8 8 4"></polyline>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 619 B After Width: | Height: | Size: 592 B |
|
|
@ -1,10 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
<svg viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
||||||
<desc>Created with Sketch.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<g id="icon/button/authorize/zodiac" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
<g id="icon/button/authorize/zodiac" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
<g id="Group-9" stroke="#1B2559">
|
<g id="Group-9" stroke="#1B2559">
|
||||||
<circle id="Oval" cx="6" cy="6" r="6"></circle>
|
<circle id="Oval" cx="6" cy="6" r="5"></circle>
|
||||||
</g>
|
</g>
|
||||||
<polyline id="Stroke-13" stroke="#1B2559" stroke-linecap="round" stroke-linejoin="round" points="4 6.66666667 5 8 8 4"></polyline>
|
<polyline id="Stroke-13" stroke="#1B2559" stroke-linecap="round" stroke-linejoin="round" points="4 6.66666667 5 8 8 4"></polyline>
|
||||||
</g>
|
</g>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 662 B After Width: | Height: | Size: 635 B |
|
|
@ -1,11 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
<svg viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
||||||
<desc>Created with Sketch.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<g id="icon/button/block/white" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
<g id="icon/button/block/white" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<g id="Group-5" stroke="#FFFFFF">
|
<g id="Group-5" stroke="#FFFFFF">
|
||||||
<path d="M12,6 C12,9.3138 9.3132,12 6,12 C2.6868,12 0,9.3138 0,6 C0,2.6862 2.6868,0 6,0 C9.3132,0 12,2.6862 12,6 Z" id="Stroke-1"></path>
|
<circle id="Oval" cx="6" cy="6" r="5"></circle>
|
||||||
<line x1="10.2" y1="1.8" x2="1.8" y2="10.2" id="Stroke-3"></line>
|
<line x1="9" y1="3.0" x2="3" y2="9" id="Stroke-3"></line>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 732 B After Width: | Height: | Size: 607 B |
|
|
@ -1,11 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
<svg viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
||||||
<desc>Created with Sketch.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<g id="icon/button/block/zodiac" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
<g id="icon/button/block/zodiac" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<g id="Group-5" stroke="#1B2559">
|
<g id="Group-5" stroke="#1B2559">
|
||||||
<path d="M12,6 C12,9.3138 9.3132,12 6,12 C2.6868,12 0,9.3138 0,6 C0,2.6862 2.6868,0 6,0 C9.3132,0 12,2.6862 12,6 Z" id="Stroke-1"></path>
|
<circle id="Oval" cx="6" cy="6" r="5"></circle>
|
||||||
<line x1="10.2" y1="1.8" x2="1.8" y2="10.2" id="Stroke-3"></line>
|
<line x1="9" y1="3.0" x2="3" y2="9" id="Stroke-3"></line>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 733 B After Width: | Height: | Size: 608 B |
|
|
@ -1,5 +1,7 @@
|
||||||
|
import * as R from 'ramda'
|
||||||
|
|
||||||
const ifNotNull = (value, valueIfNotNull) => {
|
const ifNotNull = (value, valueIfNotNull) => {
|
||||||
return value === null ? '' : valueIfNotNull
|
return R.isNil(value) ? '' : valueIfNotNull
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ifNotNull }
|
export { ifNotNull }
|
||||||
|
|
|
||||||
|
|
@ -4,107 +4,84 @@ Main menu:
|
||||||
|
|
||||||
Overall:
|
Overall:
|
||||||
- caching the page
|
- caching the page
|
||||||
- coin dropdown should show all coins
|
|
||||||
- validation is bad rn, negatives being allowed
|
- validation is bad rn, negatives being allowed
|
||||||
- input number should only allow numbers
|
|
||||||
- right aligned numbers on all tables
|
- right aligned numbers on all tables
|
||||||
- locale based mil separators 1.000 1,000
|
- locale based mil separators 1.000 1,000
|
||||||
|
|
||||||
Cashboxes:
|
Cashboxes:
|
||||||
- right aligned number (SAME EVERYWHERE)
|
- right aligned number
|
||||||
|
|
||||||
|
Locale:
|
||||||
|
- Only allow one override per machine
|
||||||
|
|
||||||
|
Notifications:
|
||||||
|
- one of the crypto balance alerts has to be optional because of migration
|
||||||
|
|
||||||
UI:
|
UI:
|
||||||
- replace all the tooltips with new component
|
|
||||||
- tooltip like components should close on esc
|
- tooltip like components should close on esc
|
||||||
- saving should be a one time thing. disable buttons so user doesnt spam it
|
- saving should be a one time thing. disable buttons so user doesnt spam it
|
||||||
- transitions
|
- transitions
|
||||||
- error handling
|
- error handling
|
||||||
- should all (machines/coins/...) be a option on some overrides?
|
|
||||||
- select components
|
- select components
|
||||||
- talk with nunu + neal: Hover css for edit buttons + first first cancel later
|
- talk with nunu + neal: Hover css for edit buttons + first first cancel later
|
||||||
- filter countries by code as well, US should go to United States
|
|
||||||
- filter prioritize the start of words(not alphabetically)
|
|
||||||
- dropdown should have everythihg selected on the top
|
|
||||||
- disable edit on non-everrides => overrides
|
- disable edit on non-everrides => overrides
|
||||||
- remove the broswer default tooltip
|
- splash screens and home
|
||||||
|
- maybe a indication that there's more to search on dropdown
|
||||||
|
- required signifier on form fields - (required) or *
|
||||||
|
- USD should show as a suffix (validate all screens)
|
||||||
|
- stop line breaking on multi select
|
||||||
|
- input width should be enough to hold values without cutting text
|
||||||
|
- font sizes could be better
|
||||||
|
- min height in virtualized table (rows get hidden if not enough height in browser)
|
||||||
|
|
||||||
Machine status:
|
Machine status:
|
||||||
- legend colors are different from the spec
|
|
||||||
- action Error/Success indication
|
|
||||||
- load machine model from l-m
|
|
||||||
- align popup title with content
|
|
||||||
- talk with neal to see if the actions should be consistent
|
|
||||||
- font-size of the 'write to confirm'
|
- font-size of the 'write to confirm'
|
||||||
- reboot icon cut off
|
|
||||||
- ask neal for the support articles
|
|
||||||
- stop line breaking on multi select
|
|
||||||
|
|
||||||
Commissions:
|
|
||||||
- overrides can be tighter. Hide coins already used by the same machine on another line.
|
|
||||||
- no negative values
|
|
||||||
- autoselect not getting errored when tabbed out
|
|
||||||
|
|
||||||
Operator Info:
|
|
||||||
- That should be paginated with routes!
|
|
||||||
|
|
||||||
Terms and Conditions:
|
|
||||||
- default values are not working properly
|
|
||||||
|
|
||||||
Contact information:
|
|
||||||
- When the fields are empty, should there be a warning somewhere? Or maybe we could create an exception that if the fields are empty they shouldn't show up
|
|
||||||
- l-m uses name, email, phone. The rest is just used for the receipt printing for now
|
|
||||||
|
|
||||||
CoinATMRadar:
|
|
||||||
- We now have photo, should we relay that info?
|
|
||||||
|
|
||||||
Sms/email:
|
|
||||||
- There's no place to pick a third party provider anymore. (sms.js, email.js)
|
|
||||||
|
|
||||||
Notifications:
|
|
||||||
- cash out 500 notes max top 500 max bottom
|
|
||||||
- crypto balance alerts input width (CHECK FOR ALL)
|
|
||||||
|
|
||||||
Locale:
|
|
||||||
- limit languages
|
|
||||||
- search crypto per name as well
|
|
||||||
- show full name on the dropdown
|
|
||||||
|
|
||||||
Machine name:
|
|
||||||
- Previously we were grabbing that from the config, but since new admin still cant change the name i`m now grabbing it from the db. Possible issues if users change the machine name from the initial one. Investivate alternatives.
|
|
||||||
|
|
||||||
Migrate:
|
Migrate:
|
||||||
- Need to write config migration.
|
- Need to write config migration.
|
||||||
- Rewrite config validate
|
- Rewrite config validate
|
||||||
- remove apply defaults
|
- remove apply defaults
|
||||||
|
|
||||||
Compliance:
|
|
||||||
- Reject Address Reuse missing
|
|
||||||
- Currently admin only handles { type: 'volume', direction: 'both' }
|
|
||||||
- Sanctions should have more care in customers.js, currently just looking if is active as if old config
|
|
||||||
|
|
||||||
Customers:
|
|
||||||
- Should add id and make it main part of the table? Name is not common at all
|
|
||||||
|
|
||||||
Logs:
|
|
||||||
- the new functionality that saves server logs to a db breaks initial install chicken-egg with db-logger
|
|
||||||
|
|
||||||
Downloading (logs and tx):
|
|
||||||
- They are always downloading from the local data, should be from server
|
|
||||||
|
|
||||||
Cash out:
|
Cash out:
|
||||||
- On off should have a fixed sized so things dont move a lot
|
|
||||||
- separate text from the first screen
|
|
||||||
- auto focus on fields after clicking next
|
|
||||||
- improve spacing around paragraphs
|
|
||||||
- button is on a wrong place on steps 2 and 3
|
|
||||||
- make it a dropdown based on the machine denomimnations settings
|
|
||||||
- ask nuno about zero conf limit
|
- ask nuno about zero conf limit
|
||||||
- USD should show as a suffix (validate all screens)
|
|
||||||
- Splash image for wizard
|
|
||||||
|
|
||||||
Server:
|
Server:
|
||||||
- Takes too long to load. Investigate
|
- Takes too long to load. Investigate
|
||||||
|
|
||||||
Review slow internet loading:
|
Review slow internet loading:
|
||||||
- Table should be loaded
|
- Table should be loaded (we want to load the table with no data)
|
||||||
|
|
||||||
|
3rd party services:
|
||||||
|
- remove strike
|
||||||
|
- ask neal anyone uses itbit
|
||||||
|
|
||||||
|
Wallet:
|
||||||
|
- ask neal and nuno how to handle unconfigured third party services on the table edit
|
||||||
|
|
||||||
|
Operator Info:
|
||||||
|
- That should be paginated with routes!
|
||||||
|
|
||||||
|
CoinATMRadar:
|
||||||
|
- relay facephoto info
|
||||||
|
- we should show the highest amount that requires a requirement
|
||||||
|
|
||||||
|
Customers:
|
||||||
|
- add status
|
||||||
|
- cash-in cash-out are reversed
|
||||||
|
|
||||||
|
Sms/email:
|
||||||
|
- There's no place to pick a third party provider anymore. (sms.js, email.js) neal + nuno
|
||||||
|
|
||||||
|
Machine name:
|
||||||
|
- update the db with whatever name is on the old config
|
||||||
|
- where to change name of the mahcines NUNO + NEAL
|
||||||
|
|
||||||
|
Compliance:
|
||||||
|
- Reject Address Reuse missing (MAKE BLACKLIST SCREEN AND PUT IT THERE)
|
||||||
|
- Currently admin only handles { type: 'amount', direction: 'both' }
|
||||||
|
- Sanctions should have more care in customers.js, currently just looking if is active as if old config
|
||||||
|
|
||||||
|
|
||||||
|
Ideas
|
||||||
|
- Transactions could have a link to the customer
|
||||||
|
- Transactions table on customer should have a link to "transactions"
|
||||||
|
|
|
||||||