From e31014dde4ebced6628e47f341829055769bfbd0 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sun, 4 Jun 2023 13:03:31 +0800 Subject: [PATCH] code refactor --- src/lib/i18n.js | 18 +- src/lib/services.js | 4 +- src/lib/userstate.js | 6 +- src/lib/utilities/account.js | 140 +++++ src/lib/utilities/category.js | 80 +++ src/lib/utilities/common.js | 297 +++++++++ src/lib/utilities/currency.js | 85 +++ src/lib/utilities/datetime.js | 309 ++++++++++ src/lib/utilities/index.js | 175 ++++++ src/lib/utilities/misc.js | 95 +++ src/lib/utils.js | 1079 --------------------------------- src/lib/webauthn.js | 22 +- src/mobile-main.js | 6 +- src/store/exchangeRates.js | 12 +- src/store/index.js | 86 +-- src/store/overview.js | 6 +- src/store/statistics.js | 10 +- src/store/token.js | 4 +- src/store/transaction.js | 10 +- src/store/twoFactorAuth.js | 4 +- src/store/user.js | 16 +- 21 files changed, 1283 insertions(+), 1181 deletions(-) create mode 100644 src/lib/utilities/account.js create mode 100644 src/lib/utilities/category.js create mode 100644 src/lib/utilities/common.js create mode 100644 src/lib/utilities/currency.js create mode 100644 src/lib/utilities/datetime.js create mode 100644 src/lib/utilities/index.js create mode 100644 src/lib/utilities/misc.js diff --git a/src/lib/i18n.js b/src/lib/i18n.js index 385e904d..914c1554 100644 --- a/src/lib/i18n.js +++ b/src/lib/i18n.js @@ -2,7 +2,7 @@ import { defaultLanguage, allLanguages } from '../locales/index.js'; import timezone from "../consts/timezone.js"; import currency from "../consts/currency.js"; import settings from "./settings.js"; -import utils from './utils.js'; +import utilities from './utilities/index.js'; const apiNotFoundErrorCode = 100001; const specifiedApiNotFoundErrors = { @@ -251,16 +251,16 @@ export function getAllMinWeekdayNames(translateFn) { } export function getAllTimezones(includeSystemDefault, translateFn) { - const defaultTimezoneOffset = utils.getTimezoneOffset(); - const defaultTimezoneOffsetMinutes = utils.getTimezoneOffsetMinutes(); + const defaultTimezoneOffset = utilities.getTimezoneOffset(); + const defaultTimezoneOffsetMinutes = utilities.getTimezoneOffsetMinutes(); const allTimezones = timezone.all; const allTimezoneInfos = []; for (let i = 0; i < allTimezones.length; i++) { allTimezoneInfos.push({ name: allTimezones[i].timezoneName, - utcOffset: (allTimezones[i].timezoneName !== timezone.utcTimezoneName ? utils.getTimezoneOffset(allTimezones[i].timezoneName) : ''), - utcOffsetMinutes: utils.getTimezoneOffsetMinutes(allTimezones[i].timezoneName), + utcOffset: (allTimezones[i].timezoneName !== timezone.utcTimezoneName ? utilities.getTimezoneOffset(allTimezones[i].timezoneName) : ''), + utcOffsetMinutes: utilities.getTimezoneOffsetMinutes(allTimezones[i].timezoneName), displayName: translateFn(`timezone.${allTimezones[i].displayName}`) }); } @@ -311,22 +311,22 @@ export function getAllCurrencies(translateFn) { } export function getDisplayCurrency(value, currencyCode, notConvertValue, translateFn) { - if (!utils.isNumber(value) && !utils.isString(value)) { + if (!utilities.isNumber(value) && !utilities.isString(value)) { return value; } - if (utils.isNumber(value)) { + if (utilities.isNumber(value)) { value = value.toString(); } if (!notConvertValue) { - const hasIncompleteFlag = utils.isString(value) && value.charAt(value.length - 1) === '+'; + const hasIncompleteFlag = utilities.isString(value) && value.charAt(value.length - 1) === '+'; if (hasIncompleteFlag) { value = value.substring(0, value.length - 1); } - value = utils.numericCurrencyToString(value); + value = utilities.numericCurrencyToString(value); if (hasIncompleteFlag) { value = value + '+'; diff --git a/src/lib/services.js b/src/lib/services.js index 6b9a233d..727c581a 100644 --- a/src/lib/services.js +++ b/src/lib/services.js @@ -2,7 +2,7 @@ import axios from 'axios'; import api from '../consts/api.js'; import userState from './userstate.js'; -import utils from './utils.js'; +import utilities from './utilities/index.js'; let needBlockRequest = false; let blockedRequests = []; @@ -16,7 +16,7 @@ axios.interceptors.request.use(config => { config.headers.Authorization = `Bearer ${token}`; } - config.headers['X-Timezone-Offset'] = utils.getTimezoneOffsetMinutes(); + config.headers['X-Timezone-Offset'] = utilities.getTimezoneOffsetMinutes(); if (needBlockRequest && !config.ignoreBlocked) { return new Promise(resolve => { diff --git a/src/lib/userstate.js b/src/lib/userstate.js index 7591aab5..0c39501d 100644 --- a/src/lib/userstate.js +++ b/src/lib/userstate.js @@ -1,7 +1,7 @@ import CryptoJS from 'crypto-js'; import settings from './settings.js'; -import utils from './utils.js'; +import utilities from './utilities/index.js'; const appLockSecretBaseStringPrefix = 'EBK_LOCK_SECRET_'; @@ -141,7 +141,7 @@ function isCorrectPinCode(pinCode) { } function updateToken(token) { - if (utils.isString(token)) { + if (utilities.isString(token)) { if (settings.isEnableApplicationLock()) { sessionStorage.setItem(tokenSessionStorageKey, token); @@ -155,7 +155,7 @@ function updateToken(token) { } function updateUserInfo(user) { - if (utils.isObject(user)) { + if (utilities.isObject(user)) { localStorage.setItem(userInfoLocalStorageKey, JSON.stringify(user)); } } diff --git a/src/lib/utilities/account.js b/src/lib/utilities/account.js new file mode 100644 index 00000000..6fc79382 --- /dev/null +++ b/src/lib/utilities/account.js @@ -0,0 +1,140 @@ +import accountConstants from '../../consts/account.js'; + +export function getAccountCategoryInfo(categoryId) { + for (let i = 0; i < accountConstants.allCategories.length; i++) { + if (accountConstants.allCategories[i].id === categoryId) { + return accountConstants.allCategories[i]; + } + } + + return null; +} + +export function getCategorizedAccounts(allAccounts) { + const ret = {}; + + for (let i = 0; i < allAccounts.length; i++) { + const account = allAccounts[i]; + + if (!ret[account.category]) { + const categoryInfo = getAccountCategoryInfo(account.category); + + if (categoryInfo) { + ret[account.category] = { + category: account.category, + name: categoryInfo.name, + icon: categoryInfo.defaultAccountIconId, + accounts: [] + }; + } + } + + if (ret[account.category]) { + const accountList = ret[account.category].accounts; + accountList.push(account); + } + } + + return ret; +} + +export function getVisibleCategorizedAccounts(categorizedAccounts) { + const ret = {}; + + for (let i = 0; i < accountConstants.allCategories.length; i++) { + const accountCategory = accountConstants.allCategories[i]; + + if (!categorizedAccounts[accountCategory.id] || !categorizedAccounts[accountCategory.id].accounts) { + continue; + } + + const allAccounts = categorizedAccounts[accountCategory.id].accounts; + const visibleAccounts = []; + const allVisibleSubAccounts = {}; + + for (let j = 0; j < allAccounts.length; j++) { + const account = allAccounts[j]; + + if (account.hidden) { + continue; + } + + visibleAccounts.push(account); + + if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && account.subAccounts) { + const visibleSubAccounts = []; + + for (let k = 0; k < account.subAccounts.length; k++) { + const subAccount = account.subAccounts[k]; + + if (!subAccount.hidden) { + visibleSubAccounts.push(subAccount); + } + } + + if (visibleSubAccounts.length > 0) { + allVisibleSubAccounts[account.id] = visibleSubAccounts; + } + } + } + + if (visibleAccounts.length > 0) { + ret[accountCategory.id] = { + category: accountCategory.id, + name: accountCategory.name, + icon: accountCategory.defaultAccountIconId, + visibleAccounts: visibleAccounts, + visibleSubAccounts: allVisibleSubAccounts + }; + } + } + + return ret; +} + +export function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter) { + const allAccountCategories = accountConstants.allCategories; + const ret = []; + + for (let categoryIdx = 0; categoryIdx < allAccountCategories.length; categoryIdx++) { + const accountCategory = allAccountCategories[categoryIdx]; + + if (!categorizedAccounts[accountCategory.id] || !categorizedAccounts[accountCategory.id].accounts) { + continue; + } + + for (let accountIdx = 0; accountIdx < categorizedAccounts[accountCategory.id].accounts.length; accountIdx++) { + const account = categorizedAccounts[accountCategory.id].accounts[accountIdx]; + + if (account.hidden || !accountFilter(account)) { + continue; + } + + if (account.type === accountConstants.allAccountTypes.SingleAccount) { + ret.push({ + balance: account.balance, + isAsset: account.isAsset, + isLiability: account.isLiability, + currency: account.currency + }); + } else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts) { + for (let subAccountIdx = 0; subAccountIdx < account.subAccounts.length; subAccountIdx++) { + const subAccount = account.subAccounts[subAccountIdx]; + + if (subAccount.hidden || !accountFilter(subAccount)) { + continue; + } + + ret.push({ + balance: subAccount.balance, + isAsset: subAccount.isAsset, + isLiability: subAccount.isLiability, + currency: subAccount.currency + }); + } + } + } + } + + return ret; +} diff --git a/src/lib/utilities/category.js b/src/lib/utilities/category.js new file mode 100644 index 00000000..1aef55a3 --- /dev/null +++ b/src/lib/utilities/category.js @@ -0,0 +1,80 @@ +import categoryConstants from '../../consts/category.js'; +import transactionConstants from '../../consts/transaction.js'; + +export function transactionTypeToCategoryType(transactionType) { + if (transactionType === transactionConstants.allTransactionTypes.Income) { + return categoryConstants.allCategoryTypes.Income; + } else if (transactionType === transactionConstants.allTransactionTypes.Expense) { + return categoryConstants.allCategoryTypes.Expense; + } else if (transactionType === transactionConstants.allTransactionTypes.Transfer) { + return categoryConstants.allCategoryTypes.Transfer; + } else { + return null; + } +} + +export function categoryTypeToTransactionType(categoryType) { + if (categoryType === categoryConstants.allCategoryTypes.Income) { + return transactionConstants.allTransactionTypes.Income; + } else if (categoryType === categoryConstants.allCategoryTypes.Expense) { + return transactionConstants.allTransactionTypes.Expense; + } else if (categoryType === categoryConstants.allCategoryTypes.Transfer) { + return transactionConstants.allTransactionTypes.Transfer; + } else { + return null; + } +} + +export function allVisibleTransactionCategories(allTransactionCategories) { + const ret = {}; + + for (let key in transactionConstants.allTransactionTypes) { + if (!Object.prototype.hasOwnProperty.call(transactionConstants.allTransactionTypes, key)) { + continue; + } + + const transactionType = transactionConstants.allTransactionTypes[key]; + + if (!allTransactionCategories[transactionType]) { + continue; + } + + const allCategories = allTransactionCategories[transactionType]; + const visibleCategories = []; + const allVisibleSubCategories = {}; + + for (let j = 0; j < allCategories.length; j++) { + const category = allCategories[j]; + + if (category.hidden) { + continue; + } + + visibleCategories.push(category); + + if (category.subCategories) { + const visibleSubCategories = []; + + for (let k = 0; k < category.subCategories.length; k++) { + const subCategory = category.subCategories[k]; + + if (!subCategory.hidden) { + visibleSubCategories.push(subCategory); + } + } + + if (visibleSubCategories.length > 0) { + allVisibleSubCategories[category.id] = visibleSubCategories; + } + } + } + + ret[transactionType.toString()] = { + type: transactionType.toString(), + visibleCategories: visibleCategories, + visibleSubCategories: allVisibleSubCategories + }; + } + + return ret; +} diff --git a/src/lib/utilities/common.js b/src/lib/utilities/common.js new file mode 100644 index 00000000..8dadc44b --- /dev/null +++ b/src/lib/utilities/common.js @@ -0,0 +1,297 @@ +import settings from "../../lib/settings"; + +export function isFunction(val) { + return typeof(val) === 'function'; +} + +export function isObject(val) { + return val != null && typeof(val) === 'object' && !isArray(val); +} + +export function isArray(val) { + if (isFunction(Array.isArray)) { + return Array.isArray(val); + } + + return Object.prototype.toString.call(val) === '[object Array]'; +} + +export function isString(val) { + return typeof(val) === 'string'; +} + +export function isNumber(val) { + return typeof(val) === 'number'; +} + +export function isBoolean(val) { + return typeof(val) === 'boolean'; +} + +export function isEquals(obj1, obj2) { + if (obj1 === obj2) { + return true; + } + + if (isArray(obj1) && isArray(obj2)) { + if (obj1.length !== obj2.length) { + return false; + } + + for (let i = 0; i < obj1.length; i++) { + if (!isEquals(obj1[i], obj2[i])) { + return false; + } + } + + return true; + } else if (isObject(obj1) && isObject(obj2)) { + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + if (keys1.length !== keys2.length) { + return false; + } + + const keyExistsMap2 = {}; + + for (let i = 0; i < keys2.length; i++) { + const key = keys2[i]; + + keyExistsMap2[key] = true; + } + + for (let i = 0; i < keys1.length; i++) { + const key = keys1[i]; + + if (!keyExistsMap2[key]) { + return false; + } + + if (!isEquals(obj1[key], obj2[key])) { + return false; + } + } + + return true; + } else { + return obj1 === obj2; + } +} + +export function appendThousandsSeparator(value) { + if (!settings.isEnableThousandsSeparator() || value.length <= 3) { + return value; + } + + const negative = value.charAt(0) === '-'; + + if (negative) { + value = value.substring(1); + } + + const dotPos = value.indexOf('.'); + const integer = dotPos < 0 ? value : value.substring(0, dotPos); + const decimals = dotPos < 0 ? '' : value.substring(dotPos + 1, value.length); + + const finalChars = []; + + for (let i = 0; i < integer.length; i++) { + if (i % 3 === 0 && i > 0) { + finalChars.push(','); + } + + finalChars.push(integer.charAt(integer.length - 1 - i)); + } + + finalChars.reverse(); + + let newInteger = finalChars.join(''); + + if (negative) { + newInteger = `-${newInteger}`; + } + + if (dotPos < 0) { + return newInteger; + } else { + return `${newInteger}.${decimals}`; + } +} + +export function formatPercent(value, precision, lowPrecisionValue) { + const ratio = Math.pow(10, precision); + const normalizedValue = Math.floor(value * ratio); + + if (value > 0 && normalizedValue < 1 && lowPrecisionValue) { + return lowPrecisionValue + '%'; + } + + const result = normalizedValue / ratio; + return result + '%'; +} + +export function limitText(value, maxLength) { + let length = 0; + + for (let i = 0; i < value.length; i++) { + const c = value.charCodeAt(i); + + if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)) { + length++; + } else { + length += 2; + } + } + + if (length <= maxLength || maxLength <= 3) { + return value; + } + + return value.substring(0, maxLength - 3) + '...'; +} + +export function base64encode(arrayBuffer) { + if (!arrayBuffer || arrayBuffer.length === 0) { + return null; + } + + return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer))); +} + +export function arrayBufferToString(arrayBuffer) { + return String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); +} + +export function stringToArrayBuffer(str){ + return Uint8Array.from(str, c => c.charCodeAt(0)).buffer; +} + +export function getNameByKeyValue(src, value, keyField, nameField, defaultName) { + if (isArray(src)) { + if (keyField) { + for (let i = 0; i < src.length; i++) { + const option = src[i]; + + if (option[keyField] === value) { + return option[nameField]; + } + } + } else { + if (src[value]) { + const option = src[value]; + + return option[nameField]; + } + } + } else if (isObject(src)) { + if (keyField) { + for (let key in src) { + if (!Object.prototype.hasOwnProperty.call(src, key)) { + continue; + } + + const option = src[key]; + + if (option[keyField] === value) { + return option[nameField]; + } + } + } else { + if (src[value]) { + const option = src[value]; + + return option[nameField]; + } + } + } + + return defaultName; +} + +export function copyObjectTo(fromObject, toObject) { + if (!isObject(fromObject)) { + return toObject; + } + + if (!isObject(toObject)) { + toObject = {}; + } + + for (let key in fromObject) { + if (!Object.prototype.hasOwnProperty.call(fromObject, key)) { + continue; + } + + const fromValue = fromObject[key]; + const toValue = toObject[key]; + + if (isArray(fromValue)) { + toObject[key] = this.copyArrayTo(fromValue, toValue); + } else if (isObject(fromValue)) { + toObject[key] = this.copyObjectTo(fromValue, toValue); + } else { + if (fromValue !== toValue) { + toObject[key] = fromValue; + } + } + } + + return toObject; +} + +export function copyArrayTo(fromArray, toArray) { + if (!isArray(fromArray)) { + return toArray; + } + + if (!isArray(toArray)) { + toArray = []; + } + + for (let i = 0; i < fromArray.length; i++) { + const fromValue = fromArray[i]; + + if (toArray.length > i) { + const toValue = toArray[i]; + + if (isArray(fromValue)) { + toArray[i] = this.copyArrayTo(fromValue, toValue); + } else if (isObject(fromValue)) { + toArray[i] = this.copyObjectTo(fromValue, toValue); + } else { + if (fromValue !== toValue) { + toArray[i] = fromValue; + } + } + } else { + if (isArray(fromValue)) { + toArray.push(this.copyArrayTo(fromValue, [])); + } else if (isObject(fromValue)) { + toArray.push(this.copyObjectTo(fromValue, {})); + } else { + toArray.push(fromValue); + } + } + } + + return toArray; +} + +export function arrangeArrayWithNewStartIndex(array, startIndex) { + if (startIndex <= 0 || startIndex >= array.length) { + return array; + } + + const newArray = []; + + for (let i = startIndex; i < array.length; i++) { + newArray.push(array[i]); + } + + for (let i = 0; i < startIndex; i++) { + newArray.push(array[i]); + } + + return newArray; +} diff --git a/src/lib/utilities/currency.js b/src/lib/utilities/currency.js new file mode 100644 index 00000000..19251638 --- /dev/null +++ b/src/lib/utilities/currency.js @@ -0,0 +1,85 @@ +import { isNumber, appendThousandsSeparator } from "./common.js"; + +export function numericCurrencyToString(num) { + let str = num.toString(); + const negative = str.charAt(0) === '-'; + + if (negative) { + str = str.substring(1); + } + + if (str.length === 0) { + str = '0.00'; + } else if (str.length === 1) { + str = '0.0' + str; + } else if (str.length === 2) { + str = '0.' + str; + } else { + let integer = str.substring(0, str.length - 2); + let decimals = str.substring(str.length - 2); + + integer = appendThousandsSeparator(integer); + + str = `${integer}.${decimals}`; + } + + if (negative) { + str = `-${str}`; + } + + return str; +} + +export function stringCurrencyToNumeric(str) { + if (!str || str.length < 1) { + return 0; + } + + const negative = str.charAt(0) === '-'; + + if (negative) { + str = str.substring(1); + } + + if (!str || str.length < 1) { + return 0; + } + + const sign = negative ? -1 : 1; + + if (str.indexOf(',')) { + str = str.replaceAll(/,/g, ''); + } + + let dotPos = str.indexOf('.'); + + if (dotPos < 0) { + return sign * parseInt(str) * 100; + } else if (dotPos === 0) { + str = '0' + str; + dotPos++; + } + + const integer = str.substring(0, dotPos); + const decimals = str.substring(dotPos + 1, str.length); + + if (decimals.length < 1) { + return sign * parseInt(integer) * 100; + } else if (decimals.length === 1) { + return sign * parseInt(integer) * 100 + sign * parseInt(decimals) * 10; + } else if (decimals.length === 2) { + return sign * parseInt(integer) * 100 + sign * parseInt(decimals); + } else { + return sign * parseInt(integer) * 100 + sign * parseInt(decimals.substring(0, 2)); + } +} + +export function getExchangedAmount(amount, fromRate, toRate) { + const exchangeRate = parseFloat(toRate) / parseFloat(fromRate); + + if (!isNumber(exchangeRate)) { + return null; + } + + return amount * exchangeRate; +} diff --git a/src/lib/utilities/datetime.js b/src/lib/utilities/datetime.js new file mode 100644 index 00000000..0f1f4b3e --- /dev/null +++ b/src/lib/utilities/datetime.js @@ -0,0 +1,309 @@ +import moment from 'moment'; + +import dateTimeConstants from '../../consts/datetime.js'; +import { isNumber } from "./common.js"; + +export function getUtcOffsetMinutesByUtcOffset(utcOffset) { + if (!utcOffset) { + return 0; + } + + const parts = utcOffset.split(':'); + + if (parts.length !== 2) { + return 0; + } + + return parseInt(parts[0]) * 60 + parseInt(parts[1]); +} + +export function getUtcOffsetByUtcOffsetMinutes(utcOffsetMinutes) { + let offsetHours = parseInt(Math.abs(utcOffsetMinutes) / 60); + let offsetMinutes = Math.abs(utcOffsetMinutes) - offsetHours * 60; + + if (offsetHours < 10) { + offsetHours = '0' + offsetHours; + } + + if (offsetMinutes < 10) { + offsetMinutes = '0' + offsetMinutes; + } + + if (utcOffsetMinutes >= 0) { + return `+${offsetHours}:${offsetMinutes}`; + } else if (utcOffsetMinutes < 0) { + return `-${offsetHours}:${offsetMinutes}`; + } +} + +export function getTimezoneOffset(timezone) { + if (timezone) { + return moment().tz(timezone).format('Z'); + } else { + return moment().format('Z'); + } +} + +export function getTimezoneOffsetMinutes(timezone) { + const utcOffset = getTimezoneOffset(timezone); + return getUtcOffsetMinutesByUtcOffset(utcOffset); +} + +export function getBrowserTimezoneOffsetMinutes() { + return -new Date().getTimezoneOffset(); +} + +export function getLocalDatetimeFromUnixTime(unixTime) { + return new Date(unixTime * 1000); +} + +export function getUnixTimeFromLocalDatetime(datetime) { + return datetime.getTime() / 1000; +} + +export function getActualUnixTimeForStore(unixTime, utcOffset, currentUtcOffset) { + return unixTime - (utcOffset - currentUtcOffset) * 60; +} + +export function getDummyUnixTimeForLocalUsage(unixTime, utcOffset, currentUtcOffset) { + return unixTime + (utcOffset - currentUtcOffset) * 60; +} + +export function getCurrentUnixTime() { + return moment().unix(); +} + +export function getCurrentDateTime() { + return moment(); +} + +export function parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset) { + if (isNumber(utcOffset)) { + if (!isNumber(currentUtcOffset)) { + currentUtcOffset = getTimezoneOffsetMinutes(); + } + + unixTime = getDummyUnixTimeForLocalUsage(unixTime, utcOffset, currentUtcOffset); + } + + return moment.unix(unixTime); +} + +export function is24HourFormat(format) { + if (format.indexOf('HH') >= 0 && format.indexOf('hh') < 0) { + return true; + } else if (format.indexOf('HH') < 0 && format.indexOf('hh') >= 0) { + return false; + } + + return true; +} + +export function formatUnixTime(unixTime, format, utcOffset, currentUtcOffset) { + return parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format); +} + +export function formatTime(dateTime, format) { + return moment(dateTime).format(format); +} + +export function getUnixTime(date) { + return moment(date).unix(); +} + +export function getYear(date) { + return moment(date).year(); +} + +export function getMonth(date) { + return moment(date).month() + 1; +} + +export function getYearAndMonth(date) { + const year = getYear(date); + let month = getMonth(date); + + if (month < 10) { + month = '0' + month; + } + + return `${year}-${month}`; +} + +export function getDay(date) { + return moment(date).date(); +} + +export function getDayOfWeekName(date) { + const dayOfWeek = moment(date).days(); + return dateTimeConstants.allWeekDaysArray[dayOfWeek].name; +} + +export function getHour(date) { + return moment(date).hour(); +} + +export function getMinute(date) { + return moment(date).minute(); +} + +export function getSecond(date) { + return moment(date).second(); +} + +export function getUnixTimeBeforeUnixTime(unixTime, amount, unit) { + return moment.unix(unixTime).subtract(amount, unit).unix(); +} + +export function getUnixTimeAfterUnixTime(unixTime, amount, unit) { + return moment.unix(unixTime).add(amount, unit).unix(); +} + +export function getMinuteFirstUnixTime(date) { + const datetime = moment(date); + return datetime.set({ second: 0, millisecond: 0 }).unix(); +} + +export function getMinuteLastUnixTime(date) { + return moment.unix(getMinuteFirstUnixTime(date)).add(1, 'minutes').subtract(1, 'seconds').unix(); +} + +export function getTodayFirstUnixTime() { + return moment().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).unix(); +} + +export function getTodayLastUnixTime() { + return moment.unix(getTodayFirstUnixTime()).add(1, 'days').subtract(1, 'seconds').unix(); +} + +export function getThisWeekFirstUnixTime(firstDayOfWeek) { + const today = moment.unix(getTodayFirstUnixTime()); + + if (!isNumber(firstDayOfWeek)) { + firstDayOfWeek = 0; + } + + let dayOfWeek = today.day() - firstDayOfWeek; + + if (dayOfWeek < 0) { + dayOfWeek += 7; + } + + return today.subtract(dayOfWeek, 'days').unix(); +} + +export function getThisWeekLastUnixTime(firstDayOfWeek) { + return moment.unix(getThisWeekFirstUnixTime(firstDayOfWeek)).add(7, 'days').subtract(1, 'seconds').unix(); +} + +export function getThisMonthFirstUnixTime() { + const today = moment.unix(getTodayFirstUnixTime()); + return today.subtract(today.date() - 1, 'days').unix(); +} + +export function getThisMonthLastUnixTime() { + return moment.unix(getThisMonthFirstUnixTime()).add(1, 'months').subtract(1, 'seconds').unix(); +} + +export function getThisYearFirstUnixTime() { + const today = moment.unix(getTodayFirstUnixTime()); + return today.subtract(today.dayOfYear() - 1, 'days').unix(); +} + +export function getThisYearLastUnixTime() { + return moment.unix(getThisYearFirstUnixTime()).add(1, 'years').subtract(1, 'seconds').unix(); +} + +export function getShiftedDateRange(minTime, maxTime, scale) { + const minDateTime = parseDateFromUnixTime(minTime).set({ second: 0, millisecond: 0 }); + const maxDateTime = parseDateFromUnixTime(maxTime).set({ second: 59, millisecond: 999 }); + + const firstDayOfMonth = minDateTime.clone().startOf('month'); + const lastDayOfMonth = maxDateTime.clone().endOf('month'); + + if (firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix()) { + const months = getYear(maxDateTime) * 12 + getMonth(maxDateTime) - getYear(minDateTime) * 12 - getMonth(minDateTime) + 1; + const newMinDateTime = minDateTime.add(months * scale, 'months'); + const newMaxDateTime = newMinDateTime.clone().add(months, 'months').subtract(1, 'seconds'); + + return { + minTime: newMinDateTime.unix(), + maxTime: newMaxDateTime.unix() + }; + } + + const range = (maxTime - minTime + 1) * scale; + + return { + minTime: minTime + range, + maxTime: maxTime + range + }; +} + +export function getDateRangeByDateType(dateType, firstDayOfWeek) { + let maxTime = 0; + let minTime = 0; + + if (dateType === dateTimeConstants.allDateRanges.All.type) { // All + maxTime = 0; + minTime = 0; + } else if (dateType === dateTimeConstants.allDateRanges.Today.type) { // Today + maxTime = getTodayLastUnixTime(); + minTime = getTodayFirstUnixTime(); + } else if (dateType === dateTimeConstants.allDateRanges.Yesterday.type) { // Yesterday + maxTime = getUnixTimeBeforeUnixTime(getTodayLastUnixTime(), 1, 'days'); + minTime = getUnixTimeBeforeUnixTime(getTodayFirstUnixTime(), 1, 'days'); + } else if (dateType === dateTimeConstants.allDateRanges.LastSevenDays.type) { // Last 7 days + maxTime = getTodayLastUnixTime(); + minTime = getUnixTimeBeforeUnixTime(getTodayFirstUnixTime(), 6, 'days'); + } else if (dateType === dateTimeConstants.allDateRanges.LastThirtyDays.type) { // Last 30 days + maxTime = getTodayLastUnixTime(); + minTime = getUnixTimeBeforeUnixTime(getTodayFirstUnixTime(), 29, 'days'); + } else if (dateType === dateTimeConstants.allDateRanges.ThisWeek.type) { // This week + maxTime = getThisWeekLastUnixTime(firstDayOfWeek); + minTime = getThisWeekFirstUnixTime(firstDayOfWeek); + } else if (dateType === dateTimeConstants.allDateRanges.LastWeek.type) { // Last week + maxTime = getUnixTimeBeforeUnixTime(getThisWeekLastUnixTime(firstDayOfWeek), 7, 'days'); + minTime = getUnixTimeBeforeUnixTime(getThisWeekFirstUnixTime(firstDayOfWeek), 7, 'days'); + } else if (dateType === dateTimeConstants.allDateRanges.ThisMonth.type) { // This month + maxTime = getThisMonthLastUnixTime(); + minTime = getThisMonthFirstUnixTime(); + } else if (dateType === dateTimeConstants.allDateRanges.LastMonth.type) { // Last month + maxTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 1, 'seconds'); + minTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 1, 'months'); + } else if (dateType === dateTimeConstants.allDateRanges.ThisYear.type) { // This year + maxTime = getThisYearLastUnixTime(); + minTime = getThisYearFirstUnixTime(); + } else if (dateType === dateTimeConstants.allDateRanges.LastYear.type) { // Last year + maxTime = getUnixTimeBeforeUnixTime(getThisYearLastUnixTime(), 1, 'years'); + minTime = getUnixTimeBeforeUnixTime(getThisYearFirstUnixTime(), 1, 'years'); + } else { + return null; + } + + return { + dateType: dateType, + maxTime: maxTime, + minTime: minTime + }; +} + +export function isDateRangeMatchFullYears(minTime, maxTime) { + const minDateTime = parseDateFromUnixTime(minTime).set({ second: 0, millisecond: 0 }); + const maxDateTime = parseDateFromUnixTime(maxTime).set({ second: 59, millisecond: 999 }); + + const firstDayOfYear = minDateTime.clone().startOf('year'); + const lastDayOfYear = maxDateTime.clone().endOf('year'); + + return firstDayOfYear.unix() === minDateTime.unix() && lastDayOfYear.unix() === maxDateTime.unix(); +} + +export function isDateRangeMatchFullMonths(minTime, maxTime) { + const minDateTime = parseDateFromUnixTime(minTime).set({ second: 0, millisecond: 0 }); + const maxDateTime = parseDateFromUnixTime(maxTime).set({ second: 59, millisecond: 999 }); + + const firstDayOfMonth = minDateTime.clone().startOf('month'); + const lastDayOfMonth = maxDateTime.clone().endOf('month'); + + return firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix(); +} diff --git a/src/lib/utilities/index.js b/src/lib/utilities/index.js new file mode 100644 index 00000000..1061a85f --- /dev/null +++ b/src/lib/utilities/index.js @@ -0,0 +1,175 @@ +import { + isFunction, + isObject, + isArray, + isString, + isNumber, + isBoolean, + isEquals, + appendThousandsSeparator, + formatPercent, + limitText, + base64encode, + arrayBufferToString, + stringToArrayBuffer, + getNameByKeyValue, + copyObjectTo, + copyArrayTo, + arrangeArrayWithNewStartIndex, +} from './common.js' + +import { + getUtcOffsetMinutesByUtcOffset, + getUtcOffsetByUtcOffsetMinutes, + getTimezoneOffset, + getTimezoneOffsetMinutes, + getBrowserTimezoneOffsetMinutes, + getLocalDatetimeFromUnixTime, + getUnixTimeFromLocalDatetime, + getActualUnixTimeForStore, + getDummyUnixTimeForLocalUsage, + getCurrentUnixTime, + getCurrentDateTime, + parseDateFromUnixTime, + is24HourFormat, + formatUnixTime, + formatTime, + getUnixTime, + getYear, + getMonth, + getYearAndMonth, + getDay, + getDayOfWeekName, + getHour, + getMinute, + getSecond, + getUnixTimeBeforeUnixTime, + getUnixTimeAfterUnixTime, + getMinuteFirstUnixTime, + getMinuteLastUnixTime, + getTodayFirstUnixTime, + getTodayLastUnixTime, + getThisWeekFirstUnixTime, + getThisWeekLastUnixTime, + getThisMonthFirstUnixTime, + getThisMonthLastUnixTime, + getThisYearFirstUnixTime, + getThisYearLastUnixTime, + getShiftedDateRange, + getDateRangeByDateType, + isDateRangeMatchFullYears, + isDateRangeMatchFullMonths, +} from './datetime.js' + +import { + numericCurrencyToString, + stringCurrencyToNumeric, + getExchangedAmount, +} from './currency.js' + +import { + generateRandomString, + parseUserAgent, + parseDeviceInfo, + makeButtonCopyToClipboard, + changeClipboardObjectText, +} from './misc.js' + +import { + transactionTypeToCategoryType, + categoryTypeToTransactionType, + allVisibleTransactionCategories, +} from './category.js' + +import { + getAccountCategoryInfo, + getCategorizedAccounts, + getVisibleCategorizedAccounts, + getAllFilteredAccountsBalance, +} from './account.js' + +export default { + // common.js + isFunction, + isObject, + isArray, + isString, + isNumber, + isBoolean, + isEquals, + appendThousandsSeparator, + formatPercent, + limitText, + base64encode, + arrayBufferToString, + stringToArrayBuffer, + getNameByKeyValue, + copyObjectTo, + copyArrayTo, + arrangeArrayWithNewStartIndex, + + // datetime.js + getUtcOffsetMinutesByUtcOffset, + getUtcOffsetByUtcOffsetMinutes, + getTimezoneOffset, + getTimezoneOffsetMinutes, + getBrowserTimezoneOffsetMinutes, + getLocalDatetimeFromUnixTime, + getUnixTimeFromLocalDatetime, + getActualUnixTimeForStore, + getDummyUnixTimeForLocalUsage, + getCurrentUnixTime, + getCurrentDateTime, + parseDateFromUnixTime, + is24HourFormat, + formatUnixTime, + formatTime, + getUnixTime, + getYear, + getMonth, + getYearAndMonth, + getDay, + getDayOfWeekName, + getHour, + getMinute, + getSecond, + getUnixTimeBeforeUnixTime, + getUnixTimeAfterUnixTime, + getMinuteFirstUnixTime, + getMinuteLastUnixTime, + getTodayFirstUnixTime, + getTodayLastUnixTime, + getThisWeekFirstUnixTime, + getThisWeekLastUnixTime, + getThisMonthFirstUnixTime, + getThisMonthLastUnixTime, + getThisYearFirstUnixTime, + getThisYearLastUnixTime, + getShiftedDateRange, + getDateRangeByDateType, + isDateRangeMatchFullYears, + isDateRangeMatchFullMonths, + + // currency.js + numericCurrencyToString, + stringCurrencyToNumeric, + getExchangedAmount, + + // misc.js + generateRandomString, + parseUserAgent, + parseDeviceInfo, + makeButtonCopyToClipboard, + changeClipboardObjectText, + + // category.js + transactionTypeToCategoryType, + categoryTypeToTransactionType, + allVisibleTransactionCategories, + + // account.js + getAccountCategoryInfo, + getCategorizedAccounts, + getVisibleCategorizedAccounts, + getAllFilteredAccountsBalance, +}; diff --git a/src/lib/utilities/misc.js b/src/lib/utilities/misc.js new file mode 100644 index 00000000..14659ce9 --- /dev/null +++ b/src/lib/utilities/misc.js @@ -0,0 +1,95 @@ +import Clipboard from 'clipboard'; +import CryptoJS from 'crypto-js'; +import uaParser from 'ua-parser-js'; + +export function generateRandomString() { + const baseString = 'ebk_' + Math.round(new Date().getTime() / 1000) + '_' + Math.random(); + return CryptoJS.SHA256(baseString).toString(); +} + +export function parseUserAgent(ua) { + const uaParseRet = uaParser(ua); + + return { + device: { + vendor: uaParseRet.device.vendor, + model: uaParseRet.device.model, + type: uaParseRet.device.type + }, + os: { + name: uaParseRet.os.name, + version: uaParseRet.os.version + }, + browser: { + name: uaParseRet.browser.name, + version: uaParseRet.browser.version + } + }; +} + +export function parseDeviceInfo(ua) { + const uaInfo = parseUserAgent(ua); + let result = ''; + + if (uaInfo.device.model) { + result = uaInfo.device.model; + } else if (uaInfo.os.name) { + result = uaInfo.os.name; + + if (uaInfo.os.version) { + result += ' ' + uaInfo.os.version; + } + } + + if (uaInfo.browser.name) { + let browserInfo = uaInfo.browser.name; + + if (uaInfo.browser.version) { + browserInfo += ' ' + uaInfo.browser.version; + } + + if (result) { + result += ' (' + browserInfo + ')'; + } else { + result = browserInfo; + } + } + + if (!result) { + return 'Unknown Device'; + } + + return result; +} + +export function makeButtonCopyToClipboard({ text, el, successCallback, errorCallback }) { + const clipboard = new Clipboard(el, { + text: function () { + return text; + } + }); + + clipboard.on('success', (e) => { + if (successCallback) { + successCallback(e); + } + }); + + clipboard.on('error', (e) => { + if (errorCallback) { + errorCallback(e); + } + }); + + return clipboard; +} + +export function changeClipboardObjectText(clipboard, text) { + if (!clipboard) { + return; + } + + clipboard.text = function () { + return text; + }; +} diff --git a/src/lib/utils.js b/src/lib/utils.js index 77a51024..e69de29b 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -1,1079 +0,0 @@ -import CryptoJS from 'crypto-js'; -import moment from 'moment'; -import Clipboard from 'clipboard'; -import uaParser from 'ua-parser-js'; - -import dateTimeConstants from '../consts/datetime.js'; -import accountConstants from '../consts/account.js'; -import categoryConstants from '../consts/category.js'; -import transactionConstants from '../consts/transaction.js'; -import settings from './settings.js'; - -function isFunction(val) { - return typeof(val) === 'function'; -} - -function isObject(val) { - return val != null && typeof(val) === 'object' && !isArray(val); -} - -function isArray(val) { - if (isFunction(Array.isArray)) { - return Array.isArray(val); - } - - return Object.prototype.toString.call(val) === '[object Array]'; -} - -function isString(val) { - return typeof(val) === 'string'; -} - -function isNumber(val) { - return typeof(val) === 'number'; -} - -function isBoolean(val) { - return typeof(val) === 'boolean'; -} - -function isEquals(obj1, obj2) { - if (obj1 === obj2) { - return true; - } - - if (isArray(obj1) && isArray(obj2)) { - if (obj1.length !== obj2.length) { - return false; - } - - for (let i = 0; i < obj1.length; i++) { - if (!isEquals(obj1[i], obj2[i])) { - return false; - } - } - - return true; - } else if (isObject(obj1) && isObject(obj2)) { - const keys1 = Object.keys(obj1); - const keys2 = Object.keys(obj2); - - if (keys1.length !== keys2.length) { - return false; - } - - const keyExistsMap2 = {}; - - for (let i = 0; i < keys2.length; i++) { - const key = keys2[i]; - - keyExistsMap2[key] = true; - } - - for (let i = 0; i < keys1.length; i++) { - const key = keys1[i]; - - if (!keyExistsMap2[key]) { - return false; - } - - if (!isEquals(obj1[key], obj2[key])) { - return false; - } - } - - return true; - } else { - return obj1 === obj2; - } -} - -function getUtcOffsetMinutesByUtcOffset(utcOffset) { - if (!utcOffset) { - return 0; - } - - const parts = utcOffset.split(':'); - - if (parts.length !== 2) { - return 0; - } - - return parseInt(parts[0]) * 60 + parseInt(parts[1]); -} - -function getUtcOffsetByUtcOffsetMinutes(utcOffsetMinutes) { - let offsetHours = parseInt(Math.abs(utcOffsetMinutes) / 60); - let offsetMinutes = Math.abs(utcOffsetMinutes) - offsetHours * 60; - - if (offsetHours < 10) { - offsetHours = '0' + offsetHours; - } - - if (offsetMinutes < 10) { - offsetMinutes = '0' + offsetMinutes; - } - - if (utcOffsetMinutes >= 0) { - return `+${offsetHours}:${offsetMinutes}`; - } else if (utcOffsetMinutes < 0) { - return `-${offsetHours}:${offsetMinutes}`; - } -} - -function getTimezoneOffset(timezone) { - if (timezone) { - return moment().tz(timezone).format('Z'); - } else { - return moment().format('Z'); - } -} - -function getTimezoneOffsetMinutes(timezone) { - const utcOffset = getTimezoneOffset(timezone); - return getUtcOffsetMinutesByUtcOffset(utcOffset); -} - -function getBrowserTimezoneOffsetMinutes() { - return -new Date().getTimezoneOffset(); -} - -function getLocalDatetimeFromUnixTime(unixTime) { - return new Date(unixTime * 1000); -} - -function getUnixTimeFromLocalDatetime(datetime) { - return datetime.getTime() / 1000; -} - -function getActualUnixTimeForStore(unixTime, utcOffset, currentUtcOffset) { - return unixTime - (utcOffset - currentUtcOffset) * 60; -} - -function getDummyUnixTimeForLocalUsage(unixTime, utcOffset, currentUtcOffset) { - return unixTime + (utcOffset - currentUtcOffset) * 60; -} - -function getCurrentUnixTime() { - return moment().unix(); -} - -function getCurrentDateTime() { - return moment(); -} - -function parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset) { - if (isNumber(utcOffset)) { - if (!isNumber(currentUtcOffset)) { - currentUtcOffset = getTimezoneOffsetMinutes(); - } - - unixTime = getDummyUnixTimeForLocalUsage(unixTime, utcOffset, currentUtcOffset); - } - - return moment.unix(unixTime); -} - -function is24HourFormat(format) { - if (format.indexOf('HH') >= 0 && format.indexOf('hh') < 0) { - return true; - } else if (format.indexOf('HH') < 0 && format.indexOf('hh') >= 0) { - return false; - } - - return true; -} - -function formatUnixTime(unixTime, format, utcOffset, currentUtcOffset) { - return parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format); -} - -function formatTime(dateTime, format) { - return moment(dateTime).format(format); -} - -function getUnixTime(date) { - return moment(date).unix(); -} - -function getYear(date) { - return moment(date).year(); -} - -function getMonth(date) { - return moment(date).month() + 1; -} - -function getYearAndMonth(date) { - const year = getYear(date); - let month = getMonth(date); - - if (month < 10) { - month = '0' + month; - } - - return `${year}-${month}`; -} - -function getDay(date) { - return moment(date).date(); -} - -function getDayOfWeekName(date) { - const dayOfWeek = moment(date).days(); - return dateTimeConstants.allWeekDaysArray[dayOfWeek].name; -} - -function getHour(date) { - return moment(date).hour(); -} - -function getMinute(date) { - return moment(date).minute(); -} - -function getSecond(date) { - return moment(date).second(); -} - -function getUnixTimeBeforeUnixTime(unixTime, amount, unit) { - return moment.unix(unixTime).subtract(amount, unit).unix(); -} - -function getUnixTimeAfterUnixTime(unixTime, amount, unit) { - return moment.unix(unixTime).add(amount, unit).unix(); -} - -function getMinuteFirstUnixTime(date) { - const datetime = moment(date); - return datetime.set({ second: 0, millisecond: 0 }).unix(); -} - -function getMinuteLastUnixTime(date) { - return moment.unix(getMinuteFirstUnixTime(date)).add(1, 'minutes').subtract(1, 'seconds').unix(); -} - -function getTodayFirstUnixTime() { - return moment().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).unix(); -} - -function getTodayLastUnixTime() { - return moment.unix(getTodayFirstUnixTime()).add(1, 'days').subtract(1, 'seconds').unix(); -} - -function getThisWeekFirstUnixTime(firstDayOfWeek) { - const today = moment.unix(getTodayFirstUnixTime()); - - if (!isNumber(firstDayOfWeek)) { - firstDayOfWeek = 0; - } - - let dayOfWeek = today.day() - firstDayOfWeek; - - if (dayOfWeek < 0) { - dayOfWeek += 7; - } - - return today.subtract(dayOfWeek, 'days').unix(); -} - -function getThisWeekLastUnixTime(firstDayOfWeek) { - return moment.unix(getThisWeekFirstUnixTime(firstDayOfWeek)).add(7, 'days').subtract(1, 'seconds').unix(); -} - -function getThisMonthFirstUnixTime() { - const today = moment.unix(getTodayFirstUnixTime()); - return today.subtract(today.date() - 1, 'days').unix(); -} - -function getThisMonthLastUnixTime() { - return moment.unix(getThisMonthFirstUnixTime()).add(1, 'months').subtract(1, 'seconds').unix(); -} - -function getThisYearFirstUnixTime() { - const today = moment.unix(getTodayFirstUnixTime()); - return today.subtract(today.dayOfYear() - 1, 'days').unix(); -} - -function getThisYearLastUnixTime() { - return moment.unix(getThisYearFirstUnixTime()).add(1, 'years').subtract(1, 'seconds').unix(); -} - -function getShiftedDateRange(minTime, maxTime, scale) { - const minDateTime = parseDateFromUnixTime(minTime).set({ second: 0, millisecond: 0 }); - const maxDateTime = parseDateFromUnixTime(maxTime).set({ second: 59, millisecond: 999 }); - - const firstDayOfMonth = minDateTime.clone().startOf('month'); - const lastDayOfMonth = maxDateTime.clone().endOf('month'); - - if (firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix()) { - const months = getYear(maxDateTime) * 12 + getMonth(maxDateTime) - getYear(minDateTime) * 12 - getMonth(minDateTime) + 1; - const newMinDateTime = minDateTime.add(months * scale, 'months'); - const newMaxDateTime = newMinDateTime.clone().add(months, 'months').subtract(1, 'seconds'); - - return { - minTime: newMinDateTime.unix(), - maxTime: newMaxDateTime.unix() - }; - } - - const range = (maxTime - minTime + 1) * scale; - - return { - minTime: minTime + range, - maxTime: maxTime + range - }; -} - -function getDateRangeByDateType(dateType, firstDayOfWeek) { - let maxTime = 0; - let minTime = 0; - - if (dateType === dateTimeConstants.allDateRanges.All.type) { // All - maxTime = 0; - minTime = 0; - } else if (dateType === dateTimeConstants.allDateRanges.Today.type) { // Today - maxTime = getTodayLastUnixTime(); - minTime = getTodayFirstUnixTime(); - } else if (dateType === dateTimeConstants.allDateRanges.Yesterday.type) { // Yesterday - maxTime = getUnixTimeBeforeUnixTime(getTodayLastUnixTime(), 1, 'days'); - minTime = getUnixTimeBeforeUnixTime(getTodayFirstUnixTime(), 1, 'days'); - } else if (dateType === dateTimeConstants.allDateRanges.LastSevenDays.type) { // Last 7 days - maxTime = getTodayLastUnixTime(); - minTime = getUnixTimeBeforeUnixTime(getTodayFirstUnixTime(), 6, 'days'); - } else if (dateType === dateTimeConstants.allDateRanges.LastThirtyDays.type) { // Last 30 days - maxTime = getTodayLastUnixTime(); - minTime = getUnixTimeBeforeUnixTime(getTodayFirstUnixTime(), 29, 'days'); - } else if (dateType === dateTimeConstants.allDateRanges.ThisWeek.type) { // This week - maxTime = getThisWeekLastUnixTime(firstDayOfWeek); - minTime = getThisWeekFirstUnixTime(firstDayOfWeek); - } else if (dateType === dateTimeConstants.allDateRanges.LastWeek.type) { // Last week - maxTime = getUnixTimeBeforeUnixTime(getThisWeekLastUnixTime(firstDayOfWeek), 7, 'days'); - minTime = getUnixTimeBeforeUnixTime(getThisWeekFirstUnixTime(firstDayOfWeek), 7, 'days'); - } else if (dateType === dateTimeConstants.allDateRanges.ThisMonth.type) { // This month - maxTime = getThisMonthLastUnixTime(); - minTime = getThisMonthFirstUnixTime(); - } else if (dateType === dateTimeConstants.allDateRanges.LastMonth.type) { // Last month - maxTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 1, 'seconds'); - minTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 1, 'months'); - } else if (dateType === dateTimeConstants.allDateRanges.ThisYear.type) { // This year - maxTime = getThisYearLastUnixTime(); - minTime = getThisYearFirstUnixTime(); - } else if (dateType === dateTimeConstants.allDateRanges.LastYear.type) { // Last year - maxTime = getUnixTimeBeforeUnixTime(getThisYearLastUnixTime(), 1, 'years'); - minTime = getUnixTimeBeforeUnixTime(getThisYearFirstUnixTime(), 1, 'years'); - } else { - return null; - } - - return { - dateType: dateType, - maxTime: maxTime, - minTime: minTime - }; -} - -function isDateRangeMatchFullYears(minTime, maxTime) { - const minDateTime = parseDateFromUnixTime(minTime).set({ second: 0, millisecond: 0 }); - const maxDateTime = parseDateFromUnixTime(maxTime).set({ second: 59, millisecond: 999 }); - - const firstDayOfYear = minDateTime.clone().startOf('year'); - const lastDayOfYear = maxDateTime.clone().endOf('year'); - - return firstDayOfYear.unix() === minDateTime.unix() && lastDayOfYear.unix() === maxDateTime.unix(); -} - -function isDateRangeMatchFullMonths(minTime, maxTime) { - const minDateTime = parseDateFromUnixTime(minTime).set({ second: 0, millisecond: 0 }); - const maxDateTime = parseDateFromUnixTime(maxTime).set({ second: 59, millisecond: 999 }); - - const firstDayOfMonth = minDateTime.clone().startOf('month'); - const lastDayOfMonth = maxDateTime.clone().endOf('month'); - - return firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix(); -} - -function copyObjectTo(fromObject, toObject) { - if (!isObject(fromObject)) { - return toObject; - } - - if (!isObject(toObject)) { - toObject = {}; - } - - for (let key in fromObject) { - if (!Object.prototype.hasOwnProperty.call(fromObject, key)) { - continue; - } - - const fromValue = fromObject[key]; - const toValue = toObject[key]; - - if (isArray(fromValue)) { - toObject[key] = this.copyArrayTo(fromValue, toValue); - } else if (isObject(fromValue)) { - toObject[key] = this.copyObjectTo(fromValue, toValue); - } else { - if (fromValue !== toValue) { - toObject[key] = fromValue; - } - } - } - - return toObject; -} - -function copyArrayTo(fromArray, toArray) { - if (!isArray(fromArray)) { - return toArray; - } - - if (!isArray(toArray)) { - toArray = []; - } - - for (let i = 0; i < fromArray.length; i++) { - const fromValue = fromArray[i]; - - if (toArray.length > i) { - const toValue = toArray[i]; - - if (isArray(fromValue)) { - toArray[i] = this.copyArrayTo(fromValue, toValue); - } else if (isObject(fromValue)) { - toArray[i] = this.copyObjectTo(fromValue, toValue); - } else { - if (fromValue !== toValue) { - toArray[i] = fromValue; - } - } - } else { - if (isArray(fromValue)) { - toArray.push(this.copyArrayTo(fromValue, [])); - } else if (isObject(fromValue)) { - toArray.push(this.copyObjectTo(fromValue, {})); - } else { - toArray.push(fromValue); - } - } - } - - return toArray; -} - -function arrangeArrayWithNewStartIndex(array, startIndex) { - if (startIndex <= 0 || startIndex >= array.length) { - return array; - } - - const newArray = []; - - for (let i = startIndex; i < array.length; i++) { - newArray.push(array[i]); - } - - for (let i = 0; i < startIndex; i++) { - newArray.push(array[i]); - } - - return newArray; -} - -function appendThousandsSeparator(value) { - if (!settings.isEnableThousandsSeparator() || value.length <= 3) { - return value; - } - - const negative = value.charAt(0) === '-'; - - if (negative) { - value = value.substring(1); - } - - const dotPos = value.indexOf('.'); - const integer = dotPos < 0 ? value : value.substring(0, dotPos); - const decimals = dotPos < 0 ? '' : value.substring(dotPos + 1, value.length); - - const finalChars = []; - - for (let i = 0; i < integer.length; i++) { - if (i % 3 === 0 && i > 0) { - finalChars.push(','); - } - - finalChars.push(integer.charAt(integer.length - 1 - i)); - } - - finalChars.reverse(); - - let newInteger = finalChars.join(''); - - if (negative) { - newInteger = `-${newInteger}`; - } - - if (dotPos < 0) { - return newInteger; - } else { - return `${newInteger}.${decimals}`; - } -} - -function numericCurrencyToString(num) { - let str = num.toString(); - const negative = str.charAt(0) === '-'; - - if (negative) { - str = str.substring(1); - } - - if (str.length === 0) { - str = '0.00'; - } else if (str.length === 1) { - str = '0.0' + str; - } else if (str.length === 2) { - str = '0.' + str; - } else { - let integer = str.substring(0, str.length - 2); - let decimals = str.substring(str.length - 2); - - integer = appendThousandsSeparator(integer); - - str = `${integer}.${decimals}`; - } - - if (negative) { - str = `-${str}`; - } - - return str; -} - -function stringCurrencyToNumeric(str) { - if (!str || str.length < 1) { - return 0; - } - - const negative = str.charAt(0) === '-'; - - if (negative) { - str = str.substring(1); - } - - if (!str || str.length < 1) { - return 0; - } - - const sign = negative ? -1 : 1; - - if (str.indexOf(',')) { - str = str.replaceAll(/,/g, ''); - } - - let dotPos = str.indexOf('.'); - - if (dotPos < 0) { - return sign * parseInt(str) * 100; - } else if (dotPos === 0) { - str = '0' + str; - dotPos++; - } - - const integer = str.substring(0, dotPos); - const decimals = str.substring(dotPos + 1, str.length); - - if (decimals.length < 1) { - return sign * parseInt(integer) * 100; - } else if (decimals.length === 1) { - return sign * parseInt(integer) * 100 + sign * parseInt(decimals) * 10; - } else if (decimals.length === 2) { - return sign * parseInt(integer) * 100 + sign * parseInt(decimals); - } else { - return sign * parseInt(integer) * 100 + sign * parseInt(decimals.substring(0, 2)); - } -} - -function getExchangedAmount(amount, fromRate, toRate) { - const exchangeRate = parseFloat(toRate) / parseFloat(fromRate); - - if (!isNumber(exchangeRate)) { - return null; - } - - return amount * exchangeRate; -} - -function formatPercent(value, precision, lowPrecisionValue) { - const ratio = Math.pow(10, precision); - const normalizedValue = Math.floor(value * ratio); - - if (value > 0 && normalizedValue < 1 && lowPrecisionValue) { - return lowPrecisionValue + '%'; - } - - const result = normalizedValue / ratio; - return result + '%'; -} - -function limitText(value, maxLength) { - let length = 0; - - for (let i = 0; i < value.length; i++) { - const c = value.charCodeAt(i); - - if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)) { - length++; - } else { - length += 2; - } - } - - if (length <= maxLength || maxLength <= 3) { - return value; - } - - return value.substring(0, maxLength - 3) + '...'; -} - -function base64encode(arrayBuffer) { - if (!arrayBuffer || arrayBuffer.length === 0) { - return null; - } - - return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer))); -} - -function arrayBufferToString(arrayBuffer) { - return String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); -} - -function stringToArrayBuffer(str){ - return Uint8Array.from(str, c => c.charCodeAt(0)).buffer; -} - -function getNameByKeyValue(src, value, keyField, nameField, defaultName) { - if (isArray(src)) { - if (keyField) { - for (let i = 0; i < src.length; i++) { - const option = src[i]; - - if (option[keyField] === value) { - return option[nameField]; - } - } - } else { - if (src[value]) { - const option = src[value]; - - return option[nameField]; - } - } - } else if (isObject(src)) { - if (keyField) { - for (let key in src) { - if (!Object.prototype.hasOwnProperty.call(src, key)) { - continue; - } - - const option = src[key]; - - if (option[keyField] === value) { - return option[nameField]; - } - } - } else { - if (src[value]) { - const option = src[value]; - - return option[nameField]; - } - } - } - - return defaultName; -} - -function generateRandomString() { - const baseString = 'ebk_' + Math.round(new Date().getTime() / 1000) + '_' + Math.random(); - return CryptoJS.SHA256(baseString).toString(); -} - -function parseUserAgent(ua) { - const uaParseRet = uaParser(ua); - - return { - device: { - vendor: uaParseRet.device.vendor, - model: uaParseRet.device.model, - type: uaParseRet.device.type - }, - os: { - name: uaParseRet.os.name, - version: uaParseRet.os.version - }, - browser: { - name: uaParseRet.browser.name, - version: uaParseRet.browser.version - } - }; -} - -function parseDeviceInfo(ua) { - const uaInfo = parseUserAgent(ua); - let result = ''; - - if (uaInfo.device.model) { - result = uaInfo.device.model; - } else if (uaInfo.os.name) { - result = uaInfo.os.name; - - if (uaInfo.os.version) { - result += ' ' + uaInfo.os.version; - } - } - - if (uaInfo.browser.name) { - let browserInfo = uaInfo.browser.name; - - if (uaInfo.browser.version) { - browserInfo += ' ' + uaInfo.browser.version; - } - - if (result) { - result += ' (' + browserInfo + ')'; - } else { - result = browserInfo; - } - } - - if (!result) { - return 'Unknown Device'; - } - - return result; -} - -function transactionTypeToCategoryType(transactionType) { - if (transactionType === transactionConstants.allTransactionTypes.Income) { - return categoryConstants.allCategoryTypes.Income; - } else if (transactionType === transactionConstants.allTransactionTypes.Expense) { - return categoryConstants.allCategoryTypes.Expense; - } else if (transactionType === transactionConstants.allTransactionTypes.Transfer) { - return categoryConstants.allCategoryTypes.Transfer; - } else { - return null; - } -} - -function categoryTypeToTransactionType(categoryType) { - if (categoryType === categoryConstants.allCategoryTypes.Income) { - return transactionConstants.allTransactionTypes.Income; - } else if (categoryType === categoryConstants.allCategoryTypes.Expense) { - return transactionConstants.allTransactionTypes.Expense; - } else if (categoryType === categoryConstants.allCategoryTypes.Transfer) { - return transactionConstants.allTransactionTypes.Transfer; - } else { - return null; - } -} - -function allVisibleTransactionCategories(allTransactionCategories) { - const ret = {}; - - for (let key in transactionConstants.allTransactionTypes) { - if (!Object.prototype.hasOwnProperty.call(transactionConstants.allTransactionTypes, key)) { - continue; - } - - const transactionType = transactionConstants.allTransactionTypes[key]; - - if (!allTransactionCategories[transactionType]) { - continue; - } - - const allCategories = allTransactionCategories[transactionType]; - const visibleCategories = []; - const allVisibleSubCategories = {}; - - for (let j = 0; j < allCategories.length; j++) { - const category = allCategories[j]; - - if (category.hidden) { - continue; - } - - visibleCategories.push(category); - - if (category.subCategories) { - const visibleSubCategories = []; - - for (let k = 0; k < category.subCategories.length; k++) { - const subCategory = category.subCategories[k]; - - if (!subCategory.hidden) { - visibleSubCategories.push(subCategory); - } - } - - if (visibleSubCategories.length > 0) { - allVisibleSubCategories[category.id] = visibleSubCategories; - } - } - } - - ret[transactionType.toString()] = { - type: transactionType.toString(), - visibleCategories: visibleCategories, - visibleSubCategories: allVisibleSubCategories - }; - } - - return ret; -} - -function getCategoryInfo(categoryId) { - for (let i = 0; i < accountConstants.allCategories.length; i++) { - if (accountConstants.allCategories[i].id === categoryId) { - return accountConstants.allCategories[i]; - } - } - - return null; -} - -function getCategorizedAccounts(allAccounts) { - const ret = {}; - - for (let i = 0; i < allAccounts.length; i++) { - const account = allAccounts[i]; - - if (!ret[account.category]) { - const categoryInfo = getCategoryInfo(account.category); - - if (categoryInfo) { - ret[account.category] = { - category: account.category, - name: categoryInfo.name, - icon: categoryInfo.defaultAccountIconId, - accounts: [] - }; - } - } - - if (ret[account.category]) { - const accountList = ret[account.category].accounts; - accountList.push(account); - } - } - - return ret; -} - -function getVisibleCategorizedAccounts(categorizedAccounts) { - const ret = {}; - - for (let i = 0; i < accountConstants.allCategories.length; i++) { - const accountCategory = accountConstants.allCategories[i]; - - if (!categorizedAccounts[accountCategory.id] || !categorizedAccounts[accountCategory.id].accounts) { - continue; - } - - const allAccounts = categorizedAccounts[accountCategory.id].accounts; - const visibleAccounts = []; - const allVisibleSubAccounts = {}; - - for (let j = 0; j < allAccounts.length; j++) { - const account = allAccounts[j]; - - if (account.hidden) { - continue; - } - - visibleAccounts.push(account); - - if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && account.subAccounts) { - const visibleSubAccounts = []; - - for (let k = 0; k < account.subAccounts.length; k++) { - const subAccount = account.subAccounts[k]; - - if (!subAccount.hidden) { - visibleSubAccounts.push(subAccount); - } - } - - if (visibleSubAccounts.length > 0) { - allVisibleSubAccounts[account.id] = visibleSubAccounts; - } - } - } - - if (visibleAccounts.length > 0) { - ret[accountCategory.id] = { - category: accountCategory.id, - name: accountCategory.name, - icon: accountCategory.defaultAccountIconId, - visibleAccounts: visibleAccounts, - visibleSubAccounts: allVisibleSubAccounts - }; - } - } - - return ret; -} - -function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter) { - const allAccountCategories = accountConstants.allCategories; - const ret = []; - - for (let categoryIdx = 0; categoryIdx < allAccountCategories.length; categoryIdx++) { - const accountCategory = allAccountCategories[categoryIdx]; - - if (!categorizedAccounts[accountCategory.id] || !categorizedAccounts[accountCategory.id].accounts) { - continue; - } - - for (let accountIdx = 0; accountIdx < categorizedAccounts[accountCategory.id].accounts.length; accountIdx++) { - const account = categorizedAccounts[accountCategory.id].accounts[accountIdx]; - - if (account.hidden || !accountFilter(account)) { - continue; - } - - if (account.type === accountConstants.allAccountTypes.SingleAccount) { - ret.push({ - balance: account.balance, - isAsset: account.isAsset, - isLiability: account.isLiability, - currency: account.currency - }); - } else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts) { - for (let subAccountIdx = 0; subAccountIdx < account.subAccounts.length; subAccountIdx++) { - const subAccount = account.subAccounts[subAccountIdx]; - - if (subAccount.hidden || !accountFilter(subAccount)) { - continue; - } - - ret.push({ - balance: subAccount.balance, - isAsset: subAccount.isAsset, - isLiability: subAccount.isLiability, - currency: subAccount.currency - }); - } - } - } - } - - return ret; -} - -function makeButtonCopyToClipboard({ text, el, successCallback, errorCallback }) { - const clipboard = new Clipboard(el, { - text: function () { - return text; - } - }); - - clipboard.on('success', (e) => { - if (successCallback) { - successCallback(e); - } - }); - - clipboard.on('error', (e) => { - if (errorCallback) { - errorCallback(e); - } - }); - - return clipboard; -} - -function changeClipboardObjectText(clipboard, text) { - if (!clipboard) { - return; - } - - clipboard.text = function () { - return text; - }; -} - -export default { - isFunction, - isObject, - isArray, - isString, - isNumber, - isBoolean, - isEquals, - getUtcOffsetMinutesByUtcOffset, - getUtcOffsetByUtcOffsetMinutes, - getTimezoneOffset, - getTimezoneOffsetMinutes, - getBrowserTimezoneOffsetMinutes, - getLocalDatetimeFromUnixTime, - getUnixTimeFromLocalDatetime, - getActualUnixTimeForStore, - getDummyUnixTimeForLocalUsage, - getCurrentUnixTime, - getCurrentDateTime, - parseDateFromUnixTime, - is24HourFormat, - formatUnixTime, - formatTime, - getUnixTime, - getYear, - getMonth, - getYearAndMonth, - getDay, - getDayOfWeekName, - getHour, - getMinute, - getSecond, - getUnixTimeBeforeUnixTime, - getUnixTimeAfterUnixTime, - getMinuteFirstUnixTime, - getMinuteLastUnixTime, - getTodayFirstUnixTime, - getTodayLastUnixTime, - getThisWeekFirstUnixTime, - getThisWeekLastUnixTime, - getThisMonthFirstUnixTime, - getThisMonthLastUnixTime, - getThisYearFirstUnixTime, - getThisYearLastUnixTime, - getShiftedDateRange, - getDateRangeByDateType, - isDateRangeMatchFullYears, - isDateRangeMatchFullMonths, - copyObjectTo, - copyArrayTo, - arrangeArrayWithNewStartIndex, - appendThousandsSeparator, - numericCurrencyToString, - stringCurrencyToNumeric, - getExchangedAmount, - formatPercent, - limitText, - base64encode, - arrayBufferToString, - stringToArrayBuffer, - getNameByKeyValue, - generateRandomString, - parseUserAgent, - parseDeviceInfo, - transactionTypeToCategoryType, - categoryTypeToTransactionType, - allVisibleTransactionCategories, - getCategoryInfo, - getCategorizedAccounts, - getVisibleCategorizedAccounts, - getAllFilteredAccountsBalance, - makeButtonCopyToClipboard, - changeClipboardObjectText, -}; diff --git a/src/lib/webauthn.js b/src/lib/webauthn.js index 39942d4a..a83f1cb3 100644 --- a/src/lib/webauthn.js +++ b/src/lib/webauthn.js @@ -1,6 +1,6 @@ import CBOR from 'cbor-js'; import logger from './logger.js'; -import utils from './utils.js'; +import utilities from './utilities/index.js'; const publicKeyCredentialCreationOptionsBaseTemplate = { attestation: "none", @@ -28,7 +28,7 @@ const publicKeyCredentialRequestOptionsBaseTemplate = { function isSupported() { return !!window.PublicKeyCredential && !!navigator.credentials - && utils.isFunction(window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable); + && utilities.isFunction(window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable); } function isCompletelySupported() { @@ -52,17 +52,17 @@ function registerCredential({ username, secret }, { nickname }) { }); } - const challenge = utils.generateRandomString(); + const challenge = utilities.generateRandomString(); const userId = `${username}|${secret}`; // username 32bytes(max) + secret 24bytes = 56bytes(max) const publicKeyCredentialCreationOptions = Object.assign({}, publicKeyCredentialCreationOptionsBaseTemplate, { - challenge: utils.stringToArrayBuffer(challenge), + challenge: utilities.stringToArrayBuffer(challenge), rp: { name: window.location.hostname, id: window.location.hostname }, user: { - id: utils.stringToArrayBuffer(userId), + id: utilities.stringToArrayBuffer(userId), name: username, displayName: nickname } @@ -83,7 +83,7 @@ function registerCredential({ username, secret }, { nickname }) { if (rawCredential && rawCredential.rawId && clientData && clientData.type === 'webauthn.create' && challengeFromClientData === challenge) { const ret = { - id: utils.base64encode(rawCredential.rawId), + id: utilities.base64encode(rawCredential.rawId), clientData: clientData, publicKey: publicKey, rawCredential: rawCredential @@ -133,12 +133,12 @@ function verifyCredential({ username }, credentialId) { }); } - const challenge = utils.generateRandomString(); + const challenge = utilities.generateRandomString(); const publicKeyCredentialRequestOptions = Object.assign({}, publicKeyCredentialRequestOptionsBaseTemplate, { - challenge: utils.stringToArrayBuffer(challenge), + challenge: utilities.stringToArrayBuffer(challenge), rpId: window.location.hostname }); - publicKeyCredentialRequestOptions.allowCredentials[0].id = utils.stringToArrayBuffer(atob(credentialId)); + publicKeyCredentialRequestOptions.allowCredentials[0].id = utilities.stringToArrayBuffer(atob(credentialId)); logger.debug('webauthn get options', publicKeyCredentialRequestOptions); @@ -147,7 +147,7 @@ function verifyCredential({ username }, credentialId) { }).then(rawCredential => { const clientData = rawCredential ? parseClientData(rawCredential) : null; const challengeFromClientData = clientData && clientData.challenge ? atob(clientData.challenge) : null; - const userIdParts = rawCredential && rawCredential.response && rawCredential.response.userHandle ? utils.arrayBufferToString(rawCredential.response.userHandle).split('|') : null; + const userIdParts = rawCredential && rawCredential.response && rawCredential.response.userHandle ? utilities.arrayBufferToString(rawCredential.response.userHandle).split('|') : null; logger.debug('webauthn get raw response', rawCredential); @@ -155,7 +155,7 @@ function verifyCredential({ username }, credentialId) { clientData && clientData.type === 'webauthn.get' && challengeFromClientData === challenge && userIdParts && userIdParts.length === 2 && userIdParts[0] === username) { const ret = { - id: utils.base64encode(rawCredential.rawId), + id: utilities.base64encode(rawCredential.rawId), userName: userIdParts[0], userSecret: userIdParts[1], clientData: clientData, diff --git a/src/mobile-main.js b/src/mobile-main.js index ff75c29c..99f75486 100644 --- a/src/mobile-main.js +++ b/src/mobile-main.js @@ -93,7 +93,7 @@ import settings from './lib/settings.js'; import services from './lib/services.js'; import userstate from './lib/userstate.js'; import webauthn from './lib/webauthn.js'; -import utils from './lib/utils.js'; +import utilities from './lib/utilities/index.js'; import { getAllLanguageInfos, getLanguageInfo, @@ -237,7 +237,7 @@ function initLocale() { logger.info(`Current timezone is ${settings.getTimezone()}`); setTimezone(settings.getTimezone()); } else { - logger.info(`No timezone is set, use browser default ${utils.getTimezoneOffset()} (maybe ${moment.tz.guess(true)})`); + logger.info(`No timezone is set, use browser default ${utilities.getTimezoneOffset()} (maybe ${moment.tz.guess(true)})`); } } @@ -283,7 +283,7 @@ app.config.globalProperties.$constants = { statistics: statistics, }; -app.config.globalProperties.$utilities = utils; +app.config.globalProperties.$utilities = utilities; app.config.globalProperties.$logger = logger; app.config.globalProperties.$webauthn = webauthn; app.config.globalProperties.$settings = settings; diff --git a/src/store/exchangeRates.js b/src/store/exchangeRates.js index b538c758..d7db105b 100644 --- a/src/store/exchangeRates.js +++ b/src/store/exchangeRates.js @@ -1,6 +1,6 @@ import services from '../lib/services.js'; import logger from '../lib/logger.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; import { STORE_LATEST_EXCHANGE_RATES @@ -10,16 +10,16 @@ const exchangeRatesLocalStorageKey = 'ebk_app_exchange_rates'; export function getLatestExchangeRates(context, { silent, force }) { const currentExchangeRateData = context.state.latestExchangeRates; - const now = utils.getCurrentUnixTime(); + const now = utilities.getCurrentUnixTime(); if (!force) { if (currentExchangeRateData && currentExchangeRateData.time && currentExchangeRateData.data && - utils.formatUnixTime(currentExchangeRateData.data.updateTime, 'YYYY-MM-DD') === utils.formatUnixTime(now, 'YYYY-MM-DD')) { + utilities.formatUnixTime(currentExchangeRateData.data.updateTime, 'YYYY-MM-DD') === utilities.formatUnixTime(now, 'YYYY-MM-DD')) { return currentExchangeRateData.data; } if (currentExchangeRateData && currentExchangeRateData.time && currentExchangeRateData.data && - utils.formatUnixTime(currentExchangeRateData.time, 'YYYY-MM-DD HH') === utils.formatUnixTime(now, 'YYYY-MM-DD HH')) { + utilities.formatUnixTime(currentExchangeRateData.time, 'YYYY-MM-DD HH') === utilities.formatUnixTime(now, 'YYYY-MM-DD HH')) { return currentExchangeRateData.data; } } @@ -37,7 +37,7 @@ export function getLatestExchangeRates(context, { silent, force }) { const currentData = getExchangeRatesFromLocalStorage(); - if (currentData && currentData.data && utils.isEquals(currentData.data, data.result)) { + if (currentData && currentData.data && utilities.isEquals(currentData.data, data.result)) { reject({ message: 'Exchange rates data is up to date' }); return; } @@ -88,7 +88,7 @@ export function getExchangedAmount(state) { return null; } - return utils.getExchangedAmount(amount, fromCurrencyExchangeRate.rate, toCurrencyExchangeRate.rate) + return utilities.getExchangedAmount(amount, fromCurrencyExchangeRate.rate, toCurrencyExchangeRate.rate) }; } diff --git a/src/store/index.js b/src/store/index.js index a500c447..986fab66 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -3,7 +3,7 @@ import currencyConstants from '../consts/currency.js'; import statisticsConstants from '../consts/statistics.js'; import userState from '../lib/userstate.js'; import settings from '../lib/settings.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; import { RESET_STATE, @@ -307,7 +307,7 @@ const stores = { } } - state.allCategorizedAccounts = utils.getCategorizedAccounts(accounts); + state.allCategorizedAccounts = utilities.getCategorizedAccounts(accounts); }, [ADD_ACCOUNT_TO_ACCOUNT_LIST] (state, account) { let insertIndexToAllList = 0; @@ -334,7 +334,7 @@ const stores = { const accountList = state.allCategorizedAccounts[account.category].accounts; accountList.push(account); } else { - state.allCategorizedAccounts = utils.getCategorizedAccounts(state.allAccounts); + state.allCategorizedAccounts = utilities.getCategorizedAccounts(state.allAccounts); } }, [SAVE_ACCOUNT_IN_ACCOUNT_LIST] (state, account) { @@ -442,7 +442,7 @@ const stores = { } if (transactions.items && transactions.items.length) { - const currentUtcOffset = utils.getTimezoneOffsetMinutes(); + const currentUtcOffset = utilities.getTimezoneOffsetMinutes(); let currentMonthListIndex = -1; let currentMonthList = null; @@ -450,10 +450,10 @@ const stores = { const item = transactions.items[i]; fillTransactionObject(state, item, currentUtcOffset); - const transactionTime = utils.parseDateFromUnixTime(item.time, item.utcOffset, currentUtcOffset); - const transactionYear = utils.getYear(transactionTime); - const transactionMonth = utils.getMonth(transactionTime); - const transactionYearMonth = utils.getYearAndMonth(transactionTime); + const transactionTime = utilities.parseDateFromUnixTime(item.time, item.utcOffset, currentUtcOffset); + const transactionYear = utilities.getYear(transactionTime); + const transactionMonth = utilities.getMonth(transactionTime); + const transactionYearMonth = utilities.getYearAndMonth(transactionTime); if (currentMonthList && currentMonthList.year === transactionYear && currentMonthList.month === transactionMonth) { currentMonthList.items.push(Object.freeze(item)); @@ -496,74 +496,74 @@ const stores = { } }, [INIT_TRANSACTION_LIST_FILTER] (state, filter) { - if (filter && utils.isNumber(filter.dateType)) { + if (filter && utilities.isNumber(filter.dateType)) { state.transactionsFilter.dateType = filter.dateType; } else { state.transactionsFilter.dateType = datetimeConstants.allDateRanges.All.type; } - if (filter && utils.isNumber(filter.maxTime)) { + if (filter && utilities.isNumber(filter.maxTime)) { state.transactionsFilter.maxTime = filter.maxTime; } else { state.transactionsFilter.maxTime = 0; } - if (filter && utils.isNumber(filter.minTime)) { + if (filter && utilities.isNumber(filter.minTime)) { state.transactionsFilter.minTime = filter.minTime; } else { state.transactionsFilter.minTime = 0; } - if (filter && utils.isNumber(filter.type)) { + if (filter && utilities.isNumber(filter.type)) { state.transactionsFilter.type = filter.type; } else { state.transactionsFilter.type = 0; } - if (filter && utils.isString(filter.categoryId)) { + if (filter && utilities.isString(filter.categoryId)) { state.transactionsFilter.categoryId = filter.categoryId; } else { state.transactionsFilter.categoryId = '0'; } - if (filter && utils.isString(filter.accountId)) { + if (filter && utilities.isString(filter.accountId)) { state.transactionsFilter.accountId = filter.accountId; } else { state.transactionsFilter.accountId = '0'; } - if (filter && utils.isString(filter.keyword)) { + if (filter && utilities.isString(filter.keyword)) { state.transactionsFilter.keyword = filter.keyword; } else { state.transactionsFilter.keyword = ''; } }, [UPDATE_TRANSACTION_LIST_FILTER] (state, filter) { - if (filter && utils.isNumber(filter.dateType)) { + if (filter && utilities.isNumber(filter.dateType)) { state.transactionsFilter.dateType = filter.dateType; } - if (filter && utils.isNumber(filter.maxTime)) { + if (filter && utilities.isNumber(filter.maxTime)) { state.transactionsFilter.maxTime = filter.maxTime; } - if (filter && utils.isNumber(filter.minTime)) { + if (filter && utilities.isNumber(filter.minTime)) { state.transactionsFilter.minTime = filter.minTime; } - if (filter && utils.isNumber(filter.type)) { + if (filter && utilities.isNumber(filter.type)) { state.transactionsFilter.type = filter.type; } - if (filter && utils.isString(filter.categoryId)) { + if (filter && utilities.isString(filter.categoryId)) { state.transactionsFilter.categoryId = filter.categoryId; } - if (filter && utils.isString(filter.accountId)) { + if (filter && utilities.isString(filter.accountId)) { state.transactionsFilter.accountId = filter.accountId; } - if (filter && utils.isString(filter.keyword)) { + if (filter && utilities.isString(filter.keyword)) { state.transactionsFilter.keyword = filter.keyword; } }, @@ -573,10 +573,10 @@ const stores = { } }, [SAVE_TRANSACTION_IN_TRANSACTION_LIST] (state, { transaction, defaultCurrency }) { - const currentUtcOffset = utils.getTimezoneOffsetMinutes(); - const transactionTime = utils.parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); - const transactionYear = utils.getYear(transactionTime); - const transactionMonth = utils.getMonth(transactionTime); + const currentUtcOffset = utilities.getTimezoneOffsetMinutes(); + const transactionTime = utilities.parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); + const transactionYear = utilities.getYear(transactionTime); + const transactionMonth = utilities.getMonth(transactionTime); for (let i = 0; i < state.transactions.length; i++) { const transactionMonthList = state.transactions[i]; @@ -837,7 +837,7 @@ const stores = { if (item.account && item.account.currency !== defaultCurrency) { const amount = getExchangedAmount(state)(item.amount, item.account.currency, defaultCurrency); - if (utils.isNumber(amount)) { + if (utilities.isNumber(amount)) { item.amountInDefaultCurrency = Math.floor(amount); } } else if (item.account && item.account.currency === defaultCurrency) { @@ -851,84 +851,84 @@ const stores = { state.transactionStatistics = statistics; }, [INIT_TRANSACTION_STATISTICS_FILTER] (state, filter) { - if (filter && utils.isNumber(filter.dateType)) { + if (filter && utilities.isNumber(filter.dateType)) { state.transactionStatisticsFilter.dateType = filter.dateType; } else { state.transactionStatisticsFilter.dateType = statisticsConstants.defaultDataRangeType; } - if (filter && utils.isNumber(filter.startTime)) { + if (filter && utilities.isNumber(filter.startTime)) { state.transactionStatisticsFilter.startTime = filter.startTime; } else { state.transactionStatisticsFilter.startTime = 0; } - if (filter && utils.isNumber(filter.endTime)) { + if (filter && utilities.isNumber(filter.endTime)) { state.transactionStatisticsFilter.endTime = filter.endTime; } else { state.transactionStatisticsFilter.endTime = 0; } - if (filter && utils.isNumber(filter.chartType)) { + if (filter && utilities.isNumber(filter.chartType)) { state.transactionStatisticsFilter.chartType = filter.chartType; } else { state.transactionStatisticsFilter.chartType = statisticsConstants.defaultChartType; } - if (filter && utils.isNumber(filter.chartDataType)) { + if (filter && utilities.isNumber(filter.chartDataType)) { state.transactionStatisticsFilter.chartDataType = filter.chartDataType; } else { state.transactionStatisticsFilter.chartDataType = statisticsConstants.defaultChartDataType; } - if (filter && utils.isObject(filter.filterAccountIds)) { + if (filter && utilities.isObject(filter.filterAccountIds)) { state.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds; } else { state.transactionStatisticsFilter.filterAccountIds = {}; } - if (filter && utils.isObject(filter.filterCategoryIds)) { + if (filter && utilities.isObject(filter.filterCategoryIds)) { state.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds; } else { state.transactionStatisticsFilter.filterCategoryIds = {}; } - if (filter && utils.isNumber(filter.sortingType)) { + if (filter && utilities.isNumber(filter.sortingType)) { state.transactionStatisticsFilter.sortingType = filter.sortingType; } else { state.transactionStatisticsFilter.sortingType = statisticsConstants.defaultSortingType; } }, [UPDATE_TRANSACTION_STATISTICS_FILTER] (state, filter) { - if (filter && utils.isNumber(filter.dateType)) { + if (filter && utilities.isNumber(filter.dateType)) { state.transactionStatisticsFilter.dateType = filter.dateType; } - if (filter && utils.isNumber(filter.startTime)) { + if (filter && utilities.isNumber(filter.startTime)) { state.transactionStatisticsFilter.startTime = filter.startTime; } - if (filter && utils.isNumber(filter.endTime)) { + if (filter && utilities.isNumber(filter.endTime)) { state.transactionStatisticsFilter.endTime = filter.endTime; } - if (filter && utils.isNumber(filter.chartType)) { + if (filter && utilities.isNumber(filter.chartType)) { state.transactionStatisticsFilter.chartType = filter.chartType; } - if (filter && utils.isNumber(filter.chartDataType)) { + if (filter && utilities.isNumber(filter.chartDataType)) { state.transactionStatisticsFilter.chartDataType = filter.chartDataType; } - if (filter && utils.isObject(filter.filterAccountIds)) { + if (filter && utilities.isObject(filter.filterAccountIds)) { state.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds; } - if (filter && utils.isObject(filter.filterCategoryIds)) { + if (filter && utilities.isObject(filter.filterCategoryIds)) { state.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds; } - if (filter && utils.isNumber(filter.sortingType)) { + if (filter && utilities.isNumber(filter.sortingType)) { state.transactionStatisticsFilter.sortingType = filter.sortingType; } }, diff --git a/src/store/overview.js b/src/store/overview.js index 290acd14..0a466baf 100644 --- a/src/store/overview.js +++ b/src/store/overview.js @@ -1,6 +1,6 @@ import services from '../lib/services.js'; import logger from '../lib/logger.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; import { getExchangedAmount } from './exchangeRates.js'; @@ -55,13 +55,13 @@ export function loadTransactionOverview(context, { defaultCurrency, dateRange, f const incomeAmount = getExchangedAmount(context.state)(amount.incomeAmount, amount.currency, defaultCurrency); const expenseAmount = getExchangedAmount(context.state)(amount.expenseAmount, amount.currency, defaultCurrency); - if (utils.isNumber(incomeAmount)) { + if (utilities.isNumber(incomeAmount)) { totalIncomeAmount += Math.floor(incomeAmount); } else { hasUnCalculatedTotalIncome = true; } - if (utils.isNumber(expenseAmount)) { + if (utilities.isNumber(expenseAmount)) { totalExpenseAmount += Math.floor(expenseAmount); } else { hasUnCalculatedTotalExpense = true; diff --git a/src/store/statistics.js b/src/store/statistics.js index 883416e4..4808000a 100644 --- a/src/store/statistics.js +++ b/src/store/statistics.js @@ -4,7 +4,7 @@ import iconConstants from '../consts/icon.js'; import colorConstants from '../consts/color.js'; import services from '../lib/services.js'; import logger from '../lib/logger.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; import { getExchangedAmount } from './exchangeRates.js'; @@ -102,7 +102,7 @@ export function statisticsItemsByTransactionStatisticsData(state) { if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type || state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type) { - if (utils.isNumber(item.amountInDefaultCurrency)) { + if (utilities.isNumber(item.amountInDefaultCurrency)) { let data = allDataItems[item.account.id]; if (data) { @@ -130,7 +130,7 @@ export function statisticsItemsByTransactionStatisticsData(state) { } } else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type || state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type) { - if (utils.isNumber(item.amountInDefaultCurrency)) { + if (utilities.isNumber(item.amountInDefaultCurrency)) { let data = allDataItems[item.primaryCategory.id]; if (data) { @@ -158,7 +158,7 @@ export function statisticsItemsByTransactionStatisticsData(state) { } } else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type || state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) { - if (utils.isNumber(item.amountInDefaultCurrency)) { + if (utilities.isNumber(item.amountInDefaultCurrency)) { let data = allDataItems[item.category.id]; if (data) { @@ -231,7 +231,7 @@ export function statisticsItemsByAccountsData(state, getters) { if (account.currency !== getters.currentUserDefaultCurrency) { amount = Math.floor(getExchangedAmount(state)(amount, account.currency, getters.currentUserDefaultCurrency)); - if (!utils.isNumber(amount)) { + if (!utilities.isNumber(amount)) { continue; } } diff --git a/src/store/token.js b/src/store/token.js index 6ad335a8..78997290 100644 --- a/src/store/token.js +++ b/src/store/token.js @@ -1,7 +1,7 @@ import userState from '../lib/userstate.js'; import services from '../lib/services.js'; import logger from '../lib/logger.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; import { STORE_USER_INFO @@ -40,7 +40,7 @@ export function refreshTokenAndRevokeOldToken(context) { if (data && data.success && data.result && data.result.newToken) { userState.updateToken(data.result.newToken); - if (data.result.user && utils.isObject(data.result.user)) { + if (data.result.user && utilities.isObject(data.result.user)) { context.commit(STORE_USER_INFO, data.result.user); } diff --git a/src/store/transaction.js b/src/store/transaction.js index bf128189..da824c8f 100644 --- a/src/store/transaction.js +++ b/src/store/transaction.js @@ -1,7 +1,7 @@ import transactionConstants from '../consts/transaction.js'; import services from '../lib/services.js'; import logger from '../lib/logger.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; import { getExchangedAmount } from './exchangeRates.js'; @@ -284,10 +284,10 @@ export function fillTransactionObject(state, transaction, currentUtcOffset) { return; } - const transactionTime = utils.parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); + const transactionTime = utilities.parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); - transaction.day = utils.getDay(transactionTime); - transaction.dayOfWeek = utils.getDayOfWeekName(transactionTime); + transaction.day = utilities.getDay(transactionTime); + transaction.dayOfWeek = utilities.getDayOfWeekName(transactionTime); if (transaction.sourceAccountId) { transaction.sourceAccount = state.allAccountsMap[transaction.sourceAccountId]; @@ -332,7 +332,7 @@ export function calculateMonthTotalAmount(state, transactionMonthList, defaultCu if (account.currency !== defaultCurrency) { const balance = getExchangedAmount(state)(amount, account.currency, defaultCurrency); - if (!utils.isNumber(balance)) { + if (!utilities.isNumber(balance)) { if (transaction.type === transactionConstants.allTransactionTypes.Expense) { hasUnCalculatedTotalExpense = true; } else if (transaction.type === transactionConstants.allTransactionTypes.Income) { diff --git a/src/store/twoFactorAuth.js b/src/store/twoFactorAuth.js index 86f7a2c3..e6cf502a 100644 --- a/src/store/twoFactorAuth.js +++ b/src/store/twoFactorAuth.js @@ -1,14 +1,14 @@ import userState from '../lib/userstate.js'; import services from '../lib/services.js'; import logger from '../lib/logger.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; export function get2FAStatus() { return new Promise((resolve, reject) => { services.get2FAStatus().then(response => { const data = response.data; - if (!data || !data.success || !data.result || !utils.isBoolean(data.result.enable)) { + if (!data || !data.success || !data.result || !utilities.isBoolean(data.result.enable)) { reject({ message: 'Unable to get current two factor authentication status' }); return; } diff --git a/src/store/user.js b/src/store/user.js index c3951cff..2cbc827f 100644 --- a/src/store/user.js +++ b/src/store/user.js @@ -2,7 +2,7 @@ import userState from '../lib/userstate.js'; import services from '../lib/services.js'; import settings from '../lib/settings.js'; import logger from '../lib/logger.js'; -import utils from '../lib/utils.js'; +import utilities from '../lib/utilities/index.js'; import { RESET_STATE, @@ -48,7 +48,7 @@ export function authorize(context, { loginName, password }) { userState.updateToken(data.result.token); - if (data.result.user && utils.isObject(data.result.user)) { + if (data.result.user && utilities.isObject(data.result.user)) { context.commit(STORE_USER_INFO, data.result.user); } @@ -107,7 +107,7 @@ export function authorize2FA(context, { token, passcode, recoveryCode }) { userState.updateToken(data.result.token); - if (data.result.user && utils.isObject(data.result.user)) { + if (data.result.user && utilities.isObject(data.result.user)) { context.commit(STORE_USER_INFO, data.result.user); } @@ -149,11 +149,11 @@ export function register(context, { user }) { userState.clearWebAuthnConfig(); } - if (data.result.token && utils.isString(data.result.token)) { + if (data.result.token && utilities.isString(data.result.token)) { userState.updateToken(data.result.token); } - if (data.result.user && utils.isObject(data.result.user)) { + if (data.result.user && utilities.isObject(data.result.user)) { context.commit(STORE_USER_INFO, data.result.user); } @@ -247,11 +247,11 @@ export function updateUserProfile(context, { profile, currentPassword }) { return; } - if (data.result.newToken && utils.isString(data.result.newToken)) { + if (data.result.newToken && utilities.isString(data.result.newToken)) { userState.updateToken(data.result.newToken); } - if (data.result.user && utils.isObject(data.result.user)) { + if (data.result.user && utilities.isObject(data.result.user)) { context.commit(STORE_USER_INFO, data.result.user); } @@ -403,5 +403,5 @@ export function currentUserDefaultAccountId(state) { export function currentUserFirstDayOfWeek(state) { const userInfo = state.currentUserInfo || {}; - return utils.isNumber(userInfo.firstDayOfWeek) ? userInfo.firstDayOfWeek : state.defaultSetting.firstDayOfWeek; + return utilities.isNumber(userInfo.firstDayOfWeek) ? userInfo.firstDayOfWeek : state.defaultSetting.firstDayOfWeek; }