From 7d6fb171586feed8110bab7eea4b07fa109d0818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Mon, 22 Nov 2021 17:30:37 +0000 Subject: [PATCH 1/5] feat: convert from using dst offsets to use timezone code feat: select timezones from current selected country --- lib/logs.js | 10 +- lib/plugins.js | 5 +- lib/routes/customerRoutes.js | 8 +- new-lamassu-admin/package-lock.json | 10 ++ new-lamassu-admin/package.json | 4 +- .../components/tooltips/GraphTooltip.js | 4 +- .../components/wrappers/HourOfDayWrapper.js | 3 +- .../Analytics/graphs/HourOfDayBarGraph.js | 3 +- .../Analytics/graphs/OverTimeDotGraph.js | 3 +- .../Graphs/RefScatterplot.js | 5 +- .../src/pages/Locales/Locales.js | 4 +- new-lamassu-admin/src/pages/Locales/helper.js | 28 ++++-- .../src/pages/Transactions/Transactions.js | 2 +- new-lamassu-admin/src/utils/timezones.js | 98 +++---------------- package-lock.json | 12 ++- package.json | 4 +- 16 files changed, 86 insertions(+), 117 deletions(-) diff --git a/lib/logs.js b/lib/logs.js index 50e806b7..44f7c793 100644 --- a/lib/logs.js +++ b/lib/logs.js @@ -1,5 +1,6 @@ const _ = require('lodash/fp') -const moment = require('moment') +const { format } = require('date-fns') +const { zonedTimeToUtc, utcToZonedTime } = require('date-fns-tz') const db = require('./db') const pgp = require('pg-promise')() @@ -112,10 +113,13 @@ function simpleGetMachineLogs (deviceId, from = new Date(0).toISOString(), until } function logDateFormat (timezone, logs, fields) { - const offset = timezone.split(':')[1] return _.map(log => { - const values = _.map(field => moment.utc(log[field]).utcOffset(parseInt(offset)).format('YYYY-MM-DDTHH:mm:ss.SSS'), fields) + const values = _.map( + field => + format(utcToZonedTime(zonedTimeToUtc(log[field], process.env.TZ), timezone), 'yyyy-MM-ddTHH:mm:ss.SSS'), + fields + ) const fieldsToOverride = _.zipObject(fields, values) return { diff --git a/lib/plugins.js b/lib/plugins.js index fe7bd663..bfafe327 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -230,7 +230,7 @@ function plugins (settings, deviceId) { const localeConfig = configManager.getLocale(deviceId, settings.config) const fiatCode = localeConfig.fiatCurrency const cryptoCodes = localeConfig.cryptoCurrencies - const timezone = localeConfig.timezone.split(':') + const timezone = localeConfig.timezone const tickerPromises = cryptoCodes.map(c => ticker.getRates(settings, fiatCode, c)) const balancePromises = cryptoCodes.map(c => fiatBalance(fiatCode, c)) @@ -239,13 +239,12 @@ function plugins (settings, deviceId) { const currentConfigVersionPromise = fetchCurrentConfigVersion() const currentAvailablePromoCodes = loyalty.getNumberOfAvailablePromoCodes() const supportsBatchingPromise = cryptoCodes.map(c => wallet.supportsBatching(settings, c)) - const timezoneObj = { utcOffset: timezone[0], dstOffset: timezone[1] } const promises = [ buildAvailableCassettes(), pingPromise, currentConfigVersionPromise, - timezoneObj + timezone ].concat( supportsBatchingPromise, tickerPromises, diff --git a/lib/routes/customerRoutes.js b/lib/routes/customerRoutes.js index 1093a91d..272da2d8 100644 --- a/lib/routes/customerRoutes.js +++ b/lib/routes/customerRoutes.js @@ -18,6 +18,8 @@ const { getCustomerById } = require('../customers') const machineLoader = require('../machine-loader') const { loadLatestConfig } = require('../new-settings-loader') +const { zonedTimeToUtc, utcToZonedTime } = require('date-fns-tz') + function updateCustomer (req, res, next) { const id = req.params.id const machineVersion = req.query.version @@ -129,14 +131,12 @@ function buildSms (data, receiptOptions) { .then(([customer, deviceConfig]) => { const formattedTx = _.mapKeys(_.camelCase)(tx) const localeConfig = configManager.getLocale(formattedTx.deviceId, config) - const timezone = localeConfig.timezone.split(':') - const dstOffset = timezone[1] + const timezone = localeConfig.timezone const cashInCommission = new BN(1).plus(new BN(formattedTx.commissionPercentage)) const rate = new BN(formattedTx.rawTickerPrice).multipliedBy(cashInCommission).decimalPlaces(2) - const date = new Date() - date.setMinutes(date.getMinutes() + parseInt(dstOffset)) + const date = utcToZonedTime(zonedTimeToUtc(new Date(), process.env.TZ), timezone) const dateString = `${date.toISOString().replace('T', ' ').slice(0, 19)}` const data = { diff --git a/new-lamassu-admin/package-lock.json b/new-lamassu-admin/package-lock.json index cad5fe31..ebbb2730 100644 --- a/new-lamassu-admin/package-lock.json +++ b/new-lamassu-admin/package-lock.json @@ -10465,6 +10465,16 @@ "whatwg-url": "^8.0.0" } }, + "date-fns": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.26.0.tgz", + "integrity": "sha512-VQI812dRi3cusdY/fhoBKvc6l2W8BPWU1FNVnFH9Nttjx4AFBRzfSVb/Eyc7jBT6e9sg1XtAGsYpBQ6c/jygbg==" + }, + "date-fns-tz": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.1.6.tgz", + "integrity": "sha512-nyy+URfFI3KUY7udEJozcoftju+KduaqkVfwyTIE0traBiVye09QnyWKLZK7drRr5h9B7sPJITmQnS3U6YOdQg==" + }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", diff --git a/new-lamassu-admin/package.json b/new-lamassu-admin/package.json index 6d4a0e43..b807b5c8 100644 --- a/new-lamassu-admin/package.json +++ b/new-lamassu-admin/package.json @@ -19,6 +19,8 @@ "classnames": "2.2.6", "countries-and-timezones": "^2.4.0", "d3": "^6.2.0", + "date-fns": "^2.26.0", + "date-fns-tz": "^1.1.6", "downshift": "3.3.4", "file-saver": "2.0.2", "formik": "2.2.0", @@ -36,8 +38,8 @@ "react": "^16.12.0", "react-copy-to-clipboard": "^5.0.2", "react-dom": "^16.10.2", - "react-material-ui-carousel": "^2.2.7", "react-dropzone": "^11.4.2", + "react-material-ui-carousel": "^2.2.7", "react-number-format": "^4.4.1", "react-otp-input": "^2.3.0", "react-router-dom": "5.1.2", 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 e46bc675..a8a5d78f 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js +++ b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js @@ -31,12 +31,12 @@ const GraphTooltip = ({ formatDate( dateInterval[1], null, - period.code === 'day' ? 'MMM D, HH:mm' : 'MMM D' + period.code === 'day' ? 'MMM d, HH:mm' : 'MMM d' ), formatDate( dateInterval[0], null, - period.code === 'day' ? 'HH:mm' : 'MMM D' + period.code === 'day' ? 'HH:mm' : 'MMM d' ) ] : [ diff --git a/new-lamassu-admin/src/pages/Analytics/components/wrappers/HourOfDayWrapper.js b/new-lamassu-admin/src/pages/Analytics/components/wrappers/HourOfDayWrapper.js index aeadafe4..fb658e70 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/wrappers/HourOfDayWrapper.js +++ b/new-lamassu-admin/src/pages/Analytics/components/wrappers/HourOfDayWrapper.js @@ -1,5 +1,6 @@ import { Box } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' +import { getTimezoneOffset } from 'date-fns-tz' import moment from 'moment' import * as R from 'ramda' import React, { useState } from 'react' @@ -47,7 +48,7 @@ const HourOfDayBarGraphHeader = ({ cashOut:
} - const offset = parseInt(timezone.split(':')[1]) * MINUTE + const offset = getTimezoneOffset(timezone) const txsPerWeekday = R.reduce( (acc, value) => { diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/HourOfDayBarGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/HourOfDayBarGraph.js index b50ccdb7..4aa36d9e 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/HourOfDayBarGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/HourOfDayBarGraph.js @@ -1,5 +1,6 @@ import BigNumber from 'bignumber.js' import * as d3 from 'd3' +import { getTimezoneOffset } from 'date-fns-tz' import moment from 'moment' import * as R from 'ramda' import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react' @@ -38,7 +39,7 @@ const Graph = ({ [] ) - const offset = parseInt(timezone.split(':')[1]) * MINUTE + const offset = getTimezoneOffset(timezone) const getTickIntervals = (domain, interval) => { const ticks = [] diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js index cb64506d..d4dc2fef 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js @@ -1,5 +1,6 @@ import BigNumber from 'bignumber.js' import * as d3 from 'd3' +import { getTimezoneOffset } from 'date-fns-tz' import moment from 'moment' import * as R from 'ramda' import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react' @@ -40,7 +41,7 @@ const Graph = ({ [] ) - const offset = parseInt(timezone.split(':')[1]) * MINUTE + const offset = getTimezoneOffset(timezone) const NOW = Date.now() + offset const periodDomains = { 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 0c974854..c0d7677e 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js @@ -1,4 +1,5 @@ import * as d3 from 'd3' +import { getTimezoneOffset } from 'date-fns-tz' import moment from 'moment' import React, { useEffect, useRef, useCallback } from 'react' @@ -11,7 +12,7 @@ const RefScatterplot = ({ data: realData, timeFrame, timezone }) => { const margin = { top: 25, right: 0, bottom: 25, left: 15 } const width = 555 - margin.left - margin.right const height = 150 - margin.top - margin.bottom - const dstOffset = parseInt(timezone.split(':')[1]) + const offset = getTimezoneOffset(timezone) // finds maximum value for the Y axis. Minimum value is 100. If value is multiple of 1000, add 100 // (this is because the Y axis looks best with multiples of 100) const findMaxY = () => { @@ -32,7 +33,7 @@ const RefScatterplot = ({ data: realData, timeFrame, timezone }) => { default: return moment .utc(v) - .add(dstOffset, 'minutes') + .add(offset, 'minutes') .format('HH:mm') } } diff --git a/new-lamassu-admin/src/pages/Locales/Locales.js b/new-lamassu-admin/src/pages/Locales/Locales.js index a91459e5..a209e753 100644 --- a/new-lamassu-admin/src/pages/Locales/Locales.js +++ b/new-lamassu-admin/src/pages/Locales/Locales.js @@ -158,6 +158,8 @@ const Locales = ({ name: SCREEN_KEY }) => { setValue(curr) } + console.log('config', config) + const onEditingDefault = (it, editing) => setEditingDefault(editing) const onEditingOverrides = (it, editing) => setEditingOverrides(editing) @@ -187,7 +189,7 @@ const Locales = ({ name: SCREEN_KEY }) => { save={handleSave} validationSchema={LocaleSchema} data={R.of(locale)} - elements={mainFields(data, onChangeCoin)} + elements={mainFields(data, onChangeCoin, R.of(locale))} setEditing={onEditingDefault} forceDisable={isEditingOverrides} /> diff --git a/new-lamassu-admin/src/pages/Locales/helper.js b/new-lamassu-admin/src/pages/Locales/helper.js index d12c267d..9ea8e8dc 100644 --- a/new-lamassu-admin/src/pages/Locales/helper.js +++ b/new-lamassu-admin/src/pages/Locales/helper.js @@ -1,18 +1,19 @@ import * as ct from 'countries-and-timezones' +// import { useFormikContext } from 'formik' import * as R from 'ramda' import * as Yup from 'yup' import Autocomplete from 'src/components/inputs/formik/Autocomplete.js' -import { getTzLabels } from 'src/utils/timezones' +// import { getTzLabels } from 'src/utils/timezones' -const getFields = (getData, names, onChange, auxElements = []) => { +const getFields = (getData, names, onChange, auxElements = [], locale) => { return R.filter( it => R.includes(it.name, names), - allFields(getData, onChange, auxElements) + allFields(getData, onChange, auxElements, locale) ) } -const allFields = (getData, onChange, auxElements = []) => { +const allFields = (getData, onChange, auxElements = [], locale) => { const getView = (data, code, compare) => it => { if (!data) return '' @@ -33,14 +34,19 @@ const allFields = (getData, onChange, auxElements = []) => { const suggestionFilter = it => R.differenceWith((x, y) => x.deviceId === y, it, overridenMachines) + const localeData = (locale && locale[0]) || {} + const machineData = getData(['machines']) const countryData = getData(['countries']) const currencyData = getData(['currencies']) const languageData = getData(['languages']) const cryptoData = getData(['cryptoCurrencies']) - const timezonesData = R.values(ct.getAllTimezones()) - const tzLabels = getTzLabels(timezonesData) + const countryTimezones = ct.getTimezonesForCountry(localeData?.country) ?? [] + const timezonesData = + R.values( + countryTimezones.map(it => ({ label: it.name, code: it.name })) ?? [] + ) ?? [] const findSuggestion = it => { const machine = R.find(R.propEq('deviceId', it.machine))(machineData) @@ -117,10 +123,10 @@ const allFields = (getData, onChange, auxElements = []) => { name: 'timezone', width: 320, size: 'sm', - view: getView(tzLabels, 'label'), + view: getView(timezonesData, 'label'), input: Autocomplete, inputProps: { - options: tzLabels, + options: timezonesData, valueProp: 'code', labelProp: 'label' } @@ -128,13 +134,15 @@ const allFields = (getData, onChange, auxElements = []) => { ] } -const mainFields = (auxData, configureCoin) => { +const mainFields = (auxData, configureCoin, locale) => { const getData = R.path(R.__, auxData) return getFields( getData, ['country', 'fiatCurrency', 'languages', 'cryptoCurrencies', 'timezone'], - configureCoin + configureCoin, + undefined, + locale ) } diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index 64cfbac4..1ea2b927 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -218,7 +218,7 @@ const Transactions = () => { { header: 'Date (UTC)', view: it => - timezone && formatDate(it.created, timezone, 'YYYY-MM-DD HH:mm:ss'), + timezone && formatDate(it.created, timezone, 'yyyy-MM-dd HH:mm:ss'), textAlign: 'right', size: 'sm', width: 195 diff --git a/new-lamassu-admin/src/utils/timezones.js b/new-lamassu-admin/src/utils/timezones.js index a4f36ab1..897501ab 100644 --- a/new-lamassu-admin/src/utils/timezones.js +++ b/new-lamassu-admin/src/utils/timezones.js @@ -1,89 +1,23 @@ -import moment from 'moment' -import * as R from 'ramda' +import { format } from 'date-fns' +import { zonedTimeToUtc, utcToZonedTime } from 'date-fns-tz' +// import moment from 'moment' +// import * as R from 'ramda' -const getPossibleUTCDSTPairs = timezones => - R.map( - it => ({ - utcOffset: it.utcOffset, - dstOffset: it.dstOffset, - utcOffsetStr: it.utcOffsetStr, - dstOffsetStr: it.dstOffsetStr - }), - R.uniqBy( - it => [it.utcOffset, it.dstOffset, it.utcOffsetStr, it.dstOffsetStr], - timezones - ) - ) +// const buildLabel = tz => { +// return `(UTC${tz.utcOffsetStr}) ${R.map(it => it.city, tz.cities).join(', ')}` +// } -const getFormattedTimezones = timezones => - R.sort( - R.ascend(R.prop('utcOffset')), - R.map( - it => ({ - utcOffset: it.utcOffset, - dstOffset: it.dstOffset, - utcOffsetStr: it.utcOffsetStr, - dstOffsetStr: it.dstOffsetStr, - cities: R.map( - ite => { - const regionCityPair = R.split('/', ite.name) - return { - region: regionCityPair[0], - city: R.replace(/_/g, ' ', regionCityPair[1]), - country: ite.country - } - }, - R.filter( - itx => - R.eqProps('utcOffset', it, itx) && - R.eqProps('dstOffset', it, itx) && - !R.isNil(itx.country) && - !R.includes('Etc', itx.name) && - R.includes('/', itx.name), - timezones - ) - ) - }), - getPossibleUTCDSTPairs(timezones) - ) +const formatDate = (date, timezone, pattern) => { + const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone + const newDate = utcToZonedTime( + zonedTimeToUtc(date, browserTimezone), + timezone ) - -const getFinalTimezones = timezones => { - const formattedTimezones = getFormattedTimezones(timezones) - const nonEmptyTimezones = R.filter( - it => !R.isEmpty(it.cities), - formattedTimezones - ) - const nonDuplicateCities = R.map( - it => ({ - ...it, - cities: R.uniqBy(R.prop('country'), R.uniqBy(R.prop('city'), it.cities)) - }), - nonEmptyTimezones - ) - return nonDuplicateCities + return format(newDate, pattern) } -const buildLabel = tz => { - return `(UTC${tz.utcOffsetStr}) ${R.map(it => it.city, tz.cities).join(', ')}` +const formatDateNonUtc = (date, pattern) => { + return format(date, pattern) } -const getTzLabels = timezones => - R.map( - it => ({ label: buildLabel(it), code: `${it.utcOffset}:${it.dstOffset}` }), - getFinalTimezones(timezones) - ) - -const formatDate = (date, timezoneCode, format) => { - const dstOffset = timezoneCode?.split(':')[1] ?? 0 - return moment - .utc(date) - .utcOffset(parseInt(dstOffset)) - .format(format) -} - -const formatDateNonUtc = (date, format) => { - return moment(date).format(format) -} - -export { getTzLabels, formatDate, formatDateNonUtc } +export { formatDate, formatDateNonUtc } diff --git a/package-lock.json b/package-lock.json index 46f1fc5f..1cc15cf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8464,10 +8464,14 @@ "integrity": "sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ==" }, "date-fns": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", - "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==", - "dev": true + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.26.0.tgz", + "integrity": "sha512-VQI812dRi3cusdY/fhoBKvc6l2W8BPWU1FNVnFH9Nttjx4AFBRzfSVb/Eyc7jBT6e9sg1XtAGsYpBQ6c/jygbg==" + }, + "date-fns-tz": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.1.6.tgz", + "integrity": "sha512-nyy+URfFI3KUY7udEJozcoftju+KduaqkVfwyTIE0traBiVye09QnyWKLZK7drRr5h9B7sPJITmQnS3U6YOdQg==" }, "date-time": { "version": "2.1.0", diff --git a/package.json b/package.json index 7792df3a..c7e9068f 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "cookie-parser": "^1.4.3", "cors": "^2.8.5", "dataloader": "^2.0.0", + "date-fns": "^2.26.0", + "date-fns-tz": "^1.1.6", "ethereumjs-tx": "^1.3.3", "ethereumjs-util": "^5.2.0", "ethereumjs-wallet": "^0.6.3", @@ -68,8 +70,8 @@ "pify": "^3.0.0", "pretty-ms": "^2.1.0", "promise-sequential": "^1.1.1", - "request-promise": "^4.2.6", "queue-promise": "^2.2.1", + "request-promise": "^4.2.6", "semver": "^7.1.3", "serve-static": "^1.12.4", "socket.io": "^2.0.3", From 973040f40976b0f1d3b32d6599ce6d618c15c828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 23 Nov 2021 16:09:15 +0000 Subject: [PATCH 2/5] feat: remove all instances of moment usage --- lib/admin/server.js | 10 +- lib/customers.js | 14 +-- lib/logs.js | 8 +- new-lamassu-admin/package-lock.json | 5 - new-lamassu-admin/package.json | 1 - .../src/components/LogsDownloaderPopper.js | 19 ++-- .../components/date-range-picker/Calendar.js | 91 ++++++++++--------- .../date-range-picker/DateRangePicker.js | 23 +++-- .../src/pages/Accounting/Accounting.js | 30 ++++-- .../components/wrappers/HourOfDayWrapper.js | 6 +- .../Analytics/graphs/HourOfDayBarGraph.js | 12 +-- .../Analytics/graphs/OverTimeDotGraph.js | 11 ++- .../src/pages/Customers/CustomerData.js | 17 ++-- .../src/pages/Customers/CustomersList.js | 5 +- .../pages/Customers/components/IdDataCard.js | 9 +- .../Customers/components/TransactionsList.js | 4 +- .../Graphs/RefScatterplot.js | 18 ++-- .../SystemPerformance/SystemPerformance.js | 31 +++---- new-lamassu-admin/src/pages/Funding.js | 10 +- .../Machines/MachineComponents/Details.js | 2 +- .../Machines/MachineComponents/Overview.js | 5 +- .../Transactions/Transactions.js | 19 +++- .../src/pages/Maintenance/CashboxHistory.js | 21 ++++- .../src/pages/Maintenance/MachineStatus.js | 7 +- new-lamassu-admin/src/pages/ServerLogs.js | 2 +- .../SessionManagement/SessionManagement.js | 36 ++++++-- .../src/pages/Transactions/DetailsCard.js | 15 ++- new-lamassu-admin/src/utils/timezones.js | 13 ++- package.json | 1 - 29 files changed, 252 insertions(+), 193 deletions(-) diff --git a/lib/admin/server.js b/lib/admin/server.js index 0aa93706..f31cf4fd 100644 --- a/lib/admin/server.js +++ b/lib/admin/server.js @@ -1,11 +1,11 @@ const _ = require('lodash/fp') -const moment = require('moment') const ticker = require('../ticker') const settingsLoader = require('./settings-loader') const db = require('../db') const machineLoader = require('../machine-loader') +const { intervalToDuration, secondsToMilliseconds, formatDuration } = require('date-fns') const CONSIDERED_UP_SECS = 30 @@ -37,8 +37,8 @@ function machinesLastPing () { if (downRows.length === 1) { const row = downRows[0] - const age = moment.duration(row.age, 'seconds') - return `${row.name} down for ${age.humanize()}` + const age = intervalToDuration({ start: 0, end: secondsToMilliseconds(row.age) }) + return `${row.name} down for ${formatDuration(age)}` } return 'Multiple machines down' @@ -54,9 +54,9 @@ function status () { return Promise.all([checkWasConfigured(), db.oneOrNone(sql, ['ping']), machinesLastPing()]) .then(([wasConfigured, statusRow, machineStatus]) => { - const age = statusRow && moment.duration(statusRow.age, 'seconds') + const age = statusRow && intervalToDuration({ start: 0, end: secondsToMilliseconds(statusRow.age) }) const up = statusRow ? statusRow.age < CONSIDERED_UP_SECS : false - const lastPing = statusRow && age.humanize() + const lastPing = statusRow && formatDuration(age) return settingsLoader.loadLatest() .catch(() => null) diff --git a/lib/customers.js b/lib/customers.js index c7aa00e3..478f6f7c 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -6,7 +6,6 @@ const makeDir = require('make-dir') const path = require('path') const fs = require('fs') const util = require('util') -const moment = require('moment') const db = require('./db') const BN = require('./bn') @@ -24,6 +23,7 @@ const operatorDataDir = _.get('operatorDataDir', options) const sms = require('./sms') const settingsLoader = require('./new-settings-loader') const logger = require('./logger') +const { sub, differenceInHours } = require('date-fns') const TX_PASSTHROUGH_ERROR_CODES = ['operatorCancel'] @@ -215,14 +215,14 @@ function getDailyVolumeMinusCurrentTxQueries (id, txId) { } function getHoursTillLimitClear (cashInDate, cashOutDate) { - let startDate = moment() - startDate = startDate.subtract(1, 'days') + let startDate = new Date() + startDate = sub(startDate, { days: 1 }) - const cashInMoment = moment(cashInDate || startDate) - const cashOutMoment = moment(cashOutDate || startDate) + const cashInMoment = new Date(cashInDate || startDate) + const cashOutMoment = new Date(cashOutDate || startDate) - const cashInDuration = moment.duration(cashInMoment.diff(startDate)).asHours() - const cashOutDuration = moment.duration(cashOutMoment.diff(startDate)).asHours() + const cashInDuration = differenceInHours(startDate, cashInMoment) + const cashOutDuration = differenceInHours(startDate, cashOutMoment) return _.ceil(_.max([cashInDuration, cashOutDuration, 0])) } diff --git a/lib/logs.js b/lib/logs.js index 44f7c793..6b6ea61f 100644 --- a/lib/logs.js +++ b/lib/logs.js @@ -113,15 +113,17 @@ function simpleGetMachineLogs (deviceId, from = new Date(0).toISOString(), until } function logDateFormat (timezone, logs, fields) { - return _.map(log => { const values = _.map( field => - format(utcToZonedTime(zonedTimeToUtc(log[field], process.env.TZ), timezone), 'yyyy-MM-ddTHH:mm:ss.SSS'), + { + if (_.isNil(log[field])) return null + const date = utcToZonedTime(log[field], timezone) + return `${format(date, 'yyyy-MM-dd')}T${format(date, 'HH:mm:ss.SSS')}` + }, fields ) const fieldsToOverride = _.zipObject(fields, values) - return { ...log, ...fieldsToOverride diff --git a/new-lamassu-admin/package-lock.json b/new-lamassu-admin/package-lock.json index ebbb2730..161c8a4e 100644 --- a/new-lamassu-admin/package-lock.json +++ b/new-lamassu-admin/package-lock.json @@ -18326,11 +18326,6 @@ "minimist": "^1.2.5" } }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", diff --git a/new-lamassu-admin/package.json b/new-lamassu-admin/package.json index b807b5c8..bb59ee3d 100644 --- a/new-lamassu-admin/package.json +++ b/new-lamassu-admin/package.json @@ -31,7 +31,6 @@ "lamassu-coins": "git+https://github.com/lamassu/lamassu-coins.git", "libphonenumber-js": "^1.7.50", "match-sorter": "^4.2.0", - "moment": "2.24.0", "pretty-ms": "^2.1.0", "qrcode.react": "0.9.3", "ramda": "^0.26.1", diff --git a/new-lamassu-admin/src/components/LogsDownloaderPopper.js b/new-lamassu-admin/src/components/LogsDownloaderPopper.js index 9d64082f..7ff6a16c 100644 --- a/new-lamassu-admin/src/components/LogsDownloaderPopper.js +++ b/new-lamassu-admin/src/components/LogsDownloaderPopper.js @@ -1,8 +1,8 @@ import { useLazyQuery } from '@apollo/react-hooks' import { makeStyles, ClickAwayListener } from '@material-ui/core' import classnames from 'classnames' +import { format, isSameDay } from 'date-fns' import FileSaver from 'file-saver' -import moment from 'moment' import * as R from 'ramda' import React, { useState, useCallback } from 'react' @@ -65,12 +65,13 @@ const DateContainer = ({ date, children, ...props }) => { {date && ( <>
-
{date.format('D')}
+
{format(date, 'd')}
- {`${date.format( + {`${format( + date, 'MMM' - )} ${date.format('YYYY')}`} - {date.format('dddd')} + )} ${format(date, 'yyyy')}`} + {format(date, 'EEEE')}
@@ -186,8 +187,8 @@ const LogsDownloaderPopover = ({ } if (!range || !range.from) return - if (range.from && !range.until) range.until = moment() - if (moment(range.from).isSame(range.until, 'day')) range.until = moment() + if (range.from && !range.until) range.until = new Date() + if (isSameDay(range.from, range.until)) range.until = new Date() if (selectedRadio === RANGE) { fetchLogs({ @@ -203,7 +204,7 @@ const LogsDownloaderPopover = ({ const createLogsFile = (logs, range) => { const formatDateFile = date => { - return formatDate(date, timezone, 'YYYY-MM-DD_HH-mm') + return formatDate(date, timezone, 'yyyy-MM-dd_HH-mm') } const blob = new window.Blob([logs], { @@ -277,7 +278,7 @@ const LogsDownloaderPopover = ({ )} diff --git a/new-lamassu-admin/src/components/date-range-picker/Calendar.js b/new-lamassu-admin/src/components/date-range-picker/Calendar.js index f93df5dd..7e0661cb 100644 --- a/new-lamassu-admin/src/components/date-range-picker/Calendar.js +++ b/new-lamassu-admin/src/components/date-range-picker/Calendar.js @@ -1,5 +1,18 @@ import { makeStyles } from '@material-ui/core/styles' -import moment from 'moment' +import { + add, + differenceInMonths, + format, + getDay, + getDaysInMonth, + isAfter, + isSameDay, + isSameMonth, + lastDayOfMonth, + startOfMonth, + startOfWeek, + sub +} from 'date-fns' import * as R from 'ramda' import React, { useState } from 'react' @@ -72,49 +85,36 @@ const styles = { const useStyles = makeStyles(styles) const Calendar = ({ minDate, maxDate, handleSelect, ...props }) => { - const [currentDisplayedMonth, setCurrentDisplayedMonth] = useState(moment()) + const [currentDisplayedMonth, setCurrentDisplayedMonth] = useState(new Date()) const classes = useStyles() - const weekdays = moment.weekdaysMin().map(day => day.slice(0, 1)) - const monthLength = month => - Number.parseInt( - moment(month) - .endOf('month') - .format('D') - ) + const weekdays = Array.from(Array(7)).map((_, i) => + format(add(startOfWeek(new Date()), { days: i }), 'EEEEE') + ) + + const monthLength = month => getDaysInMonth(month) const monthdays = month => { - const lastMonth = moment(month).subtract(1, 'month') - const lastMonthRange = R.range( - 0, - moment(month) - .startOf('month') - .weekday() - ).reverse() + const lastMonth = sub(month, { months: 1 }) + const lastMonthRange = R.range(0, getDay(startOfMonth(month))).reverse() const lastMonthDays = R.map(i => - moment(lastMonth) - .endOf('month') - .subtract(i, 'days') + sub(lastDayOfMonth(lastMonth), { days: i }) )(lastMonthRange) const thisMonthRange = R.range(0, monthLength(month)) - const thisMonthDays = R.map(i => - moment(month) - .startOf('month') - .add(i, 'days') - )(thisMonthRange) + const thisMonthDays = R.map(i => add(startOfMonth(month), { days: i }))( + thisMonthRange + ) - const nextMonth = moment(month).add(1, 'month') + const nextMonth = add(month, { months: 1 }) const nextMonthRange = R.range( 0, 42 - lastMonthDays.length - thisMonthDays.length ) - const nextMonthDays = R.map(i => - moment(nextMonth) - .startOf('month') - .add(i, 'days') - )(nextMonthRange) + const nextMonthDays = R.map(i => add(startOfMonth(nextMonth), { days: i }))( + nextMonthRange + ) return R.concat(R.concat(lastMonthDays, thisMonthDays), nextMonthDays) } @@ -122,22 +122,24 @@ const Calendar = ({ minDate, maxDate, handleSelect, ...props }) => { const getRow = (month, row) => monthdays(month).slice(row * 7 - 7, row * 7) const handleNavPrev = currentMonth => { - const prevMonth = moment(currentMonth).subtract(1, 'month') + const prevMonth = sub(currentMonth, { months: 1 }) if (!minDate) setCurrentDisplayedMonth(prevMonth) else { setCurrentDisplayedMonth( - prevMonth.isSameOrAfter(minDate, 'month') + isSameMonth(prevMonth, minDate) || + differenceInMonths(prevMonth, minDate) > 0 ? prevMonth : currentDisplayedMonth ) } } const handleNavNext = currentMonth => { - const nextMonth = moment(currentMonth).add(1, 'month') + const nextMonth = add(currentMonth, { months: 1 }) if (!maxDate) setCurrentDisplayedMonth(nextMonth) else { setCurrentDisplayedMonth( - nextMonth.isSameOrBefore(maxDate, 'month') + isSameMonth(nextMonth, maxDate) || + differenceInMonths(maxDate, nextMonth) > 0 ? nextMonth : currentDisplayedMonth ) @@ -153,9 +155,10 @@ const Calendar = ({ minDate, maxDate, handleSelect, ...props }) => { - {`${currentDisplayedMonth.format( - 'MMMM' - )} ${currentDisplayedMonth.format('YYYY')}`} + {`${format(currentDisplayedMonth, 'MMMM')} ${format( + currentDisplayedMonth, + 'yyyy' + )}`} - {`${format(currentDisplayedMonth, 'MMMM')} ${format( - currentDisplayedMonth, - 'yyyy' + {`${format('MMMM', currentDisplayedMonth)} ${format( + 'yyyy', + currentDisplayedMonth )}`}