diff --git a/lib/new-admin/graphql/resolvers/transaction.resolver.js b/lib/new-admin/graphql/resolvers/transaction.resolver.js index f21d5d67..e5b2b892 100644 --- a/lib/new-admin/graphql/resolvers/transaction.resolver.js +++ b/lib/new-admin/graphql/resolvers/transaction.resolver.js @@ -5,17 +5,17 @@ const transactions = require('../../services/transactions') const anonymous = require('../../../constants').anonymousCustomer const transactionsLoader = new DataLoader(ids => transactions.getCustomerTransactionsBatch(ids)) -const tx_logFields = ["txClass", "id", "deviceId", "toAddress", "cryptoAtoms", - "cryptoCode", "fiat", "fiatCode", "fee", "status", - "dispense", "notified", "redeem", "phone", "error", - "created", "confirmedAt", "hdIndex", "swept", "timedout", - "dispenseConfirmed", "provisioned1", "provisioned2", - "denomination1", "denomination2", "errorCode", "customerId", - "txVersion", "publishedAt", "termsAccepted", "layer2Address", - "commissionPercentage", "rawTickerPrice", "receivedCryptoAtoms", - "discount", "txHash", "customerPhone", "customerIdCardDataNumber", - "customerIdCardDataExpiration", "customerIdCardData", "customerName", - "customerFrontCameraPath", "customerIdCardPhotoPath", "expired", "machineName"] +const txLogFields = ['txClass', 'id', 'deviceId', 'toAddress', 'cryptoAtoms', + 'cryptoCode', 'fiat', 'fiatCode', 'fee', 'status', + 'dispense', 'notified', 'redeem', 'phone', 'error', + 'created', 'confirmedAt', 'hdIndex', 'swept', 'timedout', + 'dispenseConfirmed', 'provisioned1', 'provisioned2', + 'denomination1', 'denomination2', 'errorCode', 'customerId', + 'txVersion', 'publishedAt', 'termsAccepted', 'layer2Address', + 'commissionPercentage', 'rawTickerPrice', 'receivedCryptoAtoms', + 'discount', 'txHash', 'customerPhone', 'customerIdCardDataNumber', + 'customerIdCardDataExpiration', 'customerIdCardData', 'customerName', + 'customerFrontCameraPath', 'customerIdCardPhotoPath', 'expired', 'machineName'] const resolvers = { Customer: { @@ -28,7 +28,11 @@ const resolvers = { transactions: (...[, { from, until, limit, offset, deviceId }]) => transactions.batch(from, until, limit, offset, deviceId), transactionsCsv: (...[, { from, until, limit, offset }]) => - transactions.batch(from, until, limit, offset).then(data => parseAsync(data, {fields: tx_logFields})) + transactions.batch(from, until, limit, offset).then(data => parseAsync(data, { fields: txLogFields })), + transactionCsv: (...[, { id, txClass }]) => + transactions.getTx(id, txClass).then(parseAsync), + txAssociatedDataCsv: (...[, { id, txClass }]) => + transactions.getTxAssociatedData(id, txClass).then(parseAsync) } } diff --git a/lib/new-admin/graphql/types/transaction.type.js b/lib/new-admin/graphql/types/transaction.type.js index f9a062ee..99f258f2 100644 --- a/lib/new-admin/graphql/types/transaction.type.js +++ b/lib/new-admin/graphql/types/transaction.type.js @@ -48,6 +48,8 @@ const typeDef = gql` type Query { transactions(from: Date, until: Date, limit: Int, offset: Int, deviceId: ID): [Transaction] @auth transactionsCsv(from: Date, until: Date, limit: Int, offset: Int): String @auth + transactionCsv(id: ID, txClass: String): String @auth + txAssociatedDataCsv(id: ID, txClass: String): String @auth } ` diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index c2e4f0d7..88632ba0 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -162,4 +162,33 @@ function cancel (txId) { .then(() => single(txId)) } -module.exports = { batch, single, cancel, getCustomerTransactionsBatch } +function getTx (txId, txClass) { + const cashInSql = `select 'cashIn' as tx_class, txs.*, + ((not txs.send_confirmed) and (txs.created <= now() - interval $1)) as expired + from cash_in_txs as txs + where txs.id=$2` + + const cashOutSql = `select 'cashOut' as tx_class, + txs.*, + (extract(epoch from (now() - greatest(txs.created, txs.confirmed_at))) * 1000) >= $2 as expired + from cash_out_txs txs + where txs.id=$1` + + if (txClass === 'cashIn') { + return db.oneOrNone(cashInSql, [cashInTx.PENDING_INTERVAL, txId]) + } else { + return db.oneOrNone(cashOutSql, [txId, REDEEMABLE_AGE]) + } +} + +function getTxAssociatedData (txId, txClass) { + const billsSql = `select 'bills' as bills, b.* from bills b where cash_in_txs_id = $1` + const actionsSql = `select 'cash_out_actions' as cash_out_actions, actions.* from cash_out_actions actions where tx_id = $1` + if (txClass === 'cashIn') { + return db.manyOrNone(billsSql, [txId]) + } else { + return db.manyOrNone(actionsSql, [txId]) + } +} + +module.exports = { batch, single, cancel, getCustomerTransactionsBatch, getTx, getTxAssociatedData } diff --git a/new-lamassu-admin/package-lock.json b/new-lamassu-admin/package-lock.json index 0fd7ff33..763fd156 100644 --- a/new-lamassu-admin/package-lock.json +++ b/new-lamassu-admin/package-lock.json @@ -9513,8 +9513,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { "version": "6.0.0", @@ -14315,6 +14314,11 @@ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, "immer": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", @@ -14420,13 +14424,12 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "inline-style-prefixer": { @@ -14437,6 +14440,133 @@ "css-in-js-utils": "^2.0.0" } }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "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.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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 + }, + "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 + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "requires": { + "eslint-visitor-keys": "^1.1.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 + }, + "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.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", @@ -16848,6 +16978,17 @@ "object.assign": "^4.1.2" } }, + "jszip": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz", + "integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==", + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -16946,14 +17087,22 @@ } }, "libphonenumber-js": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.8.4.tgz", - "integrity": "sha512-s0fTPZRB4hcsfDL9p6wUNOLngVh4y3fBPhH33dL7OfkHA2RirI8p3rlR+4f4SMxdcng9jPNOweS2Z47BivHMYw==", + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.10.tgz", + "integrity": "sha512-XyBYwt1dQCc9emeb78uCqJv9qy9tJQsg6vYDeJt37dwBYiZga8z0rHI5dcrn3aFKz9C5Nn9azaRBC+wmW91FfQ==", "requires": { "minimist": "^1.2.5", "xml2js": "^0.4.17" } }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "requires": { + "immediate": "~3.0.5" + } + }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -18717,8 +18866,7 @@ "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "parallel-transform": { "version": "1.2.0", @@ -20369,8 +20517,7 @@ "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "progress": { "version": "2.0.3", @@ -21102,9 +21249,9 @@ } }, "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true }, "inquirer": { @@ -23284,9 +23431,20 @@ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } } }, "readdirp": { @@ -24632,6 +24790,11 @@ "resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz", "integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==" }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -26850,8 +27013,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "dev": true, + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.1", diff --git a/new-lamassu-admin/package.json b/new-lamassu-admin/package.json index 63464151..02de74c3 100644 --- a/new-lamassu-admin/package.json +++ b/new-lamassu-admin/package.json @@ -24,6 +24,7 @@ "graphql": "^14.5.8", "graphql-tag": "^2.10.3", "jss-plugin-extend": "^10.0.0", + "jszip": "^3.6.0", "libphonenumber-js": "^1.7.50", "match-sorter": "^4.2.0", "moment": "2.24.0", diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index 021c0798..91743f1d 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -1,10 +1,15 @@ +import { useLazyQuery } from '@apollo/react-hooks' import { makeStyles, Box } from '@material-ui/core' import BigNumber from 'bignumber.js' +import FileSaver from 'file-saver' +import gql from 'graphql-tag' +import JSZip from 'jszip' import moment from 'moment' +import * as R from 'ramda' import React, { memo } from 'react' import { HoverableTooltip } from 'src/components/Tooltip' -import { IDButton } from 'src/components/buttons' +import { IDButton, ActionButton } from 'src/components/buttons' import { P, Label1 } from 'src/components/typography' import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg' import { ReactComponent as CardIdIcon } from 'src/styling/icons/ID/card/zodiac.svg' @@ -12,6 +17,7 @@ import { ReactComponent as PhoneIdInverseIcon } from 'src/styling/icons/ID/phone import { ReactComponent as PhoneIdIcon } from 'src/styling/icons/ID/phone/zodiac.svg' import { ReactComponent as CamIdInverseIcon } from 'src/styling/icons/ID/photo/white.svg' import { ReactComponent as CamIdIcon } from 'src/styling/icons/ID/photo/zodiac.svg' +import { ReactComponent as Download } from 'src/styling/icons/button/download/zodiac.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 { URI } from 'src/utils/apollo' @@ -23,6 +29,27 @@ import styles from './DetailsCard.styles' import { getStatus, getStatusDetails } from './helper' const useStyles = makeStyles(styles) +const MINUTES_OFFSET = 3 +const TX_SUMMARY = gql` + query txSummaryAndLogs( + $txId: ID! + $deviceId: ID! + $limit: Int + $from: Date + $until: Date + $txClass: String + ) { + serverLogsCsv(limit: $limit, from: $from, until: $until) + machineLogsCsv( + deviceId: $deviceId + limit: $limit + from: $from + until: $until + ) + transactionCsv(id: $txId, txClass: $txClass) + txAssociatedDataCsv(id: $txId, txClass: $txClass) + } +` const formatAddress = (cryptoCode = '', address = '') => formatCryptoAddress(cryptoCode, address).replace(/(.{5})/g, '$1 ') @@ -35,6 +62,8 @@ const Label = ({ children }) => { const DetailsRow = ({ it: tx }) => { const classes = useStyles() + const zip = new JSZip() + const fiat = Number.parseFloat(tx.fiat) const crypto = toUnit(new BigNumber(tx.cryptoAtoms), tx.cryptoCode) const commissionPercentage = Number.parseFloat(tx.commissionPercentage, 2) @@ -55,6 +84,30 @@ const DetailsRow = ({ it: tx }) => { ) } + const from = moment(tx.created) + .subtract(MINUTES_OFFSET, 'm') + .format() + const until = moment(tx.created) + .add(MINUTES_OFFSET, 'm') + .format() + + const [fetchSummary] = useLazyQuery(TX_SUMMARY, { + onCompleted: data => createCsv(data) + }) + + const loadAndTxSummary = ({ id: txId, deviceId, txClass }) => { + fetchSummary({ variables: { txId, from, until, deviceId, txClass } }) + } + + const createCsv = logs => { + const zipFilename = `tx_${tx.id}_summary.zip` + const filesNames = R.keys(logs) + R.map(name => zip.file(name + '.csv', logs[name]), filesNames) + zip.generateAsync({ type: 'blob' }).then(function(content) { + FileSaver.saveAs(content, zipFilename) + }) + } + const errorElements = ( <> @@ -197,7 +250,7 @@ const DetailsRow = ({ it: tx }) => {
{getStatusDetails(tx)}
@@ -206,6 +259,22 @@ const DetailsRow = ({ it: tx }) => { errorElements )}