From 5dd8501a17c7e40c82b8790f583fc677b22c1b97 Mon Sep 17 00:00:00 2001 From: Taranto Date: Tue, 16 Jun 2020 09:43:58 +0100 Subject: [PATCH] fix: pre release screen fixes --- TODO.json | 10 - lib/cash-in/cash-in-tx.js | 2 +- lib/coinatmradar/coinatmradar.js | 2 + lib/compliance-triggers.js | 2 +- lib/customers.js | 2 +- lib/db.js | 5 +- lib/machine-loader.js | 20 +- lib/new-admin/config/accounts.js | 1 + lib/new-admin/funding.js | 9 +- lib/new-admin/graphql/schema.js | 27 +- lib/new-admin/supervisor.js | 6 +- lib/new-settings-loader.js | 2 + lib/plugins.js | 9 +- lib/routes.js | 10 +- lib/ticker.js | 1 - lib/wallet.js | 2 +- .../1592317667188-machine-version-name.js | 14 + new-lamassu-admin/package-lock.json | 159 ++++----- new-lamassu-admin/package.json | 7 +- new-lamassu-admin/src/App.js | 26 +- .../src/components/ConfirmDialog.js | 45 ++- .../src/components/HelpTooltip.js | 55 +++ .../src/components/LogsDownloaderPopper.js | 130 ++++--- new-lamassu-admin/src/components/Modal.js | 30 +- new-lamassu-admin/src/components/Popper.js | 52 ++- new-lamassu-admin/src/components/Status.js | 18 +- new-lamassu-admin/src/components/Title.js | 2 +- .../components/buttons/ActionButton.styles.js | 4 +- .../src/components/buttons/FeatureButton.js | 60 ++-- .../src/components/buttons/IDButton.js | 6 +- .../src/components/buttons/SimpleButton.js | 49 ++- .../src/components/editableTable/Header.js | 65 +++- .../src/components/editableTable/Row.js | 28 +- .../components/editableTable/Row.styles.js | 19 +- .../src/components/fake-table/Table.js | 4 +- .../src/components/fake-table/Table.styles.js | 14 +- .../src/components/inputs/base/Select.js | 6 +- .../inputs/base/TextInput.styles.js | 5 +- .../components/inputs/formik/RadioGroup.js | 1 - .../src/components/inputs/formik/index.js | 3 +- .../src/components/layout/Sidebar.js | 2 +- .../src/components/layout/TitleSection.js | 6 +- .../src/components/table/TableRow.js | 5 +- .../src/components/typography/index.js | 47 ++- .../src/components/typography/styles.js | 2 +- .../src/pages/AddMachine/AddMachine.js | 2 +- .../src/pages/Cashout/Cashout.js | 45 ++- .../src/pages/Cashout/WizardStep.js | 7 +- new-lamassu-admin/src/pages/Cashout/helper.js | 9 +- .../src/pages/Commissions/Commissions.js | 11 +- .../src/pages/Commissions/helper.js | 60 +++- .../src/pages/Customers/CustomerProfile.js | 45 ++- .../pages/Customers/CustomerProfile.styles.js | 15 + .../src/pages/Customers/Customers.js | 2 +- .../src/pages/Customers/CustomersList.js | 4 +- ...mers.styles.js => CustomersList.styles.js} | 47 +-- .../Customers/components/CustomerDetails.js | 26 +- .../src/pages/Customers/components/Field.js | 2 +- .../Customers/components/FrontCameraPhoto.js | 12 +- .../Customers/components/IdCardPhotoCard.js | 10 +- .../pages/Customers/components/IdDataCard.js | 4 +- .../pages/Customers/components/PhoneCard.js | 4 +- .../Customers/components/TransactionsList.js | 2 +- .../components/propertyCard/PropertyCard.js | 2 +- .../pages/Customers/components/variables.js | 4 - new-lamassu-admin/src/pages/Funding.js | 43 ++- new-lamassu-admin/src/pages/Funding.styles.js | 11 +- .../src/pages/Locales/Locales.js | 2 +- new-lamassu-admin/src/pages/Logs.styles.js | 14 +- new-lamassu-admin/src/pages/MachineLogs.js | 31 +- .../src/pages/Maintenance/Cashboxes.js | 2 +- .../pages/Maintenance/MachineDetailsCard.js | 299 ++++++---------- .../Maintenance/MachineDetailsCard.styles.js | 60 ++++ .../src/pages/Maintenance/MachineStatus.js | 21 +- .../src/pages/Notifications/Notifications.js | 2 +- .../sections/FiatBalanceOverrides.js | 2 + .../OperatorInfo/CoinATMRadar/CoinATMRadar.js | 3 +- .../src/pages/OperatorInfo/ContactInfo.js | 12 +- .../src/pages/OperatorInfo/OperatorInfo.js | 1 + .../ReceiptPrinting/ReceiptPrinting.js | 13 +- .../src/pages/OperatorInfo/TermsConditions.js | 17 +- new-lamassu-admin/src/pages/ServerLogs.js | 69 +--- .../src/pages/Services/FormRenderer.js | 3 +- .../src/pages/Services/Services.js | 2 +- .../src/pages/Services/schemas/bitgo.js | 37 +- .../src/pages/Services/schemas/infura.js | 4 +- .../src/pages/Transactions/DetailsCard.js | 334 +++++++++--------- .../pages/Transactions/DetailsCard.styles.js | 84 +++++ .../src/pages/Transactions/Transactions.js | 37 +- .../pages/Transactions/Transactions.styles.js | 71 +--- .../src/pages/Triggers/Triggers.js | 13 +- new-lamassu-admin/src/pages/Wallet/Wallet.js | 2 +- new-lamassu-admin/src/routing/routes.js | 46 +-- .../styling/icons/action/arrow/regular.svg | 4 +- .../src/styling/icons/action/arrow/zodiac.svg | 28 +- .../icons/circle buttons/share/white.svg | 12 + new-lamassu-admin/src/utils/apollo.js | 43 +++ new-lamassu-admin/todo.md | 109 ++++-- 98 files changed, 1569 insertions(+), 1149 deletions(-) create mode 100644 migrations/1592317667188-machine-version-name.js create mode 100644 new-lamassu-admin/src/components/HelpTooltip.js create mode 100644 new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js rename new-lamassu-admin/src/pages/Customers/{Customers.styles.js => CustomersList.styles.js} (73%) delete mode 100644 new-lamassu-admin/src/pages/Customers/components/variables.js create mode 100644 new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.styles.js create mode 100644 new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js create mode 100644 new-lamassu-admin/src/styling/icons/circle buttons/share/white.svg create mode 100644 new-lamassu-admin/src/utils/apollo.js diff --git a/TODO.json b/TODO.json index 3449044c..62e013a6 100644 --- a/TODO.json +++ b/TODO.json @@ -25,16 +25,6 @@ "rejectAddressReuseActive" ] }, - { - "code": "walletSettings", - "fields": [ - "ticker", - "wallet", - "layer2", - "exchange", - "zeroConf" - ] - }, { "code": "notifications", "fields": [ diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 2c8da04f..4f8f06f5 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -28,7 +28,7 @@ function post (machineTx, pi) { .then(([{ config }, blacklistItems]) => { // TODO new-admin: addressReuse doesnt exist // const rejectAddressReuseActive = configManager.unscoped(config).rejectAddressReuseActive - const rejectAddressReuseActive = true + const rejectAddressReuseActive = false if (_.some(it => it.created_by_operator === true)(blacklistItems)) { blacklisted = true diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index 87f8cafa..c5559c79 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -32,6 +32,7 @@ function mapCoin (rates, deviceId, settings, cryptoCode) { const cashInFee = showCommissions ? commissions.cashIn / 100 : null const cashOutFee = showCommissions ? commissions.cashOut / 100 : null + const cashInFixedFee = showCommissions ? commissions.fixedFee : null const cashInRate = showCommissions ? _.invoke('cashIn.toNumber', buildedRates) : null const cashOutRate = showCommissions ? _.invoke('cashOut.toNumber', buildedRates) : null @@ -77,6 +78,7 @@ function mapMachine (rates, settings, machineRow) { // TODO new-admin: this is relaying info with backwards compatible triggers // need to get in touch with coinatmradar before updating this + // TODO all directions and max between them instead of min const cashLimit = showLimitsAndVerification ? ( !!compatTriggers.block ? compatTriggers.block diff --git a/lib/compliance-triggers.js b/lib/compliance-triggers.js index d08cfdb7..3cfd6a20 100644 --- a/lib/compliance-triggers.js +++ b/lib/compliance-triggers.js @@ -1,7 +1,7 @@ const _ = require('lodash/fp') function getBackwardsCompatibleTriggers (triggers) { - const filtered = _.filter(_.matches({ triggerType: 'volume', cashDirection: 'both' }))(triggers) + const filtered = _.filter(_.matches({ triggerType: 'amount', cashDirection: 'both' }))(triggers) const grouped = _.groupBy(_.prop('requirement'))(filtered) return _.mapValues(_.compose(_.get('threshold'), _.minBy('threshold')))(grouped) } diff --git a/lib/customers.js b/lib/customers.js index fb5fa474..126c848d 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -456,7 +456,7 @@ function getCustomerById (id) { 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(t.fiat) over (partition by c.id) as total_spent - from customers c inner join ( + from customers c left outer join ( select 'cashIn' as tx_class, id, fiat, fiat_code, created, customer_id from cash_in_txs where send_confirmed = true union select 'cashOut' as tx_class, id, fiat, fiat_code, created, customer_id diff --git a/lib/db.js b/lib/db.js index 4a190214..265a1be0 100644 --- a/lib/db.js +++ b/lib/db.js @@ -11,7 +11,7 @@ const pgp = Pgp({ if (e.cn) logger.error('Database not reachable.') if (e.query) { logger.error(e.query) - logger.error(e.params) + e.params && logger.error(e.params) } logger.error(err) } @@ -21,11 +21,12 @@ const db = pgp(psqlUrl) eventBus.subscribe('log', args => { const { level, message, meta } = args + const msgToSave = message ? message : _.get('message', meta) const sql = `insert into server_logs (id, device_id, message, log_level, meta) values ($1, $2, $3, $4, $5) returning *` - db.one(sql, [uuid.v4(), '', message, level, meta]) + db.one(sql, [uuid.v4(), '', msgToSave, level, meta]) .then(_.mapKeys(_.camelCase)) }) diff --git a/lib/machine-loader.js b/lib/machine-loader.js index 37e5f11f..a3197be6 100644 --- a/lib/machine-loader.js +++ b/lib/machine-loader.js @@ -1,6 +1,7 @@ const _ = require('lodash/fp') const axios = require('axios') +const logger = require('./logger') const db = require('./db') const pairing = require('./pairing') const configManager = require('./new-config-manager') @@ -15,8 +16,10 @@ function getMachines () { cashbox: r.cashbox, cassette1: r.cassette1, cassette2: r.cassette2, - pairedAt: new Date(r.created).valueOf(), - lastPing: new Date(r.last_online).valueOf(), + version: r.version, + model: r.model, + pairedAt: new Date(r.created), + lastPing: new Date(r.last_online), name: r.name, // TODO: we shall start using this JSON field at some point // location: r.location, @@ -36,19 +39,12 @@ function getMachineNames (config) { const addName = r => { const cashOutConfig = configManager.getCashOut(r.deviceId, config) - const cashOut = cashOutConfig.active + const cashOut = !!cashOutConfig.active - // TODO new-admin: these two fields were not ever working - const machineModel = '' - const machineLocation = '' - - // TODO: obtain next fields from somewhere - const printer = null - const pingTime = null + // TODO new-admin actually load status based on ping. const statuses = [{label: 'Unknown detailed status', type: 'warning'}] - const softwareVersion = '' - return _.assign(r, {cashOut, machineModel, machineLocation, printer, pingTime, statuses, softwareVersion}) + return _.assign(r, {cashOut, statuses}) } return _.map(addName, machines) diff --git a/lib/new-admin/config/accounts.js b/lib/new-admin/config/accounts.js index 4d0a9ac4..349cad8c 100644 --- a/lib/new-admin/config/accounts.js +++ b/lib/new-admin/config/accounts.js @@ -1,3 +1,4 @@ +const _ = require('lodash/fp') const { COINS, ALL_CRYPTOS } = require('./coins') const { BTC, BCH, DASH, ETH, LTC, ZEC } = COINS diff --git a/lib/new-admin/funding.js b/lib/new-admin/funding.js index cbb32b37..bcfe7dc0 100644 --- a/lib/new-admin/funding.js +++ b/lib/new-admin/funding.js @@ -5,6 +5,7 @@ const configManager = require('../new-config-manager') const wallet = require('../wallet') const ticker = require('../ticker') const coinUtils = require('../coin-utils') +const logger = require('../logger') function allScopes (cryptoScopes, machineScopes) { const scopes = [] @@ -68,6 +69,9 @@ function getSingleCoinFunding (settings, fiatCode, cryptoCode) { }) } +// Promise.allSettled not running on current version of node +const reflect = p => p.then(value => ({value, status: "fulfilled" }), error => ({error: error.toString(), status: "rejected" })) + function getFunding () { return settingsLoader.loadLatest().then(settings => { const cryptoCodes = configManager.getAllCryptoCurrencies(settings.config) @@ -77,9 +81,10 @@ function getFunding () { const cryptoDisplays = _.filter(pareCoins, cryptoCurrencies) const promises = cryptoDisplays.map(it => getSingleCoinFunding(settings, fiatCode, it.cryptoCode)) - return Promise.all(promises) + return Promise.all(promises.map(reflect)) .then((response) => { - return _.toArray(_.merge(response, cryptoDisplays)) + const mapped = response.map(it => _.merge({ errorMsg: it.error }, it.value)) + return _.toArray(_.merge(mapped, cryptoDisplays)) }) }) } diff --git a/lib/new-admin/graphql/schema.js b/lib/new-admin/graphql/schema.js index 07bedf12..d1efb629 100644 --- a/lib/new-admin/graphql/schema.js +++ b/lib/new-admin/graphql/schema.js @@ -19,7 +19,6 @@ const serverLogs = require('../server-logs') const pairing = require('../pairing') const { accounts: accountsConfig, coins, countries, currencies, languages } = require('../config') -// TODO why does server logs messages can be null? const typeDefs = gql` scalar JSON scalar JSONObject @@ -54,6 +53,10 @@ const typeDefs = gql` name: String! deviceId: ID! paired: Boolean! + lastPing: Date + pairedAt: Date + version: String + model: String cashbox: Int cassette1: Int cassette2: Int @@ -123,21 +126,22 @@ const typeDefs = gql` type CoinFunds { cryptoCode: String! - fundingAddress: String! - fundingAddressUrl: String! - confirmedBalance: String! - pending: String! - fiatConfirmedBalance: String! - fiatPending: String! - fiatCode: String! - display: String! - unitScale: String! + errorMsg: String + fundingAddress: String + fundingAddressUrl: String + confirmedBalance: String + pending: String + fiatConfirmedBalance: String + fiatPending: String + fiatCode: String + display: String + unitScale: String } type ProcessStatus { name: String! state: String! - uptime: Date! + uptime: Int! } type Transaction { @@ -156,6 +160,7 @@ const typeDefs = gql` created: Date send: Boolean sendConfirmed: Boolean + dispense: Boolean timedout: Boolean sendTime: Date errorCode: String diff --git a/lib/new-admin/supervisor.js b/lib/new-admin/supervisor.js index 4fb806c4..09710eb4 100644 --- a/lib/new-admin/supervisor.js +++ b/lib/new-admin/supervisor.js @@ -2,6 +2,10 @@ const xmlrpc = require('xmlrpc') const logger = require('../logger') const { promisify } = require('util') +// TODO new-admin: add the following to supervisor config +// [inet_http_server] +// port = 127.0.0.1:9001 + function getAllProcessInfo () { const convertStates = (state) => { // From http://supervisord.org/subprocess.html#process-states @@ -45,7 +49,7 @@ function getAllProcessInfo () { { name: process.name, state: convertStates(process.statename), - uptime: (process.statename === 'RUNNING') ? new Date(process.now) - new Date(process.start) : 0 + uptime: (process.statename === 'RUNNING') ? process.now - process.start : 0 } )) }) diff --git a/lib/new-settings-loader.js b/lib/new-settings-loader.js index 3c53bd08..661fa37e 100644 --- a/lib/new-settings-loader.js +++ b/lib/new-settings-loader.js @@ -5,6 +5,7 @@ const FileAsync = require('lowdb/adapters/FileAsync') const adapter = new FileAsync('db.json') let db = null +// TODO new-admin save to actual db, like the old settings low(adapter).then(it => { db = it }) @@ -54,6 +55,7 @@ function loadLatest () { }) } +// TODO new-admin: grab correct version function load (versionId) { return new Promise((resolve) => { if (!db) { diff --git a/lib/plugins.js b/lib/plugins.js index 62dec217..b47bf989 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -185,7 +185,6 @@ function plugins (settings, deviceId) { const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config) const minimumTx = BN(commissions.minimumTx) const cashInFee = BN(commissions.fixedFee) - logger.info('FEE', cashInFee) const cashInCommission = BN(commissions.cashIn) const cashOutCommission = _.isNumber(commissions.cashOut) ? BN(commissions.cashOut) : null const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode) @@ -201,7 +200,7 @@ function plugins (settings, deviceId) { } } - function pollQueries (serialNumber, deviceTime, deviceRec) { + function pollQueries (serialNumber, deviceTime, deviceRec, machineVersion, machineModel) { const localeConfig = configManager.getLocale(deviceId, settings.config) const fiatCode = localeConfig.fiatCurrency @@ -210,7 +209,7 @@ function plugins (settings, deviceId) { const tickerPromises = cryptoCodes.map(c => ticker.getRates(settings, fiatCode, c)) const balancePromises = cryptoCodes.map(c => fiatBalance(fiatCode, c)) const testnetPromises = cryptoCodes.map(c => wallet.cryptoNetwork(settings, c)) - const pingPromise = recordPing(deviceTime) + const pingPromise = recordPing(deviceTime, machineVersion, machineModel) const currentConfigVersionPromise = fetchCurrentConfigVersion() const promises = [ @@ -244,8 +243,10 @@ function plugins (settings, deviceId) { return wallet.sendCoins(settings, tx.toAddress, tx.cryptoAtoms, tx.cryptoCode) } - function recordPing (deviceTime) { + function recordPing (deviceTime, version, model) { const devices = { + version, + model, last_online: deviceTime } diff --git a/lib/routes.js b/lib/routes.js index 493de594..303c41f5 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -15,7 +15,6 @@ const logger = require('./logger') const configManager = require('./new-config-manager') const complianceTriggers = require('./compliance-triggers') const pairing = require('./pairing') -// TODO new-admin: remove old settings loader from here. const newSettingsLoader = require('./new-settings-loader') const plugins = require('./plugins') const helpers = require('./route-helpers') @@ -51,6 +50,8 @@ function checkHasLightning (settings) { function poll (req, res, next) { const machineVersion = req.query.version + // TODO new-admin: pass this field from the machines + const machineModel = req.query.model const deviceId = req.deviceId const deviceTime = req.deviceTime const serialNumber = req.query.sn @@ -64,13 +65,12 @@ function poll (req, res, next) { const compatTriggers = complianceTriggers.getBackwardsCompatibleTriggers(triggers) const operatorInfo = configManager.getOperatorInfo(settings.config) - const terms = configManager.getTermsConditions(settings.config) const cashOutConfig = configManager.getCashOut(deviceId, settings.config) const receipt = configManager.getReceipt(settings.config) pids[deviceId] = { pid, ts: Date.now() } - return pi.pollQueries(serialNumber, deviceTime, req.query) + return pi.pollQueries(serialNumber, deviceTime, req.query, machineVersion, machineModel) .then(results => { const cassettes = results.cassettes @@ -103,7 +103,7 @@ function poll (req, res, next) { sanctionsVerificationThreshold: compatTriggers.sancations, frontCameraVerificationActive: !!compatTriggers.facephoto, frontCameraVerificationThreshold: compatTriggers.facephoto, - receiptPrintingActive: receipt.active, + receiptPrintingActive: receipt.active === "on", cassettes, twoWayMode: cashOutConfig.active, zeroConfLimit: cashOutConfig.zeroConfLimit, @@ -389,7 +389,7 @@ const localApp = express() app.use(compression({ threshold: 500 })) app.use(helmet({ noCache: true })) app.use(bodyParser.json({ limit: '2mb' })) -app.use(morgan('dev', { skip, stream: logger.stream })) +app.use(morgan(':method :url :status :response-time ms - :res[content-length]', { stream: logger.stream })) // These two have their own authorization app.post('/pair', populateDeviceId, pair) diff --git a/lib/ticker.js b/lib/ticker.js index 5ea068ec..85fc3266 100644 --- a/lib/ticker.js +++ b/lib/ticker.js @@ -13,7 +13,6 @@ function _getRates (settings, fiatCode, cryptoCode) { const config = settings.config const plugin = configManager.getWalletSettings(cryptoCode, config).ticker - logger.info(plugin) const account = settings.accounts[plugin] const ticker = ph.load(ph.TICKER, plugin) diff --git a/lib/wallet.js b/lib/wallet.js index 523bdc23..c6d56385 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -122,7 +122,7 @@ function mergeStatusMode (a, b) { } function getWalletStatus (settings, tx) { - const fudgeFactorEnabled = configManager.unscoped(settings.config).fudgeFactorActive + const fudgeFactorEnabled = configManager.getWalletSettings(tx.cryptoCode, settings.config).fudgeFactorActive const fudgeFactor = fudgeFactorEnabled ? 100 : 0 const walletStatusPromise = fetchWallet(settings, tx.cryptoCode) diff --git a/migrations/1592317667188-machine-version-name.js b/migrations/1592317667188-machine-version-name.js new file mode 100644 index 00000000..7da0f385 --- /dev/null +++ b/migrations/1592317667188-machine-version-name.js @@ -0,0 +1,14 @@ +const db = require('./db') + +exports.up = function (next) { + var sql = [ + 'alter table devices add column version text', + 'alter table devices add column model text' + ] + + db.multi(sql, next) +} + +exports.down = function (next) { + next() +} diff --git a/new-lamassu-admin/package-lock.json b/new-lamassu-admin/package-lock.json index 483b4abf..a20ce5c4 100644 --- a/new-lamassu-admin/package-lock.json +++ b/new-lamassu-admin/package-lock.json @@ -4867,123 +4867,124 @@ } } }, - "apollo-boost": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.4.7.tgz", - "integrity": "sha512-jfc3aqO0vpCV+W662EOG5gq4AH94yIsvSgAUuDvS3o/Z+8Joqn4zGC9CgLCDHusK30mFgtsEgwEe0pZoedohsQ==", - "requires": { - "apollo-cache": "^1.3.4", - "apollo-cache-inmemory": "^1.6.5", - "apollo-client": "^2.6.7", - "apollo-link": "^1.0.6", - "apollo-link-error": "^1.0.3", - "apollo-link-http": "^1.3.1", - "graphql-tag": "^2.4.2", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" - } - } - }, - "apollo-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.4.tgz", - "integrity": "sha512-7X5aGbqaOWYG+SSkCzJNHTz2ZKDcyRwtmvW4mGVLRqdQs+HxfXS4dUS2CcwrAj449se6tZ6NLUMnjko4KMt3KA==", - "requires": { - "apollo-utilities": "^1.3.3", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" - } - } - }, "apollo-cache-inmemory": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.5.tgz", - "integrity": "sha512-koB76JUDJaycfejHmrXBbWIN9pRKM0Z9CJGQcBzIOtmte1JhEBSuzsOUu7NQgiXKYI4iGoMREcnaWffsosZynA==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.6.tgz", + "integrity": "sha512-L8pToTW/+Xru2FFAhkZ1OA9q4V4nuvfoPecBM34DecAugUZEBhI2Hmpgnzq2hTKZ60LAMrlqiASm0aqAY6F8/A==", "requires": { - "apollo-cache": "^1.3.4", - "apollo-utilities": "^1.3.3", + "apollo-cache": "^1.3.5", + "apollo-utilities": "^1.3.4", "optimism": "^0.10.0", "ts-invariant": "^0.4.0", "tslib": "^1.10.0" }, "dependencies": { + "apollo-cache": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.5.tgz", + "integrity": "sha512-1XoDy8kJnyWY/i/+gLTEbYLnoiVtS8y7ikBr/IfmML4Qb+CM7dEEbIUOjnY716WqmZ/UpXIxTfJsY7rMcqiCXA==", + "requires": { + "apollo-utilities": "^1.3.4", + "tslib": "^1.10.0" + } + }, + "apollo-utilities": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz", + "integrity": "sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig==", + "requires": { + "@wry/equality": "^0.1.2", + "fast-json-stable-stringify": "^2.0.0", + "ts-invariant": "^0.4.0", + "tslib": "^1.10.0" + } + }, "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" } } }, "apollo-client": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.6.8.tgz", - "integrity": "sha512-0zvJtAcONiozpa5z5zgou83iEKkBaXhhSSXJebFHRXs100SecDojyUWKjwTtBPn9HbM6o5xrvC5mo9VQ5fgAjw==", + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.6.10.tgz", + "integrity": "sha512-jiPlMTN6/5CjZpJOkGeUV0mb4zxx33uXWdj/xQCfAMkuNAC3HN7CvYDyMHHEzmcQ5GV12LszWoQ/VlxET24CtA==", "requires": { "@types/zen-observable": "^0.8.0", - "apollo-cache": "1.3.4", + "apollo-cache": "1.3.5", "apollo-link": "^1.0.0", - "apollo-utilities": "1.3.3", + "apollo-utilities": "1.3.4", "symbol-observable": "^1.0.2", "ts-invariant": "^0.4.0", "tslib": "^1.10.0", "zen-observable": "^0.8.0" }, "dependencies": { + "apollo-cache": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.5.tgz", + "integrity": "sha512-1XoDy8kJnyWY/i/+gLTEbYLnoiVtS8y7ikBr/IfmML4Qb+CM7dEEbIUOjnY716WqmZ/UpXIxTfJsY7rMcqiCXA==", + "requires": { + "apollo-utilities": "^1.3.4", + "tslib": "^1.10.0" + } + }, + "apollo-utilities": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz", + "integrity": "sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig==", + "requires": { + "@wry/equality": "^0.1.2", + "fast-json-stable-stringify": "^2.0.0", + "ts-invariant": "^0.4.0", + "tslib": "^1.10.0" + } + }, "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" } } }, "apollo-link": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.13.tgz", - "integrity": "sha512-+iBMcYeevMm1JpYgwDEIDt/y0BB7VWyvlm/7x+TIPNLHCTCMgcEgDuW5kH86iQZWo0I7mNwQiTOz+/3ShPFmBw==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.14.tgz", + "integrity": "sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg==", "requires": { "apollo-utilities": "^1.3.0", "ts-invariant": "^0.4.0", "tslib": "^1.9.3", - "zen-observable-ts": "^0.8.20" + "zen-observable-ts": "^0.8.21" } }, "apollo-link-error": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.12.tgz", - "integrity": "sha512-psNmHyuy3valGikt/XHJfe0pKJnRX19tLLs6P6EHRxg+6q6JMXNVLYPaQBkL0FkwdTCB0cbFJAGRYCBviG8TDA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.13.tgz", + "integrity": "sha512-jAZOOahJU6bwSqb2ZyskEK1XdgUY9nkmeclCrW7Gddh1uasHVqmoYc4CKdb0/H0Y1J9lvaXKle2Wsw/Zx1AyUg==", "requires": { - "apollo-link": "^1.2.13", - "apollo-link-http-common": "^0.2.15", + "apollo-link": "^1.2.14", + "apollo-link-http-common": "^0.2.16", "tslib": "^1.9.3" } }, "apollo-link-http": { - "version": "1.5.16", - "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.16.tgz", - "integrity": "sha512-IA3xA/OcrOzINRZEECI6IdhRp/Twom5X5L9jMehfzEo2AXdeRwAMlH5LuvTZHgKD8V1MBnXdM6YXawXkTDSmJw==", + "version": "1.5.17", + "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.17.tgz", + "integrity": "sha512-uWcqAotbwDEU/9+Dm9e1/clO7hTB2kQ/94JYcGouBVLjoKmTeJTUPQKcJGpPwUjZcSqgYicbFqQSoJIW0yrFvg==", "requires": { - "apollo-link": "^1.2.13", - "apollo-link-http-common": "^0.2.15", + "apollo-link": "^1.2.14", + "apollo-link-http-common": "^0.2.16", "tslib": "^1.9.3" } }, "apollo-link-http-common": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.15.tgz", - "integrity": "sha512-+Heey4S2IPsPyTf8Ag3PugUupASJMW894iVps6hXbvwtg1aHSNMXUYO5VG7iRHkPzqpuzT4HMBanCTXPjtGzxg==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.16.tgz", + "integrity": "sha512-2tIhOIrnaF4UbQHf7kjeQA/EmSorB7+HyJIIrUjJOKBgnXwuexi8aMecRlqTIDWcyVXCeqLhUnztMa6bOH/jTg==", "requires": { - "apollo-link": "^1.2.13", + "apollo-link": "^1.2.14", "ts-invariant": "^0.4.0", "tslib": "^1.9.3" } @@ -11762,9 +11763,9 @@ } }, "graphql-tag": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", - "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.3.tgz", + "integrity": "sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA==" }, "growly": { "version": "1.3.0", @@ -26657,9 +26658,9 @@ "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" }, "zen-observable-ts": { - "version": "0.8.20", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.20.tgz", - "integrity": "sha512-2rkjiPALhOtRaDX6pWyNqK1fnP5KkJJybYebopNSn6wDG1lxBoFs2+nwwXKoA6glHIrtwrfBBy6da0stkKtTAA==", + "version": "0.8.21", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz", + "integrity": "sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg==", "requires": { "tslib": "^1.9.3", "zen-observable": "^0.8.0" diff --git a/new-lamassu-admin/package.json b/new-lamassu-admin/package.json index c0beaa39..ca8a5c8e 100644 --- a/new-lamassu-admin/package.json +++ b/new-lamassu-admin/package.json @@ -8,7 +8,11 @@ "@material-ui/icons": "4.9.1", "@material-ui/lab": "^4.0.0-alpha.47", "@use-hooks/axios": "1.3.0", - "apollo-boost": "^0.4.7", + "apollo-cache-inmemory": "^1.6.6", + "apollo-client": "^2.6.10", + "apollo-link": "^1.2.14", + "apollo-link-error": "^1.1.13", + "apollo-link-http": "^1.5.17", "axios": "0.19.0", "bignumber.js": "9.0.0", "classnames": "2.2.6", @@ -17,6 +21,7 @@ "formik": "2.1.4", "fuse.js": "^3.4.6", "graphql": "^14.5.8", + "graphql-tag": "^2.10.3", "jss-plugin-extend": "^10.0.0", "libphonenumber-js": "^1.7.50", "moment": "2.24.0", diff --git a/new-lamassu-admin/src/App.js b/new-lamassu-admin/src/App.js index 90d4ee2c..f099aeba 100644 --- a/new-lamassu-admin/src/App.js +++ b/new-lamassu-admin/src/App.js @@ -6,42 +6,20 @@ import { MuiThemeProvider, makeStyles } from '@material-ui/core/styles' -import ApolloClient from 'apollo-boost' import { setAutoFreeze } from 'immer' import { create } from 'jss' import extendJss from 'jss-plugin-extend' import React from 'react' import { BrowserRouter as Router } from 'react-router-dom' +import client from 'src/utils/apollo' + import Header from './components/layout/Header' import { tree, Routes } from './routing/routes' import global from './styling/global' import theme from './styling/theme' import { backgroundColor, mainWidth } from './styling/variables' -const defaultOptions = { - watchQuery: { - fetchPolicy: 'no-cache', - errorPolicy: 'ignore' - }, - query: { - fetchPolicy: 'no-cache', - errorPolicy: 'all' - }, - mutate: { - errorPolicy: 'all' - } -} - -const client = new ApolloClient({ - credentials: 'include', - defaultOptions, - uri: - process.env.NODE_ENV === 'development' - ? 'https://localhost:8070/graphql/' - : '/graphql' -}) - if (process.env.NODE_ENV !== 'production') { const whyDidYouRender = require('@welldone-software/why-did-you-render') whyDidYouRender(React) diff --git a/new-lamassu-admin/src/components/ConfirmDialog.js b/new-lamassu-admin/src/components/ConfirmDialog.js index b56cef22..2937817c 100644 --- a/new-lamassu-admin/src/components/ConfirmDialog.js +++ b/new-lamassu-admin/src/components/ConfirmDialog.js @@ -3,41 +3,53 @@ import { DialogActions, DialogContent, DialogContentText, - DialogTitle as MuiDialogTitle, - IconButton, makeStyles } from '@material-ui/core' -import React, { useState, memo } from 'react' +import React, { useEffect, useState, memo } from 'react' -import { Button } from '../components/buttons' -import { ReactComponent as CloseIcon } from '../styling/icons/action/close/zodiac.svg' -import { spacer } from '../styling/variables' +import { Button, IconButton } from 'src/components/buttons' +import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg' import { TextInput } from './inputs' import { H4, P } from './typography' const useStyles = makeStyles({ + label: { + fontSize: 16 + }, + spacing: { + padding: 32 + }, + wrapper: { + display: 'flex' + }, + title: { + margin: [[20, 0, 24, 16]] + }, closeButton: { - position: 'absolute', - right: spacer, - top: spacer + padding: 0, + margin: [[12, 12, 'auto', 'auto']] + // position: 'absolute', + // right: spacer, + // top: spacer } }) export const DialogTitle = ({ children, onClose }) => { const classes = useStyles() return ( - +
{children} {onClose && ( )} - +
) } @@ -49,9 +61,12 @@ export const ConfirmDialog = memo( toBeConfirmed, onConfirmed, onDissmised, + className, ...props }) => { + const classes = useStyles() const [value, setValue] = useState('') + useEffect(() => setValue(''), [open]) const handleChange = event => { setValue(event.target.value) } @@ -59,14 +74,14 @@ export const ConfirmDialog = memo( return ( -

{title}

+

{title}

{subtitle && (

{subtitle}

)}
- + - + + + ) +}) + +export default HelpTooltip diff --git a/new-lamassu-admin/src/components/LogsDownloaderPopper.js b/new-lamassu-admin/src/components/LogsDownloaderPopper.js index b97a718e..f5cfdfcc 100644 --- a/new-lamassu-admin/src/components/LogsDownloaderPopper.js +++ b/new-lamassu-admin/src/components/LogsDownloaderPopper.js @@ -5,11 +5,13 @@ import moment from 'moment' import * as R from 'ramda' import React, { useState, useCallback } from 'react' +import { FeatureButton, Link } from 'src/components/buttons' import { ReactComponent as Arrow } from 'src/styling/icons/arrow/download_logs.svg' +import { ReactComponent as DownloadInverseIcon } from 'src/styling/icons/button/download/white.svg' +import { ReactComponent as Download } from 'src/styling/icons/button/download/zodiac.svg' import { primaryColor, offColor, zircon } from 'src/styling/variables' import Popper from './Popper' -import { Link } from './buttons' import DateRangePicker from './date-range-picker/DateRangePicker' import { RadioGroup } from './inputs' import typographyStyles from './typography/styles' @@ -123,30 +125,26 @@ const styles = { } const useStyles = makeStyles(styles) +const ALL = 'all' +const RANGE = 'range' -const LogsDownloaderPopover = ({ - id, - name, - open, - anchorEl, - getTimestamp, - logs, - title -}) => { - const radioButtonAll = 'all' - const radioButtonRange = 'range' - - const [selectedRadio, setSelectedRadio] = useState(radioButtonAll) - const [range, setRange] = useState(null) +const LogsDownloaderPopover = ({ name, getTimestamp, logs, title }) => { + const [selectedRadio, setSelectedRadio] = useState(ALL) + const [range, setRange] = useState({ from: null, to: null }) + const [anchorEl, setAnchorEl] = useState(null) const classes = useStyles() const dateRangePickerClasses = { - [classes.dateRangePickerShowing]: selectedRadio === radioButtonRange, - [classes.dateRangePickerHidden]: selectedRadio === radioButtonAll + [classes.dateRangePickerShowing]: selectedRadio === RANGE, + [classes.dateRangePickerHidden]: selectedRadio === ALL } - const handleRadioButtons = R.o(setSelectedRadio, R.path(['target', 'value'])) + const handleRadioButtons = evt => { + const selectedRadio = R.path(['target', 'value'])(evt) + setSelectedRadio(selectedRadio) + if (selectedRadio === ALL) setRange({ from: null, to: null }) + } const handleRangeChange = useCallback( (from, to) => { @@ -164,7 +162,7 @@ const LogsDownloaderPopover = ({ return moment(date).format('YYYY-MM-DD_HH-mm') } - if (selectedRadio === radioButtonAll) { + if (selectedRadio === ALL) { const text = logs.map(it => JSON.stringify(it)).join('\n') const blob = new window.Blob([text], { type: 'text/plain;charset=utf-8' @@ -173,7 +171,7 @@ const LogsDownloaderPopover = ({ return } - if (selectedRadio === radioButtonRange) { + if (selectedRadio === RANGE) { const text = logs .filter(log => moment(getTimestamp(log)).isBetween(range.from, range.to, 'day', '[]') @@ -190,51 +188,67 @@ const LogsDownloaderPopover = ({ } } + const handleOpenRangePicker = event => { + setAnchorEl(anchorEl ? null : event.currentTarget) + } + const radioButtonOptions = [ - { display: 'All logs', code: radioButtonAll }, - { display: 'Date range', code: radioButtonRange } + { display: 'All logs', code: ALL }, + { display: 'Date range', code: RANGE } ] + const open = Boolean(anchorEl) + const id = open ? 'date-range-popover' : undefined + return ( - -
-
{title}
-
- -
- {selectedRadio === radioButtonRange && ( -
-
- {range && ( - <> - From -
- -
- To - - )} -
- + + +
+
{title}
+
+
- )} -
- downloadLogs(range, logs)}> - Download - + {selectedRadio === RANGE && ( +
+
+ {range && ( + <> + From +
+ +
+ To + + )} +
+ +
+ )} +
+ downloadLogs(range, logs)}> + Download + +
-
-
+ + ) } diff --git a/new-lamassu-admin/src/components/Modal.js b/new-lamassu-admin/src/components/Modal.js index fc84d0a8..98a5a362 100644 --- a/new-lamassu-admin/src/components/Modal.js +++ b/new-lamassu-admin/src/components/Modal.js @@ -3,7 +3,7 @@ import classnames from 'classnames' import React from 'react' import { IconButton } from 'src/components/buttons' -import { H1, H2 } from 'src/components/typography' +import { H1, H4 } from 'src/components/typography' import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg' const styles = { @@ -18,29 +18,29 @@ const styles = { height, display: 'flex', flexDirection: 'column', - minHeight: 400, + minHeight: height ?? 400, maxHeight: '90vh', overflowY: 'auto', borderRadius: 8, outline: 0 }), - content: { + content: ({ small }) => ({ width: '100%', display: 'flex', flexDirection: 'column', flex: 1, - padding: [[0, 32]] - }, - button: { + padding: small ? [[0, 16]] : [[0, 32]] + }), + button: ({ small }) => ({ padding: 0, - margin: [[20, 20, 'auto', 'auto']] - }, + margin: small ? [[12, 12, 'auto', 'auto']] : [[16, 16, 'auto', 'auto']] + }), header: { display: 'flex' }, - title: { - margin: [[28, 0, 8, 32]] - } + title: ({ small }) => ({ + margin: small ? [[20, 0, 8, 16]] : [[28, 0, 8, 32]] + }) } const useStyles = makeStyles(styles) @@ -49,7 +49,7 @@ const Modal = ({ width, height, title, - titleSmall, + small, infoPanel, handleClose, children, @@ -58,9 +58,9 @@ const Modal = ({ closeOnBackdropClick, ...props }) => { - const classes = useStyles({ width, height }) - const TitleCase = titleSmall ? H2 : H1 - const closeSize = titleSmall ? 16 : 20 + const classes = useStyles({ width, height, small }) + const TitleCase = small ? H4 : H1 + const closeSize = small ? 16 : 20 const innerClose = (evt, reason) => { if (!closeOnBackdropClick && reason === 'backdropClick') return diff --git a/new-lamassu-admin/src/components/Popper.js b/new-lamassu-admin/src/components/Popper.js index 5129a6bf..eacb09d1 100644 --- a/new-lamassu-admin/src/components/Popper.js +++ b/new-lamassu-admin/src/components/Popper.js @@ -5,7 +5,13 @@ import React, { useState } from 'react' import { white } from 'src/styling/variables' -const Popover = ({ children, bgColor = white, arrowSize = 7, ...props }) => { +const Popover = ({ + children, + bgColor = white, + arrowSize = 6, + className, + ...props +}) => { const [arrowRef, setArrowRef] = useState(null) const styles = { @@ -27,7 +33,24 @@ const Popover = ({ children, bgColor = white, arrowSize = 7, ...props }) => { borderLeft: [['2em', 'solid', 'transparent']], borderRight: [['2em', 'solid', 'transparent']], borderBottom: [['2em', 'solid', bgColor]], - marginTop: '-1.9em' + marginTop: '-1.9em', + '&:after': { + zIndex: -10, + content: '""', + position: 'absolute', + width: arrowSize * 3, + height: arrowSize * 3, + marginLeft: 0, + bottom: 0, + top: 'calc(50% - 0px)', + left: 0, + border: '5px solid #fff', + borderColor: 'transparent transparent #fff #fff', + transformOrigin: '0 0', + transform: 'rotate(45deg)', + boxShadow: + '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)' + } }, arrowTop: { bottom: 0, @@ -36,7 +59,24 @@ const Popover = ({ children, bgColor = white, arrowSize = 7, ...props }) => { borderLeft: [['2em', 'solid', 'transparent']], borderRight: [['2em', 'solid', 'transparent']], borderTop: [['2em', 'solid', bgColor]], - marginBottom: '-1.9em' + marginBottom: '-1.9em', + '&:after': { + zIndex: -10, + content: '""', + position: 'absolute', + width: arrowSize * 3, + height: arrowSize * 3, + marginLeft: 0, + bottom: 0, + top: -(arrowSize * 4 + 2), + left: 0, + border: '5px solid #fff', + borderColor: 'transparent transparent #fff #fff', + transformOrigin: '0 0', + transform: 'rotate(45deg)', + boxShadow: + '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)' + } }, arrowRight: { left: 0, @@ -81,6 +121,10 @@ const Popover = ({ children, bgColor = white, arrowSize = 7, ...props }) => { enabled: true, boundariesElement: 'scrollParent' }, + offset: { + enabled: true, + offset: '0, 10' + }, arrow: { enabled: true, element: arrowRef @@ -94,7 +138,7 @@ const Popover = ({ children, bgColor = white, arrowSize = 7, ...props }) => { modifiers={modifiers} className={classes.popover} {...props}> - + {children} diff --git a/new-lamassu-admin/src/components/Status.js b/new-lamassu-admin/src/components/Status.js index 926f90fc..cca3639f 100644 --- a/new-lamassu-admin/src/components/Status.js +++ b/new-lamassu-admin/src/components/Status.js @@ -1,6 +1,6 @@ -import React from 'react' import Chip from '@material-ui/core/Chip' import { makeStyles } from '@material-ui/core/styles' +import React from 'react' import { tomato, @@ -40,15 +40,21 @@ const useStyles = makeStyles({ fontSize: smallestFontSize, fontWeight: inputFontWeight, fontFamily: inputFontFamily, - paddingRight: spacer / 2, - paddingLeft: spacer / 2, + padding: [[spacer / 2, spacer]], color: ({ type }) => colors[type] } }) -const Status = ({ status }) => { +const Status = ({ status, className }) => { const classes = useStyles({ type: status.type }) - return + return ( + + ) } const MainStatus = ({ statuses }) => { @@ -59,7 +65,7 @@ const MainStatus = ({ statuses }) => { const plus = { label: `+${statuses.length - 1}`, type: mainStatus.type } return ( -
+
{statuses.length > 1 && }
diff --git a/new-lamassu-admin/src/components/Title.js b/new-lamassu-admin/src/components/Title.js index 5c7e275e..be96227b 100644 --- a/new-lamassu-admin/src/components/Title.js +++ b/new-lamassu-admin/src/components/Title.js @@ -7,7 +7,7 @@ import { H1 } from './typography' const useStyles = makeStyles({ title: { - marginTop: spacer * 3.5, + marginTop: spacer * 3, marginBottom: spacer * 3 } }) diff --git a/new-lamassu-admin/src/components/buttons/ActionButton.styles.js b/new-lamassu-admin/src/components/buttons/ActionButton.styles.js index 3f13f225..a775f811 100644 --- a/new-lamassu-admin/src/components/buttons/ActionButton.styles.js +++ b/new-lamassu-admin/src/components/buttons/ActionButton.styles.js @@ -1,3 +1,4 @@ +import typographyStyles from 'src/components/typography/styles' import { white, fontColor, @@ -6,7 +7,6 @@ import { offColor, offDarkColor } from 'src/styling/variables' -import typographyStyles from 'src/components/typography/styles' const { p } = typographyStyles @@ -27,7 +27,7 @@ export default { extend: p, cursor: 'pointer', border: 'none', - height: 24, + height: 28, outline: 0, borderRadius: 6, padding: '0 8px', diff --git a/new-lamassu-admin/src/components/buttons/FeatureButton.js b/new-lamassu-admin/src/components/buttons/FeatureButton.js index fc6b9bff..3fe97cd7 100644 --- a/new-lamassu-admin/src/components/buttons/FeatureButton.js +++ b/new-lamassu-admin/src/components/buttons/FeatureButton.js @@ -11,13 +11,19 @@ const styles = { extend: baseButton, width: baseButton.height, borderRadius: baseButton.height / 2, - display: 'flex' + display: 'flex', + padding: 0 }, primary, buttonIcon: { margin: 'auto', '& svg': { - overflow: 'visible' + width: 16, + height: 16, + overflow: 'visible', + '& g': { + strokeWidth: 1.8 + } } }, buttonIconActive: {} // required to extend primary @@ -25,29 +31,35 @@ const styles = { const useStyles = makeStyles(styles) -const FeatureButton = memo(({ className, Icon, InverseIcon, ...props }) => { - const classes = useStyles() +const FeatureButton = memo( + ({ className, Icon, InverseIcon, children, ...props }) => { + const classes = useStyles() - const classNames = { - [classes.featureButton]: true, - [classes.primary]: true + const classNames = { + [classes.featureButton]: true, + [classes.primary]: true + } + + return ( + + ) } - - return ( - - ) -}) +) export default FeatureButton diff --git a/new-lamassu-admin/src/components/buttons/IDButton.js b/new-lamassu-admin/src/components/buttons/IDButton.js index 987bd6de..593a56fd 100644 --- a/new-lamassu-admin/src/components/buttons/IDButton.js +++ b/new-lamassu-admin/src/components/buttons/IDButton.js @@ -2,13 +2,13 @@ import { makeStyles } from '@material-ui/core/styles' import classnames from 'classnames' import React, { useState, memo } from 'react' +import Popover from 'src/components/Popper' +import typographyStyles from 'src/components/typography/styles' import { subheaderColor, subheaderDarkColor, offColor } from 'src/styling/variables' -import Popover from 'src/components/Popper' -import typographyStyles from 'src/components/typography/styles' const { info2 } = typographyStyles @@ -70,6 +70,7 @@ const IDButton = memo( InverseIcon, popoverWidth = 152, children, + popoverClassname, ...props }) => { const [anchorEl, setAnchorEl] = useState(null) @@ -117,6 +118,7 @@ const IDButton = memo( )} { - const classes = useStyles() +const SimpleButton = memo( + ({ className, Icon, InverseIcon, children, color, size, ...props }) => { + const classes = useStyles() - return ( - - ) -}) + return ( + + ) + } +) export default SimpleButton diff --git a/new-lamassu-admin/src/components/editableTable/Header.js b/new-lamassu-admin/src/components/editableTable/Header.js index b514c3b1..9dcbfd02 100644 --- a/new-lamassu-admin/src/components/editableTable/Header.js +++ b/new-lamassu-admin/src/components/editableTable/Header.js @@ -1,10 +1,35 @@ +import * as R from 'ramda' import React, { useContext } from 'react' -import { Td, THead } from 'src/components/fake-table/Table' +import { + Td, + THead, + TDoubleLevelHead, + ThDoubleLevel +} from 'src/components/fake-table/Table' import { startCase } from 'src/utils/string' import TableCtx from './Context' +const groupSecondHeader = elements => { + const [toSHeader, noSHeader] = R.partition(R.has('doubleHeader'))(elements) + + if (!toSHeader.length) { + return [elements, THead] + } + + const index = R.indexOf(toSHeader[0], elements) + const width = R.compose(R.sum, R.map(R.path(['width'])))(toSHeader) + + const innerElements = R.insert( + index, + { width, elements: toSHeader, name: toSHeader[0].doubleHeader }, + noSHeader + ) + + return [innerElements, TDoubleLevelHead] +} + const Header = () => { const { elements, @@ -16,15 +41,35 @@ const Header = () => { toggleWidth, DEFAULT_COL_SIZE } = useContext(TableCtx) + + const mapElement2 = (it, idx) => { + const { width, elements, name } = it + + if (elements && elements.length) { + return ( + + {elements.map(mapElement)} + + ) + } + + return mapElement(it, idx) + } + + const mapElement = ( + { name, width = DEFAULT_COL_SIZE, header, textAlign }, + idx + ) => ( + + {header || startCase(name)} + + ) + + const [innerElements, HeaderElement] = groupSecondHeader(elements) + return ( - - {elements.map( - ({ name, width = DEFAULT_COL_SIZE, header, textAlign }, idx) => ( - - {header || startCase(name)} - - ) - )} + + {innerElements.map(mapElement2)} {enableEdit && ( Edit @@ -40,7 +85,7 @@ const Header = () => { Enable )} - + ) } diff --git a/new-lamassu-admin/src/components/editableTable/Row.js b/new-lamassu-admin/src/components/editableTable/Row.js index ab95f363..f365de97 100644 --- a/new-lamassu-admin/src/components/editableTable/Row.js +++ b/new-lamassu-admin/src/components/editableTable/Row.js @@ -83,7 +83,7 @@ const ActionCol = ({ disabled, editing }) => { ) } -const ECol = ({ editing, config }) => { +const ECol = ({ editing, config, extraPaddingRight, extraPaddingLeft }) => { const { name, input, @@ -115,7 +115,11 @@ const ECol = ({ editing, config }) => { return ( { const shouldStripe = stripeWhen && stripeWhen(values) && !editing const innerElements = shouldStripe ? groupStriped(elements) : elements + const [toSHeader] = R.partition(R.has('doubleHeader'))(elements) + + const extraPaddingLeftIndex = toSHeader?.length + ? R.indexOf(toSHeader[0], elements) + : -1 + + const extraPaddingRightIndex = toSHeader?.length + ? R.indexOf(toSHeader[toSHeader.length - 1], elements) + : -1 + return ( {innerElements.map((it, idx) => { - return + return ( + + ) })} {(enableEdit || enableDelete || enableToggle) && ( diff --git a/new-lamassu-admin/src/components/editableTable/Row.styles.js b/new-lamassu-admin/src/components/editableTable/Row.styles.js index 65faac11..c03d377f 100644 --- a/new-lamassu-admin/src/components/editableTable/Row.styles.js +++ b/new-lamassu-admin/src/components/editableTable/Row.styles.js @@ -4,11 +4,20 @@ export default { cancelButton: { marginRight: 20 }, - withSuffix: ({ textAlign }) => ({ - display: 'flex', - alignItems: 'baseline', - justifyContent: textAlign === 'right' && 'end' - }), + extraPaddingLeft: { + paddingLeft: 35 + }, + extraPaddingRight: { + paddingRight: 45 + }, + withSuffix: ({ textAlign }) => { + const justifyContent = textAlign === 'right' ? 'end' : textAlign + return { + display: 'flex', + alignItems: 'baseline', + justifyContent + } + }, suffix: { marginLeft: 7 }, diff --git a/new-lamassu-admin/src/components/fake-table/Table.js b/new-lamassu-admin/src/components/fake-table/Table.js index 2ceaee30..e560a9d8 100644 --- a/new-lamassu-admin/src/components/fake-table/Table.js +++ b/new-lamassu-admin/src/components/fake-table/Table.js @@ -65,8 +65,8 @@ const Th = ({ children, ...props }) => { ) } -const ThDoubleLevel = ({ title, children, className }) => { - const classes = useStyles() +const ThDoubleLevel = ({ title, children, className, width }) => { + const classes = useStyles({ width }) return (
diff --git a/new-lamassu-admin/src/components/fake-table/Table.styles.js b/new-lamassu-admin/src/components/fake-table/Table.styles.js index bc459a5c..d91d2091 100644 --- a/new-lamassu-admin/src/components/fake-table/Table.styles.js +++ b/new-lamassu-admin/src/components/fake-table/Table.styles.js @@ -31,11 +31,13 @@ export default { color: white, display: 'table-row' }, - thDoubleLevel: { - padding: [[0, spacer * 2]], + thDoubleLevel: ({ width }) => ({ + width, display: 'table-cell', '& > :first-child': { + margin: [[0, 10]], extend: label1, + fontWeight: 700, display: 'flex', justifyContent: 'center', alignItems: 'center', @@ -45,14 +47,12 @@ export default { height: 28 }, '& > :last-child': { + padding: [[0, 11]], display: 'table-cell', verticalAlign: 'middle', - height: tableDoubleHeaderHeight - 28, - '& > div': { - display: 'inline-block' - } + height: tableDoubleHeaderHeight - 28 } - }, + }), cellDoubleLevel: { display: 'flex', padding: [[0, spacer * 2]] diff --git a/new-lamassu-admin/src/components/inputs/base/Select.js b/new-lamassu-admin/src/components/inputs/base/Select.js index 2323fb43..15901774 100644 --- a/new-lamassu-admin/src/components/inputs/base/Select.js +++ b/new-lamassu-admin/src/components/inputs/base/Select.js @@ -1,10 +1,10 @@ -import { makeStyles } from '@material-ui/core/styles' +import { makeStyles } from '@material-ui/core' import classnames from 'classnames' import { useSelect } from 'downshift' import React from 'react' -import { ReactComponent as Arrowdown } from '../../../styling/icons/action/arrow/regular.svg' -import { startCase } from '../../../utils/string' +import { ReactComponent as Arrowdown } from 'src/styling/icons/action/arrow/regular.svg' +import { startCase } from 'src/utils/string' import styles from './Select.styles' diff --git a/new-lamassu-admin/src/components/inputs/base/TextInput.styles.js b/new-lamassu-admin/src/components/inputs/base/TextInput.styles.js index 413e8e74..d9077436 100644 --- a/new-lamassu-admin/src/components/inputs/base/TextInput.styles.js +++ b/new-lamassu-admin/src/components/inputs/base/TextInput.styles.js @@ -2,7 +2,10 @@ import { bySize, bold } from 'src/styling/helpers' import { secondaryColor } from 'src/styling/variables' export default { - size: ({ size }) => bySize(size), + size: ({ size }) => ({ + marginTop: size === 'lg' ? -2 : 0, + ...bySize(size) + }), bold, root: ({ width, textAlign }) => ({ width, diff --git a/new-lamassu-admin/src/components/inputs/formik/RadioGroup.js b/new-lamassu-admin/src/components/inputs/formik/RadioGroup.js index e7b94554..130f5282 100644 --- a/new-lamassu-admin/src/components/inputs/formik/RadioGroup.js +++ b/new-lamassu-admin/src/components/inputs/formik/RadioGroup.js @@ -13,7 +13,6 @@ const RadioGroupFormik = memo(({ label, ...props }) => { options={props.options} ariaLabel={name} onChange={e => { - console.log(e) onChange(e) props.resetError && props.resetError() }} diff --git a/new-lamassu-admin/src/components/inputs/formik/index.js b/new-lamassu-admin/src/components/inputs/formik/index.js index 30937441..1322a0dd 100644 --- a/new-lamassu-admin/src/components/inputs/formik/index.js +++ b/new-lamassu-admin/src/components/inputs/formik/index.js @@ -1,6 +1,7 @@ import Autocomplete from './Autocomplete' import Checkbox from './Checkbox' import RadioGroup from './RadioGroup' +import SecretInput from './SecretInput' import TextInput from './TextInput' -export { Autocomplete, Checkbox, TextInput, RadioGroup } +export { Autocomplete, Checkbox, TextInput, SecretInput, RadioGroup } diff --git a/new-lamassu-admin/src/components/layout/Sidebar.js b/new-lamassu-admin/src/components/layout/Sidebar.js index 1aac31c1..488a0f31 100644 --- a/new-lamassu-admin/src/components/layout/Sidebar.js +++ b/new-lamassu-admin/src/components/layout/Sidebar.js @@ -29,7 +29,7 @@ const Sidebar = ({ [classes.link]: true })} onClick={() => onClick(it)}> - {itemRender ? itemRender(it) : displayName(it)} + {itemRender ? itemRender(it, isSelected(it)) : displayName(it)}
))} {children} diff --git a/new-lamassu-admin/src/components/layout/TitleSection.js b/new-lamassu-admin/src/components/layout/TitleSection.js index 019a6ba5..ce84cd4b 100644 --- a/new-lamassu-admin/src/components/layout/TitleSection.js +++ b/new-lamassu-admin/src/components/layout/TitleSection.js @@ -1,4 +1,5 @@ import { makeStyles } from '@material-ui/core' +import classnames from 'classnames' import React from 'react' import ErrorMessage from 'src/components/ErrorMessage' @@ -8,10 +9,10 @@ import styles from './TitleSection.styles' const useStyles = makeStyles(styles) -const TitleSection = ({ title, error, labels }) => { +const TitleSection = ({ className, title, error, labels, children }) => { const classes = useStyles() return ( -
+
{title} {error && ( @@ -19,6 +20,7 @@ const TitleSection = ({ title, error, labels }) => { )}
{labels}
+ {children}
) } diff --git a/new-lamassu-admin/src/components/table/TableRow.js b/new-lamassu-admin/src/components/table/TableRow.js index 81060138..f5b28256 100644 --- a/new-lamassu-admin/src/components/table/TableRow.js +++ b/new-lamassu-admin/src/components/table/TableRow.js @@ -2,6 +2,7 @@ import { makeStyles } from '@material-ui/core/styles' import classnames from 'classnames' import React, { memo } from 'react' +import typographyStyles from 'src/components/typography/styles' import { tableCellColor, tableCellHeight, @@ -10,7 +11,6 @@ import { tableErrorColor, tableSuccessColor } from 'src/styling/variables' -import typographyStyles from 'src/components/typography/styles' const { info2, p } = typographyStyles @@ -19,8 +19,7 @@ const useStyles = makeStyles({ extend: p, padding: 4, height: tableCellHeight, - backgroundColor: tableCellColor, - boxShadow: '0 0 4px 0 rgba(0, 0, 0, 0.08)' + backgroundColor: tableCellColor }, lg: { extend: info2, diff --git a/new-lamassu-admin/src/components/typography/index.js b/new-lamassu-admin/src/components/typography/index.js index 8736e878..b014928a 100644 --- a/new-lamassu-admin/src/components/typography/index.js +++ b/new-lamassu-admin/src/components/typography/index.js @@ -6,37 +6,62 @@ import styles from './styles' const useStyles = makeStyles(styles) -function H1({ children, className, ...props }) { +function H1({ children, noMargin, className, ...props }) { const classes = useStyles() + const classNames = { + [classes.h1]: true, + [classes.noMargin]: noMargin, + [className]: !!className + } + return ( -

+

{children}

) } -function H2({ children, className, ...props }) { +function H2({ children, noMargin, className, ...props }) { const classes = useStyles() + const classNames = { + [classes.h2]: true, + [classes.noMargin]: noMargin, + [className]: !!className + } + return ( -

+

{children}

) } -function H3({ children, className, ...props }) { +function H3({ children, noMargin, className, ...props }) { const classes = useStyles() + const classNames = { + [classes.h3]: true, + [classes.noMargin]: noMargin, + [className]: !!className + } + return ( -

+

{children}

) } -function H4({ children, className, ...props }) { +function H4({ children, noMargin, className, ...props }) { const classes = useStyles() + console.log(className) + const classNames = { + [classes.h4]: true, + [classes.noMargin]: noMargin, + [className]: !!className + } + return ( -

+

{children}

) @@ -57,13 +82,13 @@ function pBuilder(elementClass) { return ({ inline, noMargin, className, children, ...props }) => { const classes = useStyles() const classNames = { + [className]: !!className, [classes[elementClass]]: elementClass, - className: true, [classes.inline]: inline, - [classes.noMarginP]: noMargin + [classes.noMargin]: noMargin } return ( -

+

{children}

) diff --git a/new-lamassu-admin/src/components/typography/styles.js b/new-lamassu-admin/src/components/typography/styles.js index 75bb70ad..2d5f90d3 100644 --- a/new-lamassu-admin/src/components/typography/styles.js +++ b/new-lamassu-admin/src/components/typography/styles.js @@ -122,7 +122,7 @@ export default { inline: { display: 'inline' }, - noMarginP: { + noMargin: { margin: 0 } } diff --git a/new-lamassu-admin/src/pages/AddMachine/AddMachine.js b/new-lamassu-admin/src/pages/AddMachine/AddMachine.js index f89c48f4..54fda4e5 100644 --- a/new-lamassu-admin/src/pages/AddMachine/AddMachine.js +++ b/new-lamassu-admin/src/pages/AddMachine/AddMachine.js @@ -1,9 +1,9 @@ import { useMutation } from '@apollo/react-hooks' import { Dialog, DialogContent, SvgIcon, IconButton } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' -import { gql } from 'apollo-boost' import classnames from 'classnames' import { Form, Formik, FastField } from 'formik' +import gql from 'graphql-tag' import QRCode from 'qrcode.react' import React, { memo, useState } from 'react' import * as Yup from 'yup' diff --git a/new-lamassu-admin/src/pages/Cashout/Cashout.js b/new-lamassu-admin/src/pages/Cashout/Cashout.js index 03dbd611..e2b1cf70 100644 --- a/new-lamassu-admin/src/pages/Cashout/Cashout.js +++ b/new-lamassu-admin/src/pages/Cashout/Cashout.js @@ -1,15 +1,30 @@ import { useQuery, useMutation } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' +import { makeStyles } from '@material-ui/core/styles' +import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' +import HelpTooltip from 'src/components/HelpTooltip' import { NamespacedTable as EditableTable } from 'src/components/editableTable' +import { Switch } from 'src/components/inputs' import TitleSection from 'src/components/layout/TitleSection' +import { P, Label2 } from 'src/components/typography' import { fromNamespace, toNamespace } from 'src/utils/config' import Wizard from './Wizard' import { DenominationsSchema, getElements } from './helper' +const useStyles = makeStyles({ + fudgeFactor: { + display: 'flex', + alignItems: 'center', + marginRight: 156 + }, + switchLabel: { + margin: 6 + } +}) + const SAVE_CONFIG = gql` mutation Save($config: JSONObject) { saveConfig(config: $config) @@ -30,6 +45,7 @@ const GET_INFO = gql` ` const CashOut = ({ name: SCREEN_KEY }) => { + const classes = useStyles() const [wizard, setWizard] = useState(false) const [error, setError] = useState(false) const { data } = useQuery(GET_INFO) @@ -47,6 +63,7 @@ const CashOut = ({ name: SCREEN_KEY }) => { } const config = data?.config && fromNamespace(SCREEN_KEY)(data.config) + const fudgeFactorActive = config?.fudgeFactorActive ?? false const locale = data?.config && fromNamespace('locale')(data.config) const machines = data?.machines ?? [] @@ -58,7 +75,31 @@ const CashOut = ({ name: SCREEN_KEY }) => { return ( <> - + +
+

Transaction fudge factor

+ { + save({ fudgeFactorActive: event.target.checked }) + }} + value={fudgeFactorActive} + /> + + {fudgeFactorActive ? 'On' : 'Off'} + + +

+ Automatically accept customer deposits as complete if their + received amount is 10 crypto atoms or less. +

+

+ (Crypto atoms are the smallest unit in each cryptocurrency. E.g., + satoshis in Bitcoin, or wei in Ethereum.) +

+
+
+
- // TODO: there was a disabled link here showing the currency code; restore it )} {lastStep && ( <>

- When enabling cash out, your bill count will be authomatically set - to zero. Make sure you physically put cash inside the cashboxes to + When enabling cash out, your bill count will be automatically set to + zero. Make sure you physically put cash inside the cashboxes to allow the machine to dispense it to your users. If you already did, make sure you set the correct cash out bill count for this machine on your Cashboxes tab under Maintenance. @@ -72,7 +71,7 @@ const WizardStep = ({

When enabling cash out, default commissions will be set. To change commissions for this machine, please go to the Commissions tab under - Settings. where you can set exceptions for each of the available + Settings where you can set exceptions for each of the available cryptocurrencies.

diff --git a/new-lamassu-admin/src/pages/Cashout/helper.js b/new-lamassu-admin/src/pages/Cashout/helper.js index 8eb9a786..25956350 100644 --- a/new-lamassu-admin/src/pages/Cashout/helper.js +++ b/new-lamassu-admin/src/pages/Cashout/helper.js @@ -13,7 +13,7 @@ const getElements = (machines, { fiatCurrency } = {}) => { { name: 'id', header: 'Machine', - width: 254, + width: 200, view: it => machines.find(({ deviceId }) => deviceId === it).name, size: 'sm', editable: false @@ -24,7 +24,8 @@ const getElements = (machines, { fiatCurrency } = {}) => { view: it => `${it} ${fiatCurrency}`, size: 'sm', stripe: true, - width: 265, + width: 200, + textAlign: 'right', input: TextInput }, { @@ -33,7 +34,8 @@ const getElements = (machines, { fiatCurrency } = {}) => { view: it => `${it} ${fiatCurrency}`, size: 'sm', stripe: true, - width: 265, + textAlign: 'right', + width: 200, input: TextInput }, { @@ -41,6 +43,7 @@ const getElements = (machines, { fiatCurrency } = {}) => { header: '0-conf Limit', size: 'sm', stripe: true, + textAlign: 'right', width: 200, input: TextInput } diff --git a/new-lamassu-admin/src/pages/Commissions/Commissions.js b/new-lamassu-admin/src/pages/Commissions/Commissions.js index 140199e7..6091b62e 100644 --- a/new-lamassu-admin/src/pages/Commissions/Commissions.js +++ b/new-lamassu-admin/src/pages/Commissions/Commissions.js @@ -1,12 +1,12 @@ import { useQuery, useMutation } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import * as R from 'ramda' import React from 'react' import { Table as EditableTable } from 'src/components/editableTable' import Section from 'src/components/layout/Section' import TitleSection from 'src/components/layout/TitleSection' -import { fromNamespace, toNamespace } from 'src/utils/config' +import { fromNamespace, toNamespace, namespaces } from 'src/utils/config' import { mainFields, @@ -44,6 +44,9 @@ const Commissions = ({ name: SCREEN_KEY }) => { }) const config = data?.config && fromNamespace(SCREEN_KEY)(data.config) + const currency = R.path(['fiatCurrency'])( + fromNamespace(namespaces.LOCALE)(data?.config) + ) const commission = config && !R.isEmpty(config) ? config : defaults @@ -71,7 +74,7 @@ const Commissions = ({ name: SCREEN_KEY }) => { save={save} validationSchema={schema} data={R.of(commission)} - elements={mainFields(data)} + elements={mainFields(currency)} />
@@ -86,7 +89,7 @@ const Commissions = ({ name: SCREEN_KEY }) => { save={saveOverrides} validationSchema={OverridesSchema} data={commission.overrides ?? []} - elements={overrides(data)} + elements={overrides(data, currency)} />
diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index 5b2bb2e9..0a5cd299 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -4,7 +4,7 @@ import * as Yup from 'yup' import { TextInput } from 'src/components/inputs/formik' import Autocomplete from 'src/components/inputs/formik/Autocomplete.js' -const getOverridesFields = getData => { +const getOverridesFields = (getData, currency) => { const getView = (data, code, compare) => it => { if (!data) return '' @@ -39,7 +39,7 @@ const getOverridesFields = getData => { }, { name: 'cryptoCurrencies', - width: 270, + width: 250, size: 'sm', view: displayCodeArray(cryptoData), input: Autocomplete, @@ -54,69 +54,91 @@ const getOverridesFields = getData => { name: 'cashIn', display: 'Cash-in', width: 140, - input: TextInput + input: TextInput, + textAlign: 'right', + suffix: '%' }, { name: 'cashOut', display: 'Cash-out', width: 140, - input: TextInput + input: TextInput, + textAlign: 'right', + suffix: '%' }, { name: 'fixedFee', display: 'Fixed fee', width: 140, - input: TextInput + input: TextInput, + doubleHeader: 'Cash-in only', + textAlign: 'right', + suffix: currency }, { name: 'minimumTx', display: 'Minimun Tx', width: 140, - input: TextInput + input: TextInput, + doubleHeader: 'Cash-in only', + textAlign: 'right', + suffix: currency } ] } -const mainFields = auxData => [ +const mainFields = currency => [ { name: 'cashIn', display: 'Cash-in', width: 169, size: 'lg', - input: TextInput + input: TextInput, + suffix: '%' }, { name: 'cashOut', display: 'Cash-out', width: 169, size: 'lg', - input: TextInput + input: TextInput, + suffix: '%' }, { name: 'fixedFee', display: 'Fixed fee', width: 169, size: 'lg', - input: TextInput + doubleHeader: 'Cash-in only', + textAlign: 'center', + input: TextInput, + suffix: currency }, { name: 'minimumTx', display: 'Minimun Tx', width: 169, size: 'lg', - input: TextInput + doubleHeader: 'Cash-in only', + textAlign: 'center', + input: TextInput, + suffix: currency } ] -const overrides = auxData => { +const overrides = (auxData, currency) => { const getData = R.path(R.__, auxData) - return getOverridesFields(getData) + return getOverridesFields(getData, currency) } const schema = Yup.object().shape({ - cashIn: Yup.number().required('Required'), - cashOut: Yup.number().required('Required'), + cashIn: Yup.number() + .max(100) + .required('Required'), + cashOut: Yup.number() + .max(100) + .required('Required'), fixedFee: Yup.number().required('Required'), minimumTx: Yup.number().required('Required') }) @@ -124,8 +146,12 @@ const schema = Yup.object().shape({ const OverridesSchema = Yup.object().shape({ machine: Yup.string().required('Required'), cryptoCurrencies: Yup.array().required('Required'), - cashIn: Yup.number().required('Required'), - cashOut: Yup.number().required('Required'), + cashIn: Yup.number() + .max(100) + .required('Required'), + cashOut: Yup.number() + .max(100) + .required('Required'), fixedFee: Yup.number().required('Required'), minimumTx: Yup.number().required('Required') }) diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js index 7bec278b..fa7973b5 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js @@ -1,23 +1,23 @@ -import { makeStyles } from '@material-ui/core/styles' +import { useQuery, useMutation } from '@apollo/react-hooks' +import { makeStyles, Breadcrumbs, Box } from '@material-ui/core' +import NavigateNextIcon from '@material-ui/icons/NavigateNext' +import gql from 'graphql-tag' import * as R from 'ramda' import React, { memo } from 'react' -import { useQuery, useMutation } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' import { useHistory, useParams } from 'react-router-dom' -import Breadcrumbs from '@material-ui/core/Breadcrumbs' -import NavigateNextIcon from '@material-ui/icons/NavigateNext' +import { ActionButton } from 'src/components/buttons' +import { Label1, Label2 } from 'src/components/typography' import { OVERRIDE_AUTHORIZED, OVERRIDE_REJECTED } from 'src/pages/Customers/components/propertyCard' -import { ActionButton } from 'src/components/buttons' -import { Label1 } from 'src/components/typography' -import { ReactComponent as BlockReversedIcon } from 'src/styling/icons/button/block/white.svg' -import { ReactComponent as BlockIcon } from 'src/styling/icons/button/block/zodiac.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 BlockReversedIcon } from 'src/styling/icons/button/block/white.svg' +import { ReactComponent as BlockIcon } from 'src/styling/icons/button/block/zodiac.svg' +import styles from './CustomerProfile.styles' import { CustomerDetails, IdDataCard, @@ -25,9 +25,8 @@ import { IdCardPhotoCard, TransactionsList } from './components' -import { mainStyles } from './Customers.styles' -const useStyles = makeStyles(mainStyles) +const useStyles = makeStyles(styles) const GET_CUSTOMER = gql` query customer($customerId: ID!) { @@ -96,8 +95,7 @@ const CustomerProfile = memo(() => { const { data: customerResponse, refetch: getCustomer } = useQuery( GET_CUSTOMER, { - variables: { customerId }, - fetchPolicy: 'no-cache' + variables: { customerId } } ) @@ -125,24 +123,25 @@ const CustomerProfile = memo(() => { return ( <> } aria-label="breadcrumb"> history.push('/compliance/customers')}> Customers - - {R.path(['name'])(customerData)} - + + Rafael{R.path(['name'])(customerData)} +
-
+ -
- Actions +
+ Actions { {`${blocked ? 'Authorize' : 'Block'} customer`}
-
-
+ + { customerData={customerData} updateCustomer={updateCustomer} /> -
+
diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js new file mode 100644 index 00000000..4bc96d91 --- /dev/null +++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.styles.js @@ -0,0 +1,15 @@ +import { comet } from 'src/styling/variables' + +export default { + labelLink: { + cursor: 'pointer', + color: comet + }, + breadcrumbs: { + margin: [[20, 0]] + }, + actionLabel: { + color: comet, + margin: [[4, 0]] + } +} diff --git a/new-lamassu-admin/src/pages/Customers/Customers.js b/new-lamassu-admin/src/pages/Customers/Customers.js index 4e0402df..2426ae5a 100644 --- a/new-lamassu-admin/src/pages/Customers/Customers.js +++ b/new-lamassu-admin/src/pages/Customers/Customers.js @@ -1,5 +1,5 @@ import { useQuery } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import * as R from 'ramda' import React from 'react' import { useHistory } from 'react-router-dom' diff --git a/new-lamassu-admin/src/pages/Customers/CustomersList.js b/new-lamassu-admin/src/pages/Customers/CustomersList.js index 97d80980..fd59f1d5 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomersList.js +++ b/new-lamassu-admin/src/pages/Customers/CustomersList.js @@ -9,9 +9,9 @@ import DataTable from 'src/components/tables/DataTable' 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 { mainStyles } from './Customers.styles' +import styles from './CustomersList.styles' -const useStyles = makeStyles(mainStyles) +const useStyles = makeStyles(styles) const CustomersList = ({ data, onClick }) => { const classes = useStyles() diff --git a/new-lamassu-admin/src/pages/Customers/Customers.styles.js b/new-lamassu-admin/src/pages/Customers/CustomersList.styles.js similarity index 73% rename from new-lamassu-admin/src/pages/Customers/Customers.styles.js rename to new-lamassu-admin/src/pages/Customers/CustomersList.styles.js index 2f8bc796..45919e70 100644 --- a/new-lamassu-admin/src/pages/Customers/Customers.styles.js +++ b/new-lamassu-admin/src/pages/Customers/CustomersList.styles.js @@ -1,39 +1,17 @@ import typographyStyles from 'src/components/typography/styles' import baseStyles from 'src/pages/Logs.styles' -import { zircon, primaryColor, comet } from 'src/styling/variables' +import { zircon, primaryColor } from 'src/styling/variables' const { label1 } = typographyStyles const { titleWrapper, titleAndButtonsContainer } = baseStyles -const mainStyles = { - rightAligned: { - display: 'flex', - flexFlow: 'column nowrap', - right: 0 - }, - actionButton: { - height: 28 - }, +export default { titleWrapper, titleAndButtonsContainer, - header: { - display: 'flex', - flex: 1, - justifyContent: 'space-between' - }, - customerDetails: { - display: 'flex', - flex: 1 - }, row: { display: 'flex', flexFlow: 'row nowrap' }, - rowCenterAligned: { - display: 'flex', - flexFlow: 'row nowrap', - alignItems: 'center' - }, rowSpaceBetween: { display: 'flex', flexFlow: 'row nowrap', @@ -50,17 +28,6 @@ const mainStyles = { textInput: { width: 144 }, - label1: { - fontFamily: 'MuseoSans', - fontSize: 12, - fontWeight: 500, - fontStretch: 'normal', - fontStyle: 'normal', - lineHeight: 1.33, - letterSpacing: 'normal', - color: comet, - margin: [[4, 0]] - }, p: { fontFamily: 'MuseoSans', fontSize: 14, @@ -71,9 +38,6 @@ const mainStyles = { letterSpacing: 'normal', color: primaryColor }, - bold: { - fontWeight: 'bold' - }, txId: { fontFamily: 'MuseoSans', whiteSpace: 'nowrap', @@ -106,7 +70,7 @@ const mainStyles = { height: 92, borderRadius: 8, backgroundColor: zircon, - margin: [[15, 28, 0, 0]], + margin: [[0, 28, 0, 0]], padding: [[30]], alignItems: 'center', justifyContent: 'space-between' @@ -124,9 +88,6 @@ const mainStyles = { height: 240, margin: [[32, 0, 0, 0]] }, - labelLink: { - cursor: 'pointer' - }, field: { position: 'relative', width: 144, @@ -158,5 +119,3 @@ const mainStyles = { maxHeight: 97 } } - -export { mainStyles } diff --git a/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js b/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js index 8e1fad4a..4f704fe7 100644 --- a/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js +++ b/new-lamassu-admin/src/pages/Customers/components/CustomerDetails.js @@ -1,18 +1,18 @@ -import { makeStyles } from '@material-ui/core/styles' -import * as R from 'ramda' +import { makeStyles, Box } from '@material-ui/core' import moment from 'moment' +import * as R from 'ramda' import React, { memo } from 'react' import { H2 } from 'src/components/typography' 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 { mainStyles } from '../Customers.styles' import { ifNotNull } from '../../../utils/nullCheck' +import styles from '../CustomersList.styles' import FrontCameraPhoto from './FrontCameraPhoto' -const useStyles = makeStyles(mainStyles) +const useStyles = makeStyles(styles) const CustomerDetails = memo(({ customer }) => { const classes = useStyles() @@ -61,30 +61,30 @@ const CustomerDetails = memo(({ customer }) => { ] return ( -
+
-
-

{R.path(['name'])(customer)}

-
-
+ +

Rafael{R.path(['name'])(customer)}

+
+ {elements.map(({ size, header }, idx) => (
{header}
))} -
-
+ + {elements.map(({ size, value }, idx) => (
{value}
))} -
+
-
+ ) }) diff --git a/new-lamassu-admin/src/pages/Customers/components/Field.js b/new-lamassu-admin/src/pages/Customers/components/Field.js index 1ef4191b..42762e12 100644 --- a/new-lamassu-admin/src/pages/Customers/components/Field.js +++ b/new-lamassu-admin/src/pages/Customers/components/Field.js @@ -3,7 +3,7 @@ import React, { memo } from 'react' import { Info3, Label1 } from 'src/components/typography' -import { mainStyles } from '../Customers.styles' +import mainStyles from '../CustomersList.styles' const useStyles = makeStyles(mainStyles) diff --git a/new-lamassu-admin/src/pages/Customers/components/FrontCameraPhoto.js b/new-lamassu-admin/src/pages/Customers/components/FrontCameraPhoto.js index 1af1f31e..8c3af79c 100644 --- a/new-lamassu-admin/src/pages/Customers/components/FrontCameraPhoto.js +++ b/new-lamassu-admin/src/pages/Customers/components/FrontCameraPhoto.js @@ -1,12 +1,11 @@ +import { Paper } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' import React, { memo } from 'react' -import { Paper } from '@material-ui/core' import { ReactComponent as CrossedCameraIcon } from 'src/styling/icons/ID/photo/crossed-camera.svg' +import { URI } from 'src/utils/apollo' -import { mainStyles } from '../Customers.styles' - -import { IMAGES_URI } from './variables' +import mainStyles from '../CustomersList.styles' const useStyles = makeStyles(mainStyles) @@ -16,10 +15,7 @@ const FrontCameraPhoto = memo(({ frontCameraPath }) => { return ( {frontCameraPath ? ( - + ) : ( )} diff --git a/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js b/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js index db7db6eb..9ace389a 100644 --- a/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/IdCardPhotoCard.js @@ -1,19 +1,19 @@ import { makeStyles } from '@material-ui/core/styles' -import * as R from 'ramda' import moment from 'moment' +import * as R from 'ramda' import React, { memo } from 'react' -import { ReactComponent as CrossedCameraIcon } from 'src/styling/icons/ID/photo/crossed-camera.svg' import { PropertyCard, OVERRIDE_AUTHORIZED, OVERRIDE_REJECTED } from 'src/pages/Customers/components/propertyCard' +import { ReactComponent as CrossedCameraIcon } from 'src/styling/icons/ID/photo/crossed-camera.svg' +import { URI } from 'src/utils/apollo' -import { mainStyles } from '../Customers.styles' +import mainStyles from '../CustomersList.styles' import Field from './Field' -import { IMAGES_URI } from './variables' const useStyles = makeStyles(mainStyles) @@ -33,7 +33,7 @@ const IdCardPhotoCard = memo(({ customerData, updateCustomer }) => { {customerData.idCardPhotoPath ? ( new BigNumber(it).toFormat(2) const getConfirmedTotal = list => { return formatNumber( list + .filter(it => !it.errorMsg) .map(it => new BigNumber(it.fiatConfirmedBalance)) .reduce(sumReducer, new BigNumber(0)) ) @@ -63,6 +65,7 @@ const getConfirmedTotal = list => { const getPendingTotal = list => { return formatNumber( list + .filter(it => !it.errorMsg) .map(it => new BigNumber(it.fiatPending)) .reduce(sumReducer, new BigNumber(0)) ) @@ -107,16 +110,29 @@ const Funding = () => { setSelected(fundingResponse?.funding[0]) } - const itemRender = it => { + const itemRender = (it, active) => { + const itemClass = { + [classes.item]: true, + [classes.inactiveItem]: !active + } + const wrapperClass = { + [classes.itemWrapper]: true, + [classes.error]: it.errorMsg + } + return ( -
+
{it.display}
-
- {it.fiatConfirmedBalance} {it.fiatCode} -
-
- {it.confirmedBalance} {it.cryptoCode} -
+ {!it.errorMsg && ( + <> +
+ {it.fiatConfirmedBalance} {it.fiatCode} +
+
+ {it.confirmedBalance} {it.cryptoCode} +
+ + )}
) } @@ -149,7 +165,14 @@ const Funding = () => {
)} - {selected && !viewHistory && ( + {selected && !viewHistory && selected.errorMsg && ( +
+
+ {selected.errorMsg} +
+
+ )} + {selected && !viewHistory && !selected.errorMsg && (

Balance ({selected.display})

diff --git a/new-lamassu-admin/src/pages/Funding.styles.js b/new-lamassu-admin/src/pages/Funding.styles.js index f59405c8..e4a60dff 100644 --- a/new-lamassu-admin/src/pages/Funding.styles.js +++ b/new-lamassu-admin/src/pages/Funding.styles.js @@ -3,7 +3,9 @@ import { disabledColor2, spacer, subheaderColor, - placeholderColor + errorColor, + placeholderColor, + comet } from 'src/styling/variables' const { label1 } = typographyStyles @@ -25,6 +27,9 @@ export default { secondSide: { marginTop: -29 }, + error: { + color: errorColor + }, coinTotal: { margin: `${spacer * 1.5}px 0` }, @@ -51,7 +56,11 @@ export default { extend: label1, margin: 2 }, + inactiveItem: { + color: comet + }, firstItem: { + fontWeight: 700, margin: 2 }, total: { diff --git a/new-lamassu-admin/src/pages/Locales/Locales.js b/new-lamassu-admin/src/pages/Locales/Locales.js index 8ad95a52..cab9cef2 100644 --- a/new-lamassu-admin/src/pages/Locales/Locales.js +++ b/new-lamassu-admin/src/pages/Locales/Locales.js @@ -1,5 +1,5 @@ import { useQuery, useMutation } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import * as R from 'ramda' import React from 'react' diff --git a/new-lamassu-admin/src/pages/Logs.styles.js b/new-lamassu-admin/src/pages/Logs.styles.js index 7fc65eb4..1b93191d 100644 --- a/new-lamassu-admin/src/pages/Logs.styles.js +++ b/new-lamassu-admin/src/pages/Logs.styles.js @@ -37,6 +37,16 @@ export default { fillColumn: { width: '100%' }, + shareButton: { + margin: 8, + display: 'flex', + alignItems: 'center', + fontSize: 12, + padding: [[0, 12]] + }, + shareIcon: { + marginRight: 6 + }, button: { margin: 8 }, @@ -45,9 +55,9 @@ export default { }, buttonsWrapper: { display: 'flex', - marginLeft: 10, + marginLeft: 16, '& > *': { - margin: 'auto 10px' + margin: 'auto 6px' } } } diff --git a/new-lamassu-admin/src/pages/MachineLogs.js b/new-lamassu-admin/src/pages/MachineLogs.js index 1bcd6018..3cdbf040 100644 --- a/new-lamassu-admin/src/pages/MachineLogs.js +++ b/new-lamassu-admin/src/pages/MachineLogs.js @@ -1,13 +1,13 @@ import { useQuery, useMutation } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core/styles' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import moment from 'moment' import * as R from 'ramda' import React, { useState } from 'react' import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper' import Title from 'src/components/Title' -import { FeatureButton, SimpleButton } from 'src/components/buttons' +import { SimpleButton } from 'src/components/buttons' import Sidebar from 'src/components/layout/Sidebar' import { Table, @@ -18,8 +18,8 @@ import { TableCell } from 'src/components/table' import { Info3 } from 'src/components/typography' -import { ReactComponent as DownloadActive } from 'src/styling/icons/button/download/white.svg' -import { ReactComponent as Download } from 'src/styling/icons/button/download/zodiac.svg' +import { ReactComponent as WhiteShareIcon } from 'src/styling/icons/circle buttons/share/white.svg' +import { ReactComponent as ShareIcon } from 'src/styling/icons/circle buttons/share/zodiac.svg' import styles from './Logs.styles' @@ -62,7 +62,6 @@ const Logs = () => { const [selected, setSelected] = useState(null) const [saveMessage, setSaveMessage] = useState(null) - const [anchorEl, setAnchorEl] = useState(null) const deviceId = selected?.deviceId @@ -76,7 +75,6 @@ const Logs = () => { const { data: logsResponse } = useQuery(GET_MACHINE_LOGS, { variables: { deviceId }, - fetchPolicy: 'no-cache', skip: !selected, onCompleted: () => setSaveMessage('') }) @@ -89,13 +87,6 @@ const Logs = () => { return R.path(['deviceId'])(selected) === it.deviceId } - const handleOpenRangePicker = event => { - setAnchorEl(anchorEl ? null : event.currentTarget) - } - - const open = Boolean(anchorEl) - const id = open ? 'date-range-popover' : undefined - return ( <>
@@ -103,25 +94,17 @@ const Logs = () => { Machine Logs {logsResponse && (
- log.timestamp} /> Share with Lamassu diff --git a/new-lamassu-admin/src/pages/Maintenance/Cashboxes.js b/new-lamassu-admin/src/pages/Maintenance/Cashboxes.js index adfeea98..d5893c00 100644 --- a/new-lamassu-admin/src/pages/Maintenance/Cashboxes.js +++ b/new-lamassu-admin/src/pages/Maintenance/Cashboxes.js @@ -1,5 +1,5 @@ import { useQuery, useMutation } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import React from 'react' import * as Yup from 'yup' diff --git a/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js index 1e39947e..720fd242 100644 --- a/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js +++ b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js @@ -1,29 +1,20 @@ import { useMutation } from '@apollo/react-hooks' import { Dialog, DialogContent } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' -import { gql } from 'apollo-boost' -import classnames from 'classnames' +import gql from 'graphql-tag' import moment from 'moment' import React, { useState } from 'react' -import { H4 } from 'src/components/typography' +import { DialogTitle, ConfirmDialog } from 'src/components/ConfirmDialog' +import { Status } from 'src/components/Status' +import ActionButton from 'src/components/buttons/ActionButton' +import { Label1, H4 } from 'src/components/typography' +import { ReactComponent as RebootReversedIcon } from 'src/styling/icons/button/reboot/white.svg' +import { ReactComponent as RebootIcon } from 'src/styling/icons/button/reboot/zodiac.svg' +import { ReactComponent as UnpairReversedIcon } from 'src/styling/icons/button/unpair/white.svg' +import { ReactComponent as UnpairIcon } from 'src/styling/icons/button/unpair/zodiac.svg' -import { DialogTitle, ConfirmDialog } from '../../components/ConfirmDialog' -import { Status } from '../../components/Status' -import ActionButton from '../../components/buttons/ActionButton' -import { ReactComponent as DownloadReversedIcon } from '../../styling/icons/button/download/white.svg' -import { ReactComponent as DownloadIcon } from '../../styling/icons/button/download/zodiac.svg' -import { ReactComponent as RebootReversedIcon } from '../../styling/icons/button/reboot/white.svg' -import { ReactComponent as RebootIcon } from '../../styling/icons/button/reboot/zodiac.svg' -import { ReactComponent as ShutdownReversedIcon } from '../../styling/icons/button/shut down/white.svg' -import { ReactComponent as ShutdownIcon } from '../../styling/icons/button/shut down/zodiac.svg' -import { ReactComponent as UnpairReversedIcon } from '../../styling/icons/button/unpair/white.svg' -import { ReactComponent as UnpairIcon } from '../../styling/icons/button/unpair/zodiac.svg' -import { zircon } from '../../styling/variables' -import { - detailsRowStyles, - labelStyles -} from '../Transactions/Transactions.styles' +import styles from './MachineDetailsCard.styles' const MACHINE_ACTION = gql` mutation MachineAction($deviceId: ID!, $action: MachineAction!) { @@ -33,30 +24,18 @@ const MACHINE_ACTION = gql` } ` -const colDivider = { - background: zircon, - width: 2 -} - -const inlineChip = { - marginInlineEnd: '0.25em' -} - -const useLStyles = makeStyles(labelStyles) +const useStyles = makeStyles(styles) const Label = ({ children }) => { - const classes = useLStyles() - - return
{children}
+ const classes = useStyles() + return {children} } -const useMDStyles = makeStyles({ ...detailsRowStyles, colDivider, inlineChip }) - const MachineDetailsRow = ({ it: machine }) => { const [errorDialog, setErrorDialog] = useState(false) const [dialogOpen, setOpen] = useState(false) const [actionMessage, setActionMessage] = useState(null) - const classes = useMDStyles() + const classes = useStyles() const unpairDialog = () => setOpen(true) @@ -79,157 +58,111 @@ const MachineDetailsRow = ({ it: machine }) => { {actionMessage}
-
-
-
-
-
-
- -
- {machine.statuses.map((status, index) => ( - - ))} -
-
-
- -
- {machine.statuses.map((...[, index]) => ( - - ))} -
-
-
+
+
+
+ +
+ {machine.statuses.map((status, index) => ( + + ))} +
+
+
+ +
+ {machine.statuses.map((...[, index]) => ( + // TODO support articles + + ))} +
+
+
+
+
+
+
+
+ +
{machine.model ?? 'unknown'}
+
+
+ +
+ {machine.pairedAt + ? moment(machine.pairedAt).format('YYYY-MM-DD HH:mm:ss') + : 'N/A'}
-
-
-
-
-
-
- -
{machine.machineModel}
-
-
- -
{machine.machineLocation}
-
-
-
-
- -
-
-
-
- -
- {moment(machine.pairedAt).format('YYYY-MM-DD HH:mm:ss')} -
-
-
- -
- {machine.softwareVersion && ( - - {machine.softwareVersion} - - )} - - Update - -
-
-
-
-
- -
-
-
-
- -
{machine.printer || 'unknown'}
-
-
- -
- - Unpair - - { - setOpen(false) - machineAction({ - variables: { - deviceId: machine.deviceId, - action: 'unpair' - } - }) - }} - onDissmised={() => { - setOpen(false) - }} - /> - { - machineAction({ - variables: { - deviceId: machine.deviceId, - action: 'reboot' - } - }) - }}> - Reboot - - { - machineAction({ - variables: { - deviceId: machine.deviceId, - action: 'shutdown' - } - }) - }}> - Shutdown - -
-
-
+
+
+ +
+ + Unpair + + { + setOpen(false) + machineAction({ + variables: { + deviceId: machine.deviceId, + action: 'unpair' + } + }) + }} + onDissmised={() => { + setOpen(false) + }} + /> + { + machineAction({ + variables: { + deviceId: machine.deviceId, + action: 'reboot' + } + }) + }}> + Reboot + + { + machineAction({ + variables: { + deviceId: machine.deviceId, + action: 'restartServices' + } + }) + }}> + Restart Services +
diff --git a/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.styles.js b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.styles.js new file mode 100644 index 00000000..5d80f71e --- /dev/null +++ b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.styles.js @@ -0,0 +1,60 @@ +import { fade } from '@material-ui/core/styles/colorManipulator' + +import { offColor, comet } from 'src/styling/variables' + +export default { + wrapper: { + display: 'flex', + marginTop: 24, + marginBottom: 32, + fontSize: 14 + }, + column1: { + width: 600 + }, + column2: { + flex: 1 + }, + lastRow: { + display: 'flex', + flexDirection: 'row' + }, + row: { + display: 'flex', + flexDirection: 'row', + marginBottom: 36 + }, + actionRow: { + display: 'flex', + flexDirection: 'row', + marginLeft: -4 + }, + action: { + marginRight: 4, + marginLeft: 4 + }, + dialog: { + width: 434 + }, + label: { + color: offColor, + margin: [[0, 0, 6, 0]] + }, + chips: { + marginLeft: -2 + }, + status: { + width: 248 + }, + machineModel: { + width: 198 + }, + separator: { + width: 1, + height: 170, + zIndex: 1, + marginRight: 60, + marginLeft: 'auto', + background: fade(comet, 0.5) + } +} diff --git a/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js b/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js index 78a9d0b1..acd39a42 100644 --- a/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js +++ b/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js @@ -1,6 +1,6 @@ import { useQuery } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import moment from 'moment' import * as R from 'ramda' import React from 'react' @@ -20,6 +20,8 @@ const GET_MACHINES = gql` machines { name deviceId + lastPing + pairedAt paired cashbox cassette1 @@ -42,35 +44,28 @@ const MachineStatus = () => { const elements = [ { header: 'Machine Name', - width: 232, + width: 250, size: 'sm', textAlign: 'left', view: m => m.name }, { header: 'Status', - width: 349, + width: 350, size: 'sm', textAlign: 'left', view: m => }, { header: 'Last ping', - width: 192, + width: 200, size: 'sm', textAlign: 'left', - view: m => moment(m.lastPing).fromNow() - }, - { - header: 'Ping Time', - width: 155, - size: 'sm', - textAlign: 'left', - view: m => m.pingTime || 'unknown' + view: m => (m.lastPing ? moment(m.lastPing).fromNow() : 'unknown') }, { header: 'Software Version', - width: 201, + width: 200, size: 'sm', textAlign: 'left', view: m => m.softwareVersion || 'unknown' diff --git a/new-lamassu-admin/src/pages/Notifications/Notifications.js b/new-lamassu-admin/src/pages/Notifications/Notifications.js index ffcd3fac..c2b54edd 100644 --- a/new-lamassu-admin/src/pages/Notifications/Notifications.js +++ b/new-lamassu-admin/src/pages/Notifications/Notifications.js @@ -1,5 +1,5 @@ import { useQuery, useMutation } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' diff --git a/new-lamassu-admin/src/pages/Notifications/sections/FiatBalanceOverrides.js b/new-lamassu-admin/src/pages/Notifications/sections/FiatBalanceOverrides.js index 2e6484e9..98dc939e 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/FiatBalanceOverrides.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/FiatBalanceOverrides.js @@ -72,6 +72,7 @@ const FiatBalanceOverrides = ({ section }) => { display: 'Cash-out 1', width: 155, textAlign: 'right', + doubleHeader: 'Cash-out (Cassette Empty)', bold: true, input: TextInputFormik, suffix: 'notes' @@ -81,6 +82,7 @@ const FiatBalanceOverrides = ({ section }) => { display: 'Cash-out 2', width: 155, textAlign: 'right', + doubleHeader: 'Cash-out (Cassette Empty)', bold: true, input: TextInputFormik, suffix: 'notes' diff --git a/new-lamassu-admin/src/pages/OperatorInfo/CoinATMRadar/CoinATMRadar.js b/new-lamassu-admin/src/pages/OperatorInfo/CoinATMRadar/CoinATMRadar.js index 0736dbf8..fe867ab9 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/CoinATMRadar/CoinATMRadar.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/CoinATMRadar/CoinATMRadar.js @@ -1,6 +1,6 @@ import { useQuery, useMutation } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core/styles' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState, memo } from 'react' @@ -47,7 +47,6 @@ const CoinATMRadar = memo(() => { const classes = useStyles() - // TODO: treat errors on useMutation and useQuery const [saveConfig] = useMutation(SAVE_CONFIG, { onCompleted: configResponse => setCoinAtmRadarConfig( diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js b/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js index 8b1adfe3..98b38c75 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js @@ -1,8 +1,8 @@ import { useQuery, useMutation } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core' -import { gql } from 'apollo-boost' import classnames from 'classnames' import { Form, Formik, Field as FormikField } from 'formik' +import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' import * as Yup from 'yup' @@ -22,14 +22,14 @@ import { } from './OperatorInfo.styles' const validationSchema = Yup.object().shape({ - active: Yup.boolean().required(), - name: Yup.string().required(), - phone: Yup.string().required(), + active: Yup.boolean(), + name: Yup.string(), + phone: Yup.string(), email: Yup.string() .email('Please enter a valid email address') .required(), - website: Yup.string().required(), - companyNumber: Yup.string().required() + website: Yup.string(), + companyNumber: Yup.string() }) const fieldStyles = { diff --git a/new-lamassu-admin/src/pages/OperatorInfo/OperatorInfo.js b/new-lamassu-admin/src/pages/OperatorInfo/OperatorInfo.js index 998f0c0f..191a3045 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/OperatorInfo.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/OperatorInfo.js @@ -16,6 +16,7 @@ const styles = { height: '100%' }, content: { + flex: 1, marginLeft: 48, paddingTop: 15 } diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting/ReceiptPrinting.js b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting/ReceiptPrinting.js index 556637ee..386ab8ab 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting/ReceiptPrinting.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting/ReceiptPrinting.js @@ -1,6 +1,6 @@ // import { makeStyles } from '@material-ui/core/styles' import { useQuery, useMutation } from '@apollo/react-hooks' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState, memo } from 'react' @@ -49,10 +49,10 @@ const receiptPrintingOptions = [ code: 'off', display: 'Off' }, - { - code: 'optional', - display: 'Optional (ask user)' - }, + // { + // code: 'optional', + // display: 'Optional (ask user)' + // }, { code: 'on', display: 'On' @@ -64,10 +64,8 @@ const ReceiptPrinting = memo(() => { // const classes = useStyles() - // TODO: treat errors on useMutation and useQuery const [saveConfig] = useMutation(SAVE_CONFIG, { onCompleted: configResponse => { - console.log(configResponse.saveConfig) return setReceiptPrintingConfig( fromNamespace(namespaces.RECEIPT, configResponse.saveConfig) ) @@ -87,7 +85,6 @@ const ReceiptPrinting = memo(() => { }) if (!receiptPrintingConfig) return null - console.log(receiptPrintingConfig) return ( <> diff --git a/new-lamassu-admin/src/pages/OperatorInfo/TermsConditions.js b/new-lamassu-admin/src/pages/OperatorInfo/TermsConditions.js index ccfa0e52..ae21e3cc 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/TermsConditions.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/TermsConditions.js @@ -1,8 +1,8 @@ import { useQuery, useMutation } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core' -import { gql } from 'apollo-boost' import classnames from 'classnames' import { Form, Formik, Field } from 'formik' +import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' import * as Yup from 'yup' @@ -83,25 +83,30 @@ const TermsConditions = () => { { name: 'title', label: 'Screen title', - value: formData.title ?? '' + value: formData.title ?? '', + width: 282 }, { name: 'text', label: 'Text content', value: formData.text ?? '', - multiline: true + width: 502, + multiline: true, + rows: 6 }, { name: 'acceptButtonText', label: 'Accept button text', value: formData.acceptButtonText ?? '', - placeholder: 'I accept' + placeholder: 'I accept', + width: 282 }, { name: 'cancelButtonText', label: 'Cancel button text', value: formData.cancelButtonText ?? '', - placeholder: 'Cancel' + placeholder: 'Cancel', + width: 282 } ] @@ -145,10 +150,12 @@ const TermsConditions = () => { id={f.name} name={f.name} component={TextInputFormik} + width={f.width} placeholder={f.placeholder} type="text" label={f.label} multiline={f.multiline} + rows={f.rows} rowsMax="6" onFocus={() => setError(null)} /> diff --git a/new-lamassu-admin/src/pages/ServerLogs.js b/new-lamassu-admin/src/pages/ServerLogs.js index c7b791df..624261b5 100644 --- a/new-lamassu-admin/src/pages/ServerLogs.js +++ b/new-lamassu-admin/src/pages/ServerLogs.js @@ -1,6 +1,6 @@ import { useQuery, useMutation } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core' -import { gql } from 'apollo-boost' +import gql from 'graphql-tag' import moment from 'moment' import * as R from 'ramda' import React, { useState } from 'react' @@ -8,7 +8,7 @@ import React, { useState } from 'react' import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper' import Title from 'src/components/Title' import Uptime from 'src/components/Uptime' -import { FeatureButton, SimpleButton } from 'src/components/buttons' +import { SimpleButton } from 'src/components/buttons' import { Select } from 'src/components/inputs' import { Table, @@ -20,8 +20,8 @@ import { } from 'src/components/table' import { Info3 } from 'src/components/typography' import typographyStyles from 'src/components/typography/styles' -import { ReactComponent as DownloadActive } from 'src/styling/icons/button/download/white.svg' -import { ReactComponent as Download } from 'src/styling/icons/button/download/zodiac.svg' +import { ReactComponent as WhiteShareIcon } from 'src/styling/icons/circle buttons/share/white.svg' +import { ReactComponent as ShareIcon } from 'src/styling/icons/circle buttons/share/zodiac.svg' import { offColor } from 'src/styling/variables' import logsStyles from './Logs.styles' @@ -41,7 +41,6 @@ const localStyles = { margin: 'auto 0 auto 0' }, headerLine2: { - height: 60, display: 'flex', justifyContent: 'space-between', marginBottom: 24 @@ -61,24 +60,14 @@ const formatDate = date => { return moment(date).format('YYYY-MM-DD HH:mm') } -const GET_VERSION = gql` - query { - serverVersion - } -` - -const GET_UPTIME = gql` +const GET_DATA = gql` { + serverVersion uptime { name state uptime } - } -` - -const GET_SERVER_LOGS = gql` - { serverLogs { logLevel id @@ -87,7 +76,6 @@ const GET_SERVER_LOGS = gql` } } ` - const SUPPORT_LOGS = gql` mutation ServerSupportLogs { serverSupportLogs { @@ -101,30 +89,19 @@ const Logs = () => { const [saveMessage, setSaveMessage] = useState(null) const [logLevel, setLogLevel] = useState(SHOW_ALL) - const [anchorEl, setAnchorEl] = useState(null) - const { data: version } = useQuery(GET_VERSION) - const serverVersion = version?.serverVersion - - const { data: uptimeResponse } = useQuery(GET_UPTIME) - const processStates = uptimeResponse?.uptime ?? [] - - const { data: logsResponse } = useQuery(GET_SERVER_LOGS, { - fetchPolicy: 'no-cache', + const { data } = useQuery(GET_DATA, { onCompleted: () => setSaveMessage('') }) + const serverVersion = data?.serverVersion + const processStates = data?.uptime ?? [] + const [sendSnapshot, { loading }] = useMutation(SUPPORT_LOGS, { onError: () => setSaveMessage('Failure saving snapshot'), onCompleted: () => setSaveMessage('✓ Saved latest snapshot') }) - const handleOpenRangePicker = event => { - setAnchorEl(anchorEl ? null : event.currentTarget) - } - - const open = Boolean(anchorEl) - const id = open ? 'date-range-popover' : undefined const getLogLevels = R.compose( R.prepend(SHOW_ALL), R.uniq, @@ -137,27 +114,19 @@ const Logs = () => {
Server - {logsResponse && ( + {data && (
- log.timestamp} /> Share with Lamassu @@ -170,11 +139,11 @@ const Logs = () => {
- {logsResponse && ( + {data && (