From 7d9c46824229c66a14f03603e38db3eead4d316b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 24 May 2022 18:32:38 +0100 Subject: [PATCH 01/53] fix: remove cash-in transaction retry --- lib/cash-in/cash-in-tx.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 8f7703cb..cc676554 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -148,18 +148,17 @@ function postProcess (r, pi, isBlacklisted, addressReuse, walletScore) { } }) .catch(err => { - // Important: We don't know what kind of error this is - // so not safe to assume that funds weren't sent. - // Therefore, don't set sendPending to false except for - // errors (like InsufficientFundsError) that are guaranteed - // not to send. - const sendPending = err.name !== 'InsufficientFundsError' + // Important: We don't know what kind of error this is + // so not safe to assume that funds weren't sent. + + // Setting sendPending to true ensures that the transaction gets + // silently terminated and no retries are done return { sendTime: 'now()^', error: err.message, errorCode: err.name, - sendPending + sendPending: true } }) .then(sendRec => { From 5567f7800538143c0b4b7c7f41d687b262ad9419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 14 Jun 2022 18:17:15 +0100 Subject: [PATCH 02/53] fix: locales wizard account save function --- new-lamassu-admin/src/pages/Locales/Locales.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/new-lamassu-admin/src/pages/Locales/Locales.js b/new-lamassu-admin/src/pages/Locales/Locales.js index 3a820c8a..1afdf1ce 100644 --- a/new-lamassu-admin/src/pages/Locales/Locales.js +++ b/new-lamassu-admin/src/pages/Locales/Locales.js @@ -61,8 +61,9 @@ const GET_DATA = gql` ` const SAVE_CONFIG = gql` - mutation Save($config: JSONObject) { + mutation Save($config: JSONObject, $accounts: JSONObject) { saveConfig(config: $config) + saveAccounts(accounts: $accounts) } ` @@ -134,9 +135,9 @@ const Locales = ({ name: SCREEN_KEY }) => { return save(newConfig) } - const save = config => { + const save = (config, accounts) => { setDataToSave(null) - return saveConfig({ variables: { config } }) + return saveConfig({ variables: { config, accounts } }) } const saveOverrides = it => { @@ -162,8 +163,8 @@ const Locales = ({ name: SCREEN_KEY }) => { const onEditingDefault = (it, editing) => setEditingDefault(editing) const onEditingOverrides = (it, editing) => setEditingOverrides(editing) - const wizardSave = it => - save(toNamespace(namespaces.WALLETS)(it)).then(it => { + const wizardSave = (config, accounts) => + save(toNamespace(namespaces.WALLETS)(config), accounts).then(it => { onChangeFunction() setOnChangeFunction(null) return it From e9a7cf2903e3a34637cc7e733827a304f53ca8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Fri, 1 Jul 2022 18:09:01 +0100 Subject: [PATCH 03/53] fix: add fallbackfee and rpcworkqueue values on bitcoind.conf --- lib/blockchain/bitcoin.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/blockchain/bitcoin.js b/lib/blockchain/bitcoin.js index 12c96815..80b6dd3a 100644 --- a/lib/blockchain/bitcoin.js +++ b/lib/blockchain/bitcoin.js @@ -55,6 +55,20 @@ function updateCore (coinRec, isCurrentlyRunning) { common.es(`echo "\nlistenonion=0" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`) } + if (common.es(`grep "fallbackfee=" ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf || true`)) { + common.logger.info(`fallbackfee already defined, skipping...`) + } else { + common.logger.info(`Setting 'fallbackfee=0.00005' in config file...`) + common.es(`echo "\nfallbackfee=0.00005" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`) + } + + if (common.es(`grep "rpcworkqueue=" ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf || true`)) { + common.logger.info(`rpcworkqueue already defined, skipping...`) + } else { + common.logger.info(`Setting 'rpcworkqueue=2000' in config file...`) + common.es(`echo "\nrpcworkqueue=2000" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`) + } + if (isCurrentlyRunning && !isDevMode()) { common.logger.info('Starting wallet...') common.es(`sudo supervisorctl start bitcoin`) From 8bd481c8e42880b0f36d67ac2b03364040150eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Wed, 20 Jul 2022 18:29:05 +0100 Subject: [PATCH 04/53] fix: transaction details ID button popper positioning --- new-lamassu-admin/src/components/Popper.js | 46 +++++++++++++------ .../src/components/buttons/IDButton.js | 6 ++- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/new-lamassu-admin/src/components/Popper.js b/new-lamassu-admin/src/components/Popper.js index db01740d..a933e39d 100644 --- a/new-lamassu-admin/src/components/Popper.js +++ b/new-lamassu-admin/src/components/Popper.js @@ -105,20 +105,29 @@ const Popover = ({ const classes = useStyles() - const arrowClasses = { + const getArrowClasses = placement => ({ [classes.arrow]: true, - [classes.arrowBottom]: props.placement === 'bottom', - [classes.arrowTop]: props.placement === 'top', - [classes.arrowRight]: props.placement === 'right', - [classes.arrowLeft]: props.placement === 'left' + [classes.arrowBottom]: placement === 'bottom', + [classes.arrowTop]: placement === 'top', + [classes.arrowRight]: placement === 'right', + [classes.arrowLeft]: placement === 'left' + }) + + const flipPlacements = { + top: ['bottom'], + bottom: ['top'], + left: ['right'], + right: ['left'] } - const modifiers = R.merge(props.modifiers, { + const modifiers = R.mergeDeepLeft(props.modifiers, { flip: { - enabled: false + enabled: R.defaultTo(false, props.flip), + allowedAutoPlacements: flipPlacements[props.placement], + boundary: 'clippingParents' }, preventOverflow: { - enabled: true, + enabled: R.defaultTo(true, props.preventOverflow), boundariesElement: 'scrollParent' }, offset: { @@ -126,7 +135,7 @@ const Popover = ({ offset: '0, 10' }, arrow: { - enabled: true, + enabled: R.defaultTo(true, props.showArrow), element: arrowRef }, computeStyle: { @@ -134,6 +143,12 @@ const Popover = ({ } }) + if (props.preventOverflow === false) { + modifiers.hide = { + enabled: false + } + } + return ( <> - - - {children} - + {({ placement }) => ( + + + {children} + + )} ) diff --git a/new-lamassu-admin/src/components/buttons/IDButton.js b/new-lamassu-admin/src/components/buttons/IDButton.js index e6e9b55a..15c55602 100644 --- a/new-lamassu-admin/src/components/buttons/IDButton.js +++ b/new-lamassu-admin/src/components/buttons/IDButton.js @@ -56,7 +56,8 @@ const styles = { alignItems: 'center', borderRadius: 4, '& img': { - maxHeight: 145 + height: 145, + minWidth: 200 } } } @@ -127,7 +128,8 @@ const IDButton = memo( anchorEl={anchorEl} onClose={handleClose} arrowSize={3} - placement="top"> + placement="top" + flip>
{children}
From 61130157563e3d57f03f5a820e850aaae3bf956a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Jul 2022 18:09:56 +0100 Subject: [PATCH 05/53] fix: add click away listener to tooltips --- new-lamassu-admin/src/components/Tooltip.js | 47 ++++++++++----------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/new-lamassu-admin/src/components/Tooltip.js b/new-lamassu-admin/src/components/Tooltip.js index 2fa5b7f9..3808c286 100644 --- a/new-lamassu-admin/src/components/Tooltip.js +++ b/new-lamassu-admin/src/components/Tooltip.js @@ -69,30 +69,29 @@ const HoverableTooltip = memo(({ parentElements, children, width }) => { const handler = usePopperHandler(width) return ( -
- {!R.isNil(parentElements) && ( -
- {parentElements} -
- )} - {R.isNil(parentElements) && ( - - )} - -
{children}
-
-
+ +
+ {!R.isNil(parentElements) && ( +
+ {parentElements} +
+ )} + {R.isNil(parentElements) && ( + + )} + +
{children}
+
+
+
) }) From 65e5c12b9221423e01feb8f1b3142ac3e834ce5c Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 26 Sep 2022 14:40:59 +0200 Subject: [PATCH 06/53] fix: display error status --- .../src/pages/Transactions/CopyToClipboard.js | 4 +++- .../src/pages/Transactions/DetailsCard.js | 15 ++++++++------- .../src/pages/Transactions/DetailsCard.styles.js | 4 ++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js b/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js index 1c14a2e3..b6c63914 100644 --- a/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js +++ b/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js @@ -17,6 +17,7 @@ const CopyToClipboard = ({ buttonClassname, children, wrapperClassname, + removeSpace = true, ...props }) => { const [anchorEl, setAnchorEl] = useState(null) @@ -46,7 +47,8 @@ const CopyToClipboard = ({ {children}
- +
- {getStatusDetails(tx) ? ( - -

{getStatusDetails(tx)}

-
- ) : ( - errorElements - )} + {errorElements} {((tx.txClass === 'cashOut' && getStatus(tx) === 'Pending') || (tx.txClass === 'cashIn' && getStatus(tx) === 'Batched')) && ( Date: Thu, 20 Oct 2022 23:25:33 +0200 Subject: [PATCH 07/53] fix: typeface --- new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js index a55d40db..e7ec6e01 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js @@ -1,7 +1,7 @@ import typographyStyles from 'src/components/typography/styles' import { offColor, comet, white, tomato } from 'src/styling/variables' -const { p } = typographyStyles +const { p, label3 } = typographyStyles export default { wrapper: { @@ -139,6 +139,7 @@ export default { width: 250 }, errorCopy: { + extend: label3, lineBreak: 'normal', maxWidth: 180 } From f079a2926b3a528a453f3ec7ea31475ce643c423 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Wed, 10 Aug 2022 23:20:45 +0200 Subject: [PATCH 08/53] feat: add period of three days --- new-lamassu-admin/src/pages/Analytics/Analytics.js | 2 ++ .../src/pages/Analytics/graphs/OverTimeDotGraph.js | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index b7eed8fa..2e0afc7f 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -34,11 +34,13 @@ const REPRESENTING_OPTIONS = [ ] const PERIOD_OPTIONS = [ { code: 'day', display: 'Last 24 hours' }, + { code: 'threeDays', display: 'Last 3 days' }, { code: 'week', display: 'Last 7 days' }, { code: 'month', display: 'Last 30 days' } ] const TIME_OPTIONS = { day: DAY, + threeDays: 3 * DAY, week: WEEK, month: MONTH } diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js index acd7a181..2dad847c 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js @@ -46,6 +46,7 @@ const Graph = ({ const periodDomains = { day: [NOW - DAY, NOW], + threeDays: [NOW - 3 * DAY, NOW], week: [NOW - WEEK, NOW], month: [NOW - MONTH, NOW] } @@ -58,6 +59,12 @@ const Graph = ({ tick: d3.utcHour.every(1), labelFormat: '%H:%M' }, + threeDays: { + freq: 12, + step: 6 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%a %d' + }, week: { freq: 7, step: 24 * 60 * 60 * 1000, From 80715259b1af76e06fe59c1ba1d1e8ef556ecb20 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Thu, 11 Aug 2022 20:19:59 +0200 Subject: [PATCH 09/53] feat: add y log scale --- .../src/pages/Analytics/Analytics.styles.js | 24 ++++++- .../components/wrappers/OverTimeWrapper.js | 11 ++- .../src/pages/Analytics/graphs/Graph.js | 4 +- .../Analytics/graphs/OverTimeDotGraph.js | 69 +++++++++++-------- 4 files changed, 75 insertions(+), 33 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js b/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js index 089547f8..8274d929 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js @@ -1,4 +1,14 @@ -import { offDarkColor, tomato, neon, java } from 'src/styling/variables' +import { + offColor, + offDarkColor, + tomato, + neon, + java +} from 'src/styling/variables' + +import typographyStyles from '../../components/typography/styles' + +const { label1 } = typographyStyles const styles = { overviewLegend: { @@ -135,6 +145,18 @@ const styles = { topMachinesRadio: { display: 'flex', flexDirection: 'row' + }, + graphHeaderSwitchBox: { + display: 'flex', + flexDirection: 'column', + '& > *': { + margin: 0 + }, + '& > :first-child': { + marginBottom: 2, + extend: label1, + color: offColor + } } } diff --git a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js index 502d817a..def8fe90 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js +++ b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js @@ -1,8 +1,8 @@ import { Box } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' -import React from 'react' +import React, { useState } from 'react' -import { Select } from 'src/components/inputs' +import { Select, Switch } from 'src/components/inputs' import { H2 } from 'src/components/typography' import { primaryColor } from 'src/styling/variables' @@ -25,6 +25,8 @@ const OverTimeDotGraphHeader = ({ }) => { const classes = useStyles() + const [logarithmic, setLogarithmic] = useState() + const legend = { cashIn:
, cashOut:
, @@ -57,6 +59,10 @@ const OverTimeDotGraphHeader = ({
+
+ Log. scale + setLogarithmic(event.target.checked)} /> +
+
+
+ + + ) +} + +export default VolumeOverTimeGraphHeader diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js b/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js index 720ee687..18ac8fdf 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js @@ -5,6 +5,7 @@ import GraphTooltip from '../components/tooltips/GraphTooltip' import HourOfDayBarGraph from './HourOfDayBarGraph' import OverTimeDotGraph from './OverTimeDotGraph' +import OverTimeLineGraph from './OverTimeLineGraph' import TopMachinesBarGraph from './TopMachinesBarGraph' const GraphWrapper = ({ @@ -37,6 +38,19 @@ const GraphWrapper = ({ log={log} /> ) + case 'volumeOverTime': + return ( + + ) case 'topMachinesVolume': return ( { + const ref = useRef(null) + + const GRAPH_POPOVER_WIDTH = 150 + const GRAPH_POPOVER_MARGIN = 25 + const GRAPH_HEIGHT = 401 + const GRAPH_WIDTH = 1163 + const GRAPH_MARGIN = useMemo( + () => ({ + top: 25, + right: 3.5, + bottom: 27, + left: 36.5 + }), + [] + ) + + const offset = getTimezoneOffset(timezone) + const NOW = Date.now() + offset + + const periodDomains = { + day: [NOW - DAY, NOW], + threeDays: [NOW - 3 * DAY, NOW], + week: [NOW - WEEK, NOW], + month: [NOW - MONTH, NOW] + } + + const dataPoints = useMemo( + () => ({ + day: { + freq: 24, + step: 60 * 60 * 1000, + tick: d3.utcHour.every(1), + labelFormat: '%H:%M' + }, + threeDays: { + freq: 12, + step: 6 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%a %d' + }, + week: { + freq: 7, + step: 24 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%a %d' + }, + month: { + freq: 30, + step: 24 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%d' + } + }), + [] + ) + + const getPastAndCurrentDayLabels = useCallback(d => { + const currentDate = new Date(d) + const currentDateDay = currentDate.getUTCDate() + const currentDateWeekday = currentDate.getUTCDay() + const currentDateMonth = currentDate.getUTCMonth() + + const previousDate = new Date(currentDate.getTime()) + previousDate.setUTCDate(currentDateDay - 1) + + const previousDateDay = previousDate.getUTCDate() + const previousDateWeekday = previousDate.getUTCDay() + const previousDateMonth = previousDate.getUTCMonth() + + const daysOfWeek = Array.from(Array(7)).map((_, i) => + format('EEE', add({ days: i }, startOfWeek(new Date()))) + ) + + const months = Array.from(Array(12)).map((_, i) => + format('LLL', add({ months: i }, startOfYear(new Date()))) + ) + + return { + previous: + currentDateMonth !== previousDateMonth + ? months[previousDateMonth] + : `${daysOfWeek[previousDateWeekday]} ${previousDateDay}`, + current: + currentDateMonth !== previousDateMonth + ? months[currentDateMonth] + : `${daysOfWeek[currentDateWeekday]} ${currentDateDay}` + } + }, []) + + const buildTicks = useCallback( + domain => { + const points = [] + + const roundDate = d => { + const step = dataPoints[period.code].step + return new Date(Math.ceil(d.valueOf() / step) * step) + } + + for (let i = 0; i <= dataPoints[period.code].freq; i++) { + const stepDate = new Date(NOW - i * dataPoints[period.code].step) + if (roundDate(stepDate) > domain[1]) continue + if (stepDate < domain[0]) continue + points.push(roundDate(stepDate)) + } + + return points + }, + [NOW, dataPoints, period.code] + ) + + const buildAreas = useCallback( + domain => { + const points = [] + + points.push(domain[1]) + + const roundDate = d => { + const step = dataPoints[period.code].step + return new Date(Math.ceil(d.valueOf() / step) * step) + } + + for (let i = 0; i <= dataPoints[period.code].freq; i++) { + const stepDate = new Date(NOW - i * dataPoints[period.code].step) + if (roundDate(stepDate) > new Date(domain[1])) continue + if (stepDate < new Date(domain[0])) continue + points.push(roundDate(stepDate)) + } + + points.push(domain[0]) + + return points + }, + [NOW, dataPoints, period.code] + ) + + const x = d3 + .scaleUtc() + .domain(periodDomains[period.code]) + .range([GRAPH_MARGIN.left, GRAPH_WIDTH - GRAPH_MARGIN.right]) + + // Create a second X axis for mouseover events to be placed correctly across the entire graph width and not limited by X's domain + const x2 = d3 + .scaleUtc() + .domain(periodDomains[period.code]) + .range([GRAPH_MARGIN.left, GRAPH_WIDTH]) + + const bins = buildAreas(x.domain()) + .sort((a, b) => compareDesc(a.date, b.date)) + .map(addMilliseconds(-dataPoints[period.code].step)) + .map((date, i, dates) => { + // move first and last bin in such way + // that all bin have uniform width + if (i === 0) + return addMilliseconds(dataPoints[period.code].step, dates[1]) + else if (i === dates.length - 1) + return addMilliseconds( + -dataPoints[period.code].step, + dates[dates.length - 2] + ) + else return date + }) + .map(date => { + const middleOfBin = addMilliseconds( + dataPoints[period.code].step / 2, + date + ) + + const txs = data.filter(tx => { + const txCreated = new Date(tx.created) + const shift = new Date(txCreated.getTime() + offset) + + return ( + Math.abs(differenceInMilliseconds(shift, middleOfBin)) < + dataPoints[period.code].step / 2 + ) + }) + + const cashIn = txs + .filter(tx => tx.txClass === 'cashIn') + .reduce((sum, tx) => sum + new BigNumber(tx.fiat).toNumber(), 0) + + const cashOut = txs + .filter(tx => tx.txClass === 'cashOut') + .reduce((sum, tx) => sum + new BigNumber(tx.fiat).toNumber(), 0) + + return { date: middleOfBin, cashIn, cashOut } + }) + + const min = d3.min(bins, d => Math.min(d.cashIn, d.cashOut)) ?? 0 + const max = d3.max(bins, d => Math.max(d.cashIn, d.cashOut)) ?? 1000 + + const yLin = d3 + .scaleLinear() + .domain([0, (max === min ? min + 1000 : max) * 1.03]) + .nice() + .range([GRAPH_HEIGHT - GRAPH_MARGIN.bottom, GRAPH_MARGIN.top]) + + const yLog = d3 + .scaleLog() + .domain([ + min === 0 ? 1 : min * 0.9, + (max === min ? min + Math.pow(10, 2 * min + 1) : max) * 2 + ]) + .clamp(true) + .range([GRAPH_HEIGHT - GRAPH_MARGIN.bottom, GRAPH_MARGIN.top]) + + const y = log ? yLog : yLin + + const getAreaInterval = (breakpoints, dataLimits, graphLimits) => { + const fullBreakpoints = [ + graphLimits[1], + ...R.filter(it => it > dataLimits[0] && it < dataLimits[1], breakpoints), + dataLimits[0] + ] + + const intervals = [] + for (let i = 0; i < fullBreakpoints.length - 1; i++) { + intervals.push([fullBreakpoints[i], fullBreakpoints[i + 1]]) + } + + return intervals + } + + const getAreaIntervalByX = (intervals, xValue) => { + return R.find(it => xValue <= it[0] && xValue >= it[1], intervals) ?? [0, 0] + } + + const getDateIntervalByX = (areas, intervals, xValue) => { + const flattenIntervals = R.uniq(R.flatten(intervals)) + + // flattenIntervals and areas should have the same number of elements + for (let i = intervals.length - 1; i >= 0; i--) { + if (xValue < flattenIntervals[i]) { + return [areas[i], areas[i + 1]] + } + } + } + + const buildXAxis = useCallback( + g => + g + .attr( + 'transform', + `translate(0, ${GRAPH_HEIGHT - GRAPH_MARGIN.bottom})` + ) + .call( + d3 + .axisBottom(x) + .ticks(dataPoints[period.code].tick) + .tickFormat(d => { + return d3.timeFormat(dataPoints[period.code].labelFormat)( + d.getTime() + d.getTimezoneOffset() * MINUTE + ) + }) + .tickSizeOuter(0) + ) + .call(g => + g + .select('.domain') + .attr('stroke', primaryColor) + .attr('stroke-width', 1) + ), + [GRAPH_MARGIN, dataPoints, period.code, x] + ) + + const buildYAxis = useCallback( + g => + g + .attr('transform', `translate(${GRAPH_MARGIN.left}, 0)`) + .call( + d3 + .axisLeft(y) + .ticks(GRAPH_HEIGHT / 100) + .tickSizeOuter(0) + .tickFormat(d => { + if (log && !['1', '2', '5'].includes(d.toString()[0])) return '' + + if (d > 999) return Math.floor(d / 1000) + 'k' + else return d + }) + ) + .select('.domain') + .attr('stroke', primaryColor) + .attr('stroke-width', 1), + [GRAPH_MARGIN, y, log] + ) + + const buildGrid = useCallback( + g => { + g.attr('stroke', subheaderDarkColor) + .attr('fill', subheaderDarkColor) + // Vertical lines + .call(g => + g + .append('g') + .selectAll('line') + .data(buildTicks(x.domain())) + .join('line') + .attr('x1', d => 0.5 + x(d)) + .attr('x2', d => 0.5 + x(d)) + .attr('y1', GRAPH_MARGIN.top) + .attr('y2', GRAPH_HEIGHT - GRAPH_MARGIN.bottom) + ) + // Horizontal lines + .call(g => + g + .append('g') + .selectAll('line') + .data( + d3 + .axisLeft(y) + .scale() + .ticks(GRAPH_HEIGHT / 100) + ) + .join('line') + .attr('y1', d => 0.5 + y(d)) + .attr('y2', d => 0.5 + y(d)) + .attr('x1', GRAPH_MARGIN.left) + .attr('x2', GRAPH_WIDTH) + ) + // Vertical transparent rectangles for events + .call(g => + g + .append('g') + .selectAll('line') + .data(buildAreas(x.domain())) + .join('rect') + .attr('x', d => x(d)) + .attr('y', GRAPH_MARGIN.top) + .attr('width', d => { + const xValue = Math.round(x(d) * 100) / 100 + const intervals = getAreaInterval( + buildAreas(x.domain()).map(it => Math.round(x(it) * 100) / 100), + x.range(), + x2.range() + ) + const interval = getAreaIntervalByX(intervals, xValue) + return Math.round((interval[0] - interval[1]) * 100) / 100 + }) + .attr( + 'height', + GRAPH_HEIGHT - GRAPH_MARGIN.bottom - GRAPH_MARGIN.top + ) + .attr('stroke', 'transparent') + .attr('fill', 'transparent') + .on('mouseover', d => { + const xValue = Math.round(d.target.x.baseVal.value * 100) / 100 + const areas = buildAreas(x.domain()) + const intervals = getAreaInterval( + buildAreas(x.domain()).map(it => Math.round(x(it) * 100) / 100), + x.range(), + x2.range() + ) + + const dateInterval = getDateIntervalByX(areas, intervals, xValue) + if (!dateInterval) return + const filteredData = data.filter(it => { + const created = new Date(it.created) + const tzCreated = created.setTime(created.getTime() + offset) + return ( + tzCreated > new Date(dateInterval[1]) && + tzCreated <= new Date(dateInterval[0]) + ) + }) + + const rectXCoords = { + left: R.clone(d.target.getBoundingClientRect().x), + right: R.clone( + d.target.getBoundingClientRect().x + + d.target.getBoundingClientRect().width + ) + } + + const xCoord = + d.target.x.baseVal.value < 0.75 * GRAPH_WIDTH + ? rectXCoords.right + GRAPH_POPOVER_MARGIN + : rectXCoords.left - + GRAPH_POPOVER_WIDTH - + GRAPH_POPOVER_MARGIN + const yCoord = R.clone(d.target.getBoundingClientRect().y) + + setSelectionDateInterval(dateInterval) + setSelectionData(filteredData) + setSelectionCoords({ + x: Math.round(xCoord), + y: Math.round(yCoord) + }) + + d3.select(d.target).attr('fill', subheaderColor) + }) + .on('mouseleave', d => { + d3.select(d.target).attr('fill', 'transparent') + setSelectionDateInterval(null) + setSelectionData(null) + setSelectionCoords(null) + }) + ) + // Thick vertical lines + .call(g => + g + .append('g') + .selectAll('line') + .data( + buildTicks(x.domain()).filter(x => { + if (period.code === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + ) + .join('line') + .attr('class', 'dateSeparator') + .attr('x1', d => 0.5 + x(d)) + .attr('x2', d => 0.5 + x(d)) + .attr('y1', GRAPH_MARGIN.top - 50) + .attr('y2', GRAPH_HEIGHT - GRAPH_MARGIN.bottom) + .attr('stroke-width', 5) + .join('text') + ) + // Left side breakpoint label + .call(g => { + const separator = d3 + ?.select('.dateSeparator') + ?.node() + ?.getBBox() + + if (!separator) return + + const breakpoint = buildTicks(x.domain()).filter(x => { + if (period.code === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + + const labels = getPastAndCurrentDayLabels(breakpoint) + + return g + .append('text') + .attr('x', separator.x - 10) + .attr('y', separator.y + 33) + .attr('text-anchor', 'end') + .attr('dy', '.25em') + .text(labels.previous) + }) + // Right side breakpoint label + .call(g => { + const separator = d3 + ?.select('.dateSeparator') + ?.node() + ?.getBBox() + + if (!separator) return + + const breakpoint = buildTicks(x.domain()).filter(x => { + if (period.code === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + + const labels = getPastAndCurrentDayLabels(breakpoint) + + return g + .append('text') + .attr('x', separator.x + 10) + .attr('y', separator.y + 33) + .attr('text-anchor', 'start') + .attr('dy', '.25em') + .text(labels.current) + }) + }, + [ + GRAPH_MARGIN, + buildTicks, + getPastAndCurrentDayLabels, + x, + x2, + y, + period, + buildAreas, + data, + offset, + setSelectionCoords, + setSelectionData, + setSelectionDateInterval + ] + ) + + const formatTicksText = useCallback( + () => + d3 + .selectAll('.tick text') + .style('stroke', fontColor) + .style('fill', fontColor) + .style('stroke-width', 0.5) + .style('font-family', fontSecondary), + [] + ) + + const formatText = useCallback( + () => + d3 + .selectAll('text') + .style('stroke', offColor) + .style('fill', offColor) + .style('stroke-width', 0.5) + .style('font-family', fontSecondary), + [] + ) + + const formatTicks = useCallback(() => { + d3.selectAll('.tick line') + .style('stroke', primaryColor) + .style('fill', primaryColor) + }, []) + + const drawData = useCallback( + g => { + g.append('clipPath') + .attr('id', 'clip-path') + .append('rect') + .attr('x', GRAPH_MARGIN.left) + .attr('y', GRAPH_MARGIN.top) + .attr('width', GRAPH_WIDTH) + .attr('height', GRAPH_HEIGHT - GRAPH_MARGIN.bottom - GRAPH_MARGIN.top) + .attr('fill', java) + + g.append('g') + .attr('clip-path', 'url(#clip-path)') + .selectAll('circle .cashIn') + .data(bins) + .join('circle') + .attr('cx', d => x(d.date)) + .attr('cy', d => y(d.cashIn)) + .attr('fill', java) + .attr('r', 3.5) + + g.append('g') + .attr('clip-path', 'url(#clip-path)') + .selectAll('circle .cashIn') + .data(bins) + .join('circle') + .attr('cx', d => x(d.date)) + .attr('cy', d => y(d.cashOut)) + .attr('fill', neon) + .attr('r', 3.5) + + g.append('path') + .datum(bins) + .attr('fill', 'none') + .attr('stroke', java) + .attr('stroke-width', 3) + .attr('clip-path', 'url(#clip-path)') + .attr( + 'd', + d3 + .line() + .curve(d3.curveMonotoneX) + .x(d => x(d.date)) + .y(d => y(d.cashIn)) + ) + + g.append('path') + .datum(bins) + .attr('fill', 'none') + .attr('stroke', neon) + .attr('stroke-width', 3) + .attr('clip-path', 'url(#clip-path)') + .attr( + 'd', + d3 + .line() + .curve(d3.curveMonotoneX) + .x(d => x(d.date)) + .y(d => y(d.cashOut)) + ) + }, + [x, y, bins, GRAPH_MARGIN] + ) + + const drawChart = useCallback(() => { + const svg = d3 + .select(ref.current) + .attr('viewBox', [0, 0, GRAPH_WIDTH, GRAPH_HEIGHT]) + + svg.append('g').call(buildGrid) + svg.append('g').call(drawData) + svg.append('g').call(buildXAxis) + svg.append('g').call(buildYAxis) + svg.append('g').call(formatTicksText) + svg.append('g').call(formatText) + svg.append('g').call(formatTicks) + + return svg.node() + }, [ + buildGrid, + buildXAxis, + buildYAxis, + drawData, + formatText, + formatTicks, + formatTicksText + ]) + + useEffect(() => { + d3.select(ref.current) + .selectAll('*') + .remove() + drawChart() + }, [drawChart]) + + return +} + +export default memo( + Graph, + (prev, next) => + R.equals(prev.period, next.period) && + R.equals(prev.selectedMachine, next.selectedMachine) && + R.equals(prev.log, next.log) +) From b5e798339be008144a3b04c65391965c5ceed76a Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:33:54 +0200 Subject: [PATCH 11/53] fix: use `k` for thousands fix: graph tooltip for `threeDays` interval fix: y domain for log graph fix: line graph drawing order fix: line graph dots --- .../components/tooltips/GraphTooltip.js | 9 ++++-- .../Analytics/graphs/OverTimeDotGraph.js | 8 +++-- .../Analytics/graphs/OverTimeLineGraph.js | 32 ++++++++++--------- .../Graphs/RefScatterplot.js | 12 ++++++- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js index 89208a4a..02b1ab19 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js +++ b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js @@ -29,12 +29,14 @@ const GraphTooltip = ({ formatDate( dateInterval[1], null, - period.code === 'day' ? 'MMM d, HH:mm' : 'MMM d' + R.includes(period.code, ['day', 'threeDays']) + ? 'MMM d, HH:mm' + : 'MMM d' ), formatDate( dateInterval[0], null, - period.code === 'day' ? 'HH:mm' : 'MMM d' + R.includes(period.code, ['day', 'threeDays']) ? 'HH:mm' : 'MMM d' ) ] : [ @@ -56,7 +58,8 @@ const GraphTooltip = ({ return ( - {period.code === 'day' || R.includes('hourOfDay', representing.code) + {R.includes(period.code, ['day', 'threeDays']) || + R.includes('hourOfDay', representing.code) ? `${formattedDateInterval[0]} - ${formattedDateInterval[1]}` : `${formattedDateInterval[0]}`} diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js index 1b86af23..bf705a09 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js @@ -15,6 +15,7 @@ import { fontSecondary, subheaderColor } from 'src/styling/variables' +import { numberToFiatAmount } from 'src/utils/number' import { MINUTE, DAY, WEEK, MONTH } from 'src/utils/time' const Graph = ({ @@ -37,7 +38,7 @@ const Graph = ({ top: 25, right: 3.5, bottom: 27, - left: 36.5 + left: 38 }), [] ) @@ -260,8 +261,9 @@ const Graph = ({ .tickFormat(d => { if (log && !['1', '2', '5'].includes(d.toString()[0])) return '' - if (d > 1000) return Math.floor(d / 1000) + 'k' - else return d + if (d >= 1000) return numberToFiatAmount(d / 1000) + 'k' + + return numberToFiatAmount(d) }) ) .select('.domain') diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js index f2ac39fa..6c5613a1 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js @@ -23,6 +23,7 @@ import { fontSecondary, subheaderColor } from 'src/styling/variables' +import { numberToFiatAmount } from 'src/utils/number' import { MINUTE, DAY, WEEK, MONTH } from 'src/utils/time' const Graph = ({ @@ -45,7 +46,7 @@ const Graph = ({ top: 25, right: 3.5, bottom: 27, - left: 36.5 + left: 38 }), [] ) @@ -234,7 +235,7 @@ const Graph = ({ const yLog = d3 .scaleLog() .domain([ - min === 0 ? 1 : min * 0.9, + min === 0 ? 0.9 : min * 0.9, (max === min ? min + Math.pow(10, 2 * min + 1) : max) * 2 ]) .clamp(true) @@ -311,8 +312,9 @@ const Graph = ({ .tickFormat(d => { if (log && !['1', '2', '5'].includes(d.toString()[0])) return '' - if (d > 999) return Math.floor(d / 1000) + 'k' - else return d + if (d >= 1000) return numberToFiatAmount(d / 1000) + 'k' + + return numberToFiatAmount(d) }) ) .select('.domain') @@ -564,17 +566,7 @@ const Graph = ({ .attr('cx', d => x(d.date)) .attr('cy', d => y(d.cashIn)) .attr('fill', java) - .attr('r', 3.5) - - g.append('g') - .attr('clip-path', 'url(#clip-path)') - .selectAll('circle .cashIn') - .data(bins) - .join('circle') - .attr('cx', d => x(d.date)) - .attr('cy', d => y(d.cashOut)) - .attr('fill', neon) - .attr('r', 3.5) + .attr('r', d => (d.cashIn === 0 ? 0 : 3.5)) g.append('path') .datum(bins) @@ -591,6 +583,16 @@ const Graph = ({ .y(d => y(d.cashIn)) ) + g.append('g') + .attr('clip-path', 'url(#clip-path)') + .selectAll('circle .cashIn') + .data(bins) + .join('circle') + .attr('cx', d => x(d.date)) + .attr('cy', d => y(d.cashOut)) + .attr('fill', neon) + .attr('r', d => (d.cashOut === 0 ? 0 : 3.5)) + g.append('path') .datum(bins) .attr('fill', 'none') diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js index 9d3d288d..6148c966 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js @@ -12,6 +12,7 @@ import { fontSecondary, backgroundColor } from 'src/styling/variables' +import { numberToFiatAmount } from 'src/utils/number' import { MINUTE, DAY, WEEK, MONTH } from 'src/utils/time' const Graph = ({ data, timeFrame, timezone }) => { @@ -172,7 +173,16 @@ const Graph = ({ data, timeFrame, timezone }) => { g => g .attr('transform', `translate(${GRAPH_MARGIN.left}, 0)`) - .call(d3.axisLeft(y).ticks(5)) + .call( + d3 + .axisLeft(y) + .ticks(5) + .tickFormat(d => { + if (d >= 1000) return numberToFiatAmount(d / 1000) + 'k' + + return numberToFiatAmount(d) + }) + ) .call(g => g.select('.domain').remove()) .selectAll('text') .attr('dy', '-0.25rem'), From 1d37608a191dfd0e565278e3917e8890607195ba Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 15 Aug 2022 16:13:25 +0200 Subject: [PATCH 12/53] feat: change average to median --- .../src/pages/Analytics/Analytics.js | 18 ++++++++---------- .../components/wrappers/OverTimeWrapper.js | 4 ++-- .../pages/Analytics/graphs/OverTimeDotGraph.js | 8 ++++---- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index 5e8d94bd..2bf8e278 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -227,13 +227,11 @@ const Analytics = () => { previous: filteredData(period.code).previous.length } - const avgAmount = { - current: - R.sum(R.map(d => d.fiat, filteredData(period.code).current)) / - (txs.current === 0 ? 1 : txs.current), - previous: - R.sum(R.map(d => d.fiat, filteredData(period.code).previous)) / - (txs.previous === 0 ? 1 : txs.previous) + const median = values => (values.length === 0 ? 0 : R.median(values)) + + const medianAmount = { + current: median(R.map(d => d.fiat, filteredData(period.code).current)), + previous: median(R.map(d => d.fiat, filteredData(period.code).previous)) } const txVolume = { @@ -365,9 +363,9 @@ const Analytics = () => { />
diff --git a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js index def8fe90..6efaaf40 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js +++ b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js @@ -31,7 +31,7 @@ const OverTimeDotGraphHeader = ({ cashIn:
, cashOut:
, transaction:
, - average: ( + median: ( - +
diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js index bf705a09..9da30a97 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js @@ -498,9 +498,9 @@ const Graph = ({ const buildAvg = useCallback( g => { - const mean = d3.mean(data, d => new BigNumber(d.fiat).toNumber()) ?? 0 + const median = d3.median(data, d => new BigNumber(d.fiat).toNumber()) ?? 0 - if (log && mean === 0) return + if (log && median === 0) return g.attr('stroke', primaryColor) .attr('stroke-width', 3) @@ -508,8 +508,8 @@ const Graph = ({ .call(g => g .append('line') - .attr('y1', 0.5 + y(mean)) - .attr('y2', 0.5 + y(mean)) + .attr('y1', 0.5 + y(median)) + .attr('y2', 0.5 + y(median)) .attr('x1', GRAPH_MARGIN.left) .attr('x2', GRAPH_WIDTH) ) From 909fbb7ae21635160920ac5705c0a391833ed158 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 15 Aug 2022 17:42:56 +0200 Subject: [PATCH 13/53] fix: tooltip format --- .../components/tooltips/GraphTooltip.js | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js index 02b1ab19..ff32a290 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js +++ b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js @@ -26,20 +26,12 @@ const GraphTooltip = ({ const formattedDateInterval = !R.includes('hourOfDay', representing.code) ? [ - formatDate( - dateInterval[1], - null, - R.includes(period.code, ['day', 'threeDays']) - ? 'MMM d, HH:mm' - : 'MMM d' - ), - formatDate( - dateInterval[0], - null, - R.includes(period.code, ['day', 'threeDays']) ? 'HH:mm' : 'MMM d' - ) + formatDate(dateInterval[1], null, 'MMM d'), + formatDate(dateInterval[1], null, 'HH:mm'), + formatDate(dateInterval[0], null, 'HH:mm') ] : [ + formatDate(dateInterval[1], null, 'MMM d'), formatDateNonUtc(dateInterval[1], 'HH:mm'), formatDateNonUtc(dateInterval[0], 'HH:mm') ] @@ -57,11 +49,11 @@ const GraphTooltip = ({ return ( + {!R.includes('hourOfDay', representing.code) && ( + {`${formattedDateInterval[0]}`} + )} - {R.includes(period.code, ['day', 'threeDays']) || - R.includes('hourOfDay', representing.code) - ? `${formattedDateInterval[0]} - ${formattedDateInterval[1]}` - : `${formattedDateInterval[0]}`} + {`${formattedDateInterval[1]} - ${formattedDateInterval[2]}`}

{R.length(data)}{' '} From a247b3661eb7395bcc13a793587b97daf1a79d2b Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Thu, 28 Jul 2022 20:24:18 +0200 Subject: [PATCH 14/53] fix: photo roll height --- new-lamassu-admin/src/components/Carousel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/components/Carousel.js b/new-lamassu-admin/src/components/Carousel.js index 5e0475aa..f093eef3 100644 --- a/new-lamassu-admin/src/components/Carousel.js +++ b/new-lamassu-admin/src/components/Carousel.js @@ -13,9 +13,10 @@ const useStyles = makeStyles({ display: 'flex' }, imgInner: { - objectFit: 'cover', + objectFit: 'contain', objectPosition: 'center', width: 500, + height: 400, marginBottom: 40 } }) From e3fe2bc04eeea1e2230f47f4cd97776e148a975d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 31 May 2022 23:05:48 +0100 Subject: [PATCH 15/53] feat: allow for edited customer photos to be previewed --- .../src/pages/Customers/CustomerData.js | 78 +++++++++++++------ .../Customers/components/EditableCard.js | 17 ++-- 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/new-lamassu-admin/src/pages/Customers/CustomerData.js b/new-lamassu-admin/src/pages/Customers/CustomerData.js index b605eb07..af232e7f 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerData.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerData.js @@ -77,6 +77,8 @@ const CustomerData = ({ }) => { const classes = useStyles() const [listView, setListView] = useState(false) + const [previewPhoto, setPreviewPhoto] = useState(null) + const [previewCard, setPreviewCard] = useState(null) const idData = R.path(['idCardData'])(customer) const rawExpirationDate = R.path(['expirationDate'])(idData) @@ -213,9 +215,6 @@ const CustomerData = ({ { title: 'Name', titleIcon: , - authorize: () => {}, - reject: () => {}, - save: () => {}, isAvailable: false, editable: true }, @@ -226,7 +225,7 @@ const CustomerData = ({ authorize: () => updateCustomer({ sanctionsOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ sanctionsOverride: OVERRIDE_REJECTED }), - children: {sanctionsDisplay}, + children: () => {sanctionsDisplay}, isAvailable: !R.isNil(sanctions), editable: true }, @@ -238,20 +237,33 @@ const CustomerData = ({ authorize: () => updateCustomer({ frontCameraOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ frontCameraOverride: OVERRIDE_REJECTED }), - save: values => - replacePhoto({ + save: values => { + setPreviewPhoto(null) + return replacePhoto({ newPhoto: values.frontCamera, photoType: 'frontCamera' - }), + }) + }, + cancel: () => setPreviewPhoto(null), deleteEditedData: () => deleteEditedData({ frontCamera: null }), - children: customer.frontCameraPath ? ( - - ) : null, + children: values => { + if (values.frontCamera !== previewPhoto) { + setPreviewPhoto(values.frontCamera) + } + + return customer.frontCameraPath ? ( + + ) : null + }, hasImage: true, validationSchema: customerDataSchemas.frontCamera, initialValues: initialValues.frontCamera, @@ -266,18 +278,33 @@ const CustomerData = ({ authorize: () => updateCustomer({ idCardPhotoOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ idCardPhotoOverride: OVERRIDE_REJECTED }), - save: values => - replacePhoto({ + save: values => { + setPreviewCard(null) + return replacePhoto({ newPhoto: values.idCardPhoto, photoType: 'idCardPhoto' - }), + }) + }, + cancel: () => setPreviewCard(null), deleteEditedData: () => deleteEditedData({ idCardPhoto: null }), - children: customer.idCardPhotoPath ? ( - - ) : null, + children: values => { + if (values.idCardPhoto !== previewCard) { + setPreviewCard(values.idCardPhoto) + } + + return customer.idCardPhotoPath ? ( + + ) : null + }, hasImage: true, validationSchema: customerDataSchemas.idCardPhoto, initialValues: initialValues.idCardPhoto, @@ -292,6 +319,7 @@ const CustomerData = ({ authorize: () => updateCustomer({ usSsnOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ usSsnOverride: OVERRIDE_REJECTED }), save: values => editCustomer(values), + children: () => {}, deleteEditedData: () => deleteEditedData({ usSsn: null }), validationSchema: customerDataSchemas.usSsn, initialValues: initialValues.usSsn, @@ -427,6 +455,7 @@ const CustomerData = ({ titleIcon, fields, save, + cancel, deleteEditedData, retrieveAdditionalData, children, @@ -453,6 +482,7 @@ const CustomerData = ({ validationSchema={validationSchema} initialValues={initialValues} save={save} + cancel={cancel} deleteEditedData={deleteEditedData} retrieveAdditionalData={retrieveAdditionalData} editable={editable}> diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 1dc71165..3ea7a03f 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -3,7 +3,7 @@ import { makeStyles } from '@material-ui/core/styles' import classnames from 'classnames' import { Form, Formik, Field as FormikField } from 'formik' import * as R from 'ramda' -import { useState, React } from 'react' +import { useState, React, useRef } from 'react' import ErrorMessage from 'src/components/ErrorMessage' import PromptWhenDirty from 'src/components/PromptWhenDirty' @@ -132,14 +132,15 @@ const ReadOnlyField = ({ field, value, ...props }) => { const EditableCard = ({ fields, - save, - authorize, + save = () => {}, + cancel = () => {}, + authorize = () => {}, hasImage, - reject, + reject = () => {}, state, title, titleIcon, - children, + children = () => {}, validationSchema, initialValues, deleteEditedData, @@ -149,6 +150,8 @@ const EditableCard = ({ }) => { const classes = useStyles() + const formRef = useRef() + const [editing, setEditing] = useState(false) const [input, setInput] = useState(null) const [error, setError] = useState(null) @@ -187,8 +190,9 @@ const EditableCard = ({

)}
- {children} + {children(formRef.current?.values ?? {})} cancel()} type="reset"> Cancel From 37e235452b5c5ba1f4463a3fc493a56e6fe46c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Fri, 16 Sep 2022 05:26:30 +0100 Subject: [PATCH 16/53] feat: add robots.txt to lamassu-server and lamassu-admin fix: fail fast on lamassu-server default route access --- lib/routes.js | 9 +++++++++ new-lamassu-admin/public/robots.txt | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 new-lamassu-admin/public/robots.txt diff --git a/lib/routes.js b/lib/routes.js index 6248fc8e..7cc6bb5b 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -56,6 +56,15 @@ app.use(nocache()) app.use(express.json({ limit: '2mb' })) app.use(morgan(':method :url :status :response-time ms -- :req[content-length]/:res[content-length] b', { stream: logger.stream })) +app.use('/robots.txt', (req, res) => { + res.type('text/plain') + res.send("User-agent: *\nDisallow: /") +}) + +app.get('/', (req, res) => { + res.status(404).json({ error: 'No such route' }) +}) + // app /pair and /ca routes app.use('/', pairingRoutes) diff --git a/new-lamassu-admin/public/robots.txt b/new-lamassu-admin/public/robots.txt new file mode 100644 index 00000000..77470cb3 --- /dev/null +++ b/new-lamassu-admin/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file From 04052bfc8e0256915fc616f93ecbc0e858a0c243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 6 Oct 2022 19:17:03 +0100 Subject: [PATCH 17/53] fix: remove JSON from 404 response --- lib/routes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 7cc6bb5b..49ddddf2 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -62,7 +62,7 @@ app.use('/robots.txt', (req, res) => { }) app.get('/', (req, res) => { - res.status(404).json({ error: 'No such route' }) + res.sendStatus(404) }) // app /pair and /ca routes From c77fda262355652e9c18aa2733e0645d42ad2ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 7 Jul 2022 19:28:33 +0100 Subject: [PATCH 18/53] feat: add button to check against OFAC sanction list --- lib/customers.js | 1 + lib/new-admin/admin-server.js | 3 +- lib/new-admin/graphql/resolvers/index.js | 2 ++ .../graphql/resolvers/sanctions.resolver.js | 14 ++++++++++ lib/new-admin/graphql/types/index.js | 2 ++ lib/new-admin/graphql/types/sanctions.type.js | 13 +++++++++ lib/new-admin/middlewares/index.js | 2 ++ .../middlewares/loadSanctionLists.js | 28 +++++++++++++++++++ .../src/pages/Customers/CustomerData.js | 15 ++++++++-- .../src/pages/Customers/CustomerProfile.js | 26 ++++++++++++++++- .../Customers/components/EditableCard.js | 13 ++++++++- 11 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 lib/new-admin/graphql/resolvers/sanctions.resolver.js create mode 100644 lib/new-admin/graphql/types/sanctions.type.js create mode 100644 lib/new-admin/middlewares/loadSanctionLists.js diff --git a/lib/customers.js b/lib/customers.js index d7975972..23542928 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -114,6 +114,7 @@ function update (id, data, userToken) { async function updateCustomer (id, data, userToken) { const formattedData = _.pick( [ + 'sanctions', 'authorized_override', 'id_card_photo_override', 'id_card_data_override', diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index 3b13daf8..e2a7ab70 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -20,7 +20,7 @@ const { typeDefs, resolvers } = require('./graphql/schema') const findOperatorId = require('../middlewares/operatorId') const computeSchema = require('../compute-schema') const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants') -const { session, cleanUserSessions, buildApolloContext } = require('./middlewares') +const { session, cleanUserSessions, buildApolloContext, loadSanctionLists } = require('./middlewares') const devMode = require('minimist')(process.argv.slice(2)).dev @@ -48,6 +48,7 @@ app.use(express.static(path.resolve(__dirname, '..', '..', 'public'))) app.use(cleanUserSessions(USER_SESSIONS_CLEAR_INTERVAL)) app.use(computeSchema) app.use(findOperatorId) +app.use(loadSanctionLists) app.use(session) app.use(graphqlUploadExpress()) diff --git a/lib/new-admin/graphql/resolvers/index.js b/lib/new-admin/graphql/resolvers/index.js index 81e79614..a20d9216 100644 --- a/lib/new-admin/graphql/resolvers/index.js +++ b/lib/new-admin/graphql/resolvers/index.js @@ -14,6 +14,7 @@ const machine = require('./machine.resolver') const notification = require('./notification.resolver') const pairing = require('./pairing.resolver') const rates = require('./rates.resolver') +const sanctions = require('./sanctions.resolver') const scalar = require('./scalar.resolver') const settings = require('./settings.resolver') const sms = require('./sms.resolver') @@ -37,6 +38,7 @@ const resolvers = [ notification, pairing, rates, + sanctions, scalar, settings, sms, diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js new file mode 100644 index 00000000..9bd211dd --- /dev/null +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -0,0 +1,14 @@ +const _ = require('lodash/fp') +const ofac = require('../../../ofac') + +const resolvers = { + Query: { + checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => { + const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) + + return { ofacSanctioned: _.size(ofacMatches) > 0 } + } + } +} + +module.exports = resolvers diff --git a/lib/new-admin/graphql/types/index.js b/lib/new-admin/graphql/types/index.js index a1886a28..f4794b67 100644 --- a/lib/new-admin/graphql/types/index.js +++ b/lib/new-admin/graphql/types/index.js @@ -14,6 +14,7 @@ const machine = require('./machine.type') const notification = require('./notification.type') const pairing = require('./pairing.type') const rates = require('./rates.type') +const sanctions = require('./sanctions.type') const scalar = require('./scalar.type') const settings = require('./settings.type') const sms = require('./sms.type') @@ -37,6 +38,7 @@ const types = [ notification, pairing, rates, + sanctions, scalar, settings, sms, diff --git a/lib/new-admin/graphql/types/sanctions.type.js b/lib/new-admin/graphql/types/sanctions.type.js new file mode 100644 index 00000000..76a5e572 --- /dev/null +++ b/lib/new-admin/graphql/types/sanctions.type.js @@ -0,0 +1,13 @@ +const { gql } = require('apollo-server-express') + +const typeDef = gql` + type SanctionMatches { + ofacSanctioned: Boolean + } + + type Query { + checkAgainstSanctions(firstName: String, lastName: String, birthdate: String): SanctionMatches @auth + } +` + +module.exports = typeDef diff --git a/lib/new-admin/middlewares/index.js b/lib/new-admin/middlewares/index.js index cedba31c..21cd4751 100644 --- a/lib/new-admin/middlewares/index.js +++ b/lib/new-admin/middlewares/index.js @@ -1,9 +1,11 @@ const cleanUserSessions = require('./cleanUserSessions') const buildApolloContext = require('./context') +const loadSanctionLists = require('./loadSanctionLists') const session = require('./session') module.exports = { cleanUserSessions, buildApolloContext, + loadSanctionLists, session } diff --git a/lib/new-admin/middlewares/loadSanctionLists.js b/lib/new-admin/middlewares/loadSanctionLists.js new file mode 100644 index 00000000..48d2c0b8 --- /dev/null +++ b/lib/new-admin/middlewares/loadSanctionLists.js @@ -0,0 +1,28 @@ +const logger = require('../../logger') +const sanctions = require('../../ofac') + +const sanctionStatus = { + loaded: false, + timestamp: null +} + +const loadSanctionLists = (req, res, next) => { + if (!sanctionStatus.loaded) { + logger.info('No sanction lists loaded. Loading sanctions...') + return sanctions.load() + .then(() => { + logger.info('OFAC sanction list loaded!') + sanctionStatus.loaded = true + sanctionStatus.timestamp = Date.now() + return next() + }) + .catch(e => { + logger.error('Couldn\'t load OFAC sanction list!') + return next(e) + }) + } + + return next() +} + +module.exports = loadSanctionLists diff --git a/new-lamassu-admin/src/pages/Customers/CustomerData.js b/new-lamassu-admin/src/pages/Customers/CustomerData.js index b605eb07..affe5159 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerData.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerData.js @@ -73,7 +73,8 @@ const CustomerData = ({ authorizeCustomRequest, updateCustomEntry, retrieveAdditionalDataDialog, - setRetrieve + setRetrieve, + checkAgainstSanctions }) => { const classes = useStyles() const [listView, setListView] = useState(false) @@ -172,6 +173,14 @@ const CustomerData = ({ idCardData: R.merge(idData, formatDates(values)) }), validationSchema: customerDataSchemas.idCardData, + checkAgainstSanctions: () => + checkAgainstSanctions({ + variables: { + firstName: initialValues.idCardData.firstName, + lastName: initialValues.idCardData.lastName, + birthdate: R.replace(/-/g, '')(initialValues.idCardData.dateOfBirth) + } + }), initialValues: initialValues.idCardData, isAvailable: !R.isNil(idData), editable: true @@ -434,7 +443,8 @@ const CustomerData = ({ initialValues, hasImage, hasAdditionalData, - editable + editable, + checkAgainstSanctions }, idx ) => { @@ -455,6 +465,7 @@ const CustomerData = ({ save={save} deleteEditedData={deleteEditedData} retrieveAdditionalData={retrieveAdditionalData} + checkAgainstSanctions={checkAgainstSanctions} editable={editable}> ) } diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js index d9256f3b..3c03cb4f 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js @@ -1,4 +1,4 @@ -import { useQuery, useMutation } from '@apollo/react-hooks' +import { useQuery, useMutation, useLazyQuery } from '@apollo/react-hooks' import { makeStyles, Breadcrumbs, @@ -292,6 +292,22 @@ const GET_ACTIVE_CUSTOM_REQUESTS = gql` } ` +const CHECK_AGAINST_SANCTIONS = gql` + query checkAgainstSanctions( + $firstName: String + $lastName: String + $birthdate: String + ) { + checkAgainstSanctions( + firstName: $firstName + lastName: $lastName + birthdate: $birthdate + ) { + ofacSanctioned + } + } +` + const CustomerProfile = memo(() => { const history = useHistory() @@ -400,6 +416,13 @@ const CustomerProfile = memo(() => { onCompleted: () => getCustomer() }) + const [checkAgainstSanctions] = useLazyQuery(CHECK_AGAINST_SANCTIONS, { + onCompleted: ({ checkAgainstSanctions: { ofacSanctioned } }) => + updateCustomer({ + sanctions: !ofacSanctioned + }) + }) + const updateCustomer = it => setCustomer({ variables: { @@ -662,6 +685,7 @@ const CustomerProfile = memo(() => { authorizeCustomRequest={authorizeCustomRequest} updateCustomEntry={updateCustomEntry} setRetrieve={setRetrieve} + checkAgainstSanctions={checkAgainstSanctions} retrieveAdditionalDataDialog={ { diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 1dc71165..ce5c85bd 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -145,7 +145,8 @@ const EditableCard = ({ deleteEditedData, retrieveAdditionalData, hasAdditionalData = true, - editable + editable, + checkAgainstSanctions }) => { const classes = useStyles() @@ -273,6 +274,16 @@ const EditableCard = ({ Retrieve API data )} + {checkAgainstSanctions && ( + checkAgainstSanctions()}> + Check against OFAC sanction list + + )} {editable && ( Date: Fri, 8 Jul 2022 18:17:30 +0100 Subject: [PATCH 19/53] fix: remove sanction loader middleware --- lib/new-admin/admin-server.js | 3 +- .../graphql/resolvers/sanctions.resolver.js | 34 ++++++++++++++++--- lib/new-admin/middlewares/index.js | 2 -- .../middlewares/loadSanctionLists.js | 28 --------------- 4 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 lib/new-admin/middlewares/loadSanctionLists.js diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index e2a7ab70..3b13daf8 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -20,7 +20,7 @@ const { typeDefs, resolvers } = require('./graphql/schema') const findOperatorId = require('../middlewares/operatorId') const computeSchema = require('../compute-schema') const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants') -const { session, cleanUserSessions, buildApolloContext, loadSanctionLists } = require('./middlewares') +const { session, cleanUserSessions, buildApolloContext } = require('./middlewares') const devMode = require('minimist')(process.argv.slice(2)).dev @@ -48,7 +48,6 @@ app.use(express.static(path.resolve(__dirname, '..', '..', 'public'))) app.use(cleanUserSessions(USER_SESSIONS_CLEAR_INTERVAL)) app.use(computeSchema) app.use(findOperatorId) -app.use(loadSanctionLists) app.use(session) app.use(graphqlUploadExpress()) diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js index 9bd211dd..3945516a 100644 --- a/lib/new-admin/graphql/resolvers/sanctions.resolver.js +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -1,13 +1,37 @@ const _ = require('lodash/fp') +const logger = require('../../../logger') const ofac = require('../../../ofac') +const T = require('../../../time') + +const sanctionStatus = { + loaded: false, + timestamp: null +} + +const loadOrUpdateSanctions = () => { + if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.minute)) { + logger.info('No sanction lists loaded. Loading sanctions...') + return ofac.load() + .then(() => { + logger.info('OFAC sanction list loaded!') + sanctionStatus.loaded = true + sanctionStatus.timestamp = Date.now() + }) + .catch(e => { + logger.error('Couldn\'t load OFAC sanction list!') + }) + } + + return Promise.resolve() +} const resolvers = { Query: { - checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => { - const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) - - return { ofacSanctioned: _.size(ofacMatches) > 0 } - } + checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => loadOrUpdateSanctions() + .then(() => { + const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) + return { ofacSanctioned: _.size(ofacMatches) > 0 } + }) } } diff --git a/lib/new-admin/middlewares/index.js b/lib/new-admin/middlewares/index.js index 21cd4751..cedba31c 100644 --- a/lib/new-admin/middlewares/index.js +++ b/lib/new-admin/middlewares/index.js @@ -1,11 +1,9 @@ const cleanUserSessions = require('./cleanUserSessions') const buildApolloContext = require('./context') -const loadSanctionLists = require('./loadSanctionLists') const session = require('./session') module.exports = { cleanUserSessions, buildApolloContext, - loadSanctionLists, session } diff --git a/lib/new-admin/middlewares/loadSanctionLists.js b/lib/new-admin/middlewares/loadSanctionLists.js deleted file mode 100644 index 48d2c0b8..00000000 --- a/lib/new-admin/middlewares/loadSanctionLists.js +++ /dev/null @@ -1,28 +0,0 @@ -const logger = require('../../logger') -const sanctions = require('../../ofac') - -const sanctionStatus = { - loaded: false, - timestamp: null -} - -const loadSanctionLists = (req, res, next) => { - if (!sanctionStatus.loaded) { - logger.info('No sanction lists loaded. Loading sanctions...') - return sanctions.load() - .then(() => { - logger.info('OFAC sanction list loaded!') - sanctionStatus.loaded = true - sanctionStatus.timestamp = Date.now() - return next() - }) - .catch(e => { - logger.error('Couldn\'t load OFAC sanction list!') - return next(e) - }) - } - - return next() -} - -module.exports = loadSanctionLists From 30a43869ec860f9232b9183d2a40faf28803db13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Mon, 11 Jul 2022 02:06:14 +0100 Subject: [PATCH 20/53] fix: increase OFAC list update timer --- lib/new-admin/graphql/resolvers/sanctions.resolver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js index 3945516a..95cf2d88 100644 --- a/lib/new-admin/graphql/resolvers/sanctions.resolver.js +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -9,7 +9,7 @@ const sanctionStatus = { } const loadOrUpdateSanctions = () => { - if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.minute)) { + if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.day)) { logger.info('No sanction lists loaded. Loading sanctions...') return ofac.load() .then(() => { From cec02c52ba68118195c39c9ea2e47d2e9730deef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Sat, 8 Oct 2022 01:08:29 +0100 Subject: [PATCH 21/53] fix: resolve full sanction checking flow in the backend --- .../graphql/resolvers/sanctions.resolver.js | 37 +++------------- lib/new-admin/graphql/types/sanctions.type.js | 2 +- lib/sanctions.js | 44 +++++++++++++++++++ .../src/pages/Customers/CustomerData.js | 4 +- .../src/pages/Customers/CustomerProfile.js | 17 ++----- 5 files changed, 55 insertions(+), 49 deletions(-) create mode 100644 lib/sanctions.js diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js index 95cf2d88..bb1a8862 100644 --- a/lib/new-admin/graphql/resolvers/sanctions.resolver.js +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -1,37 +1,12 @@ -const _ = require('lodash/fp') -const logger = require('../../../logger') -const ofac = require('../../../ofac') -const T = require('../../../time') - -const sanctionStatus = { - loaded: false, - timestamp: null -} - -const loadOrUpdateSanctions = () => { - if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.day)) { - logger.info('No sanction lists loaded. Loading sanctions...') - return ofac.load() - .then(() => { - logger.info('OFAC sanction list loaded!') - sanctionStatus.loaded = true - sanctionStatus.timestamp = Date.now() - }) - .catch(e => { - logger.error('Couldn\'t load OFAC sanction list!') - }) - } - - return Promise.resolve() -} +const sanctions = require('../../../sanctions') +const authentication = require('../modules/userManagement') const resolvers = { Query: { - checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => loadOrUpdateSanctions() - .then(() => { - const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) - return { ofacSanctioned: _.size(ofacMatches) > 0 } - }) + checkAgainstSanctions: (...[, { customerId }, context]) => { + const token = authentication.getToken(context) + return sanctions.checkByUser(customerId, token) + } } } diff --git a/lib/new-admin/graphql/types/sanctions.type.js b/lib/new-admin/graphql/types/sanctions.type.js index 76a5e572..b7899da6 100644 --- a/lib/new-admin/graphql/types/sanctions.type.js +++ b/lib/new-admin/graphql/types/sanctions.type.js @@ -6,7 +6,7 @@ const typeDef = gql` } type Query { - checkAgainstSanctions(firstName: String, lastName: String, birthdate: String): SanctionMatches @auth + checkAgainstSanctions(customerId: ID): SanctionMatches @auth } ` diff --git a/lib/sanctions.js b/lib/sanctions.js new file mode 100644 index 00000000..34b1b7fd --- /dev/null +++ b/lib/sanctions.js @@ -0,0 +1,44 @@ +const _ = require('lodash/fp') +const ofac = require('./ofac') +const T = require('./time') +const logger = require('./logger') +const customers = require('./customers') + +const sanctionStatus = { + loaded: false, + timestamp: null +} + +const loadOrUpdateSanctions = () => { + if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.day)) { + logger.info('No sanction lists loaded. Loading sanctions...') + return ofac.load() + .then(() => { + logger.info('OFAC sanction list loaded!') + sanctionStatus.loaded = true + sanctionStatus.timestamp = Date.now() + }) + .catch(e => { + logger.error('Couldn\'t load OFAC sanction list!') + }) + } + + return Promise.resolve() +} + +const checkByUser = (customerId, userToken) => { + return Promise.all([loadOrUpdateSanctions(), customers.getCustomerById(customerId)]) + .then(([, customer]) => { + const { firstName, lastName, dateOfBirth } = customer?.idCardData + const birthdate = _.replace(/-/g, '')(dateOfBirth) + const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) + const isOfacSanctioned = _.size(ofacMatches) > 0 + customers.updateCustomer(customerId, { sanctions: !isOfacSanctioned }, userToken) + + return { ofacSanctioned: isOfacSanctioned } + }) +} + +module.exports = { + checkByUser +} diff --git a/new-lamassu-admin/src/pages/Customers/CustomerData.js b/new-lamassu-admin/src/pages/Customers/CustomerData.js index affe5159..5edbe829 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerData.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerData.js @@ -176,9 +176,7 @@ const CustomerData = ({ checkAgainstSanctions: () => checkAgainstSanctions({ variables: { - firstName: initialValues.idCardData.firstName, - lastName: initialValues.idCardData.lastName, - birthdate: R.replace(/-/g, '')(initialValues.idCardData.dateOfBirth) + customerId: R.path(['id'])(customer) } }), initialValues: initialValues.idCardData, diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js index 3c03cb4f..44478022 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js @@ -293,16 +293,8 @@ const GET_ACTIVE_CUSTOM_REQUESTS = gql` ` const CHECK_AGAINST_SANCTIONS = gql` - query checkAgainstSanctions( - $firstName: String - $lastName: String - $birthdate: String - ) { - checkAgainstSanctions( - firstName: $firstName - lastName: $lastName - birthdate: $birthdate - ) { + query checkAgainstSanctions($customerId: ID) { + checkAgainstSanctions(customerId: $customerId) { ofacSanctioned } } @@ -417,10 +409,7 @@ const CustomerProfile = memo(() => { }) const [checkAgainstSanctions] = useLazyQuery(CHECK_AGAINST_SANCTIONS, { - onCompleted: ({ checkAgainstSanctions: { ofacSanctioned } }) => - updateCustomer({ - sanctions: !ofacSanctioned - }) + onCompleted: () => getCustomer() }) const updateCustomer = it => From 7bf7e49cf733c2c0f2f3fb96e01822ba6a217443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Sun, 12 Mar 2023 20:20:24 +0000 Subject: [PATCH 22/53] fix: CEX.IO missing credential UID --- new-lamassu-admin/src/pages/Services/schemas/cex.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/new-lamassu-admin/src/pages/Services/schemas/cex.js b/new-lamassu-admin/src/pages/Services/schemas/cex.js index 2c67aa1c..3cfacbd7 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/cex.js +++ b/new-lamassu-admin/src/pages/Services/schemas/cex.js @@ -17,6 +17,13 @@ export default { face: true, long: true }, + { + code: 'uid', + display: 'User ID', + component: TextInputFormik, + face: true, + long: true + }, { code: 'privateKey', display: 'Private Key', @@ -28,6 +35,9 @@ export default { apiKey: Yup.string('The API key must be a string') .max(100, 'The API key is too long') .required('The API key is required'), + uid: Yup.string('The User ID must be a string') + .max(100, 'The User ID is too long') + .required('The User ID is required'), privateKey: Yup.string('The private key must be a string') .max(100, 'The private key is too long') .test(secretTest(account?.privateKey, 'private key')) From 2f8d02cd7eacfdb2086a6de25626fde70716c76f Mon Sep 17 00:00:00 2001 From: josepfo Date: Tue, 17 Jan 2023 18:29:06 +0000 Subject: [PATCH 23/53] fix: hide replace button if state is pending --- .../src/pages/Customers/components/EditableCard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 1dc71165..02dbbe57 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -314,7 +314,7 @@ const EditableCard = ({ {editing && (
- {hasImage && ( + {hasImage && state !== OVERRIDE_PENDING && ( Date: Mon, 7 Nov 2022 18:55:35 +0100 Subject: [PATCH 24/53] fix: table scrollbar offsetting columns --- new-lamassu-admin/src/styling/global/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/new-lamassu-admin/src/styling/global/index.js b/new-lamassu-admin/src/styling/global/index.js index 4e5083ef..ceebff20 100644 --- a/new-lamassu-admin/src/styling/global/index.js +++ b/new-lamassu-admin/src/styling/global/index.js @@ -64,6 +64,9 @@ export default { // forcing styling onto inner container '.ReactVirtualized__Grid__innerScrollContainer': { overflow: 'inherit !important' + }, + '.ReactVirtualized__Grid.ReactVirtualized__List': { + overflowY: 'overlay !important' } } } From 72eb8517312c025f58c43019e0a062498ff38692 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Tue, 13 Dec 2022 11:32:59 +0100 Subject: [PATCH 25/53] fix: standardize caps --- .../src/components/editableTable/Header.js | 4 ++-- .../machineActions/MachineActions.js | 2 +- .../src/pages/Cashout/WizardStep.js | 2 +- .../Commissions/components/CommissionsList.js | 4 ++-- .../src/pages/Customers/CustomersList.js | 2 +- .../Customers/components/CustomerSidebar.js | 2 +- new-lamassu-admin/src/pages/Funding.js | 2 +- new-lamassu-admin/src/pages/MachineLogs.js | 2 +- .../src/pages/Maintenance/CashUnits.js | 2 +- .../src/pages/Maintenance/CashboxHistory.js | 2 +- .../pages/Maintenance/MachineDetailsCard.js | 4 ++-- .../src/pages/Maintenance/MachineStatus.js | 6 ++--- .../sections/CryptoBalanceAlerts.js | 4 ++-- .../src/pages/Notifications/sections/Setup.js | 6 ++--- .../src/pages/OperatorInfo/ContactInfo.js | 4 ++-- .../src/pages/OperatorInfo/ReceiptPrinting.js | 2 +- .../src/pages/Services/Services.js | 2 +- .../SessionManagement/SessionManagement.js | 2 +- .../pages/UserManagement/UserManagement.js | 2 +- new-lamassu-admin/src/pages/Wallet/Wallet.js | 2 +- new-lamassu-admin/src/pages/Wallet/helper.js | 10 ++++----- .../src/routing/lamassu.routes.js | 22 +++++++++---------- new-lamassu-admin/src/routing/pazuz.routes.js | 14 ++++++------ new-lamassu-admin/src/utils/string.js | 10 ++++++++- 24 files changed, 61 insertions(+), 53 deletions(-) diff --git a/new-lamassu-admin/src/components/editableTable/Header.js b/new-lamassu-admin/src/components/editableTable/Header.js index 07efcdac..b6ca9b2c 100644 --- a/new-lamassu-admin/src/components/editableTable/Header.js +++ b/new-lamassu-admin/src/components/editableTable/Header.js @@ -9,7 +9,7 @@ import { TDoubleLevelHead, ThDoubleLevel } from 'src/components/fake-table/Table' -import { startCase } from 'src/utils/string' +import { sentenceCase } from 'src/utils/string' import TableCtx from './Context' @@ -99,7 +99,7 @@ const Header = () => { <>{attachOrderedByToComplexHeader(header) ?? header} ) : ( - {!R.isNil(display) ? display : startCase(name)}{' '} + {!R.isNil(display) ? display : sentenceCase(name)}{' '} {!R.isNil(orderedBy) && R.equals(name, orderedBy.code) && '-'} )} diff --git a/new-lamassu-admin/src/components/machineActions/MachineActions.js b/new-lamassu-admin/src/components/machineActions/MachineActions.js index d9ede4f1..d62833a0 100644 --- a/new-lamassu-admin/src/components/machineActions/MachineActions.js +++ b/new-lamassu-admin/src/components/machineActions/MachineActions.js @@ -187,7 +187,7 @@ const MachineActions = memo(({ machine, onActionSuccess }) => { display: 'Restart services for' }) }}> - Restart Services + Restart services {machine.model === 'aveiro' && ( Default Commissions diff --git a/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js b/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js index 9ea641a1..ebf4f82e 100644 --- a/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js +++ b/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js @@ -37,7 +37,7 @@ const SHOW_ALL = { const ORDER_OPTIONS = [ { code: 'machine', - display: 'Machine Name' + display: 'Machine name' }, { code: 'cryptoCurrencies', @@ -53,7 +53,7 @@ const ORDER_OPTIONS = [ }, { code: 'fixedFee', - display: 'Fixed Fee' + display: 'Fixed fee' }, { code: 'minimumTx', diff --git a/new-lamassu-admin/src/pages/Customers/CustomersList.js b/new-lamassu-admin/src/pages/Customers/CustomersList.js index a7ed2a92..df39f4d9 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomersList.js +++ b/new-lamassu-admin/src/pages/Customers/CustomersList.js @@ -36,7 +36,7 @@ const CustomersList = ({ view: getName }, { - header: 'Total TXs', + header: 'Total Txs', width: 126, textAlign: 'right', view: it => `${Number.parseInt(it.totalTxs)}` diff --git a/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js b/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js index 6bcf3444..a698a218 100644 --- a/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js +++ b/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js @@ -26,7 +26,7 @@ const CustomerSidebar = ({ isSelected, onClick }) => { }, { code: 'customerData', - display: 'Customer Data', + display: 'Customer data', Icon: CustomerDataIcon, InverseIcon: CustomerDataReversedIcon }, diff --git a/new-lamassu-admin/src/pages/Funding.js b/new-lamassu-admin/src/pages/Funding.js index e642aaf3..9462ea1c 100644 --- a/new-lamassu-admin/src/pages/Funding.js +++ b/new-lamassu-admin/src/pages/Funding.js @@ -164,7 +164,7 @@ const Funding = () => { {funding.length && (
- Total Crypto Balance + Total crypto balance {getConfirmedTotal(funding)} diff --git a/new-lamassu-admin/src/pages/MachineLogs.js b/new-lamassu-admin/src/pages/MachineLogs.js index d06f4a2c..88bc6478 100644 --- a/new-lamassu-admin/src/pages/MachineLogs.js +++ b/new-lamassu-admin/src/pages/MachineLogs.js @@ -111,7 +111,7 @@ const Logs = () => { <>
- Machine Logs + Machine logs {logsResponse && (
{ !dataLoading && ( <> { }, { name: 'billCount', - header: 'Bill Count', + header: 'Bill count', width: 115, textAlign: 'left', input: NumberInput, diff --git a/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js index 0aaf1ea2..5551f009 100644 --- a/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js +++ b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js @@ -92,7 +92,7 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess, timezone }) => { - + {modelPrettifier[machine.model]} @@ -126,7 +126,7 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess, timezone }) => { - + {machine.packetLoss ? new BigNumber(machine.packetLoss).toFixed(3).toString() + diff --git a/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js b/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js index 035f2d33..e50eaf5c 100644 --- a/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js +++ b/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js @@ -74,7 +74,7 @@ const MachineStatus = () => { const elements = [ { - header: 'Machine Name', + header: 'Machine name', width: 250, size: 'sm', textAlign: 'left', @@ -111,7 +111,7 @@ const MachineStatus = () => { : 'unknown' }, { - header: 'Software Version', + header: 'Software version', width: 200, size: 'sm', textAlign: 'left', @@ -134,7 +134,7 @@ const MachineStatus = () => { <>
- Machine Status + Machine status
diff --git a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js index 270a9edb..a626020b 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js @@ -32,7 +32,7 @@ const CryptoBalanceAlerts = ({ section, fieldWidth }) => { section={section} decoration={currency} className={classes.cryptoBalanceAlertsForm} - title="Default (Low Balance)" + title="Default (Low balance)" label="Alert me under" editing={isEditing(LOW_BALANCE_KEY)} disabled={isDisabled(LOW_BALANCE_KEY)} @@ -49,7 +49,7 @@ const CryptoBalanceAlerts = ({ section, fieldWidth }) => { save={save} decoration={currency} className={classes.cryptoBalanceAlertsSecondForm} - title="Default (High Balance)" + title="Default (High balance)" label="Alert me over" editing={isEditing(HIGH_BALANCE_KEY)} disabled={isDisabled(HIGH_BALANCE_KEY)} diff --git a/new-lamassu-admin/src/pages/Notifications/sections/Setup.js b/new-lamassu-admin/src/pages/Notifications/sections/Setup.js index 2e8d7583..cd512b9e 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/Setup.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/Setup.js @@ -12,7 +12,7 @@ import { } from 'src/components/fake-table/Table' import { Switch } from 'src/components/inputs' import { fromNamespace, toNamespace } from 'src/utils/config' -import { startCase } from 'src/utils/string' +import { sentenceCase } from 'src/utils/string' import NotificationsCtx from '../NotificationsContext' @@ -62,7 +62,7 @@ const Row = ({ return ( - {shouldUpperCase ? R.toUpper(namespace) : startCase(namespace)} + {shouldUpperCase ? R.toUpper(namespace) : sentenceCase(namespace)} @@ -127,7 +127,7 @@ const Setup = ({ wizard, forceDisable }) => { Channel {Object.keys(sizes).map(it => ( - {startCase(it)} + {sentenceCase(it)} ))} diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js b/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js index e1b68f21..bb3f9bb8 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js @@ -136,7 +136,7 @@ const ContactInfo = ({ wizard }) => { const fields = [ { name: 'name', - label: 'Full name', + label: 'Company name', value: info.name ?? '', component: TextInput }, @@ -160,7 +160,7 @@ const ContactInfo = ({ wizard }) => { }, { name: 'companyNumber', - label: 'Company number', + label: 'Company registration number', value: info.companyNumber ?? '', component: TextInput } diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js index dd3f9d19..9b90c14a 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js @@ -109,7 +109,7 @@ const ReceiptPrinting = memo(({ wizard }) => { }, { name: 'companyNumber', - display: 'Company number' + display: 'Company registration number' }, { name: 'machineLocation', diff --git a/new-lamassu-admin/src/pages/Services/Services.js b/new-lamassu-admin/src/pages/Services/Services.js index 966038c9..6a2e08d8 100644 --- a/new-lamassu-admin/src/pages/Services/Services.js +++ b/new-lamassu-admin/src/pages/Services/Services.js @@ -103,7 +103,7 @@ const Services = () => { return (
- + {R.values(schemas).map(schema => ( diff --git a/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js b/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js index 83457474..bc7fbe02 100644 --- a/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js +++ b/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js @@ -108,7 +108,7 @@ const SessionManagement = () => { return ( <> - + { return ( <> - + { <>
{ }, { name: 'allowTransactionBatching', - header: `Allow BTC Transaction Batching`, + header: `Allow BTC transaction batching`, size: 'sm', stripe: true, width: 260, @@ -119,7 +119,7 @@ const getAdvancedWalletElements = () => { }, { name: 'feeMultiplier', - header: `BTC Miner's Fee`, + header: `BTC Miner's fee`, size: 'sm', stripe: true, width: 250, @@ -179,7 +179,7 @@ const getAdvancedWalletElementsOverrides = ( }, { name: 'feeMultiplier', - header: `Miner's Fee`, + header: `Miner's fee`, size: 'sm', stripe: true, width: 250, @@ -280,7 +280,7 @@ const getElements = (cryptoCurrencies, accounts, onChange, wizard = false) => { }, { name: 'zeroConf', - header: 'Confidence Checking', + header: 'Confidence checking', size: 'sm', stripe: true, view: (it, row) => { @@ -304,7 +304,7 @@ const getElements = (cryptoCurrencies, accounts, onChange, wizard = false) => { }, { name: 'zeroConfLimit', - header: '0-conf Limit', + header: '0-conf limit', size: 'sm', stripe: true, view: (it, row) => diff --git a/new-lamassu-admin/src/routing/lamassu.routes.js b/new-lamassu-admin/src/routing/lamassu.routes.js index 4b2ca01f..873fc0fb 100644 --- a/new-lamassu-admin/src/routing/lamassu.routes.js +++ b/new-lamassu-admin/src/routing/lamassu.routes.js @@ -49,7 +49,7 @@ const getLamassuRoutes = () => [ children: [ { key: 'cash_units', - label: 'Cash Units', + label: 'Cash units', route: '/maintenance/cash-units', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: CashUnits @@ -63,14 +63,14 @@ const getLamassuRoutes = () => [ }, { key: 'logs', - label: 'Machine Logs', + label: 'Machine logs', route: '/maintenance/logs', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineLogs }, { key: 'machine-status', - label: 'Machine Status', + label: 'Machine status', route: '/maintenance/machine-status', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineStatus @@ -130,7 +130,7 @@ const getLamassuRoutes = () => [ }, { key: 'services', - label: '3rd Party Services', + label: '3rd Party services', route: '/settings/3rd-party-services', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: Services @@ -144,9 +144,9 @@ const getLamassuRoutes = () => [ }, { key: namespaces.OPERATOR_INFO, - label: 'Operator Info', + label: 'Operator info', route: '/settings/operator-info', - title: 'Operator Information', + title: 'Operator information', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], get component() { return () => ( @@ -232,7 +232,7 @@ const getLamassuRoutes = () => [ key: 'loyalty', label: 'Loyalty', route: '/compliance/loyalty', - title: 'Loyalty Panel', + title: 'Loyalty panel', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], get component() { return () => ( @@ -247,14 +247,14 @@ const getLamassuRoutes = () => [ children: [ { key: 'individual-discounts', - label: 'Individual Discounts', + label: 'Individual discounts', route: '/compliance/loyalty/individual-discounts', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: IndividualDiscounts }, { key: 'promo-codes', - label: 'Promo Codes', + label: 'Promo codes', route: '/compliance/loyalty/codes', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: PromoCodes @@ -280,14 +280,14 @@ const getLamassuRoutes = () => [ children: [ { key: 'user-management', - label: 'User Management', + label: 'User management', route: '/system/user-management', allowedRoles: [ROLES.SUPERUSER], component: UserManagement }, { key: 'session-management', - label: 'Session Management', + label: 'Session management', route: '/system/session-management', allowedRoles: [ROLES.SUPERUSER], component: SessionManagement diff --git a/new-lamassu-admin/src/routing/pazuz.routes.js b/new-lamassu-admin/src/routing/pazuz.routes.js index e0a9be94..f6ad9d21 100644 --- a/new-lamassu-admin/src/routing/pazuz.routes.js +++ b/new-lamassu-admin/src/routing/pazuz.routes.js @@ -56,14 +56,14 @@ const getPazuzRoutes = () => [ }, { key: 'logs', - label: 'Machine Logs', + label: 'Machine logs', route: '/maintenance/logs', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineLogs }, { key: 'machine-status', - label: 'Machine Status', + label: 'Machine status', route: '/maintenance/machine-status', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineStatus @@ -123,9 +123,9 @@ const getPazuzRoutes = () => [ }, { key: namespaces.OPERATOR_INFO, - label: 'Operator Info', + label: 'Operator info', route: '/settings/operator-info', - title: 'Operator Information', + title: 'Operator information', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], get component() { return () => ( @@ -232,7 +232,7 @@ const getPazuzRoutes = () => [ }, { key: 'promo-codes', - label: 'Promo Codes', + label: 'Promo codes', route: '/compliance/loyalty/codes', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: PromoCodes @@ -290,14 +290,14 @@ const getPazuzRoutes = () => [ children: [ { key: 'user-management', - label: 'User Management', + label: 'User management', route: '/system/user-management', allowedRoles: [ROLES.SUPERUSER], component: UserManagement }, { key: 'session-management', - label: 'Session Management', + label: 'Session management', route: '/system/session-management', allowedRoles: [ROLES.SUPERUSER], component: SessionManagement diff --git a/new-lamassu-admin/src/utils/string.js b/new-lamassu-admin/src/utils/string.js index 837369c8..d210cfba 100644 --- a/new-lamassu-admin/src/utils/string.js +++ b/new-lamassu-admin/src/utils/string.js @@ -26,7 +26,15 @@ const startCase = R.compose( splitOnUpper ) +const sentenceCase = R.compose(onlyFirstToUpper, S.joinWith(' '), splitOnUpper) + const singularOrPlural = (amount, singularStr, pluralStr) => parseInt(amount) === 1 ? singularStr : pluralStr -export { startCase, onlyFirstToUpper, formatLong, singularOrPlural } +export { + startCase, + onlyFirstToUpper, + formatLong, + singularOrPlural, + sentenceCase +} From 644a6b32bd12630182299c4f283896be21c81c5b Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Tue, 13 Dec 2022 11:34:19 +0100 Subject: [PATCH 26/53] fix: standardize caps --- .../src/pages/Analytics/Analytics.js | 2 +- .../src/pages/Commissions/helper.js | 10 ++++----- .../pages/Customers/components/IdDataCard.js | 4 ++-- .../src/pages/Customers/helper.js | 2 +- new-lamassu-admin/src/pages/Locales/helper.js | 6 ++--- .../sections/CryptoBalanceOverrides.js | 4 ++-- .../src/pages/Services/Services.js | 2 +- .../src/pages/Services/schemas/binance.js | 4 ++-- .../src/pages/Services/schemas/binanceus.js | 4 ++-- .../src/pages/Services/schemas/bitgo.js | 22 +++++++++---------- .../src/pages/Services/schemas/bitstamp.js | 4 ++-- .../src/pages/Services/schemas/blockcypher.js | 4 ++-- .../src/pages/Services/schemas/cex.js | 4 ++-- .../src/pages/Services/schemas/itbit.js | 4 ++-- .../src/pages/Services/schemas/kraken.js | 4 ++-- .../src/pages/Services/schemas/mailgun.js | 6 ++--- .../src/pages/Services/schemas/singlebitgo.js | 6 ++--- .../src/pages/Services/schemas/twilio.js | 6 ++--- .../src/pages/Transactions/Transactions.js | 2 +- new-lamassu-admin/src/pages/Wallet/helper.js | 2 +- .../src/routing/lamassu.routes.js | 2 +- new-lamassu-admin/src/routing/pazuz.routes.js | 2 +- 22 files changed, 53 insertions(+), 53 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index b7eed8fa..46d85572 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -29,7 +29,7 @@ const useStyles = makeStyles(styles) const MACHINE_OPTIONS = [{ code: 'all', display: 'All machines' }] const REPRESENTING_OPTIONS = [ { code: 'overTime', display: 'Over time' }, - { code: 'topMachines', display: 'Top Machines' }, + { code: 'topMachines', display: 'Top machines' }, { code: 'hourOfTheDay', display: 'Hour of the day' } ] const PERIOD_OPTIONS = [ diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index f93e6789..6418afa4 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -245,7 +245,7 @@ const getSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed Fee') + .label('Fixed fee') .min(0) .max(highestBill) .required(), @@ -326,7 +326,7 @@ const getOverridesSchema = (values, rawData, locale) => { return true } }) - .label('Crypto Currencies') + .label('Crypto currencies') .required() .min(1), cashIn: Yup.number() @@ -340,7 +340,7 @@ const getOverridesSchema = (values, rawData, locale) => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed Fee') + .label('Fixed fee') .min(0) .max(highestBill) .required(), @@ -437,7 +437,7 @@ const getListCommissionsSchema = locale => { .label('Machine') .required(), cryptoCurrencies: Yup.array() - .label('Crypto Currency') + .label('Crypto currency') .required() .min(1), cashIn: Yup.number() @@ -451,7 +451,7 @@ const getListCommissionsSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed Fee') + .label('Fixed fee') .min(0) .max(highestBill) .required(), diff --git a/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js b/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js index 3083283f..12a838db 100644 --- a/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js @@ -32,7 +32,7 @@ const IdDataCard = memo(({ customerData, updateCustomer }) => { size: 160 }, { - header: 'Birth Date', + header: 'Birth date', display: (rawDob && format('yyyy-MM-dd')(parse(new Date(), 'yyyyMMdd', rawDob))) ?? @@ -61,7 +61,7 @@ const IdDataCard = memo(({ customerData, updateCustomer }) => { size: 120 }, { - header: 'Expiration Date', + header: 'Expiration date', display: ifNotNull( rawExpirationDate, format('yyyy-MM-dd', rawExpirationDate) diff --git a/new-lamassu-admin/src/pages/Customers/helper.js b/new-lamassu-admin/src/pages/Customers/helper.js index 42e38317..84954b99 100644 --- a/new-lamassu-admin/src/pages/Customers/helper.js +++ b/new-lamassu-admin/src/pages/Customers/helper.js @@ -411,7 +411,7 @@ const customerDataElements = { }, { name: 'expirationDate', - label: 'Expiration Date', + label: 'Expiration date', component: TextInput, editable: true }, diff --git a/new-lamassu-admin/src/pages/Locales/helper.js b/new-lamassu-admin/src/pages/Locales/helper.js index 32b14e4e..2c050694 100644 --- a/new-lamassu-admin/src/pages/Locales/helper.js +++ b/new-lamassu-admin/src/pages/Locales/helper.js @@ -157,7 +157,7 @@ const LocaleSchema = Yup.object().shape({ .label('Country') .required(), fiatCurrency: Yup.string() - .label('Fiat Currency') + .label('Fiat currency') .required(), languages: Yup.array() .label('Languages') @@ -165,7 +165,7 @@ const LocaleSchema = Yup.object().shape({ .min(1) .max(4), cryptoCurrencies: Yup.array() - .label('Crypto Currencies') + .label('Crypto currencies') .required() .min(1), timezone: Yup.string() @@ -186,7 +186,7 @@ const OverridesSchema = Yup.object().shape({ .min(1) .max(4), cryptoCurrencies: Yup.array() - .label('Crypto Currencies') + .label('Crypto currencies') .required() .min(1) }) diff --git a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js index dcd2fb4e..c4957965 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js @@ -62,7 +62,7 @@ const CryptoBalanceOverrides = ({ section }) => { .nullable() .required(), [LOW_BALANCE_KEY]: Yup.number() - .label('Low Balance') + .label('Low balance') .when(HIGH_BALANCE_KEY, { is: HIGH_BALANCE_KEY => !HIGH_BALANCE_KEY, then: Yup.number().required() @@ -73,7 +73,7 @@ const CryptoBalanceOverrides = ({ section }) => { .max(CURRENCY_MAX) .nullable(), [HIGH_BALANCE_KEY]: Yup.number() - .label('High Balance') + .label('High balance') .when(LOW_BALANCE_KEY, { is: LOW_BALANCE_KEY => !LOW_BALANCE_KEY, then: Yup.number().required() diff --git a/new-lamassu-admin/src/pages/Services/Services.js b/new-lamassu-admin/src/pages/Services/Services.js index 6a2e08d8..72eab97b 100644 --- a/new-lamassu-admin/src/pages/Services/Services.js +++ b/new-lamassu-admin/src/pages/Services/Services.js @@ -103,7 +103,7 @@ const Services = () => { return (
- + {R.values(schemas).map(schema => ( diff --git a/new-lamassu-admin/src/pages/Services/schemas/binance.js b/new-lamassu-admin/src/pages/Services/schemas/binance.js index 8e4e9bd4..6be4be26 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/binance.js +++ b/new-lamassu-admin/src/pages/Services/schemas/binance.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/binanceus.js b/new-lamassu-admin/src/pages/Services/schemas/binanceus.js index eee1ece7..7afd724b 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/binanceus.js +++ b/new-lamassu-admin/src/pages/Services/schemas/binanceus.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/bitgo.js b/new-lamassu-admin/src/pages/Services/schemas/bitgo.js index f810a728..2e57b9a0 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/bitgo.js +++ b/new-lamassu-admin/src/pages/Services/schemas/bitgo.js @@ -26,7 +26,7 @@ export default { elements: [ { code: 'token', - display: 'API Token', + display: 'API token', component: TextInput, face: true, long: true @@ -47,52 +47,52 @@ export default { }, { code: 'BTCWalletId', - display: 'BTC Wallet ID', + display: 'BTC wallet ID', component: TextInput }, { code: 'BTCWalletPassphrase', - display: 'BTC Wallet Passphrase', + display: 'BTC wallet passphrase', component: SecretInput }, { code: 'LTCWalletId', - display: 'LTC Wallet ID', + display: 'LTC wallet ID', component: TextInput }, { code: 'LTCWalletPassphrase', - display: 'LTC Wallet Passphrase', + display: 'LTC wallet passphrase', component: SecretInput }, { code: 'ZECWalletId', - display: 'ZEC Wallet ID', + display: 'ZEC wallet ID', component: TextInput }, { code: 'ZECWalletPassphrase', - display: 'ZEC Wallet Passphrase', + display: 'ZEC wallet passphrase', component: SecretInput }, { code: 'BCHWalletId', - display: 'BCH Wallet ID', + display: 'BCH wallet ID', component: TextInput }, { code: 'BCHWalletPassphrase', - display: 'BCH Wallet Passphrase', + display: 'BCH wallet passphrase', component: SecretInput }, { code: 'DASHWalletId', - display: 'DASH Wallet ID', + display: 'DASH wallet ID', component: TextInput }, { code: 'DASHWalletPassphrase', - display: 'DASH Wallet Passphrase', + display: 'DASH wallet passphrase', component: SecretInput } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js b/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js index df8e8105..431fcfb5 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js +++ b/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js @@ -19,14 +19,14 @@ export default { }, { code: 'key', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'secret', - display: 'API Secret', + display: 'API secret', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js b/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js index 3515eb1e..d0875577 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js +++ b/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js @@ -9,14 +9,14 @@ export default { elements: [ { code: 'token', - display: 'API Token', + display: 'API token', component: TextInput, face: true, long: true }, { code: 'confidenceFactor', - display: 'Confidence Factor', + display: 'Confidence factor', component: NumberInput, face: true }, diff --git a/new-lamassu-admin/src/pages/Services/schemas/cex.js b/new-lamassu-admin/src/pages/Services/schemas/cex.js index 2c67aa1c..c43b6bda 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/cex.js +++ b/new-lamassu-admin/src/pages/Services/schemas/cex.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/itbit.js b/new-lamassu-admin/src/pages/Services/schemas/itbit.js index 702ca29e..949ba692 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/itbit.js +++ b/new-lamassu-admin/src/pages/Services/schemas/itbit.js @@ -26,12 +26,12 @@ export default { }, { code: 'clientKey', - display: 'Client Key', + display: 'Client key', component: TextInputFormik }, { code: 'clientSecret', - display: 'Client Secret', + display: 'Client secret', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/kraken.js b/new-lamassu-admin/src/pages/Services/schemas/kraken.js index 752c3f7a..733cebe4 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/kraken.js +++ b/new-lamassu-admin/src/pages/Services/schemas/kraken.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/mailgun.js b/new-lamassu-admin/src/pages/Services/schemas/mailgun.js index 151344e9..80e1f615 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/mailgun.js +++ b/new-lamassu-admin/src/pages/Services/schemas/mailgun.js @@ -9,7 +9,7 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik }, { @@ -19,13 +19,13 @@ export default { }, { code: 'fromEmail', - display: 'From Email', + display: 'From email', component: TextInputFormik, face: true }, { code: 'toEmail', - display: 'To Email', + display: 'To email', component: TextInputFormik, face: true } diff --git a/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js b/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js index 5af804ca..9e206632 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js +++ b/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js @@ -13,7 +13,7 @@ const singleBitgo = code => ({ elements: [ { code: 'token', - display: 'API Token', + display: 'API token', component: TextInput, face: true, long: true @@ -34,12 +34,12 @@ const singleBitgo = code => ({ }, { code: `${code}WalletId`, - display: `${code} Wallet ID`, + display: `${code} wallet ID`, component: TextInput }, { code: `${code}WalletPassphrase`, - display: `${code} Wallet Passphrase`, + display: `${code} wallet passphrase`, component: SecretInput } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/twilio.js b/new-lamassu-admin/src/pages/Services/schemas/twilio.js index 1ed2228f..4628edb3 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/twilio.js +++ b/new-lamassu-admin/src/pages/Services/schemas/twilio.js @@ -17,18 +17,18 @@ export default { }, { code: 'authToken', - display: 'Auth Token', + display: 'Auth token', component: SecretInputFormik }, { code: 'fromNumber', - display: 'Twilio Number (international format)', + display: 'Twilio number (international format)', component: TextInputFormik, face: true }, { code: 'toNumber', - display: 'Notifications Number (international format)', + display: 'Notifications number (international format)', component: TextInputFormik, face: true } diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index 2559dfbf..cd49ca34 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -323,7 +323,7 @@ const Transactions = () => { loading={filtersLoading} filters={filters} options={filterOptions} - inputPlaceholder={'Search Transactions'} + inputPlaceholder={'Search transactions'} onChange={onFilterChange} />
diff --git a/new-lamassu-admin/src/pages/Wallet/helper.js b/new-lamassu-admin/src/pages/Wallet/helper.js index 1f6d6c61..7747292f 100644 --- a/new-lamassu-admin/src/pages/Wallet/helper.js +++ b/new-lamassu-admin/src/pages/Wallet/helper.js @@ -119,7 +119,7 @@ const getAdvancedWalletElements = () => { }, { name: 'feeMultiplier', - header: `BTC Miner's fee`, + header: `BTC miner's fee`, size: 'sm', stripe: true, width: 250, diff --git a/new-lamassu-admin/src/routing/lamassu.routes.js b/new-lamassu-admin/src/routing/lamassu.routes.js index 873fc0fb..ec5d5325 100644 --- a/new-lamassu-admin/src/routing/lamassu.routes.js +++ b/new-lamassu-admin/src/routing/lamassu.routes.js @@ -130,7 +130,7 @@ const getLamassuRoutes = () => [ }, { key: 'services', - label: '3rd Party services', + label: 'Third-party services', route: '/settings/3rd-party-services', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: Services diff --git a/new-lamassu-admin/src/routing/pazuz.routes.js b/new-lamassu-admin/src/routing/pazuz.routes.js index f6ad9d21..8551c123 100644 --- a/new-lamassu-admin/src/routing/pazuz.routes.js +++ b/new-lamassu-admin/src/routing/pazuz.routes.js @@ -225,7 +225,7 @@ const getPazuzRoutes = () => [ children: [ { key: 'individual-discounts', - label: 'Individual Discounts', + label: 'Individual discounts', route: '/compliance/loyalty/individual-discounts', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: IndividualDiscounts From 0db359afa39f926ae93642062bf6600cf6b84793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 30 Nov 2022 15:47:17 +0000 Subject: [PATCH 27/53] fix: add 2 decimal places to commission --- new-lamassu-admin/src/pages/Transactions/DetailsCard.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index cd40af4b..936c6ced 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -131,8 +131,9 @@ const DetailsRow = ({ it: tx, timezone }) => { ) const commission = BigNumber(tx.profit).toFixed(2, 1) // ROUND_DOWN - const commissionPercentage = + const commissionPercentage = BigNumber( Number.parseFloat(tx.commissionPercentage, 2) * 100 + ).toFixed(2, 1) // ROUND_DOWN const cashInFee = isCashIn ? Number.parseFloat(tx.cashInFee) : 0 const fiat = BigNumber(tx.fiat) .minus(cashInFee) From 9f84ae97f2f0320eca5a6160f6e9548e1db71b33 Mon Sep 17 00:00:00 2001 From: siiky Date: Wed, 27 Nov 2024 10:24:08 +0000 Subject: [PATCH 28/53] chore: fix functions' docs --- lib/customers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/customers.js b/lib/customers.js index d7975972..96e36bd8 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -80,7 +80,7 @@ function getWithEmail (email) { * * @param {string} id Customer's id * @param {object} data Fields to update - * @param {string} Acting user's token + * @param {string} userToken Acting user's token * * @returns {Promise} Newly updated Customer */ @@ -229,7 +229,7 @@ function enhanceEditedPhotos (fields) { /** * Remove the edited data from the db record * - * @name enhanceOverrideFields + * @name deleteEditedData * @function * * @param {string} id Customer's id From b86bcf63ffe0f1ead05212399a91f8efdac03388 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 6 Feb 2023 13:29:08 +0100 Subject: [PATCH 29/53] fix: cash boxes table height --- new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js b/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js index 5d793293..389968bc 100644 --- a/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js +++ b/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js @@ -5,7 +5,7 @@ export default { height: 36 }, tBody: { - maxHeight: '65vh', + maxHeight: 'calc(100vh - 350px)', overflow: 'auto' }, tableWidth: { From ac35e5c006060576b8f3c5cef3d204e4d0ab99e7 Mon Sep 17 00:00:00 2001 From: siiky Date: Wed, 27 Nov 2024 10:24:44 +0000 Subject: [PATCH 30/53] refactor: remove unused argument --- lib/routes/customerRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/routes/customerRoutes.js b/lib/routes/customerRoutes.js index f9120b84..1b51b872 100644 --- a/lib/routes/customerRoutes.js +++ b/lib/routes/customerRoutes.js @@ -108,7 +108,7 @@ function updateCustomer (req, res, next) { .then(_.merge(patch)) .then(newPatch => customers.updatePhotoCard(id, newPatch)) .then(newPatch => customers.updateFrontCamera(id, newPatch)) - .then(newPatch => customers.update(id, newPatch, null, txId)) + .then(newPatch => customers.update(id, newPatch, null)) .then(customer => { createPendingManualComplianceNotifs(settings, customer, deviceId) respond(req, res, { customer }) From ac7bcac53f2f4211634a523c0b01c65b781cab97 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 6 Feb 2023 13:33:36 +0100 Subject: [PATCH 31/53] fix: cashbox history table height --- .../src/pages/Maintenance/CashboxHistory.js | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js b/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js index 139899d1..080868cb 100644 --- a/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js +++ b/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js @@ -51,6 +51,12 @@ const styles = { display: 'flex', flexDirection: 'row', justifyContent: 'space-between' + }, + tableWrapper: { + display: 'flex', + flexDirection: 'column', + flex: 1, + marginBottom: 80 } } @@ -243,13 +249,15 @@ const CashboxHistory = ({ machines, currency, timezone }) => { ] return ( - +
+ +
) } From b44a7e2d750f137b0380522a3f1e78d6139604b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Wed, 9 Mar 2022 17:51:24 +0000 Subject: [PATCH 32/53] fix: correctly hide secret fields from GQL results --- lib/new-settings-loader.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/new-settings-loader.js b/lib/new-settings-loader.js index 76cd120c..e571d1e2 100644 --- a/lib/new-settings-loader.js +++ b/lib/new-settings-loader.js @@ -100,16 +100,19 @@ function loadAccounts (schemaVersion) { .then(_.compose(_.defaultTo({}), _.get('data.accounts'))) } +function hideSecretFields (accounts) { + return _.flow( + _.filter(path => !_.isEmpty(_.get(path, accounts))), + _.reduce( + (accounts, path) => _.assoc(path, PASSWORD_FILLED, accounts), + accounts + ) + )(SECRET_FIELDS) +} + function showAccounts (schemaVersion) { return loadAccounts(schemaVersion) - .then(accounts => { - const filledSecretPaths = _.compact(_.map(path => { - if (!_.isEmpty(_.get(path, accounts))) { - return path - } - }, SECRET_FIELDS)) - return _.compose(_.map(path => _.assoc(path, PASSWORD_FILLED), filledSecretPaths))(accounts) - }) + .then(hideSecretFields) } const insertConfigRow = (dbOrTx, data) => From c5e781883698bee23a586b27a42736d9951dd0c7 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:12 +0100 Subject: [PATCH 33/53] feat: add cash-out fixed fee columns to DB --- .../1732790112740-add-cashout-fee-to-cash_out_txs.js | 7 +++++++ migrations/1732790112741-add-cashout-fee-to-user_config.js | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js create mode 100644 migrations/1732790112741-add-cashout-fee-to-user_config.js diff --git a/migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js b/migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js new file mode 100644 index 00000000..ad5df91b --- /dev/null +++ b/migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js @@ -0,0 +1,7 @@ +const db = require('./db') + +exports.up = next => db.multi([ + 'ALTER TABLE cash_out_txs ADD COLUMN fixed_fee numeric(14, 5) NOT NULL DEFAULT 0;' +], next) + +exports.down = next => next() diff --git a/migrations/1732790112741-add-cashout-fee-to-user_config.js b/migrations/1732790112741-add-cashout-fee-to-user_config.js new file mode 100644 index 00000000..92296e38 --- /dev/null +++ b/migrations/1732790112741-add-cashout-fee-to-user_config.js @@ -0,0 +1,7 @@ +const { saveConfig } = require('../lib/new-settings-loader') + +exports.up = next => saveConfig({ 'commissions_cashOutFixedFee': 0 }) + .then(next) + .catch(next) + +exports.down = next => next() From 5b55ce89d8f673f7845e20b246ac41424dcf8065 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:14 +0100 Subject: [PATCH 34/53] feat: add support for multiple double-headers to `EditableTable` --- .../src/components/editableTable/Header.js | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/new-lamassu-admin/src/components/editableTable/Header.js b/new-lamassu-admin/src/components/editableTable/Header.js index b6ca9b2c..2c422e43 100644 --- a/new-lamassu-admin/src/components/editableTable/Header.js +++ b/new-lamassu-admin/src/components/editableTable/Header.js @@ -22,22 +22,27 @@ const styles = { const useStyles = makeStyles(styles) 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 + const doubleHeader = R.prop('doubleHeader') + const sameDoubleHeader = (a, b) => doubleHeader(a) === doubleHeader(b) + const group = R.pipe( + R.groupWith(sameDoubleHeader), + R.map(group => + R.isNil(doubleHeader(group[0])) // No doubleHeader + ? group + : [ + { + width: R.sum(R.map(R.prop('width'), group)), + elements: group, + name: doubleHeader(group[0]) + } + ] + ), + R.reduce(R.concat, []) ) - return [innerElements, TDoubleLevelHead] + return R.all(R.pipe(doubleHeader, R.isNil), elements) + ? [elements, THead] + : [group(elements), TDoubleLevelHead] } const Header = () => { From d6d7753e076d12ba38b44e30ac23b96fbc0823f8 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:16 +0100 Subject: [PATCH 35/53] feat: add cash-out fixed fee to Admin UI --- .../src/pages/Commissions/helper.js | 70 +++++++++++++++++-- .../Commissions/Commissions.js | 5 +- .../MachineComponents/Commissions/helper.js | 8 +++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index 6418afa4..c7f098a6 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -156,6 +156,20 @@ const getOverridesFields = (getData, currency, auxElements) => { inputProps: { decimalPlaces: 2 } + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 144, + doubleHeader: 'Cash-out only', + textAlign: 'center', + editingAlign: 'right', + input: NumberInput, + suffix: currency, + bold: bold, + inputProps: { + decimalPlaces: 2 + } } ] } @@ -218,6 +232,20 @@ const mainFields = currency => [ inputProps: { decimalPlaces: 2 } + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 169, + doubleHeader: 'Cash-out only', + textAlign: 'center', + editingAlign: 'right', + input: NumberInput, + suffix: currency, + bold: bold, + inputProps: { + decimalPlaces: 2 + } } ] @@ -245,7 +273,7 @@ const getSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed fee') + .label('Cash-in fixed fee') .min(0) .max(highestBill) .required(), @@ -253,6 +281,11 @@ const getSchema = locale => { .label('Minimum Tx') .min(0) .max(highestBill) + .required(), + cashOutFixedFee: Yup.number() + .label('Cash-out fixed fee') + .min(0) + .max(highestBill) .required() }) } @@ -340,7 +373,7 @@ const getOverridesSchema = (values, rawData, locale) => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed fee') + .label('Cash-in fixed fee') .min(0) .max(highestBill) .required(), @@ -348,6 +381,11 @@ const getOverridesSchema = (values, rawData, locale) => { .label('Minimum Tx') .min(0) .max(highestBill) + .required(), + cashOutFixedFee: Yup.number() + .label('Cash-out fixed fee') + .min(0) + .max(highestBill) .required() }) } @@ -356,7 +394,8 @@ const defaults = { cashIn: '', cashOut: '', fixedFee: '', - minimumTx: '' + minimumTx: '', + cashOutFixedFee: '' } const overridesDefaults = { @@ -365,7 +404,8 @@ const overridesDefaults = { cashIn: '', cashOut: '', fixedFee: '', - minimumTx: '' + minimumTx: '', + cashOutFixedFee: '' } const getOrder = ({ machine, cryptoCurrencies }) => { @@ -385,6 +425,7 @@ const createCommissions = (cryptoCode, deviceId, isDefault, config) => { fixedFee: config.fixedFee, cashOut: config.cashOut, cashIn: config.cashIn, + cashOutFixedFee: config.cashOutFixedFee, machine: deviceId, cryptoCurrencies: [cryptoCode], default: isDefault, @@ -451,7 +492,7 @@ const getListCommissionsSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed fee') + .label('Cash-in fixed fee') .min(0) .max(highestBill) .required(), @@ -459,6 +500,11 @@ const getListCommissionsSchema = locale => { .label('Minimum Tx') .min(0) .max(highestBill) + .required(), + cashOutFixedFee: Yup.number() + .label('Cash-out fixed fee') + .min(0) + .max(highestBill) .required() }) } @@ -544,6 +590,20 @@ const getListCommissionsFields = (getData, currency, defaults) => { inputProps: { decimalPlaces: 2 } + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 144, + doubleHeader: 'Cash-out only', + textAlign: 'center', + editingAlign: 'right', + input: NumberInput, + suffix: currency, + bold: bold, + inputProps: { + decimalPlaces: 2 + } } ] } diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js index caf876e9..a9f8766b 100644 --- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js +++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js @@ -64,10 +64,11 @@ const Commissions = ({ name: SCREEN_KEY, id: deviceId }) => { cashIn: config.cashIn, cashOut: config.cashOut, fixedFee: config.fixedFee, - minimumTx: config.minimumTx + minimumTx: config.minimumTx, + cashOutFixedFee: config.cashOutFixedFee }, R.project( - ['cashIn', 'cashOut', 'fixedFee', 'minimumTx'], + ['cashIn', 'cashOut', 'fixedFee', 'minimumTx', 'cashOutFixedFee'], R.filter( o => R.includes(coin.code, o.cryptoCurrencies) || diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js index 649979db..cbc47265 100644 --- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js @@ -61,6 +61,14 @@ const getOverridesFields = currency => { doubleHeader: 'Cash-in only', textAlign: 'right', suffix: currency + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 155, + doubleHeader: 'Cash-out only', + textAlign: 'right', + suffix: currency } ] } From 83595efd8e07045e5887a858ec566ee5c8691506 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:19 +0100 Subject: [PATCH 36/53] feat: send cash-out fixed fee to Coin ATM Radar --- lib/coinatmradar/coinatmradar.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index f6ead34a..88b9eaf4 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -29,6 +29,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 cashOutFixedFee = showCommissions ? commissions.cashOutFixedFee : null const cashInRate = showCommissions ? _.invoke('cashIn.toNumber', buildedRates) : null const cashOutRate = showCommissions ? _.invoke('cashOut.toNumber', buildedRates) : null @@ -37,6 +38,7 @@ function mapCoin (rates, deviceId, settings, cryptoCode) { cashInFee, cashOutFee, cashInFixedFee, + cashOutFixedFee, cashInRate, cashOutRate } From 35b1a69434f9a3a19b686d755fa480a72b8ac2db Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:21 +0100 Subject: [PATCH 37/53] feat: add cash-out fixed fee to Server-Machine GraphQL API --- lib/graphql/resolvers.js | 1 + lib/graphql/types.js | 1 + lib/plugins.js | 2 ++ 3 files changed, 4 insertions(+) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index cf4f4da0..1270f1f3 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -89,6 +89,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings 'cashInCommission', 'cashInFee', 'cashOutCommission', + 'cashOutFee', 'cryptoCode', 'cryptoCodeDisplay', 'cryptoNetwork', diff --git a/lib/graphql/types.js b/lib/graphql/types.js index 466391f9..89296c6c 100644 --- a/lib/graphql/types.js +++ b/lib/graphql/types.js @@ -6,6 +6,7 @@ type Coin { display: String! minimumTx: String! cashInFee: String! + cashOutFee: String! cashInCommission: String! cashOutCommission: String! cryptoNetwork: String! diff --git a/lib/plugins.js b/lib/plugins.js index f1587f07..d5bfcb4f 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -249,6 +249,7 @@ function plugins (settings, deviceId) { const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config) const minimumTx = new BN(commissions.minimumTx) const cashInFee = new BN(commissions.fixedFee) + const cashOutFee = new BN(commissions.cashOutFixedFee) const cashInCommission = new BN(commissions.cashIn) const cashOutCommission = _.isNumber(commissions.cashOut) ? new BN(commissions.cashOut) : null const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode) @@ -261,6 +262,7 @@ function plugins (settings, deviceId) { isCashInOnly: Boolean(cryptoRec.isCashinOnly), minimumTx: BN.max(minimumTx, cashInFee), cashInFee, + cashOutFee, cashInCommission, cashOutCommission, cryptoNetwork, From 8fc3d7d81927389ec88bc7bdb2ad73cd56bd50d9 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:23 +0100 Subject: [PATCH 38/53] refactor: rename `cashInFee` to `fixedFee` --- lib/new-admin/graphql/types/transaction.type.js | 2 +- lib/new-admin/services/transactions.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/new-admin/graphql/types/transaction.type.js b/lib/new-admin/graphql/types/transaction.type.js index 8c43f49e..ae57a365 100644 --- a/lib/new-admin/graphql/types/transaction.type.js +++ b/lib/new-admin/graphql/types/transaction.type.js @@ -23,7 +23,7 @@ const typeDef = gql` errorCode: String operatorCompleted: Boolean sendPending: Boolean - cashInFee: String + fixedFee: String minimumTx: Float customerId: ID isAnonymous: Boolean diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index 733fcad9..67972c19 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -50,7 +50,19 @@ function batch ( excludeTestingCustomers = false, simplified ) { - const packager = _.flow(_.flatten, _.orderBy(_.property('created'), ['desc']), _.map(camelize), addProfits, addNames) + const packager = _.flow( + _.flatten, + _.orderBy(_.property('created'), ['desc']), + _.map(_.flow( + camelize, + _.mapKeys(k => + k == 'cashInFee' ? 'fixedFee' : + k + ) + )), + addProfits, + addNames + ) const cashInSql = `SELECT 'cashIn' AS tx_class, txs.*, c.phone AS customer_phone, From dc9ca619bd483424735f771836e5313474309fae Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:25 +0100 Subject: [PATCH 39/53] feat: include cash-out fee in transaction updates --- lib/tx.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tx.js b/lib/tx.js index 92e1dea6..3e3dc27e 100644 --- a/lib/tx.js +++ b/lib/tx.js @@ -40,6 +40,7 @@ function massage (tx, pi) { : { cryptoAtoms: new BN(r.cryptoAtoms), fiat: new BN(r.fiat), + cashOutFee: new BN(r.cashOutFee), rawTickerPrice: r.rawTickerPrice ? new BN(r.rawTickerPrice) : null, commissionPercentage: new BN(r.commissionPercentage) } From e7ca33c8a4f40515ea97a5db39b989bb42091f60 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:28 +0100 Subject: [PATCH 40/53] refactor: use the common `fixedFee` field --- new-lamassu-admin/src/pages/Analytics/Analytics.js | 2 +- .../Dashboard/SystemPerformance/Graphs/RefLineChart.js | 4 ++-- .../pages/Dashboard/SystemPerformance/SystemPerformance.js | 2 +- .../Machines/MachineComponents/Transactions/Transactions.js | 2 +- new-lamassu-admin/src/pages/Transactions/DetailsCard.js | 6 +++--- new-lamassu-admin/src/pages/Transactions/Transactions.js | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index 46d85572..34711b36 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -77,7 +77,7 @@ const GET_TRANSACTIONS = gql` hasError: error deviceId fiat - cashInFee + fixedFee fiatCode cryptoAtoms cryptoCode diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js index b9f82f44..4c3ea952 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js @@ -5,10 +5,10 @@ import React, { useEffect, useRef, useCallback } from 'react' import { backgroundColor, zircon, primaryColor } from 'src/styling/variables' const transactionProfit = tx => { - const cashInFee = tx.cashInFee ? Number.parseFloat(tx.cashInFee) : 0 + const fixedFee = tx.fixedFee ? Number.parseFloat(tx.fixedFee) : 0 const commission = Number.parseFloat(tx.commissionPercentage) * Number.parseFloat(tx.fiat) - return commission + cashInFee + return commission + fixedFee } const mockPoint = (tx, offsetMs, profit) => { diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js index 457869ce..4ae6ec87 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js @@ -36,7 +36,7 @@ const GET_DATA = gql` transactions(excludeTestingCustomers: $excludeTestingCustomers) { fiatCode fiat - cashInFee + fixedFee commissionPercentage created txClass diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js index bb360152..7c13ffa6 100644 --- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js @@ -40,7 +40,7 @@ const GET_TRANSACTIONS = gql` hasError: error deviceId fiat - cashInFee + fixedFee fiatCode cryptoAtoms cryptoCode diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index cd40af4b..27cf2c5b 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -133,9 +133,9 @@ const DetailsRow = ({ it: tx, timezone }) => { const commission = BigNumber(tx.profit).toFixed(2, 1) // ROUND_DOWN const commissionPercentage = Number.parseFloat(tx.commissionPercentage, 2) * 100 - const cashInFee = isCashIn ? Number.parseFloat(tx.cashInFee) : 0 + const fixedFee = Number.parseFloat(tx.fixedFee) || 0 const fiat = BigNumber(tx.fiat) - .minus(cashInFee) + .minus(fixedFee) .toFixed(2, 1) // ROUND_DOWN const crypto = getCryptoAmount(tx) const cryptoFee = tx.fee ? `${getCryptoFeeAmount(tx)} ${tx.fiatCode}` : 'N/A' @@ -350,7 +350,7 @@ const DetailsRow = ({ it: tx, timezone }) => {
-
{isCashIn ? `${cashInFee} ${tx.fiatCode}` : 'N/A'}
+
{`${fixedFee} ${tx.fiatCode}`}
diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index cd49ca34..55666384 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -105,7 +105,7 @@ const GET_TRANSACTIONS = gql` deviceId fiat fee - cashInFee + fixedFee fiatCode cryptoAtoms cryptoCode From ce8295e54a21d7460c257ea32d395c1217fba1f3 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:34 +0100 Subject: [PATCH 41/53] refactor: use proft calculated in GraphQL resolver --- .../Dashboard/SystemPerformance/Graphs/RefLineChart.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js index 4c3ea952..8fafd220 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js @@ -4,12 +4,7 @@ import React, { useEffect, useRef, useCallback } from 'react' import { backgroundColor, zircon, primaryColor } from 'src/styling/variables' -const transactionProfit = tx => { - const fixedFee = tx.fixedFee ? Number.parseFloat(tx.fixedFee) : 0 - const commission = - Number.parseFloat(tx.commissionPercentage) * Number.parseFloat(tx.fiat) - return commission + fixedFee -} +const transactionProfit = R.prop('profit') const mockPoint = (tx, offsetMs, profit) => { const date = new Date(new Date(tx.created).getTime() + offsetMs).toISOString() From e0d8f7c24d0c836ea99229239f351dfc3810966b Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:37 +0100 Subject: [PATCH 42/53] fix: DB doesn't like bn.js numbers --- lib/cash-out/cash-out-helper.js | 2 +- lib/tx.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cash-out/cash-out-helper.js b/lib/cash-out/cash-out-helper.js index a98f7a31..cae14a0d 100644 --- a/lib/cash-out/cash-out-helper.js +++ b/lib/cash-out/cash-out-helper.js @@ -51,7 +51,7 @@ const mapValuesWithKey = _.mapValues.convert({cap: false}) function convertBigNumFields (obj) { const convert = (value, key) => { - if (_.includes(key, [ 'cryptoAtoms', 'receivedCryptoAtoms', 'fiat' ])) { + if (_.includes(key, [ 'cryptoAtoms', 'receivedCryptoAtoms', 'fiat', 'fixedFee', 'fixedFeeCrypto' ])) { return value.toString() } diff --git a/lib/tx.js b/lib/tx.js index 3e3dc27e..2e777c51 100644 --- a/lib/tx.js +++ b/lib/tx.js @@ -40,7 +40,7 @@ function massage (tx, pi) { : { cryptoAtoms: new BN(r.cryptoAtoms), fiat: new BN(r.fiat), - cashOutFee: new BN(r.cashOutFee), + fixedFee: new BN(r.fixedFee), rawTickerPrice: r.rawTickerPrice ? new BN(r.rawTickerPrice) : null, commissionPercentage: new BN(r.commissionPercentage) } From 599dbf86799d72ee10af62b5aa0cb3a1cd883e47 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:39 +0100 Subject: [PATCH 43/53] fix: make commission details list fit --- new-lamassu-admin/src/pages/Commissions/helper.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index c7f098a6..7cbdc868 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -533,7 +533,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'cryptoCurrencies', display: 'Crypto Currency', - width: 255, + width: 150, view: R.prop(0), size: 'sm', editable: false @@ -542,7 +542,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { header: cashInHeader, name: 'cashIn', display: 'Cash-in', - width: 130, + width: 120, input: NumberInput, textAlign: 'right', suffix: '%', @@ -555,7 +555,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { header: cashOutHeader, name: 'cashOut', display: 'Cash-out', - width: 140, + width: 126, input: NumberInput, textAlign: 'right', greenText: true, @@ -568,7 +568,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'fixedFee', display: 'Fixed fee', - width: 144, + width: 140, input: NumberInput, doubleHeader: 'Cash-in only', textAlign: 'right', @@ -581,7 +581,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'minimumTx', display: 'Minimum Tx', - width: 144, + width: 140, input: NumberInput, doubleHeader: 'Cash-in only', textAlign: 'right', @@ -594,7 +594,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'cashOutFixedFee', display: 'Fixed fee', - width: 144, + width: 140, doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', From 6d141f816dc474ed77fe448e6582ed38cff1631a Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:41 +0100 Subject: [PATCH 44/53] fix: make cash-out fixed fee overrides green --- new-lamassu-admin/src/pages/Commissions/helper.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index 7cbdc868..9b91e943 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -237,6 +237,7 @@ const mainFields = currency => [ name: 'cashOutFixedFee', display: 'Fixed fee', width: 169, + size: 'lg', doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', @@ -595,12 +596,12 @@ const getListCommissionsFields = (getData, currency, defaults) => { name: 'cashOutFixedFee', display: 'Fixed fee', width: 140, + input: NumberInput, doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', - input: NumberInput, suffix: currency, - bold: bold, + textStyle: obj => getTextStyle(obj), inputProps: { decimalPlaces: 2 } From 328257432e1023a77ebf3ffb92fda63608309b54 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:43 +0100 Subject: [PATCH 45/53] fix: make the non-list view overrides narrower --- new-lamassu-admin/src/pages/Commissions/helper.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index 9b91e943..5447d2c7 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -91,7 +91,7 @@ const getOverridesFields = (getData, currency, auxElements) => { }, { name: 'cryptoCurrencies', - width: 280, + width: 145, size: 'sm', view: displayCodeArray(cryptoData), input: Autocomplete, @@ -108,7 +108,7 @@ const getOverridesFields = (getData, currency, auxElements) => { header: cashInHeader, name: 'cashIn', display: 'Cash-in', - width: 130, + width: 123, input: NumberInput, textAlign: 'right', suffix: '%', @@ -121,7 +121,7 @@ const getOverridesFields = (getData, currency, auxElements) => { header: cashOutHeader, name: 'cashOut', display: 'Cash-out', - width: 130, + width: 127, input: NumberInput, textAlign: 'right', suffix: '%', @@ -133,7 +133,7 @@ const getOverridesFields = (getData, currency, auxElements) => { { name: 'fixedFee', display: 'Fixed fee', - width: 144, + width: 126, input: NumberInput, doubleHeader: 'Cash-in only', textAlign: 'right', @@ -146,7 +146,7 @@ const getOverridesFields = (getData, currency, auxElements) => { { name: 'minimumTx', display: 'Minimum Tx', - width: 169, + width: 140, doubleHeader: 'Cash-in only', textAlign: 'center', editingAlign: 'right', @@ -160,7 +160,7 @@ const getOverridesFields = (getData, currency, auxElements) => { { name: 'cashOutFixedFee', display: 'Fixed fee', - width: 144, + width: 134, doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', From 0c1fd7ce87dd6f67a2bb06d7103838b58a4f82f6 Mon Sep 17 00:00:00 2001 From: siiky Date: Tue, 18 Oct 2022 17:00:29 +0100 Subject: [PATCH 46/53] fix: export fixed fee and transaction fee --- lib/new-admin/services/transactions.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index 67972c19..546ef0b3 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -165,7 +165,7 @@ function batch ( function advancedBatch (data) { const fields = ['txClass', 'id', 'deviceId', 'toAddress', 'cryptoAtoms', 'cryptoCode', 'fiat', 'fiatCode', 'fee', 'status', 'fiatProfit', 'cryptoAmount', - 'dispense', 'notified', 'redeem', 'phone', 'error', + 'dispense', 'notified', 'redeem', 'phone', 'error', 'fixedFee', 'created', 'confirmedAt', 'hdIndex', 'swept', 'timedout', 'dispenseConfirmed', 'provisioned1', 'provisioned2', 'provisioned3', 'provisioned4', 'provisionedRecycler1', 'provisionedRecycler2', 'provisionedRecycler3', 'provisionedRecycler4', 'provisionedRecycler5', 'provisionedRecycler6', @@ -181,7 +181,9 @@ function advancedBatch (data) { ...it, status: getStatus(it), fiatProfit: getProfit(it).toString(), - cryptoAmount: getCryptoAmount(it).toString() + cryptoAmount: getCryptoAmount(it).toString(), + fixedFee: it.fixedFee ?? null, + fee: it.fee ?? null, })) return _.compose(_.map(_.pick(fields)), addAdvancedFields)(data) From 52a3d4cf81785401a8583ede5f79f541dc0b7fd1 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 24 Oct 2022 18:10:24 +0200 Subject: [PATCH 47/53] fix: tooltip doesn't stay open --- new-lamassu-admin/src/components/Tooltip.js | 31 ++++++++++++++++--- .../src/pages/Accounting/Accounting.js | 6 ++-- .../src/pages/Blacklist/Blacklist.js | 25 +++++++++++---- .../src/pages/Cashout/Cashout.js | 29 ++++++++++++++--- .../src/pages/Commissions/Commissions.js | 22 +++++++++++++ .../Customers/components/EditableCard.js | 3 +- .../src/pages/Locales/Locales.js | 20 ++++++++++-- .../LoyaltyPanel/IndividualDiscountModal.js | 6 ++-- .../src/pages/LoyaltyPanel/PromoCodesModal.js | 6 ++-- .../src/pages/Maintenance/CashUnits.js | 18 +++++++++-- .../pages/Maintenance/Wizard/WizardStep.js | 6 ++-- .../src/pages/Notifications/Notifications.js | 21 ++++++++++++- .../src/pages/OperatorInfo/CoinATMRadar.js | 13 ++++++-- .../src/pages/OperatorInfo/ContactInfo.js | 14 ++++++++- .../src/pages/OperatorInfo/ReceiptPrinting.js | 14 +++++++++ .../OperatorInfo/SMSNotices/SMSNotices.js | 19 +++++++++--- .../src/pages/OperatorInfo/TermsConditions.js | 14 ++++++++- .../src/pages/Transactions/DetailsCard.js | 6 ++-- .../src/pages/Transactions/Transactions.js | 19 +++++++++++- .../src/pages/Triggers/Triggers.js | 6 ++-- new-lamassu-admin/src/pages/Wallet/Wallet.js | 17 ++++++++++ .../src/pages/Wizard/components/Twilio.js | 6 ++-- 22 files changed, 269 insertions(+), 52 deletions(-) diff --git a/new-lamassu-admin/src/components/Tooltip.js b/new-lamassu-admin/src/components/Tooltip.js index 2fa5b7f9..40c85c36 100644 --- a/new-lamassu-admin/src/components/Tooltip.js +++ b/new-lamassu-admin/src/components/Tooltip.js @@ -13,6 +13,16 @@ const useStyles = makeStyles({ cursor: 'pointer', marginTop: 4 }, + relativelyPositioned: { + position: 'relative' + }, + safeSpace: { + position: 'absolute', + backgroundColor: '#0000', + height: 40, + left: '-50%', + width: '200%' + }, popoverContent: ({ width }) => ({ width, padding: [[10, 15]] @@ -27,6 +37,10 @@ const usePopperHandler = width => { setHelpPopperAnchorEl(helpPopperAnchorEl ? null : event.currentTarget) } + const openHelpPopper = event => { + setHelpPopperAnchorEl(event.currentTarget) + } + const handleCloseHelpPopper = () => { setHelpPopperAnchorEl(null) } @@ -38,25 +52,32 @@ const usePopperHandler = width => { helpPopperAnchorEl, helpPopperOpen, handleOpenHelpPopper, + openHelpPopper, handleCloseHelpPopper } } -const Tooltip = memo(({ children, width, Icon = HelpIcon }) => { +const HelpTooltip = memo(({ children, width }) => { const handler = usePopperHandler(width) return ( -
+
+ {handler.helpPopperOpen && ( +
+ )}
{children}
@@ -96,4 +117,4 @@ const HoverableTooltip = memo(({ parentElements, children, width }) => { ) }) -export { Tooltip, HoverableTooltip } +export { HoverableTooltip, HelpTooltip } diff --git a/new-lamassu-admin/src/pages/Accounting/Accounting.js b/new-lamassu-admin/src/pages/Accounting/Accounting.js index 09b38d0b..dcc6b18d 100644 --- a/new-lamassu-admin/src/pages/Accounting/Accounting.js +++ b/new-lamassu-admin/src/pages/Accounting/Accounting.js @@ -6,7 +6,7 @@ import * as R from 'ramda' import React, { useContext } from 'react' import AppContext from 'src/AppContext' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import TitleSection from 'src/components/layout/TitleSection' import DataTable from 'src/components/tables/DataTable' import { H4, Info2, P } from 'src/components/typography' @@ -128,9 +128,9 @@ const Accounting = () => { {it.description} {!!it.extraInfo && ( - +

{it.extraInfo}

-
+ )}
) diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index b4918993..dec75592 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -7,8 +7,13 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' -import { HoverableTooltip } from 'src/components/Tooltip' -import { Link, Button, IconButton } from 'src/components/buttons' +import { HelpTooltip } from 'src/components/Tooltip' +import { + Link, + Button, + IconButton, + SupportLinkButton +} from 'src/components/buttons' import { Switch } from 'src/components/inputs' import Sidebar from 'src/components/layout/Sidebar' import TitleSection from 'src/components/layout/TitleSection' @@ -251,13 +256,13 @@ const Blacklist = () => { value={enablePaperWalletOnly} /> {enablePaperWalletOnly ? 'On' : 'Off'} - +

The "Enable paper wallet (only)" option means that only paper wallets will be printed for users, and they won't be permitted to scan an address from their own wallet.

-
+ { value={rejectAddressReuse} /> {rejectAddressReuse ? 'On' : 'Off'} - +

The "Reject reused addresses" option means that all addresses that are used once will be automatically rejected if there's an attempt to use them again on a new transaction.

-
+

+ For details please read the relevant knowledgebase article: +

+ +
{ return ( !loading && ( <> - + +

+ For details on configuring cash-out, please read the relevant + knowledgebase article: +

+ + + }>

Transaction fudge factor

{ {fudgeFactorActive ? 'On' : 'Off'} - +

Automatically accept customer deposits as complete if their received amount is 100 crypto atoms or less. @@ -114,7 +129,13 @@ const CashOut = ({ name: SCREEN_KEY }) => { (Crypto atoms are the smallest unit in each cryptocurrency. E.g., satoshis in Bitcoin, or wei in Ethereum.)

-
+

For details please read the relevant knowledgebase article:

+ +
{ } ]} iconClassName={classes.listViewButton} + appendix={ + +

+ For details about commissions, please read the relevant + knowledgebase articles: +

+ + +
+ } /> {!showMachines && !loading && ( diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 0eb0be28..89479a02 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -8,6 +8,7 @@ import { useState, React, useRef } from 'react' import ErrorMessage from 'src/components/ErrorMessage' import PromptWhenDirty from 'src/components/PromptWhenDirty' import { MainStatus } from 'src/components/Status' +// import { HelpTooltip } from 'src/components/Tooltip' import { ActionButton } from 'src/components/buttons' import { Label1, P, H3 } from 'src/components/typography' import { @@ -182,7 +183,7 @@ const EditableCard = ({

{title}

{ // TODO: Enable for next release - /* */ + /* */ }
{state && authorize && ( diff --git a/new-lamassu-admin/src/pages/Locales/Locales.js b/new-lamassu-admin/src/pages/Locales/Locales.js index 3a820c8a..7956121a 100644 --- a/new-lamassu-admin/src/pages/Locales/Locales.js +++ b/new-lamassu-admin/src/pages/Locales/Locales.js @@ -5,7 +5,8 @@ import * as R from 'ramda' import React, { useState } from 'react' import Modal from 'src/components/Modal' -import { Link } from 'src/components/buttons' +import { HelpTooltip } from 'src/components/Tooltip' +import { Link, SupportLinkButton } from 'src/components/buttons' import { Table as EditableTable } from 'src/components/editableTable' import Section from 'src/components/layout/Section' import TitleSection from 'src/components/layout/TitleSection' @@ -176,7 +177,22 @@ const Locales = ({ name: SCREEN_KEY }) => { close={() => setDataToSave(null)} save={() => dataToSave && save(dataToSave)} /> - + +

+ For details on configuring languages, please read the relevant + knowledgebase article: +

+ + + } + />

Define discount rate

- +

This is a percentage discount off of your existing commission rates for a customer entering this code at @@ -110,7 +110,7 @@ const IndividualDiscountModal = ({ code is set for 50%, then you'll instead be charging 4% on transactions using the code.

-
+
{ />

Define discount rate

- +

This is a percentage discount off of your existing commission rates for a customer entering this code at the @@ -80,7 +80,7 @@ const PromoCodesModal = ({ showModal, onClose, errorMsg, addCode }) => { set for 50%, then you'll instead be charging 4% on transactions using the code.

-
+
{ } ]} iconClassName={classes.listViewButton} - className={classes.tableWidth}> + className={classes.tableWidth} + appendix={ + +

+ For details on configuring cash boxes and cassettes, please read + the relevant knowledgebase article: +

+ +
+ }> {!showHistory && ( Cash box resets diff --git a/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js b/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js index 04595563..b8468472 100644 --- a/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js +++ b/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js @@ -6,7 +6,7 @@ import React from 'react' import ErrorMessage from 'src/components/ErrorMessage' import Stepper from 'src/components/Stepper' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { Button } from 'src/components/buttons' import { Cashbox } from 'src/components/inputs/cashbox/Cashbox' import { NumberInput, RadioGroup } from 'src/components/inputs/formik' @@ -245,12 +245,12 @@ const WizardStep = ({ classes.centerAlignment )}>

Since previous update

- +

Number of bills inside the cash box, since the last cash box changes.

-
+
- {displayTitle && } + {displayTitle && ( + +

+ For details on configuring notifications, please read the + relevant knowledgebase article: +

+ + + } + /> + )} {displayThirdPartyProvider && (
{

Coin ATM Radar share settings

- +

For details on configuring this panel, please read the relevant knowledgebase article{' '} @@ -78,7 +80,12 @@ const CoinATMRadar = memo(({ wizard }) => { .

-
+ +
{ <>

Contact information

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +

Info card enabled?

diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js index 9b90c14a..2c59c3ce 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js @@ -4,11 +4,14 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { memo } from 'react' +import { HelpTooltip } from 'src/components/Tooltip' import { BooleanPropertiesTable } from 'src/components/booleanPropertiesTable' import { Switch } from 'src/components/inputs' import { H4, P, Label2 } from 'src/components/typography' import { fromNamespace, toNamespace, namespaces } from 'src/utils/config' +import { SupportLinkButton } from '../../components/buttons' + import { global } from './OperatorInfo.styles' const useStyles = makeStyles(global) @@ -47,6 +50,17 @@ const ReceiptPrinting = memo(({ wizard }) => { <>

Receipt options

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +

Enable receipt printing

diff --git a/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js index 232ad92d..3cd29f10 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js @@ -4,8 +4,8 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' -import { HoverableTooltip } from 'src/components/Tooltip' -import { IconButton } from 'src/components/buttons' +import { HelpTooltip } from 'src/components/Tooltip' +import { IconButton, SupportLinkButton } from 'src/components/buttons' import { Switch } from 'src/components/inputs' import DataTable from 'src/components/tables/DataTable' import { H4, P, Label3 } from 'src/components/typography' @@ -162,9 +162,9 @@ const SMSNotices = () => { !R.isEmpty(TOOLTIPS[it.event]) ? (
{R.prop('messageName', it)} - +

{TOOLTIPS[it.event]}

-
+
) : ( R.prop('messageName', it) @@ -237,6 +237,17 @@ const SMSNotices = () => { <>

SMS notices

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +
{showModal && ( { <>

Terms & Conditions

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +

Show on screen

diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index cd40af4b..1bdb5ed3 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -11,7 +11,7 @@ import * as R from 'ramda' import React, { memo, useState } from 'react' import { ConfirmDialog } from 'src/components/ConfirmDialog' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip, HoverableTooltip } from 'src/components/Tooltip' import { IDButton, ActionButton } from 'src/components/buttons' import { P, Label1 } from 'src/components/typography' import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg' @@ -358,9 +358,9 @@ const DetailsRow = ({ it: tx, timezone }) => {
{!R.isNil(tx.walletScore) && ( - + {`Chain analysis score: ${tx.walletScore}/10`} - + )}
diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index cd49ca34..4b3b9326 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -11,6 +11,8 @@ import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper' import SearchBox from 'src/components/SearchBox' import SearchFilter from 'src/components/SearchFilter' import Title from 'src/components/Title' +import { HelpTooltip } from 'src/components/Tooltip' +import { SupportLinkButton } from 'src/components/buttons' 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' @@ -233,7 +235,22 @@ const Transactions = () => { }, { header: 'Status', - view: it => getStatus(it), + view: it => { + if (getStatus(it) === 'Pending') + return ( +
+ {'Pending'} + + + +
+ ) + else return getStatus(it) + }, textAlign: 'left', size: 'sm', width: 80 diff --git a/new-lamassu-admin/src/pages/Triggers/Triggers.js b/new-lamassu-admin/src/pages/Triggers/Triggers.js index 07629699..02a9fc49 100644 --- a/new-lamassu-admin/src/pages/Triggers/Triggers.js +++ b/new-lamassu-admin/src/pages/Triggers/Triggers.js @@ -6,7 +6,7 @@ import * as R from 'ramda' import React, { useState } from 'react' import Modal from 'src/components/Modal' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { Link, SupportLinkButton } from 'src/components/buttons' import { Switch } from 'src/components/inputs' import TitleSection from 'src/components/layout/TitleSection' @@ -187,13 +187,13 @@ const Triggers = () => { {rejectAddressReuse ? 'On' : 'Off'} - +

This option requires a user to scan a different cryptocurrency address if they attempt to scan one that had been previously used for a transaction in your network

-
+ )} diff --git a/new-lamassu-admin/src/pages/Wallet/Wallet.js b/new-lamassu-admin/src/pages/Wallet/Wallet.js index e2d74ec0..eaf1148e 100644 --- a/new-lamassu-admin/src/pages/Wallet/Wallet.js +++ b/new-lamassu-admin/src/pages/Wallet/Wallet.js @@ -5,6 +5,8 @@ import * as R from 'ramda' import React, { useState } from 'react' import Modal from 'src/components/Modal' +import { HelpTooltip } from 'src/components/Tooltip' +import { SupportLinkButton } from 'src/components/buttons' import { NamespacedTable as EditableTable } from 'src/components/editableTable' import TitleSection from 'src/components/layout/TitleSection' import FormRenderer from 'src/pages/Services/FormRenderer' @@ -13,6 +15,8 @@ import { ReactComponent as ReverseSettingsIcon } from 'src/styling/icons/circle import { ReactComponent as SettingsIcon } from 'src/styling/icons/circle buttons/settings/zodiac.svg' import { fromNamespace, toNamespace } from 'src/utils/config' +import { P } from '../../components/typography' + import AdvancedWallet from './AdvancedWallet' import styles from './Wallet.styles.js' import Wizard from './Wizard' @@ -124,6 +128,19 @@ const Wallet = ({ name: SCREEN_KEY }) => { toggle: setAdvancedSettings } ]} + appendix={ + +

+ For details on configuring wallets, please read the relevant + knowledgebase article: +

+ +
+ } />
{!advancedSettings && ( diff --git a/new-lamassu-admin/src/pages/Wizard/components/Twilio.js b/new-lamassu-admin/src/pages/Wizard/components/Twilio.js index a8a55bed..e553290c 100644 --- a/new-lamassu-admin/src/pages/Wizard/components/Twilio.js +++ b/new-lamassu-admin/src/pages/Wizard/components/Twilio.js @@ -5,7 +5,7 @@ import gql from 'graphql-tag' import React, { useState } from 'react' import InfoMessage from 'src/components/InfoMessage' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { Button, SupportLinkButton } from 'src/components/buttons' import { RadioGroup } from 'src/components/inputs' import { H1, H4, P } from 'src/components/typography' @@ -102,7 +102,7 @@ function Twilio({ doContinue }) {

Will you setup a two way machine or compliance?

- +

Two-way machines allow your customers not only to buy (cash-in) but also sell cryptocurrencies (cash-out). @@ -111,7 +111,7 @@ function Twilio({ doContinue }) { You’ll need an SMS service for cash-out transactions and for any compliance triggers

-
+ Date: Thu, 28 Nov 2024 11:30:35 +0000 Subject: [PATCH 48/53] refactor: don't send transactions' `expired` field --- lib/tx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tx.js b/lib/tx.js index 92e1dea6..4a1d9b3c 100644 --- a/lib/tx.js +++ b/lib/tx.js @@ -69,7 +69,7 @@ function cancel (txId) { } function customerHistory (customerId, thresholdDays) { - const sql = `SELECT * FROM ( + const sql = `SELECT ch.id, ch.created, ch.fiat, ch.direction FROM ( SELECT txIn.id, txIn.created, txIn.fiat, 'cashIn' AS direction, ((NOT txIn.send_confirmed) AND (txIn.created <= now() - interval $3)) AS expired FROM cash_in_txs txIn From d64c4a4df6a83359da30eb54e2b94260f341d568 Mon Sep 17 00:00:00 2001 From: siiky Date: Thu, 28 Nov 2024 13:01:09 +0000 Subject: [PATCH 49/53] feat: add read/written bytes from/to request/response Based on `count-response-size-middleware`. --- lib/middlewares/addRWBytes.js | 15 +++++++++++++++ lib/routes.js | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 lib/middlewares/addRWBytes.js diff --git a/lib/middlewares/addRWBytes.js b/lib/middlewares/addRWBytes.js new file mode 100644 index 00000000..46a79275 --- /dev/null +++ b/lib/middlewares/addRWBytes.js @@ -0,0 +1,15 @@ +const addRWBytes = () => (req, res, next) => { + const handle = () => { + res.removeListener('finish', handle) + res.removeListener('close', handle) + res.bytesRead = req.connection.bytesRead + res.bytesWritten = req.connection.bytesWritten + } + + res.on('finish', handle) + res.on('close', handle) + + next() +} + +module.exports = addRWBytes diff --git a/lib/routes.js b/lib/routes.js index 6248fc8e..0d0cb5d0 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -7,10 +7,11 @@ const nocache = require('nocache') const logger = require('./logger') +const addRWBytes = require('./middlewares/addRWBytes') const authorize = require('./middlewares/authorize') +const computeSchema = require('./middlewares/compute-schema') const errorHandler = require('./middlewares/errorHandler') const filterOldRequests = require('./middlewares/filterOldRequests') -const computeSchema = require('./middlewares/compute-schema') const findOperatorId = require('./middlewares/operatorId') const populateDeviceId = require('./middlewares/populateDeviceId') const populateSettings = require('./middlewares/populateSettings') @@ -50,6 +51,7 @@ const configRequiredRoutes = [ ] // middleware setup +app.use(addRWBytes()) app.use(compression({ threshold: 500 })) app.use(helmet()) app.use(nocache()) From 2e4eb9a2e7801d4e9c2d65cd23b2c52acc925823 Mon Sep 17 00:00:00 2001 From: siiky Date: Thu, 28 Nov 2024 13:01:54 +0000 Subject: [PATCH 50/53] feat: add read/written bytes to logs --- lib/routes.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 0d0cb5d0..e6654121 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -56,7 +56,10 @@ app.use(compression({ threshold: 500 })) app.use(helmet()) app.use(nocache()) app.use(express.json({ limit: '2mb' })) -app.use(morgan(':method :url :status :response-time ms -- :req[content-length]/:res[content-length] b', { stream: logger.stream })) + +morgan.token('bytesRead', (_req, res) => res.bytesRead) +morgan.token('bytesWritten', (_req, res) => res.bytesWritten) +app.use(morgan(':method :url :status :response-time ms -- :bytesRead/:bytesWritten B', { stream: logger.stream })) // app /pair and /ca routes app.use('/', pairingRoutes) From d0573daa74e416a894c6ad20d6746b059446b9e9 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 08:36:48 +0000 Subject: [PATCH 51/53] build: fix eslint error --- new-lamassu-admin/src/pages/Transactions/DetailsCard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index 9bb4c96a..364a56b5 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -11,7 +11,7 @@ import * as R from 'ramda' import React, { memo, useState } from 'react' import { ConfirmDialog } from 'src/components/ConfirmDialog' -import { HelpTooltip, HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { IDButton, ActionButton } from 'src/components/buttons' import { P, Label1 } from 'src/components/typography' import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg' From 4074636663b48272537c33b9a6f73a080e935260 Mon Sep 17 00:00:00 2001 From: josepfo Date: Thu, 8 Dec 2022 16:29:01 +0000 Subject: [PATCH 52/53] fix: add screen options missing field --- lib/graphql/resolvers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index 1270f1f3..da4759e3 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -103,7 +103,8 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings _.pick([ 'coins', 'configVersion', - 'timezone' + 'timezone', + 'screenOptions' ]), _.update('coins', massageCoins), _.set('serverVersion', VERSION), From c5f3caab2f9418d0d191c902eda7f5373f31ce82 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 10:19:24 +0000 Subject: [PATCH 53/53] Revert "fix: add screen options missing field" This reverts commit 4074636663b48272537c33b9a6f73a080e935260. --- lib/graphql/resolvers.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index da4759e3..1270f1f3 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -103,8 +103,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings _.pick([ 'coins', 'configVersion', - 'timezone', - 'screenOptions' + 'timezone' ]), _.update('coins', massageCoins), _.set('serverVersion', VERSION),