migrate to typescript

This commit is contained in:
MaysWind
2024-12-29 14:24:37 +08:00
parent b638a73e4d
commit 2560a70e5e
171 changed files with 3402 additions and 2557 deletions
+30 -27
View File
@@ -1,36 +1,39 @@
import globals from 'globals';
import pluginVue from 'eslint-plugin-vue';
import vueTsEslintConfig from '@vue/eslint-config-typescript';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import js from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
import { includeIgnoreFile } from '@eslint/compat';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const gitignorePath = path.resolve(__dirname, '.gitignore');
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});
export default [...compat.extends('eslint:recommended', 'plugin:vue/vue3-essential'),
includeIgnoreFile(gitignorePath), {
export default [
...pluginVue.configs['flat/essential'],
...vueTsEslintConfig(),
{
languageOptions: {
globals: {
...globals.node,
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
}
},
},
{
ignores: [
'dist/**',
'**/*.{js,jsx,cjs,mjs}'
]
},
{
files: [
"**/*.{vue,js,jsx,cjs,mjs}"
'**/*.{vue,ts,tsx,mts,js,jsx,cjs,mjs}'
],
rules: {
'vue/no-use-v-if-with-v-for': 'off',
'vue/valid-v-slot': ['error', {
allowModifiers: true,
'@typescript-eslint/no-this-alias': ['error', {
allowedNames: ['self']
}],
'vue/valid-v-slot': ['error', {
allowModifiers: true
}],
'vue/block-lang': ['error', {
script: {
lang: ['ts', 'js']
}
}],
}
},
}];
];
+875 -235
View File
File diff suppressed because it is too large Load Diff
+11 -6
View File
@@ -15,7 +15,7 @@
"serve": "cross-env NODE_ENV=development vite",
"build": "cross-env NODE_ENV=production vite build",
"serve:dist": "vite preview",
"lint": "eslint . --fix"
"lint": "tsc --noEmit && eslint . --fix"
},
"dependencies": {
"@mdi/js": "^7.4.47",
@@ -47,20 +47,25 @@
"vuetify": "^3.7.6"
},
"devDependencies": {
"@eslint/compat": "^1.2.4",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.17.0",
"@tsconfig/node22": "^22.0.0",
"@types/crypto-js": "^4.2.2",
"@types/git-rev-sync": "^2.0.2",
"@types/node": "^22.10.2",
"@types/ua-parser-js": "^0.7.39",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/eslint-config-typescript": "^14.1.3",
"@vue/tsconfig": "^0.7.0",
"cross-env": "^7.0.3",
"eslint": "^9.17.0",
"eslint-plugin-vue": "^9.32.0",
"git-rev-sync": "^3.0.2",
"globals": "^15.14.0",
"postcss-preset-env": "^10.1.2",
"sass": "^1.83.0",
"typescript": "^5.7.2",
"vite": "^6.0.5",
"vite-plugin-pwa": "^0.21.1",
"vite-plugin-vuetify": "^2.0.4"
"vite-plugin-vuetify": "^2.0.4",
"vue-tsc": "^2.1.10"
},
"browserslist": [
"> 1%",
+11 -10
View File
@@ -26,10 +26,11 @@ import { useUserStore } from '@/stores/user.js';
import { useTokensStore } from '@/stores/token.js';
import { useExchangeRatesStore } from '@/stores/exchangeRates.js';
import assetConstants from '@/consts/asset.js';
import { isProduction } from '@/lib/version.js';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { ThemeType } from '@/core/theme.ts';
import { isProduction } from '@/lib/version.ts';
import { loadMapAssets } from '@/lib/map/index.js';
import { getSystemTheme, setExpenseAndIncomeAmountColor } from '@/lib/ui.js';
import { getSystemTheme, setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
export default {
data() {
@@ -40,7 +41,7 @@ export default {
computed: {
...mapStores(useRootStore, useSettingsStore, useUserStore, useTokensStore, useExchangeRatesStore),
ezBookkeepingLogoPath() {
return assetConstants.ezBookkeepingLogoPath;
return APPLICATION_LOGO_PATH;
},
currentNotificationContent() {
return this.rootStore.currentNotification;
@@ -55,10 +56,10 @@ export default {
const self = this;
const theme = useTheme();
if (self.settingsStore.appSettings.theme === 'light') {
theme.global.name.value = 'light';
} else if (self.settingsStore.appSettings.theme === 'dark') {
theme.global.name.value = 'dark';
if (self.settingsStore.appSettings.theme === ThemeType.Light) {
theme.global.name.value = ThemeType.Light;
} else if (self.settingsStore.appSettings.theme === ThemeType.Dark) {
theme.global.name.value = ThemeType.Dark;
} else {
theme.global.name.value = getSystemTheme();
}
@@ -66,9 +67,9 @@ export default {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) {
if (self.settingsStore.appSettings.theme === 'auto') {
if (e.matches) {
theme.global.name.value = 'dark';
theme.global.name.value = ThemeType.Dark;
} else {
theme.global.name.value = 'light';
theme.global.name.value = ThemeType.Light;
}
}
});
+8 -7
View File
@@ -15,21 +15,22 @@ import { useUserStore } from '@/stores/user.js';
import { useTokensStore } from '@/stores/token.js';
import { useExchangeRatesStore } from '@/stores/exchangeRates.js';
import assetConstants from '@/consts/asset.js';
import { isProduction } from '@/lib/version.js';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { ThemeType } from '@/core/theme.ts';
import { isProduction } from '@/lib/version.ts';
import { getTheme, isEnableAnimate } from '@/lib/settings.js';
import { loadMapAssets } from '@/lib/map/index.js';
import { setExpenseAndIncomeAmountColor } from '@/lib/ui.js';
import { isModalShowing, setAppFontSize } from '@/lib/ui.mobile.js';
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
import { isModalShowing, setAppFontSize } from '@/lib/ui/mobile.js';
export default {
data() {
const self = this;
let darkMode = 'auto';
if (getTheme() === 'light') {
if (getTheme() === ThemeType.Light) {
darkMode = false;
} else if (getTheme() === 'dark') {
} else if (getTheme() === ThemeType.Dark) {
darkMode = true;
}
@@ -112,7 +113,7 @@ export default {
if (newValue) {
f7ready((f7) => {
self.notification = f7.notification.create({
icon: `<img alt="logo" src="${assetConstants.ezBookkeepingLogoPath}" />`,
icon: `<img alt="logo" src="${APPLICATION_LOGO_PATH}" />`,
title: self.$t('global.app.title'),
text: newValue,
closeOnClick: true,
+1 -1
View File
@@ -11,7 +11,7 @@
<script>
import {
copyObjectTo
} from '@/lib/common.js';
} from '@/lib/common.ts';
import {
createMapHolder,
initMapInstance,
+10 -10
View File
@@ -34,8 +34,8 @@ import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
import transactionConstants from '@/consts/transaction.js';
import { removeAll } from '@/lib/common.js';
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts';
import { removeAll } from '@/lib/common.ts';
import logger from '@/lib/logger.js';
export default {
@@ -76,7 +76,7 @@ export default {
return self.$t('Amount value is not number');
}
return (val >= transactionConstants.minAmountNumber && val <= transactionConstants.maxAmountNumber) || self.$t('Amount value exceeds limitation');
return (val >= TRANSACTION_MIN_AMOUNT && val <= TRANSACTION_MAX_AMOUNT) || self.$t('Amount value exceeds limitation');
} catch (ex) {
logger.warn('cannot parse amount in amount input, original value is ' + v, ex);
return self.$t('Amount value is not number');
@@ -222,7 +222,7 @@ export default {
}
let decimalLength = 0;
let decimalIndex = str.indexOf(decimalSeparator);
const decimalIndex = str.indexOf(decimalSeparator);
if (decimalIndex >= 0) {
decimalLength = str.length - str.indexOf(decimalSeparator) - 1;
@@ -285,16 +285,16 @@ export default {
e.preventDefault();
},
getValidFormattedValue(value, textualValue, hasDecimalSeparator) {
let maxLength = transactionConstants.maxAmountNumber.toString().length;
let maxLength = TRANSACTION_MAX_AMOUNT.toString().length;
if (value < 0) {
maxLength = transactionConstants.minAmountNumber.toString().length;
maxLength = TRANSACTION_MIN_AMOUNT.toString().length;
}
if (value < transactionConstants.minAmountNumber) {
return this.getFormattedValue(this.userStore, transactionConstants.minAmountNumber);
} else if (value > transactionConstants.maxAmountNumber) {
return this.getFormattedValue(this.userStore, transactionConstants.maxAmountNumber);
if (value < TRANSACTION_MIN_AMOUNT) {
return this.getFormattedValue(this.userStore, TRANSACTION_MIN_AMOUNT);
} else if (value > TRANSACTION_MAX_AMOUNT) {
return this.getFormattedValue(this.userStore, TRANSACTION_MAX_AMOUNT);
}
if (!hasDecimalSeparator && textualValue.length > maxLength) {
+5 -5
View File
@@ -39,10 +39,10 @@
</template>
<script>
import colorConstants from '@/consts/color.js';
import { arrayContainsFieldValue } from '@/lib/common.js';
import { getColorsInRows } from '@/lib/color.js';
import { scrollToSelectedItem } from '@/lib/ui.desktop.js';
import { DEFAULT_ICON_COLOR } from '@/consts/color.ts';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getColorsInRows } from '@/lib/color.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.js';
import {
mdiSquareRounded,
@@ -89,7 +89,7 @@ export default {
return arrayContainsFieldValue(row, 'id', this.modelValue);
},
getFinalColor(color) {
if (color && color !== colorConstants.defaultAccountColor) {
if (color && color !== DEFAULT_ICON_COLOR) {
return '#' + color;
} else {
return 'var(--default-icon-color)';
+1 -1
View File
@@ -15,7 +15,7 @@
</template>
<script>
import { isString } from '@/lib/common.js';
import { isString } from '@/lib/common.ts';
export default {
props: [
@@ -60,7 +60,8 @@ import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import datetimeConstants from '@/consts/datetime.js';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.js';
import { ThemeType } from '@/core/theme.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import {
getCurrentUnixTime,
getCurrentYear,
@@ -122,7 +123,7 @@ export default {
}
},
isDarkMode() {
return this.globalTheme.global.name.value === 'dark';
return this.globalTheme.global.name.value === ThemeType.Dark;
},
firstDayOfWeek() {
return this.userStore.currentUserFirstDayOfWeek;
+3 -2
View File
@@ -43,7 +43,8 @@ import { useTheme } from 'vuetify';
import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.js';
import { ThemeType } from '@/core/theme.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import {
getCurrentYear,
getTimezoneOffsetMinutes,
@@ -90,7 +91,7 @@ export default {
}
},
isDarkMode() {
return this.globalTheme.global.name.value === 'dark';
return this.globalTheme.global.name.value === ThemeType.Dark;
},
firstDayOfWeek() {
return this.userStore.currentUserFirstDayOfWeek;
+3 -3
View File
@@ -37,9 +37,9 @@
</template>
<script>
import { arrayContainsFieldValue } from '@/lib/common.js';
import { getIconsInRows } from '@/lib/icon.js';
import { scrollToSelectedItem } from '@/lib/ui.desktop.js';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getIconsInRows } from '@/lib/icon.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.js';
import {
mdiCheck
+12 -12
View File
@@ -12,9 +12,9 @@
</template>
<script>
import iconConstants from '@/consts/icon.js';
import colorConstants from '@/consts/color.js';
import { isNumber } from '@/lib/common.js';
import { ALL_ACCOUNT_ICONS, DEFAULT_ACCOUNT_ICON, ALL_CATEGORY_ICONS, DEFAULT_CATEGORY_ICON } from '@/consts/icon.ts';
import { DEFAULT_ICON_COLOR, DEFAULT_ACCOUNT_COLOR, DEFAULT_CATEGORY_COLOR } from '@/consts/color.ts';
import { isNumber } from '@/lib/common.ts';
import {
mdiEyeOffOutline
@@ -74,25 +74,25 @@ export default {
iconId = iconId.toString();
}
if (!iconConstants.allAccountIcons[iconId]) {
return iconConstants.defaultAccountIcon.icon;
if (!ALL_ACCOUNT_ICONS[iconId]) {
return DEFAULT_ACCOUNT_ICON.icon;
}
return iconConstants.allAccountIcons[iconId].icon;
return ALL_ACCOUNT_ICONS[iconId].icon;
},
getCategoryIcon(iconId) {
if (isNumber(iconId)) {
iconId = iconId.toString();
}
if (!iconConstants.allCategoryIcons[iconId]) {
return iconConstants.defaultCategoryIcon.icon;
if (!ALL_CATEGORY_ICONS[iconId]) {
return DEFAULT_CATEGORY_ICON.icon;
}
return iconConstants.allCategoryIcons[iconId].icon;
return ALL_CATEGORY_ICONS[iconId].icon;
},
getAccountIconStyle(color, defaultColor, additionalColorAttr) {
if (color && color !== colorConstants.defaultAccountColor) {
if (color && color !== DEFAULT_ACCOUNT_COLOR) {
color = '#' + color;
} else {
color = defaultColor;
@@ -113,7 +113,7 @@ export default {
return ret;
},
getCategoryIconStyle(color, defaultColor, additionalColorAttr) {
if (color && color !== colorConstants.defaultCategoryColor) {
if (color && color !== DEFAULT_CATEGORY_COLOR) {
color = '#' + color;
} else {
color = defaultColor;
@@ -134,7 +134,7 @@ export default {
return ret;
},
getDefaultIconStyle(color, defaultColor, additionalColorAttr) {
if (color && color !== colorConstants.defaultColor) {
if (color && color !== DEFAULT_ICON_COLOR) {
color = '#' + color;
} else {
color = defaultColor;
@@ -69,6 +69,7 @@ import { useTheme } from 'vuetify';
import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import { ThemeType } from '@/core/theme.ts';
import {
getYearMonthObjectFromString,
getYearMonthStringFromObject,
@@ -125,7 +126,7 @@ export default {
}
},
isDarkMode() {
return this.globalTheme.global.name.value === 'dark';
return this.globalTheme.global.name.value === ThemeType.Dark;
},
isYearFirst() {
return this.$locale.isLongDateMonthAfterYear(this.userStore);
+5 -4
View File
@@ -10,7 +10,8 @@ import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
import colorConstants from '@/consts/color.js';
import { DEFAULT_ICON_COLOR, DEFAULT_CHART_COLORS } from '@/consts/color.ts';
import { ThemeType } from '@/core/theme.ts';
import { formatPercent } from '@/lib/numeral.js';
export default {
@@ -40,7 +41,7 @@ export default {
computed: {
...mapStores(useSettingsStore, useUserStore),
isDarkMode() {
return this.globalTheme.global.name.value === 'dark';
return this.globalTheme.global.name.value === ThemeType.Dark;
},
itemsMap: function () {
const map = {};
@@ -87,7 +88,7 @@ export default {
percent: (item[this.percentField] > 0 || item[this.percentField] === 0 || item[this.percentField] === '0') ? item[this.percentField] : (item[this.valueField] / totalValidValue * 100),
actualPercent: item[this.valueField] / totalValidValue,
itemStyle: {
color: this.getColor(item[this.colorField] ? item[this.colorField] : colorConstants.defaultChartColors[validItems.length % colorConstants.defaultChartColors.length]),
color: this.getColor(item[this.colorField] ? item[this.colorField] : DEFAULT_CHART_COLORS[validItems.length % DEFAULT_CHART_COLORS.length]),
},
selected: true,
sourceItem: item
@@ -283,7 +284,7 @@ export default {
}
},
getColor: function (color) {
if (color && color !== colorConstants.defaultColor) {
if (color && color !== DEFAULT_ICON_COLOR) {
color = '#' + color;
}
@@ -58,9 +58,9 @@
import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import templateConstants from '@/consts/template.js';
import { sortNumbersArray } from '@/lib/common.js';
import { scrollToSelectedItem } from '@/lib/ui.desktop.js';
import { ScheduledTemplateFrequencyType } from '@/core/template.ts';
import { sortNumbersArray } from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.js';
export default {
props: [
@@ -85,7 +85,7 @@ export default {
return this.$locale.getAllTransactionScheduledFrequencyTypes();
},
allTemplateScheduledFrequencyTypes() {
return templateConstants.allTemplateScheduledFrequencyTypes;
return ScheduledTemplateFrequencyType.all();
},
allWeekDays() {
return this.$locale.getAllWeekDays(this.firstDayOfWeek);
@@ -113,9 +113,9 @@ export default {
if (this.type !== value) {
this.$emit('update:type', value);
if (value === templateConstants.allTemplateScheduledFrequencyTypes.Weekly.type) {
if (value === ScheduledTemplateFrequencyType.Weekly.type) {
this.frequencyValue = [this.firstDayOfWeek];
} else if (value === templateConstants.allTemplateScheduledFrequencyTypes.Monthly.type) {
} else if (value === ScheduledTemplateFrequencyType.Monthly.type) {
this.frequencyValue = [1];
} else {
this.frequencyValue = [];
@@ -141,9 +141,9 @@ export default {
}
},
displayFrequency() {
if (this.type === templateConstants.allTemplateScheduledFrequencyTypes.Disabled.type) {
if (this.type === ScheduledTemplateFrequencyType.Disabled.type) {
return this.$t('Disabled');
} else if (this.type === templateConstants.allTemplateScheduledFrequencyTypes.Weekly.type) {
} else if (this.type === ScheduledTemplateFrequencyType.Weekly.type) {
if (this.frequencyValue.length) {
return this.$t('format.misc.everyMultiDaysOfWeek', {
days: this.$locale.getMultiWeekdayLongNames(this.frequencyValue, this.firstDayOfWeek)
@@ -151,7 +151,7 @@ export default {
} else {
return this.$t('Weekly');
}
} else if (this.type === templateConstants.allTemplateScheduledFrequencyTypes.Monthly.type) {
} else if (this.type === ScheduledTemplateFrequencyType.Monthly.type) {
if (this.frequencyValue.length) {
return this.$t('format.misc.everyMultiDaysOfMonth', {
days: this.$locale.getMultiMonthdayShortNames(this.frequencyValue)
@@ -30,7 +30,7 @@
<script>
import { getMobileUrlQrCodePath } from '@/lib/qrcode.js';
import { getMobileVersionPath } from '@/lib/version.js';
import { getMobileVersionPath } from '@/lib/version.ts';
export default {
props: [
+7 -6
View File
@@ -10,13 +10,14 @@ import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
import colorConstants from '@/consts/color.js';
import { DEFAULT_ICON_COLOR, DEFAULT_CHART_COLORS } from '@/consts/color.ts';
import datetimeConstants from '@/consts/datetime.js';
import statisticsConstants from '@/consts/statistics.js';
import { ThemeType } from '@/core/theme.ts';
import {
isArray,
isNumber
} from '@/lib/common.js';
} from '@/lib/common.ts';
import {
getYearMonthFirstUnixTime,
getYearMonthLastUnixTime,
@@ -59,7 +60,7 @@ export default {
computed: {
...mapStores(useSettingsStore, useUserStore),
isDarkMode() {
return this.globalTheme.global.name.value === 'dark';
return this.globalTheme.global.name.value === ThemeType.Dark;
},
itemsMap: function () {
const map = {};
@@ -167,7 +168,7 @@ export default {
id: (this.idField && item[this.idField]) ? item[this.idField] : this.getItemName(item[this.nameField]),
name: (this.idField && item[this.idField]) ? item[this.idField] : this.getItemName(item[this.nameField]),
itemStyle: {
color: this.getColor(item[this.colorField] ? item[this.colorField] : colorConstants.defaultChartColors[i % colorConstants.defaultChartColors.length]),
color: this.getColor(item[this.colorField] ? item[this.colorField] : DEFAULT_CHART_COLORS[i % DEFAULT_CHART_COLORS.length]),
},
selected: true,
type: 'line',
@@ -212,7 +213,7 @@ export default {
const maxValueText = this.getDisplayCurrency(maxValue, this.defaultCurrency);
const minValueText = this.getDisplayCurrency(minValue, this.defaultCurrency);
let maxLengthText = maxValueText.length > minValueText.length ? maxValueText : minValueText;
const maxLengthText = maxValueText.length > minValueText.length ? maxValueText : minValueText;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
@@ -387,7 +388,7 @@ export default {
});
},
getColor: function (color) {
if (color && color !== colorConstants.defaultColor) {
if (color && color !== DEFAULT_ICON_COLOR) {
color = '#' + color;
}
+2 -2
View File
@@ -79,8 +79,8 @@ import {
getItemByKeyValue,
getNameByKeyValue,
getPrimaryValueBySecondaryValue
} from '@/lib/common.js';
import { scrollToSelectedItem } from '@/lib/ui.desktop.js';
} from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.js';
import {
mdiChevronRight
@@ -29,9 +29,9 @@
</template>
<script>
import { arrayContainsFieldValue } from '@/lib/common.js';
import { getColorsInRows } from '@/lib/color.js';
import { scrollToSelectedItem } from '@/lib/ui.mobile.js';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getColorsInRows } from '@/lib/color.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.js';
export default {
props: [
@@ -57,7 +57,7 @@ import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import datetimeConstants from '@/consts/datetime.js';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.js';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import {
getCurrentUnixTime,
getCurrentYear,
@@ -53,7 +53,7 @@ import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import datetimeConstants from '@/consts/datetime.js';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.js';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import {
getCurrentUnixTime,
getCurrentYear,
@@ -65,7 +65,7 @@ import {
getTimeValues,
getCombinedDateAndTimeValues
} from '@/lib/datetime.js';
import { createInlinePicker } from '@/lib/ui.mobile.js';
import { createInlinePicker } from '@/lib/ui/mobile.js';
export default {
props: [
+3 -3
View File
@@ -29,9 +29,9 @@
</template>
<script>
import { arrayContainsFieldValue } from '@/lib/common.js';
import { getIconsInRows } from '@/lib/icon.js';
import { scrollToSelectedItem } from '@/lib/ui.mobile.js';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getIconsInRows } from '@/lib/icon.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.js';
export default {
props: [
+3 -3
View File
@@ -25,7 +25,7 @@
</template>
<script>
import { makeButtonCopyToClipboard, changeClipboardObjectText } from '@/lib/misc.js';
import { ClipboardHolder } from '@/lib/clipboard.ts';
export default {
props: [
@@ -54,7 +54,7 @@ export default {
watch: {
'information': function (newValue) {
if (this.clipboardHolder) {
changeClipboardObjectText(this.clipboardHolder, newValue);
this.clipboardHolder.setClipboardText(newValue);
}
}
},
@@ -73,7 +73,7 @@ export default {
}
if (self.$refs.copyToClipboardIcon) {
self.clipboardHolder = makeButtonCopyToClipboard({
self.clipboardHolder = ClipboardHolder.create({
el: '#copy-to-clipboard-icon',
text: self.information,
successCallback: function () {
+12 -12
View File
@@ -5,9 +5,9 @@
</template>
<script>
import iconConstants from '@/consts/icon.js';
import colorConstants from '@/consts/color.js';
import { isNumber } from '@/lib/common.js';
import { ALL_ACCOUNT_ICONS, DEFAULT_ACCOUNT_ICON, ALL_CATEGORY_ICONS, DEFAULT_CATEGORY_ICON } from '@/consts/icon.ts';
import { DEFAULT_ICON_COLOR, DEFAULT_ACCOUNT_COLOR, DEFAULT_CATEGORY_COLOR } from '@/consts/color.ts';
import { isNumber } from '@/lib/common.ts';
export default {
props: [
@@ -58,25 +58,25 @@ export default {
iconId = iconId.toString();
}
if (!iconConstants.allAccountIcons[iconId]) {
return iconConstants.defaultAccountIcon.icon;
if (!ALL_ACCOUNT_ICONS[iconId]) {
return DEFAULT_ACCOUNT_ICON.icon;
}
return iconConstants.allAccountIcons[iconId].icon;
return ALL_ACCOUNT_ICONS[iconId].icon;
},
getCategoryIcon(iconId) {
if (isNumber(iconId)) {
iconId = iconId.toString();
}
if (!iconConstants.allCategoryIcons[iconId]) {
return iconConstants.defaultCategoryIcon.icon;
if (!ALL_CATEGORY_ICONS[iconId]) {
return DEFAULT_CATEGORY_ICON.icon;
}
return iconConstants.allCategoryIcons[iconId].icon;
return ALL_CATEGORY_ICONS[iconId].icon;
},
getAccountIconStyle(color, defaultColor, additionalColorAttr) {
if (color && color !== colorConstants.defaultAccountColor) {
if (color && color !== DEFAULT_ACCOUNT_COLOR) {
color = '#' + color;
} else {
color = defaultColor;
@@ -93,7 +93,7 @@ export default {
return ret;
},
getCategoryIconStyle(color, defaultColor, additionalColorAttr) {
if (color && color !== colorConstants.defaultCategoryColor) {
if (color && color !== DEFAULT_CATEGORY_COLOR) {
color = '#' + color;
} else {
color = defaultColor;
@@ -110,7 +110,7 @@ export default {
return ret;
},
getDefaultIconStyle(color, defaultColor, additionalColorAttr) {
if (color && color !== colorConstants.defaultColor) {
if (color && color !== DEFAULT_ICON_COLOR) {
color = '#' + color;
} else {
color = defaultColor;
@@ -32,7 +32,7 @@
</template>
<script>
import { scrollToSelectedItem } from '@/lib/ui.mobile.js';
import { scrollToSelectedItem } from '@/lib/ui/mobile.js';
export default {
props: [
+6 -6
View File
@@ -69,8 +69,8 @@
import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import currencyConstants from '@/consts/currency.js';
import { isString, isNumber, removeAll } from '@/lib/common.js';
import { ALL_CURRENCIES } from '@/consts/currency.ts';
import { isString, isNumber, removeAll } from '@/lib/common.ts';
export default {
props: [
@@ -100,11 +100,11 @@ export default {
return this.$locale.getCurrentDecimalSeparator(this.userStore);
},
supportDecimalSeparator() {
if (!this.currency || !currencyConstants.all[this.currency] || !isNumber(currencyConstants.all[this.currency].fraction)) {
if (!this.currency || !ALL_CURRENCIES[this.currency] || !isNumber(ALL_CURRENCIES[this.currency].fraction)) {
return true;
}
return currencyConstants.all[this.currency].fraction > 0;
return ALL_CURRENCIES[this.currency].fraction > 0;
},
currentDisplay() {
const previousValue = this.$locale.appendDigitGroupingSymbol(this.userStore, this.previousValue);
@@ -160,8 +160,8 @@ export default {
return str;
}
let integer = str.substring(0, decimalSeparatorPos);
let decimals = str.substring(decimalSeparatorPos + 1, str.length);
const integer = str.substring(0, decimalSeparatorPos);
const decimals = str.substring(decimalSeparatorPos + 1, str.length);
let newDecimals = '';
for (let i = decimals.length - 1; i >= 0; i--) {
+3 -3
View File
@@ -81,7 +81,7 @@ import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
import colorConstants from '@/consts/color.js';
import { DEFAULT_ICON_COLOR, DEFAULT_CHART_COLORS } from '@/consts/color.ts';
import { formatPercent } from '@/lib/numeral.js';
export default {
@@ -139,7 +139,7 @@ export default {
value: item[this.valueField],
percent: (item[this.percentField] > 0 || item[this.percentField] === 0 || item[this.percentField] === '0') ? item[this.percentField] : (item[this.valueField] / totalValidValue * 100),
actualPercent: item[this.valueField] / totalValidValue,
color: item[this.colorField] ? item[this.colorField] : colorConstants.defaultChartColors[validItems.length % colorConstants.defaultChartColors.length],
color: item[this.colorField] ? item[this.colorField] : DEFAULT_CHART_COLORS[validItems.length % DEFAULT_CHART_COLORS.length],
sourceItem: item
};
@@ -223,7 +223,7 @@ export default {
}
},
getColor: function (color) {
if (color && color !== colorConstants.defaultColor) {
if (color && color !== DEFAULT_ICON_COLOR) {
color = '#' + color;
} else {
color = 'var(--default-icon-color)';
@@ -68,9 +68,9 @@
import { mapStores } from 'pinia';
import { useUserStore } from '@/stores/user.js';
import templateConstants from '@/consts/template.js';
import { sortNumbersArray } from '@/lib/common.js';
import { scrollToSelectedItem } from '@/lib/ui.mobile.js';
import { ScheduledTemplateFrequencyType } from '@/core/template.ts';
import { sortNumbersArray } from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.js';
export default {
props: [
@@ -100,7 +100,7 @@ export default {
return this.$locale.getAllTransactionScheduledFrequencyTypes();
},
allTemplateScheduledFrequencyTypes() {
return templateConstants.allTemplateScheduledFrequencyTypes;
return ScheduledTemplateFrequencyType.all();
},
allWeekDays() {
return this.$locale.getAllWeekDays(this.firstDayOfWeek);
@@ -134,9 +134,9 @@ export default {
if (this.currentFrequencyType !== value) {
this.currentFrequencyType = value;
if (value === templateConstants.allTemplateScheduledFrequencyTypes.Weekly.type) {
if (value === ScheduledTemplateFrequencyType.Weekly.type) {
this.currentFrequencyValue = [this.firstDayOfWeek];
} else if (value === templateConstants.allTemplateScheduledFrequencyTypes.Monthly.type) {
} else if (value === ScheduledTemplateFrequencyType.Monthly.type) {
this.currentFrequencyValue = [1];
} else {
this.currentFrequencyValue = [];
@@ -79,8 +79,8 @@
import { mapStores } from 'pinia';
import { useTransactionTagsStore } from '@/stores/transactionTag.js';
import { copyArrayTo } from '@/lib/common.js';
import { scrollToSelectedItem } from '@/lib/ui.mobile.js';
import { copyArrayTo } from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.js';
export default {
props: [
@@ -41,8 +41,8 @@
</template>
<script>
import { isArray } from '@/lib/common.js';
import { scrollToSelectedItem } from '@/lib/ui.mobile.js';
import { isArray } from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.js';
export default {
props: [
@@ -85,7 +85,7 @@ export default {
if (isArray(this.items)) {
count = this.items.length;
} else {
for (let field in this.items) {
for (const field in this.items) {
if (!Object.prototype.hasOwnProperty.call(this.items, field)) {
continue;
}
+4 -4
View File
@@ -93,10 +93,10 @@ import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
import colorConstants from '@/consts/color.js';
import { DEFAULT_ICON_COLOR, DEFAULT_CHART_COLORS } from '@/consts/color.ts';
import datetimeConstants from '@/consts/datetime.js';
import statisticsConstants from '@/consts/statistics.js';
import { isNumber } from '@/lib/common.js';
import { isNumber } from '@/lib/common.ts';
import {
getYearMonthFirstUnixTime,
getYearMonthLastUnixTime,
@@ -154,7 +154,7 @@ export default {
const legend = {
id: id,
name: (this.nameField && item[this.nameField]) ? this.getItemName(item[this.nameField]) : id,
color: this.getColor(item[this.colorField] ? item[this.colorField] : colorConstants.defaultChartColors[i % colorConstants.defaultChartColors.length]),
color: this.getColor(item[this.colorField] ? item[this.colorField] : DEFAULT_CHART_COLORS[i % DEFAULT_CHART_COLORS.length]),
displayOrders: (this.displayOrdersField && item[this.displayOrdersField]) ? item[this.displayOrdersField] : [0]
};
@@ -322,7 +322,7 @@ export default {
}
},
getColor: function (color) {
if (color && color !== colorConstants.defaultColor) {
if (color && color !== DEFAULT_ICON_COLOR) {
color = '#' + color;
}
@@ -65,8 +65,8 @@
import {
getItemByKeyValue,
getPrimaryValueBySecondaryValue
} from '@/lib/common.js';
import { scrollToSelectedItem } from '@/lib/ui.mobile.js';
} from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.js';
export default {
props: [
-80
View File
@@ -1,80 +0,0 @@
const allAccountCategories = {
Cash: {
id: 1,
name: 'Cash',
defaultAccountIconId: '1'
},
CheckingAccount: {
id: 2,
name: 'Checking Account',
defaultAccountIconId: '100'
},
SavingsAccount: {
id: 8,
name: 'Savings Account',
defaultAccountIconId: '100'
},
CreditCard: {
id: 3,
name: 'Credit Card',
defaultAccountIconId: '100'
},
VirtualAccount: {
id: 4,
name: 'Virtual Account',
defaultAccountIconId: '500'
},
DebtAccount: {
id: 5,
name: 'Debt Account',
defaultAccountIconId: '600'
},
Receivables: {
id: 6,
name: 'Receivables',
defaultAccountIconId: '700'
},
CertificatePfDeposit: {
id: 9,
name: 'Certificate of Deposit',
defaultAccountIconId: '110'
},
InvestmentAccount: {
id: 7,
name: 'Investment Account',
defaultAccountIconId: '800'
}
};
const allAccountCategoriesArray = [
allAccountCategories.Cash,
allAccountCategories.CheckingAccount,
allAccountCategories.SavingsAccount,
allAccountCategories.CreditCard,
allAccountCategories.VirtualAccount,
allAccountCategories.DebtAccount,
allAccountCategories.Receivables,
allAccountCategories.CertificatePfDeposit,
allAccountCategories.InvestmentAccount
];
const allAccountTypes = {
SingleAccount: 1,
MultiSubAccounts: 2
};
const allAccountTypesArray = [
{
id: allAccountTypes.SingleAccount,
name: 'Single Account'
}, {
id: allAccountTypes.MultiSubAccounts,
name: 'Multiple Sub-accounts'
}
];
export default {
cashCategoryType: allAccountCategories.Cash.id,
creditCardCategoryType: allAccountCategories.CreditCard.id,
allCategories: allAccountCategoriesArray,
allAccountTypes: allAccountTypes,
allAccountTypesArray: allAccountTypesArray,
};
+36 -39
View File
@@ -1,27 +1,45 @@
const defaultTimeout = 10000; // 10s
const uploadTimeout = 30000; // 30s
const importTimeout = 1800000; // 1800s
const baseApiUrlPath = '/api';
const baseQrcodePath = '/qrcode';
const baseProxyUrlPath = '/proxy';
const baseAmapApiProxyUrlPath = '/_AMapService';
const apiNotFoundErrorCode = 100001;
const validatorErrorCode = 200000;
const userEmailNotVerifiedErrorCode = 201020;
const transactionCannotCreateInThisTimeErrorCode = 205017;
const transactionCannotModifyInThisTimeErrorCode = 205018;
const transactionPictureNotFoundErrorCode = 211001;
const googleMapJavascriptUrl = 'https://maps.googleapis.com/maps/api/js';
const baiduMapJavascriptUrl = 'https://api.map.baidu.com/api?v=3.0';
const amapJavascriptUrl = 'https://webapi.amap.com/maps?v=2.0';
export const BASE_API_URL_PATH: string = '/api';
export const BASE_QRCODE_PATH: string = '/qrcode';
export const BASE_PROXY_URL_PATH: string = '/proxy';
export const BASE_AMAP_API_PROXY_URL_PATH: string = '/_AMapService';
const specifiedApiNotFoundErrors = {
export const DEFAULT_API_TIMEOUT: number = 10000; // 10s
export const DEFAULT_UPLOAD_API_TIMEOUT: number = 30000; // 30s
export const DEFAULT_IMPORT_API_TIMEOUT: number = 1800000; // 1800s
export const GOOGLE_MAP_JAVASCRIPT_URL: string = 'https://maps.googleapis.com/maps/api/js';
export const BAIDU_MAP_JAVASCRIPT_URL: string = 'https://api.map.baidu.com/api?v=3.0';
export const AMAP_JAVASCRIPT_URL: string = 'https://webapi.amap.com/maps?v=2.0';
export enum KnownErrorCode {
ApiNotFound = 100001,
ValidatorError = 200000,
UserEmailNotVerified = 201020,
TransactionCannotCreateInThisTime = 205017,
TransactionCannotModifyInThisTime = 205018,
TransactionPictureNotFound = 211001
}
export interface SpecifiedApiError {
readonly message: string;
}
export const SPECIFIED_API_NOT_FOUND_ERRORS: Record<string, SpecifiedApiError> = {
'/api/register.json': {
message: 'User registration is disabled'
}
};
const parameterizedErrors = [
export interface ParameterizedError {
readonly localeKey: string;
readonly regex: RegExp;
readonly parameters: {
readonly field: string;
readonly localized: boolean;
}[];
}
export const PARAMETERIZED_ERRORS: ParameterizedError[] = [
{
localeKey: 'parameter invalid',
regex: /^parameter "(\w+)" is invalid$/,
@@ -142,24 +160,3 @@ const parameterizedErrors = [
}]
}
];
export default {
defaultTimeout: defaultTimeout,
uploadTimeout: uploadTimeout,
importTimeout: importTimeout,
baseApiUrlPath: baseApiUrlPath,
baseQrcodePath: baseQrcodePath,
baseProxyUrlPath: baseProxyUrlPath,
baseAmapApiProxyUrlPath: baseAmapApiProxyUrlPath,
apiNotFoundErrorCode: apiNotFoundErrorCode,
validatorErrorCode: validatorErrorCode,
userEmailNotVerifiedErrorCode: userEmailNotVerifiedErrorCode,
transactionCannotCreateInThisTimeErrorCode: transactionCannotCreateInThisTimeErrorCode,
transactionCannotModifyInThisTimeErrorCode: transactionCannotModifyInThisTimeErrorCode,
transactionPictureNotFoundErrorCode: transactionPictureNotFoundErrorCode,
specifiedApiNotFoundErrors: specifiedApiNotFoundErrors,
parameterizedErrors: parameterizedErrors,
googleMapJavascriptUrl: googleMapJavascriptUrl,
baiduMapJavascriptUrl: baiduMapJavascriptUrl,
amapJavascriptUrl: amapJavascriptUrl
}
-6
View File
@@ -1,6 +0,0 @@
const baseImagePath = 'img';
const ezBookkeepingLogoPath = baseImagePath + '/ezbookkeeping-192.png';
export default {
ezBookkeepingLogoPath: ezBookkeepingLogoPath
}
+2
View File
@@ -0,0 +1,2 @@
const baseImagePath: string = 'img';
export const APPLICATION_LOGO_PATH: string = baseImagePath + '/ezbookkeeping-192.png';
@@ -1,10 +1,19 @@
const allCategoryTypes = {
Income: 1,
Expense: 2,
Transfer: 3
};
import type { ColorValue } from '@/core/color.ts';
const defaultExpenseCategories = [
export interface PresetCategory {
name: string;
categoryIconId: string;
color: ColorValue;
subCategories: PresetSubCategory[];
}
export interface PresetSubCategory {
name: string;
categoryIconId: string;
color: ColorValue;
}
export const DEFAULT_EXPENSE_CATEGORIES: PresetCategory[] = [
{
name: 'Food & Drink',
categoryIconId: '1',
@@ -294,7 +303,7 @@ const defaultExpenseCategories = [
}
];
const defaultIncomeCategories = [
export const DEFAULT_INCOME_CATEGORIES: PresetCategory[] = [
{
name: 'Occupational Earnings',
categoryIconId: '2000',
@@ -373,7 +382,7 @@ const defaultIncomeCategories = [
}
];
const defaultTransferCategories = [
export const DEFAULT_TRANSFER_CATEGORIES: PresetCategory[] = [
{
name: 'General Transfer',
categoryIconId: '4000',
@@ -447,10 +456,3 @@ const defaultTransferCategories = [
]
}
];
export default {
allCategoryTypes: allCategoryTypes,
defaultExpenseCategories: defaultExpenseCategories,
defaultIncomeCategories: defaultIncomeCategories,
defaultTransferCategories: defaultTransferCategories,
};
-98
View File
@@ -1,98 +0,0 @@
const defaultColor = '000000';
const allAvailableColors = [
'000000', // black
'8e8e93', // gray
'ff3b30', // red
'ff2d55', // pink
'ff6b22', // deep orange
'ff9500', // orange
'ffcc00', // yellow
'cddc39', // lime
'009688', // teal
'4cd964', // green
'5ac8fa', // light blue
'2196f3', // blue
'673ab7', // deep purple
'9c27b0', // purple
];
const defaultChartColors = [
'cc4a66',
'e3564a',
'fc892c',
'ffc349',
'4dd291',
'24ceb3',
'2ab4d0',
'065786',
'713670',
'8e1d51'
];
const allAmountColors = {
Green: {
type: 1,
name: 'Green',
lightThemeColor: '#009688',
darkThemeColor: '#009688',
expenseClassName: 'expense-amount-color-green',
incomeClassName: 'income-amount-color-green'
},
Red: {
type: 2,
name: 'Red',
lightThemeColor: '#d43f3f',
darkThemeColor: '#d43f3f',
expenseClassName: 'expense-amount-color-red',
incomeClassName: 'income-amount-color-red'
},
Yellow: {
type: 3,
name: 'Yellow',
lightThemeColor: '#e2b60a',
darkThemeColor: '#e2b60a',
expenseClassName: 'expense-amount-color-yellow',
incomeClassName: 'income-amount-color-yellow'
},
BlackOrWhite: {
type: 4,
name: 'Black or White',
lightThemeColor: '#413935',
darkThemeColor: '#fcf0e3',
expenseClassName: 'expense-amount-color-blackorwhite',
incomeClassName: 'income-amount-color-blackorwhite'
}
}
const allAmountColorsArray = [
allAmountColors.Green,
allAmountColors.Red,
allAmountColors.Yellow,
allAmountColors.BlackOrWhite
];
const allAmountColorTypesMap = {
[allAmountColors.Green.type]: allAmountColors.Green,
[allAmountColors.Red.type]: allAmountColors.Red,
[allAmountColors.Yellow.type]: allAmountColors.Yellow,
[allAmountColors.BlackOrWhite.type]: allAmountColors.BlackOrWhite
};
const defaultExpenseIncomeAmountValue = 0;
const defaultExpenseAmountColor = allAmountColors.Green;
const defaultIncomeAmountColor = allAmountColors.Red;
export default {
defaultColor: defaultColor,
allAccountColors: allAvailableColors,
defaultAccountColor: defaultColor,
allCategoryColors: allAvailableColors,
defaultCategoryColor: defaultColor,
defaultChartColors: defaultChartColors,
allAmountColors: allAmountColors,
allAmountColorsArray: allAmountColorsArray,
allAmountColorTypesMap: allAmountColorTypesMap,
defaultExpenseIncomeAmountValue: defaultExpenseIncomeAmountValue,
defaultExpenseAmountColor: defaultExpenseAmountColor,
defaultIncomeAmountColor: defaultIncomeAmountColor,
};
+40
View File
@@ -0,0 +1,40 @@
import type { ColorValue } from '@/core/color.ts';
const defaultColor: ColorValue = '000000';
export const DEFAULT_ICON_COLOR: ColorValue = defaultColor;
export const DEFAULT_ACCOUNT_COLOR: ColorValue = defaultColor;
export const DEFAULT_CATEGORY_COLOR: ColorValue = defaultColor;
const allAvailableColors: ColorValue[] = [
'000000', // black
'8e8e93', // gray
'ff3b30', // red
'ff2d55', // pink
'ff6b22', // deep orange
'ff9500', // orange
'ffcc00', // yellow
'cddc39', // lime
'009688', // teal
'4cd964', // green
'5ac8fa', // light blue
'2196f3', // blue
'673ab7', // deep purple
'9c27b0', // purple
];
export const ALL_ACCOUNT_COLORS: ColorValue[] = allAvailableColors;
export const ALL_CATEGORY_COLORS: ColorValue[] = allAvailableColors;
export const DEFAULT_CHART_COLORS: ColorValue[] = [
'cc4a66',
'e3564a',
'fc892c',
'ffc349',
'4dd291',
'24ceb3',
'2ab4d0',
'065786',
'713670',
'8e1d51'
];
+13 -177
View File
@@ -1,9 +1,16 @@
const parentAccountCurrencyPlaceholder = '---';
const defaultCurrencySymbol = '¤';
export interface CurrencyInfo {
readonly code: string,
readonly fraction?: number,
readonly symbol?: {
readonly normal: string,
readonly plural?: string
},
readonly unit: string
}
// ISO 4217
// Reference: https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/lists/list-one.xml
const allCurrencies = {
export const ALL_CURRENCIES: Record<string, CurrencyInfo> = {
'AED': { // UAE Dirham
code: 'AED',
fraction: 2,
@@ -1284,177 +1291,6 @@ const allCurrencies = {
}
};
const allCurrencyDisplaySymbol = {
None: 0,
Symbol: 1,
Code: 2,
Unit: 3,
Name: 4
};
const allCurrencyDisplayLocation = {
BeforeAmount: 0,
AfterAmount: 1
};
const allCurrencyDisplayType = {
None: {
type: 1,
name: 'None',
fraction: 2,
symbol: allCurrencyDisplaySymbol.None,
separator: ''
},
SymbolBeforeAmount: {
type: 2,
name: 'Currency Symbol',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Symbol,
location: allCurrencyDisplayLocation.BeforeAmount,
separator: ' '
},
SymbolAfterAmount: {
type: 3,
name: 'Currency Symbol',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Symbol,
location: allCurrencyDisplayLocation.AfterAmount,
separator: ' '
},
SymbolBeforeAmountWithoutSpace: {
type: 4,
name: 'Currency Symbol',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Symbol,
location: allCurrencyDisplayLocation.BeforeAmount,
separator: ''
},
SymbolAfterAmountWithoutSpace: {
type: 5,
name: 'Currency Symbol',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Symbol,
location: allCurrencyDisplayLocation.AfterAmount,
separator: ''
},
CodeBeforeAmount: {
type: 6,
name: 'Currency Code',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Code,
location: allCurrencyDisplayLocation.BeforeAmount,
separator: ' '
},
CodeAfterAmount: {
type: 7,
name: 'Currency Code',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Code,
location: allCurrencyDisplayLocation.AfterAmount,
separator: ' '
},
UnitBeforeAmount: {
type: 8,
name: 'Currency Unit',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Unit,
location: allCurrencyDisplayLocation.BeforeAmount,
separator: ' '
},
UnitAfterAmount: {
type: 9,
name: 'Currency Unit',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Unit,
location: allCurrencyDisplayLocation.AfterAmount,
separator: ' '
},
NameBeforeAmount: {
type: 10,
name: 'Currency Name',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Name,
location: allCurrencyDisplayLocation.BeforeAmount,
separator: ' '
},
NameAfterAmount: {
type: 11,
name: 'Currency Name',
fraction: 2,
symbol: allCurrencyDisplaySymbol.Name,
location: allCurrencyDisplayLocation.AfterAmount,
separator: ' '
}
};
const allCurrencyDisplayTypeArray = [
allCurrencyDisplayType.None,
allCurrencyDisplayType.SymbolBeforeAmount,
allCurrencyDisplayType.SymbolAfterAmount,
allCurrencyDisplayType.SymbolBeforeAmountWithoutSpace,
allCurrencyDisplayType.SymbolAfterAmountWithoutSpace,
allCurrencyDisplayType.CodeBeforeAmount,
allCurrencyDisplayType.CodeAfterAmount,
allCurrencyDisplayType.UnitBeforeAmount,
allCurrencyDisplayType.UnitAfterAmount,
allCurrencyDisplayType.NameBeforeAmount,
allCurrencyDisplayType.NameAfterAmount
];
const allCurrencyDisplayTypeMap = {
[allCurrencyDisplayType.None.type]: allCurrencyDisplayType.None,
[allCurrencyDisplayType.SymbolBeforeAmount.type]: allCurrencyDisplayType.SymbolBeforeAmount,
[allCurrencyDisplayType.SymbolAfterAmount.type]: allCurrencyDisplayType.SymbolAfterAmount,
[allCurrencyDisplayType.SymbolBeforeAmountWithoutSpace.type]: allCurrencyDisplayType.SymbolBeforeAmountWithoutSpace,
[allCurrencyDisplayType.SymbolAfterAmountWithoutSpace.type]: allCurrencyDisplayType.SymbolAfterAmountWithoutSpace,
[allCurrencyDisplayType.CodeBeforeAmount.type]: allCurrencyDisplayType.CodeBeforeAmount,
[allCurrencyDisplayType.CodeAfterAmount.type]: allCurrencyDisplayType.CodeAfterAmount,
[allCurrencyDisplayType.UnitBeforeAmount.type]: allCurrencyDisplayType.UnitBeforeAmount,
[allCurrencyDisplayType.UnitAfterAmount.type]: allCurrencyDisplayType.UnitAfterAmount,
[allCurrencyDisplayType.NameBeforeAmount.type]: allCurrencyDisplayType.NameBeforeAmount,
[allCurrencyDisplayType.NameAfterAmount.type]: allCurrencyDisplayType.NameAfterAmount
};
const defaultCurrency = allCurrencies.USD.code;
const defaultCurrencyDisplayType = allCurrencyDisplayType.SymbolBeforeAmount;
const defaultCurrencyDisplayTypeValue = 0;
const allCurrencySortingTypes = {
Name: {
type: 0,
name: 'Currency Name'
},
CurrencyCode: {
type: 1,
name: 'Currency Code'
},
ExchangeRate: {
type: 2,
name: 'Exchange Rate'
}
};
const allCurrencySortingTypesArray = [
allCurrencySortingTypes.Name,
allCurrencySortingTypes.CurrencyCode,
allCurrencySortingTypes.ExchangeRate
]
const defaultCurrencySortingType = allCurrencySortingTypes.Name.type;
export default {
parentAccountCurrencyPlaceholder: parentAccountCurrencyPlaceholder,
defaultCurrencySymbol: defaultCurrencySymbol,
all: allCurrencies,
defaultCurrency: defaultCurrency,
allCurrencyDisplaySymbol: allCurrencyDisplaySymbol,
allCurrencyDisplayLocation: allCurrencyDisplayLocation,
allCurrencyDisplayType: allCurrencyDisplayType,
allCurrencyDisplayTypeArray: allCurrencyDisplayTypeArray,
allCurrencyDisplayTypeMap: allCurrencyDisplayTypeMap,
defaultCurrencyDisplayType: defaultCurrencyDisplayType,
defaultCurrencyDisplayTypeValue: defaultCurrencyDisplayTypeValue,
allCurrencySortingTypes: allCurrencySortingTypes,
allCurrencySortingTypesArray: allCurrencySortingTypesArray,
defaultCurrencySortingType: defaultCurrencySortingType
};
export const DEFAULT_CURRENCY_SYMBOL: string = '¤';
export const DEFAULT_CURRENCY_CODE: string = ALL_CURRENCIES.USD.code;
export const PARENT_ACCOUNT_CURRENCY_PLACEHOLDER: string = '---';
+19 -7
View File
@@ -1,6 +1,23 @@
const supportedImageExtensions = '.jpg,.jpeg,.png,.gif,.webp';
export const SUPPORTED_IMAGE_EXTENSIONS: string = '.jpg,.jpeg,.png,.gif,.webp';
const supportedImportFileTypes = [
export interface ImportFileType {
readonly type: string;
readonly name: string;
readonly extensions: string;
readonly subTypes?: ImportFileTypeSubType[];
readonly document?: {
readonly supportMultiLanguages: boolean | string;
readonly anchor: string;
};
}
export interface ImportFileTypeSubType {
readonly type: string;
readonly name: string;
readonly extensions?: string;
}
export const SUPPORTED_IMPORT_FILE_TYPES: ImportFileType[] = [
{
type: 'ezbookkeeping',
name: 'ezbookkeeping Data Export File',
@@ -120,8 +137,3 @@ const supportedImportFileTypes = [
}
}
];
export default {
supportedImageExtensions: supportedImageExtensions,
supportedImportFileTypes: supportedImportFileTypes
}
-50
View File
@@ -1,50 +0,0 @@
const allFontSize = {
Small: {
type: 0,
className: 'font-size-small'
},
Default: {
type: 1,
className: 'font-size-default'
},
Large: {
type: 2,
className: 'font-size-large'
},
XLarge: {
type: 3,
className: 'font-size-x-large'
},
XXLarge: {
type: 4,
className: 'font-size-xx-large'
},
XXXLarge: {
type: 5,
className: 'font-size-xxx-large'
},
XXXXLarge: {
type: 6,
className: 'font-size-xxxx-large'
}
}
const allFontSizeArray = [
allFontSize.Small,
allFontSize.Default,
allFontSize.Large,
allFontSize.XLarge,
allFontSize.XXLarge,
allFontSize.XXXLarge,
allFontSize.XXXXLarge
];
const defaultFontSize = allFontSize.Default;
const fontSizePreviewClassNamePrefix = 'preview-';
export default {
allFontSize: allFontSize,
allFontSizeArray: allFontSizeArray,
defaultFontSize: defaultFontSize,
fontSizePreviewClassNamePrefix: fontSizePreviewClassNamePrefix
};
+11 -12
View File
@@ -1,5 +1,8 @@
const defaultAccountIconId = '1';
const allAccountIcons = {
import type { IconInfo } from '@/core/icon.ts';
export const DEFAULT_ACCOUNT_ICON_ID = '1';
export const ALL_ACCOUNT_ICONS: Record<string, IconInfo> = {
// 1 - 99 : Cash Symbols
'1': {
icon: 'las la-wallet'
@@ -158,8 +161,11 @@ const allAccountIcons = {
}
};
const defaultCategoryIconId = '1';
const allCategoryIcons = {
export const DEFAULT_ACCOUNT_ICON = ALL_ACCOUNT_ICONS[DEFAULT_ACCOUNT_ICON_ID];
export const DEFAULT_CATEGORY_ICON_ID = '1';
export const ALL_CATEGORY_ICONS = {
// 1 - 99 : Expense - Food & Drink
'1': {
icon: 'las la-utensils'
@@ -830,11 +836,4 @@ const allCategoryIcons = {
}
};
export default {
allAccountIcons: allAccountIcons,
defaultAccountIconId: defaultAccountIconId,
defaultAccountIcon: allAccountIcons[defaultAccountIconId],
allCategoryIcons: allCategoryIcons,
defaultCategoryIconId: defaultCategoryIconId,
defaultCategoryIcon: allCategoryIcons[defaultCategoryIconId]
};
export const DEFAULT_CATEGORY_ICON = ALL_CATEGORY_ICONS[DEFAULT_CATEGORY_ICON_ID];
+20 -5
View File
@@ -1,4 +1,23 @@
const leafletTileSources = {
export interface PresetLeafletTileSource {
readonly tileUrlFormat: string;
readonly tileUrlSubDomains: string;
readonly tileUrlExtraParams?: PresetLeafletTileSourceExtraParam[];
readonly annotationUrlFormat?: string;
readonly annotationUrlSubDomains?: string;
readonly annotationUrlExtraParams?: PresetLeafletTileSourceExtraParam[];
readonly minZoom: number;
readonly maxZoom: number;
readonly defaultZoomLevel: number;
readonly website: string;
readonly attribution: string;
}
export interface PresetLeafletTileSourceExtraParam {
readonly paramName: string;
readonly paramValueType: string;
}
export const LEAFLET_TILE_SOURCES: Record<string, PresetLeafletTileSource> = {
'openstreetmap': {
tileUrlFormat: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
tileUrlSubDomains: 'abc',
@@ -96,7 +115,3 @@ const leafletTileSources = {
attribution : '<a href="https://www.tianditu.gov.cn" class="external" target="_blank">天地图</a>'
}
}
export default {
leafletTileSources: leafletTileSources
}
-24
View File
@@ -1,24 +0,0 @@
const allTemplateTypes = {
Normal: 1,
Schedule: 2,
};
const allTemplateScheduledFrequencyTypes = {
Disabled: {
type: 0,
name: 'Disabled'
},
Weekly: {
type: 1,
name: 'Weekly'
},
Monthly: {
type: 2,
name: 'Monthly'
}
};
export default {
allTemplateTypes: allTemplateTypes,
allTemplateScheduledFrequencyTypes: allTemplateScheduledFrequencyTypes,
}
@@ -1,5 +1,15 @@
export interface TimezoneInfo {
readonly displayName: string;
readonly timezoneName: string;
}
export const UTC_TIMEZONE: TimezoneInfo = {
displayName: 'Coordinated Universal Time',
timezoneName: 'Etc/GMT'
};
// Reference: https://github.com/nodatime/nodatime/blob/main/data/cldr/windowsZones-45.xml
const allAvailableTimezones = [
export const ALL_TIMEZONES: TimezoneInfo[] = [
// UTC-12:00
{
displayName: 'International Date Line West',
@@ -591,17 +601,3 @@ const allAvailableTimezones = [
timezoneName: 'Pacific/Kiritimati'
}
];
const allTimezoneTypesUsedForStatistics = {
ApplicationTimezone: 0,
TransactionTimezone: 1
};
const defaultTimezoneTypesUsedForStatistics = allTimezoneTypesUsedForStatistics.ApplicationTimezone;
export default {
all: allAvailableTimezones,
utcTimezoneName: 'Etc/GMT',
allTimezoneTypesUsedForStatistics: allTimezoneTypesUsedForStatistics,
defaultTimezoneTypesUsedForStatistics: defaultTimezoneTypesUsedForStatistics
};
-72
View File
@@ -1,72 +0,0 @@
const allTransactionTypes = {
ModifyBalance: 1,
Income: 2,
Expense: 3,
Transfer: 4
};
const allTransactionEditScopeTypes = {
None: {
type: 0,
name: 'None'
},
All: {
type: 1,
name: 'All'
},
TodayOrLater: {
type: 2,
name: 'Today or later'
},
Recent24HoursOrLater: {
type: 3,
name: 'Recent 24 hours or later'
},
ThisWeekOrLater: {
type: 4,
name: 'This week or later'
},
ThisMonthOrLater: {
type: 5,
name: 'This month or later'
},
ThisYearOrLater: {
type: 6,
name: 'This year or later'
}
};
const allTransactionTagFilterTypes = {
HasAny: {
type: 0,
name: 'With Any Selected Tags'
},
HasAll: {
type: 1,
name: 'With All Selected Tags'
},
NotHasAny: {
type: 2,
name: 'Without Any Selected Tags'
},
NotHasAll: {
type: 3,
name: 'Without All Selected Tags'
}
};
const defaultTransactionTagFilterType = allTransactionTagFilterTypes.HasAny;
const minAmountNumber = -99999999999; // -999999999.99
const maxAmountNumber = 99999999999; // 999999999.99
const maxPictureCount = 10;
export default {
allTransactionTypes: allTransactionTypes,
allTransactionEditScopeTypes: allTransactionEditScopeTypes,
allTransactionTagFilterTypes: allTransactionTagFilterTypes,
defaultTransactionTagFilterType: defaultTransactionTagFilterType,
minAmountNumber: minAmountNumber,
maxAmountNumber: maxAmountNumber,
maxPictureCount: maxPictureCount,
};
+3
View File
@@ -0,0 +1,3 @@
export const TRANSACTION_MIN_AMOUNT: number = -99999999999; // -999999999.99
export const TRANSACTION_MAX_AMOUNT: number = 99999999999; // 999999999.99
export const TRANSACTION_MAX_PICTURE_COUNT: number = 10;
+80
View File
@@ -0,0 +1,80 @@
import type { TypeAndName } from './base.ts';
type AccountTypeName = 'SingleAccount' | 'MultiSubAccounts';
export class AccountType implements TypeAndName {
private static readonly allInstances: AccountType[] = [];
private static readonly allInstancesByTypeName: Record<string, AccountType> = {};
public static readonly SingleAccount = new AccountType(1, 'SingleAccount', 'Single Account');
public static readonly MultiSubAccounts = new AccountType(2, 'MultiSubAccounts', 'Multiple Sub-accounts');
public readonly type: number;
public readonly typeName: AccountTypeName;
public readonly name: string;
private constructor(type: number, typeName: AccountTypeName, name: string) {
this.type = type;
this.typeName = typeName;
this.name = name;
AccountType.allInstances.push(this);
AccountType.allInstancesByTypeName[typeName] = this;
}
public static values(): AccountType[] {
return AccountType.allInstances;
}
public static all(): Record<AccountTypeName, AccountType> {
return AccountType.allInstancesByTypeName;
}
}
type AccountCategoryTypeName = 'Cash' | 'CheckingAccount' | 'SavingsAccount' | 'CreditCard' | 'VirtualAccount' | 'DebtAccount' | 'Receivables' | 'CertificateOfDeposit' | 'InvestmentAccount';
export class AccountCategory implements TypeAndName {
private static readonly allInstances: AccountCategory[] = [];
private static readonly allInstancesByType: Record<number, AccountCategory> = {};
private static readonly allInstancesByTypeName: Record<string, AccountCategory> = {};
public static readonly Cash = new AccountCategory(1, 'Cash', 'Cash', '1');
public static readonly CheckingAccount = new AccountCategory(2, 'CheckingAccount', 'Checking Account', '100');
public static readonly SavingsAccount = new AccountCategory(8, 'SavingsAccount', 'Savings Account', '100');
public static readonly CreditCard = new AccountCategory(3, 'CreditCard', 'Credit Card', '100');
public static readonly VirtualAccount = new AccountCategory(4, 'VirtualAccount', 'Virtual Account', '500');
public static readonly DebtAccount = new AccountCategory(5, 'DebtAccount', 'Debt Account', '600');
public static readonly Receivables = new AccountCategory(6, 'Receivables', 'Receivables', '700');
public static readonly CertificateOfDeposit = new AccountCategory(9, 'CertificateOfDeposit', 'Certificate of Deposit', '110');
public static readonly InvestmentAccount = new AccountCategory(7, 'InvestmentAccount', 'Investment Account', '800');
public static readonly Default = AccountCategory.Cash;
public readonly type: number;
public readonly typeName: AccountCategoryTypeName;
public readonly name: string;
public readonly defaultAccountIconId: string;
private constructor(type: number, typeName: AccountCategoryTypeName, name: string, defaultAccountIconId: string) {
this.type = type;
this.typeName = typeName;
this.name = name;
this.defaultAccountIconId = defaultAccountIconId;
AccountCategory.allInstances.push(this);
AccountCategory.allInstancesByType[type] = this;
AccountCategory.allInstancesByTypeName[typeName] = this;
}
public static values(): AccountCategory[] {
return AccountCategory.allInstances;
}
public static all(): Record<AccountCategoryTypeName, AccountCategory> {
return AccountCategory.allInstancesByTypeName;
}
public static valueOf(type: number): AccountCategory {
return AccountCategory.allInstancesByType[type];
}
}
+9
View File
@@ -0,0 +1,9 @@
export interface TypeAndName {
readonly type: number;
readonly name: string;
}
export interface TypeAndDisplayName {
readonly type: number;
readonly displayName: string;
}
+5
View File
@@ -0,0 +1,5 @@
export enum CategoryType {
Income = 1,
Expense = 2,
Transfer = 3
}
+53
View File
@@ -0,0 +1,53 @@
import type { TypeAndName } from './base.ts';
export type ColorValue = string;
export interface ColorInfo {
readonly color: ColorValue;
}
export interface AmountColor {
readonly expenseAmountColor: ColorValue;
readonly incomeAmountColor: ColorValue;
}
export class PresetAmountColor implements TypeAndName {
private static readonly allInstances: PresetAmountColor[] = [];
private static readonly allInstancesByType: Record<number, PresetAmountColor> = {};
public static readonly SystemDefaultType: number = 0;
public static readonly Green = new PresetAmountColor(1, 'Green', '#009688', '#009688', 'expense-amount-color-green', 'income-amount-color-green');
public static readonly Red = new PresetAmountColor(2, 'Red', '#d43f3f', '#d43f3f', 'expense-amount-color-red', 'income-amount-color-red');
public static readonly Yellow = new PresetAmountColor(3, 'Yellow', '#e2b60a', '#e2b60a', 'expense-amount-color-yellow', 'income-amount-color-yellow');
public static readonly BlackOrWhite = new PresetAmountColor(4, 'Black or White', '#413935', '#fcf0e3', 'expense-amount-color-blackorwhite', 'income-amount-color-blackorwhite');
public static readonly DefaultExpenseColor = PresetAmountColor.Green;
public static readonly DefaultIncomeColor = PresetAmountColor.Red;
public readonly type: number;
public readonly name: string;
public readonly lightThemeColor: string;
public readonly darkThemeColor: string;
public readonly expenseClassName: string;
public readonly incomeClassName: string;
private constructor(type: number, name: string, lightThemeColor: string, darkThemeColor: string, expenseClassName: string, incomeClassName: string) {
this.type = type;
this.name = name;
this.lightThemeColor = lightThemeColor;
this.darkThemeColor = darkThemeColor;
this.expenseClassName = expenseClassName;
this.incomeClassName = incomeClassName;
PresetAmountColor.allInstances.push(this);
PresetAmountColor.allInstancesByType[type] = this;
}
public static values(): PresetAmountColor[] {
return PresetAmountColor.allInstances;
}
public static valueOf(type: number): PresetAmountColor {
return PresetAmountColor.allInstancesByType[type];
}
}
+98
View File
@@ -0,0 +1,98 @@
import type { TypeAndName } from './base.ts';
export enum CurrencyDisplaySymbol {
None = 0,
Symbol = 1,
Code = 2,
Unit = 3,
Name = 4
}
export enum CurrencyDisplayLocation {
BeforeAmount = 0,
AfterAmount = 1
}
export interface CurrencyPrependAndAppendText {
prependText?: string;
appendText?: string;
}
export class CurrencyDisplayType implements TypeAndName {
private static readonly allInstances: CurrencyDisplayType[] = [];
private static readonly allInstancesByType: Record<number, CurrencyDisplayType> = {};
private static readonly allInstancesByTypeName: Record<string, CurrencyDisplayType> = {};
public static readonly LanguageDefaultType = 0;
public static readonly None = new CurrencyDisplayType(1, 'None', 'None', 2, CurrencyDisplaySymbol.None, undefined, '');
public static readonly SymbolBeforeAmount = new CurrencyDisplayType(2, 'SymbolBeforeAmount', 'Currency Symbol', 2, CurrencyDisplaySymbol.Symbol, CurrencyDisplayLocation.BeforeAmount, ' ');
public static readonly SymbolAfterAmount = new CurrencyDisplayType(3, 'SymbolAfterAmount', 'Currency Symbol', 2, CurrencyDisplaySymbol.Symbol, CurrencyDisplayLocation.AfterAmount, ' ');
public static readonly SymbolBeforeAmountWithoutSpace = new CurrencyDisplayType(4, 'SymbolBeforeAmountWithoutSpace', 'Currency Symbol', 2, CurrencyDisplaySymbol.Symbol, CurrencyDisplayLocation.BeforeAmount, '');
public static readonly SymbolAfterAmountWithoutSpace = new CurrencyDisplayType(5, 'SymbolAfterAmountWithoutSpace', 'Currency Symbol', 2, CurrencyDisplaySymbol.Symbol, CurrencyDisplayLocation.AfterAmount, '');
public static readonly CodeBeforeAmount = new CurrencyDisplayType(6, 'CodeBeforeAmount', 'Currency Code', 2, CurrencyDisplaySymbol.Code, CurrencyDisplayLocation.BeforeAmount, ' ');
public static readonly CodeAfterAmount = new CurrencyDisplayType(7, 'CodeAfterAmount', 'Currency Code', 2, CurrencyDisplaySymbol.Code, CurrencyDisplayLocation.AfterAmount, ' ');
public static readonly UnitBeforeAmount = new CurrencyDisplayType(8, 'UnitBeforeAmount', 'Currency Unit', 2, CurrencyDisplaySymbol.Unit, CurrencyDisplayLocation.BeforeAmount, ' ');
public static readonly UnitAfterAmount = new CurrencyDisplayType(9, 'UnitAfterAmount', 'Currency Unit', 2, CurrencyDisplaySymbol.Unit, CurrencyDisplayLocation.AfterAmount, ' ');
public static readonly NameBeforeAmount = new CurrencyDisplayType(10, 'NameBeforeAmount', 'Currency Name', 2, CurrencyDisplaySymbol.Name, CurrencyDisplayLocation.BeforeAmount, ' ');
public static readonly NameAfterAmount = new CurrencyDisplayType(11, 'NameAfterAmount', 'Currency Name', 2, CurrencyDisplaySymbol.Name, CurrencyDisplayLocation.AfterAmount, ' ');
public static readonly Default = CurrencyDisplayType.SymbolBeforeAmount;
public readonly type: number;
public readonly typeName: string;
public readonly name: string;
public readonly fraction: number;
public readonly symbol: CurrencyDisplaySymbol;
public readonly location: CurrencyDisplayLocation | undefined;
public readonly separator: string;
private constructor(type: number, typeName: string, name: string, fraction: number, symbol: CurrencyDisplaySymbol, location: CurrencyDisplayLocation | undefined, separator: string) {
this.type = type;
this.typeName = typeName;
this.name = name;
this.fraction = fraction;
this.symbol = symbol;
this.location = location;
this.separator = separator;
CurrencyDisplayType.allInstances.push(this);
CurrencyDisplayType.allInstancesByType[type] = this;
CurrencyDisplayType.allInstancesByTypeName[typeName] = this;
}
public static values(): CurrencyDisplayType[] {
return CurrencyDisplayType.allInstances;
}
public static valueOf(type: number): CurrencyDisplayType {
return CurrencyDisplayType.allInstancesByType[type];
}
public static parse(typeName: string): CurrencyDisplayType {
return CurrencyDisplayType.allInstancesByTypeName[typeName];
}
}
export class CurrencySortingType implements TypeAndName {
private static readonly allInstances: CurrencySortingType[] = [];
public static readonly Name = new CurrencySortingType(0, 'Currency Name');
public static readonly CurrencyCode = new CurrencySortingType(1, 'Currency Code');
public static readonly ExchangeRate = new CurrencySortingType(2, 'Exchange Rate');
public static readonly Default = CurrencySortingType.Name;
public readonly type: number;
public readonly name: string;
private constructor(type: number, name: string) {
this.type = type;
this.name = name;
CurrencySortingType.allInstances.push(this);
}
public static values(): CurrencySortingType[] {
return CurrencySortingType.allInstances;
}
}
+20
View File
@@ -0,0 +1,20 @@
export class MeridiemIndicator {
private static readonly allInstances: MeridiemIndicator[] = [];
public static readonly AM = new MeridiemIndicator(0, 'AM');
public static readonly PM = new MeridiemIndicator(1, 'PM');
public readonly type: number;
public readonly value: string;
private constructor(type: number, value: string) {
this.type = type;
this.value = value;
MeridiemIndicator.allInstances.push(this);
}
public static values(): MeridiemIndicator[] {
return MeridiemIndicator.allInstances;
}
}
+30
View File
@@ -0,0 +1,30 @@
export class FontSize {
private static readonly allInstances: FontSize[] = [];
public static readonly Small = new FontSize(0, 'font-size-small');
public static readonly Default = new FontSize(1, 'font-size-default');
public static readonly Large = new FontSize(2, 'font-size-large');
public static readonly XLarge = new FontSize(3, 'font-size-x-large');
public static readonly XXLarge = new FontSize(4, 'font-size-xx-large');
public static readonly XXXLarge = new FontSize(5, 'font-size-xxx-large');
public static readonly XXXXLarge = new FontSize(6, 'font-size-xxxx-large');
public static readonly MinimumFontSize = FontSize.Small;
public static readonly MaximumFontSize = FontSize.XXXXLarge;
public readonly type: number;
public readonly className: string;
private constructor(type: number, className: string) {
this.type = type;
this.className = className;
FontSize.allInstances.push(this);
}
public static values(): FontSize[] {
return FontSize.allInstances;
}
}
export const FONT_SIZE_PREVIEW_CLASSNAME_PREFIX: string = 'preview-';
+10
View File
@@ -0,0 +1,10 @@
export type LineAwesomeIconClassName = string;
export interface IconInfo {
readonly icon: LineAwesomeIconClassName;
}
export interface IconInfoWithId {
readonly id: string;
readonly icon: LineAwesomeIconClassName;
}
+72
View File
@@ -0,0 +1,72 @@
import type { TypeAndName } from './base.ts';
type TemplateTypeName = 'Normal' | 'Schedule';
export class TemplateType implements TypeAndName {
private static readonly allInstances: TemplateType[] = [];
private static readonly allInstancesByType: Record<number, TemplateType> = {};
private static readonly allInstancesByTypeName: Record<string, TemplateType> = {};
public static readonly Normal = new TemplateType(1, 'Normal');
public static readonly Schedule = new TemplateType(2, 'Schedule');
public readonly type: number;
public readonly name: TemplateTypeName;
private constructor(type: number, name: TemplateTypeName) {
this.type = type;
this.name = name;
TemplateType.allInstances.push(this);
TemplateType.allInstancesByType[type] = this;
TemplateType.allInstancesByTypeName[name] = this;
}
public static values(): TemplateType[] {
return TemplateType.allInstances;
}
public static all(): Record<TemplateTypeName, TemplateType> {
return TemplateType.allInstancesByTypeName;
}
public static valueOf(type: number): TemplateType {
return TemplateType.allInstancesByType[type];
}
}
type ScheduledTemplateFrequencyTypeName = 'Disabled' | 'Weekly' | 'Monthly';
export class ScheduledTemplateFrequencyType implements TypeAndName {
private static readonly allInstances: ScheduledTemplateFrequencyType[] = [];
private static readonly allInstancesByType: Record<number, ScheduledTemplateFrequencyType> = {};
private static readonly allInstancesByTypeName: Record<string, ScheduledTemplateFrequencyType> = {};
public static readonly Disabled = new ScheduledTemplateFrequencyType(0, 'Disabled');
public static readonly Weekly = new ScheduledTemplateFrequencyType(1, 'Weekly');
public static readonly Monthly = new ScheduledTemplateFrequencyType(2, 'Monthly');
public readonly type: number;
public readonly name: ScheduledTemplateFrequencyTypeName;
private constructor(type: number, name: ScheduledTemplateFrequencyTypeName) {
this.type = type;
this.name = name;
ScheduledTemplateFrequencyType.allInstances.push(this);
ScheduledTemplateFrequencyType.allInstancesByType[type] = this;
ScheduledTemplateFrequencyType.allInstancesByTypeName[name] = this;
}
public static values(): ScheduledTemplateFrequencyType[] {
return ScheduledTemplateFrequencyType.allInstances;
}
public static all(): Record<ScheduledTemplateFrequencyTypeName, ScheduledTemplateFrequencyType> {
return ScheduledTemplateFrequencyType.allInstancesByTypeName;
}
public static valueOf(type: number): ScheduledTemplateFrequencyType {
return ScheduledTemplateFrequencyType.allInstancesByType[type];
}
}
+4
View File
@@ -0,0 +1,4 @@
export enum ThemeType {
Light = 'light',
Dark = 'dark'
}
+16
View File
@@ -0,0 +1,16 @@
import type { TypeAndName } from './base.ts';
export class TimezoneTypeForStatistics implements TypeAndName {
public static readonly ApplicationTimezone = new TimezoneTypeForStatistics(0, 'Application Timezone');
public static readonly TransactionTimezone = new TimezoneTypeForStatistics(1, 'Transaction Timezone');
public static readonly Default = TimezoneTypeForStatistics.ApplicationTimezone;
public readonly type: number;
public readonly name: string;
private constructor(type: number, name: string) {
this.type = type;
this.name = name;
}
}
+59
View File
@@ -0,0 +1,59 @@
import type { TypeAndName } from './base.ts';
export enum TransactionType {
ModifyBalance = 1,
Income = 2,
Expense = 3,
Transfer = 4
}
export class TransactionEditScopeType implements TypeAndName {
private static readonly allInstances: TransactionEditScopeType[] = [];
public static readonly None = new TransactionEditScopeType(0, 'None');
public static readonly All = new TransactionEditScopeType(1, 'All');
public static readonly TodayOrLater = new TransactionEditScopeType(2, 'Today or later');
public static readonly Recent24HoursOrLater = new TransactionEditScopeType(3, 'Recent 24 hours or later');
public static readonly ThisWeekOrLater = new TransactionEditScopeType(4, 'This week or later');
public static readonly ThisMonthOrLater = new TransactionEditScopeType(5, 'This month or later');
public static readonly ThisYearOrLater = new TransactionEditScopeType(6, 'This year or later');
public readonly type: number;
public readonly name: string;
private constructor(type: number, name: string) {
this.type = type;
this.name = name;
TransactionEditScopeType.allInstances.push(this);
}
public static values(): TransactionEditScopeType[] {
return TransactionEditScopeType.allInstances;
}
}
export class TransactionTagFilterType implements TypeAndName {
private static readonly allInstances: TransactionTagFilterType[] = [];
public static readonly HasAny = new TransactionTagFilterType(0, 'With Any Selected Tags');
public static readonly HasAll = new TransactionTagFilterType(1, 'With All Selected Tags');
public static readonly NotHasAny = new TransactionTagFilterType(2, 'Without Any Selected Tags');
public static readonly NotHasAll = new TransactionTagFilterType(3, 'Without All Selected Tags');
public static readonly Default = TransactionTagFilterType.HasAny;
public readonly type: number;
public readonly name: string;
private constructor(type: number, name: string) {
this.type = type;
this.name = name;
TransactionTagFilterType.allInstances.push(this);
}
public static values(): TransactionTagFilterType[] {
return TransactionTagFilterType.allInstances;
}
}
+1 -1
View File
@@ -70,7 +70,7 @@ import draggable from 'vuedraggable';
import router from '@/router/desktop.js';
import { getVersion, getBuildTime } from '@/lib/version.js';
import { getVersion, getBuildTime } from '@/lib/version.ts';
import userstate from '@/lib/userstate.js';
import {
getI18nOptions,
+1 -1
View File
@@ -1,4 +1,4 @@
import { autoChangeTextareaSize } from '@/lib/ui.mobile.js';
import { autoChangeTextareaSize } from '@/lib/ui/mobile.js';
export default {
mounted(el) {
+12
View File
@@ -0,0 +1,12 @@
declare const __EZBOOKKEEPING_IS_PRODUCTION__: boolean;
declare const __EZBOOKKEEPING_VERSION__: string;
declare const __EZBOOKKEEPING_BUILD_UNIX_TIME__: string;
declare const __EZBOOKKEEPING_BUILD_COMMIT_HASH__: string;
declare const __EZBOOKKEEPING_LICENSE__: string;
declare const __EZBOOKKEEPING_THIRD_PARTY_LICENSES__: string[];
interface Window {
EZBOOKKEEPING_SERVER_SETTINGS?: {
[key: string]: string | number | boolean | undefined | null;
};
}
+41 -47
View File
@@ -1,5 +1,5 @@
import currencyConstants from '@/consts/currency.js';
import accountConstants from '@/consts/account.js';
import { AccountType, AccountCategory } from '@/core/account.ts';
import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts';
export function setAccountModelByAnotherAccount(account, account2) {
account.id = account2.id;
@@ -16,22 +16,12 @@ export function setAccountModelByAnotherAccount(account, account2) {
account.visible = !account2.hidden;
}
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 getAccountOrSubAccountId(account, subAccountId) {
if (account.type === accountConstants.allAccountTypes.SingleAccount) {
if (account.type === AccountType.SingleAccount.type) {
return account.id;
} else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && !subAccountId) {
} else if (account.type === AccountType.MultiSubAccounts.type && !subAccountId) {
return account.id;
} else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && subAccountId) {
} else if (account.type === AccountType.MultiSubAccounts.type && subAccountId) {
if (!account.subAccounts || !account.subAccounts.length) {
return null;
}
@@ -51,11 +41,11 @@ export function getAccountOrSubAccountId(account, subAccountId) {
}
export function getAccountOrSubAccountComment(account, subAccountId) {
if (account.type === accountConstants.allAccountTypes.SingleAccount) {
if (account.type === AccountType.SingleAccount.type) {
return account.comment;
} else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && !subAccountId) {
} else if (account.type === AccountType.MultiSubAccounts.type && !subAccountId) {
return account.comment;
} else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && subAccountId) {
} else if (account.type === AccountType.MultiSubAccounts.type && subAccountId) {
if (!account.subAccounts || !account.subAccounts.length) {
return null;
}
@@ -109,7 +99,7 @@ export function getCategorizedAccountsMap(allAccounts) {
const account = allAccounts[i];
if (!ret[account.category]) {
const categoryInfo = getAccountCategoryInfo(account.category);
const categoryInfo = AccountCategory.valueOf(account.category);
if (categoryInfo) {
ret[account.category] = {
@@ -132,16 +122,17 @@ export function getCategorizedAccountsMap(allAccounts) {
export function getCategorizedAccounts(allAccounts) {
const ret = [];
const allCategories = AccountCategory.values();
const categorizedAccounts = getCategorizedAccountsMap(allAccounts);
for (let i = 0; i < accountConstants.allCategories.length; i++) {
const category = accountConstants.allCategories[i];
for (let i = 0; i < allCategories.length; i++) {
const category = allCategories[i];
if (!categorizedAccounts[category.id]) {
if (!categorizedAccounts[category.type]) {
continue;
}
const accountCategory = categorizedAccounts[category.id];
const accountCategory = categorizedAccounts[category.type];
ret.push(accountCategory);
}
@@ -150,15 +141,16 @@ export function getCategorizedAccounts(allAccounts) {
export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) {
const ret = [];
const allCategories = AccountCategory.values();
for (let i = 0; i < accountConstants.allCategories.length; i++) {
const accountCategory = accountConstants.allCategories[i];
for (let i = 0; i < allCategories.length; i++) {
const accountCategory = allCategories[i];
if (!categorizedAccountsMap[accountCategory.id] || !categorizedAccountsMap[accountCategory.id].accounts) {
if (!categorizedAccountsMap[accountCategory.type] || !categorizedAccountsMap[accountCategory.type].accounts) {
continue;
}
const allAccounts = categorizedAccountsMap[accountCategory.id].accounts;
const allAccounts = categorizedAccountsMap[accountCategory.type].accounts;
const allSubAccounts = {};
const allVisibleSubAccountCounts = {};
const allFirstVisibleSubAccountIndexes = {};
@@ -176,7 +168,7 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) {
}
}
if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && account.subAccounts) {
if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) {
let visibleSubAccountCount = 0;
let firstVisibleSubAccountIndex = -1;
@@ -202,7 +194,7 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) {
if (allAccounts.length > 0) {
ret.push({
category: accountCategory.id,
category: accountCategory.type,
name: accountCategory.name,
icon: accountCategory.defaultAccountIconId,
allAccounts: allAccounts,
@@ -219,31 +211,31 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) {
}
export function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter) {
const allAccountCategories = accountConstants.allCategories;
const allAccountCategories = AccountCategory.values();
const ret = [];
for (let categoryIdx = 0; categoryIdx < allAccountCategories.length; categoryIdx++) {
const accountCategory = allAccountCategories[categoryIdx];
if (!categorizedAccounts[accountCategory.id] || !categorizedAccounts[accountCategory.id].accounts) {
if (!categorizedAccounts[accountCategory.type] || !categorizedAccounts[accountCategory.type].accounts) {
continue;
}
for (let accountIdx = 0; accountIdx < categorizedAccounts[accountCategory.id].accounts.length; accountIdx++) {
const account = categorizedAccounts[accountCategory.id].accounts[accountIdx];
for (let accountIdx = 0; accountIdx < categorizedAccounts[accountCategory.type].accounts.length; accountIdx++) {
const account = categorizedAccounts[accountCategory.type].accounts[accountIdx];
if (account.hidden || !accountFilter(account)) {
continue;
}
if (account.type === accountConstants.allAccountTypes.SingleAccount) {
if (account.type === AccountType.SingleAccount.type) {
ret.push({
balance: account.balance,
isAsset: account.isAsset,
isLiability: account.isLiability,
currency: account.currency
});
} else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts && account.subAccounts) {
} else if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) {
for (let subAccountIdx = 0; subAccountIdx < account.subAccounts.length; subAccountIdx++) {
const subAccount = account.subAccounts[subAccountIdx];
@@ -307,7 +299,7 @@ export function getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(allAccounts,
const account = allAccounts[accountId];
if (account.currency === currencyConstants.parentAccountCurrencyPlaceholder) {
if (account.currency === PARENT_ACCOUNT_CURRENCY_PLACEHOLDER) {
continue;
}
@@ -326,9 +318,9 @@ export function getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(allAccounts,
}
export function selectAccountOrSubAccounts(filterAccountIds, account, value) {
if (account.type === accountConstants.allAccountTypes.SingleAccount) {
if (account.type === AccountType.SingleAccount.type) {
filterAccountIds[account.id] = value;
} else if (account.type === accountConstants.allAccountTypes.MultiSubAccounts) {
} else if (account.type === AccountType.MultiSubAccounts.type) {
if (!account.subAccounts || !account.subAccounts.length) {
return;
}
@@ -348,7 +340,7 @@ export function selectAll(filterAccountIds, allAccountsMap) {
const account = allAccountsMap[accountId];
if (account && account.type === accountConstants.allAccountTypes.SingleAccount) {
if (account && account.type === AccountType.SingleAccount.type) {
filterAccountIds[account.id] = false;
}
}
@@ -362,7 +354,7 @@ export function selectNone(filterAccountIds, allAccountsMap) {
const account = allAccountsMap[accountId];
if (account && account.type === accountConstants.allAccountTypes.SingleAccount) {
if (account && account.type === AccountType.SingleAccount.type) {
filterAccountIds[account.id] = true;
}
}
@@ -376,7 +368,7 @@ export function selectInvert(filterAccountIds, allAccountsMap) {
const account = allAccountsMap[accountId];
if (account && account.type === accountConstants.allAccountTypes.SingleAccount) {
if (account && account.type === AccountType.SingleAccount.type) {
filterAccountIds[account.id] = !filterAccountIds[account.id];
}
}
@@ -415,9 +407,11 @@ export function isAccountOrSubAccountsHasButNotAllChecked(account, filterAccount
}
export function setAccountSuitableIcon(account, oldCategory, newCategory) {
for (let i = 0; i < accountConstants.allCategories.length; i++) {
if (accountConstants.allCategories[i].id === oldCategory) {
if (account.icon !== accountConstants.allCategories[i].defaultAccountIconId) {
const allCategories = AccountCategory.values();
for (let i = 0; i < allCategories.length; i++) {
if (allCategories[i].type === oldCategory) {
if (account.icon !== allCategories[i].defaultAccountIconId) {
return;
} else {
break;
@@ -425,9 +419,9 @@ export function setAccountSuitableIcon(account, oldCategory, newCategory) {
}
}
for (let i = 0; i < accountConstants.allCategories.length; i++) {
if (accountConstants.allCategories[i].id === newCategory) {
account.icon = accountConstants.allCategories[i].defaultAccountIconId;
for (let i = 0; i < allCategories.length; i++) {
if (allCategories[i].type === newCategory) {
account.icon = allCategories[i].defaultAccountIconId;
}
}
}
+20 -20
View File
@@ -1,5 +1,5 @@
import categoryConstants from '@/consts/category.js';
import transactionConstants from '@/consts/transaction.js';
import { CategoryType } from '@/core/category.ts';
import { TransactionType } from '@/core/transaction.ts';
export function setCategoryModelByAnotherCategory(category, category2) {
category.id = category2.id;
@@ -13,24 +13,24 @@ export function setCategoryModelByAnotherCategory(category, category2) {
}
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;
if (transactionType === TransactionType.Income) {
return CategoryType.Income;
} else if (transactionType === TransactionType.Expense) {
return CategoryType.Expense;
} else if (transactionType === TransactionType.Transfer) {
return CategoryType.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;
if (categoryType === CategoryType.Income) {
return TransactionType.Income;
} else if (categoryType === CategoryType.Expense) {
return TransactionType.Expense;
} else if (categoryType === CategoryType.Transfer) {
return TransactionType.Transfer;
} else {
return null;
}
@@ -73,16 +73,16 @@ export function getTransactionSecondaryCategoryName(categoryId, allCategories) {
export function allTransactionCategoriesWithVisibleCount(allTransactionCategories, allowCategoryTypes) {
const ret = {};
const hasAllowCategoryTypes = allowCategoryTypes
&& (allowCategoryTypes[categoryConstants.allCategoryTypes.Income.toString()]
|| allowCategoryTypes[categoryConstants.allCategoryTypes.Expense.toString()]
|| allowCategoryTypes[categoryConstants.allCategoryTypes.Transfer.toString()]);
&& (allowCategoryTypes[CategoryType.Income.toString()]
|| allowCategoryTypes[CategoryType.Expense.toString()]
|| allowCategoryTypes[CategoryType.Transfer.toString()]);
for (let key in categoryConstants.allCategoryTypes) {
if (!Object.prototype.hasOwnProperty.call(categoryConstants.allCategoryTypes, key)) {
for (let key in CategoryType) {
if (!Object.prototype.hasOwnProperty.call(CategoryType, key)) {
continue;
}
const categoryType = categoryConstants.allCategoryTypes[key];
const categoryType = CategoryType[key];
if (!allTransactionCategories[categoryType]) {
continue;
+76
View File
@@ -0,0 +1,76 @@
import Clipboard from 'clipboard';
export interface ClipboardCreateContext {
readonly el: string | Element;
readonly text: string;
readonly successCallback?: (e: ClipboardEvent) => void;
readonly errorCallback?: (e: ClipboardEvent) => void;
}
export interface ClipboardEvent {
readonly text: string;
readonly action: string;
}
export class ClipboardTextHolder {
private text: string;
constructor(text: string) {
this.text = text;
}
public getText(): string {
return this.text;
}
public setText(text: string): void {
this.text = text;
}
}
export class ClipboardHolder {
private readonly textHolder: ClipboardTextHolder;
private readonly clipboard: Clipboard;
private constructor(textHolder: ClipboardTextHolder, clipboard: Clipboard) {
this.textHolder = textHolder;
this.clipboard = clipboard;
}
public setClipboardText(text: string): void {
this.textHolder.setText(text);
}
public destroy(): void {
this.clipboard.destroy();
}
public static create({ el, text, successCallback, errorCallback }: ClipboardCreateContext): ClipboardHolder {
const textHolder = new ClipboardTextHolder(text);
const clipboard = new Clipboard(el, {
text: function () {
return textHolder.getText();
}
});
clipboard.on('success', (e) => {
if (successCallback) {
successCallback({
text: e.text,
action: e.action
});
}
});
clipboard.on('error', (e) => {
if (errorCallback) {
errorCallback({
text: e.text,
action: e.action
});
}
});
return new ClipboardHolder(textHolder, clipboard);
}
}
-16
View File
@@ -1,16 +0,0 @@
export function getColorsInRows(allColorInfos, itemPerRow) {
const ret = [];
let rowCount = -1;
for (let i = 0; i < allColorInfos.length; i++) {
if (i % itemPerRow === 0) {
ret[++rowCount] = [];
}
ret[rowCount].push({
color: allColorInfos[i]
});
}
return ret;
}
+18
View File
@@ -0,0 +1,18 @@
import type { ColorValue, ColorInfo } from '@/core/color.ts';
export function getColorsInRows(allColorValues: ColorValue[], itemPerRow: number): ColorInfo[][] {
const ret: ColorInfo[][] = [];
let rowCount = -1;
for (let i = 0; i < allColorValues.length; i++) {
if (i % itemPerRow === 0) {
ret[++rowCount] = [];
}
ret[rowCount].push({
color: allColorValues[i]
});
}
return ret;
}
+119 -96
View File
@@ -1,16 +1,16 @@
export function isFunction(val) {
export function isFunction(val: unknown): boolean {
return typeof(val) === 'function';
}
export function isDefined(val) {
export function isDefined(val: unknown): boolean {
return typeof val !== 'undefined';
}
export function isObject(val) {
export function isObject(val: unknown): boolean {
return val != null && typeof(val) === 'object' && !isArray(val);
}
export function isArray(val) {
export function isArray(val: unknown): boolean {
if (isFunction(Array.isArray)) {
return Array.isArray(val);
}
@@ -18,23 +18,23 @@ export function isArray(val) {
return Object.prototype.toString.call(val) === '[object Array]';
}
export function isString(val) {
export function isString(val: unknown): boolean {
return typeof(val) === 'string';
}
export function isNumber(val) {
export function isNumber(val: unknown): boolean {
return typeof(val) === 'number';
}
export function isInteger(val) {
export function isInteger(val: unknown): boolean {
return Number.isInteger(val);
}
export function isBoolean(val) {
export function isBoolean(val: unknown): boolean {
return typeof(val) === 'boolean';
}
export function isYearMonth(val) {
export function isYearMonth(val: unknown): boolean {
if (typeof(val) !== 'string') {
return false;
}
@@ -45,50 +45,53 @@ export function isYearMonth(val) {
return false;
}
return parseInt(items[0]) && parseInt(items[1]);
return !!parseInt(items[0]) && !!parseInt(items[1]);
}
export function isEquals(obj1, obj2) {
export function isEquals(obj1: unknown, obj2: unknown): boolean {
if (obj1 === obj2) {
return true;
}
if (isArray(obj1) && isArray(obj2)) {
if (obj1.length !== obj2.length) {
const arr1 = obj1 as unknown[];
const arr2 = obj2 as unknown[];
if (arr1.length !== arr2.length) {
return false;
}
for (let i = 0; i < obj1.length; i++) {
if (!isEquals(obj1[i], obj2[i])) {
for (let i = 0; i < arr1.length; i++) {
if (!isEquals(arr1[i], arr2[i])) {
return false;
}
}
return true;
} else if (isObject(obj1) && isObject(obj2)) {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
const keys1 = Object.keys(obj1 as Record<string, unknown>);
const keys2 = Object.keys(obj2 as Record<string, unknown>);
if (keys1.length !== keys2.length) {
return false;
}
const keyExistsMap2 = {};
const keyExistsMap2 = new Map<string, boolean>();
for (let i = 0; i < keys2.length; i++) {
const key = keys2[i];
keyExistsMap2[key] = true;
keyExistsMap2.set(key, true);
}
for (let i = 0; i < keys1.length; i++) {
const key = keys1[i];
if (!keyExistsMap2[key]) {
if (!keyExistsMap2.get(key)) {
return false;
}
if (!isEquals(obj1[key], obj2[key])) {
if (!isEquals((obj1 as Record<string, unknown>)[key], (obj2 as Record<string, unknown>)[key])) {
return false;
}
}
@@ -99,7 +102,7 @@ export function isEquals(obj1, obj2) {
}
}
export function isYearMonthEquals(val1, val2) {
export function isYearMonthEquals(val1: unknown, val2: unknown): boolean {
if (typeof(val1) !== 'string' || typeof(val2) !== 'string') {
return false;
}
@@ -111,15 +114,15 @@ export function isYearMonthEquals(val1, val2) {
return false;
}
return (parseInt(items1[0]) && parseInt(items1[1])) && (parseInt(items1[0]) === parseInt(items2[0])) && (parseInt(items1[1]) === parseInt(items2[1]));
return (!!parseInt(items1[0]) && !!parseInt(items1[1])) && (parseInt(items1[0]) === parseInt(items2[0])) && (parseInt(items1[1]) === parseInt(items2[1]));
}
export function isObjectEmpty(obj) {
export function isObjectEmpty(obj: object): boolean {
if (!obj) {
return true;
}
for (let field in obj) {
for (const field in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, field)) {
continue;
}
@@ -130,20 +133,20 @@ export function isObjectEmpty(obj) {
return true;
}
export function sortNumbersArray(array) {
export function sortNumbersArray(array: number[]): number[] {
return array.sort(function (num1, num2) {
return num1 - num2;
});
}
export function getObjectOwnFieldCount(object) {
export function getObjectOwnFieldCount(object: object): number {
let count = 0;
if (!object || !isObject(object)) {
return count;
}
for (let field in object) {
for (const field in object) {
if (!Object.prototype.hasOwnProperty.call(object, field)) {
continue;
}
@@ -154,7 +157,7 @@ export function getObjectOwnFieldCount(object) {
return count;
}
export function replaceAll(value, originalValue, targetValue) {
export function replaceAll(value: string, originalValue: string, targetValue: string): string {
// Escape special characters in originalValue to safely use it in a regex pattern.
// This ensures that characters like . (dot), * (asterisk), +, ?, etc. are treated literally,
// rather than as special regex symbols.
@@ -163,11 +166,11 @@ export function replaceAll(value, originalValue, targetValue) {
return value.replaceAll(new RegExp(escapedOriginalValue, 'g'), targetValue);
}
export function removeAll(value, originalValue) {
export function removeAll(value: string, originalValue: string): string {
return replaceAll(value, originalValue, '');
}
export function limitText(value, maxLength) {
export function limitText(value: string, maxLength: number): string {
let length = 0;
for (let i = 0; i < value.length; i++) {
@@ -187,7 +190,7 @@ export function limitText(value, maxLength) {
return value.substring(0, maxLength - 3) + '...';
}
export function getTextBefore(fullText, text) {
export function getTextBefore(fullText: string, text: string): string {
if (!text) {
return fullText;
}
@@ -201,7 +204,7 @@ export function getTextBefore(fullText, text) {
return '';
}
export function getTextAfter(fullText, text) {
export function getTextAfter(fullText: string, text: string): string {
if (!text) {
return fullText;
}
@@ -216,15 +219,15 @@ export function getTextAfter(fullText, text) {
return '';
}
export function base64encode(arrayBuffer) {
if (!arrayBuffer || arrayBuffer.length === 0) {
export function base64encode(arrayBuffer: ArrayBuffer): string | null {
if (!arrayBuffer) {
return null;
}
return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
return btoa(String.fromCharCode.apply(null, Array.from(new Uint8Array(arrayBuffer))));
}
export function base64decode(str) {
export function base64decode(str: string): string | null {
if (!str) {
return '';
}
@@ -232,56 +235,64 @@ export function base64decode(str) {
return atob(str);
}
export function arrayBufferToString(arrayBuffer) {
return String.fromCharCode.apply(null, new Uint8Array(arrayBuffer));
export function arrayBufferToString(arrayBuffer: ArrayBuffer): string {
return String.fromCharCode.apply(null, Array.from(new Uint8Array(arrayBuffer)));
}
export function stringToArrayBuffer(str){
export function stringToArrayBuffer(str: string): ArrayBuffer {
return Uint8Array.from(str, c => c.charCodeAt(0)).buffer;
}
export function getFirstVisibleItem(items, hiddenField) {
if (isArray(items) && items.length > 0) {
for (let i = 0; i < items.length; i++) {
if (hiddenField && items[i][hiddenField]) {
export function getFirstVisibleItem(items: Record<string, unknown>[] | Record<string, Record<string, unknown>>, hiddenField: string): unknown {
if (isArray(items) && (items as Record<string, unknown>[]).length > 0) {
const arr = items as Record<string, unknown>[];
for (let i = 0; i < arr.length; i++) {
if (hiddenField && arr[i][hiddenField]) {
continue;
}
return items[i];
return arr[i];
}
} else if (isObject(items)) {
for (let field in items) {
if (!Object.prototype.hasOwnProperty.call(items, field)) {
const obj = items as Record<string, Record<string, unknown>>;
for (const field in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, field)) {
continue;
}
if (hiddenField && items[field][hiddenField]) {
if (hiddenField && obj[field][hiddenField]) {
continue;
}
return items[field];
return obj[field];
}
}
return null;
}
export function getItemByKeyValue(src, value, keyField) {
export function getItemByKeyValue(src: Record<string, unknown>[] | Record<string, Record<string, unknown>>, value: unknown, keyField: string) {
if (isArray(src)) {
for (let i = 0; i < src.length; i++) {
const item = src[i];
const arr = src as Record<string, unknown>[];
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if (item[keyField] === value) {
return item;
}
}
} else if (isObject(src)) {
for (let field in src) {
const obj = src as Record<string, Record<string, unknown>>;
for (const field in obj) {
if (!Object.prototype.hasOwnProperty.call(src, field)) {
continue;
}
const item = src[field];
const item = obj[field];
if (item[keyField] === value) {
return item;
@@ -292,39 +303,47 @@ export function getItemByKeyValue(src, value, keyField) {
return null;
}
export function getNameByKeyValue(src, value, keyField, nameField, defaultName) {
export function getNameByKeyValue(src: Record<string, unknown>[] | Record<string, Record<string, unknown>>, value: unknown, keyField: string, nameField: string, defaultName: string): unknown {
if (isArray(src)) {
const arr = src as Record<string, unknown>[];
if (keyField) {
for (let i = 0; i < src.length; i++) {
const option = src[i];
for (let i = 0; i < arr.length; i++) {
const option = arr[i];
if (option[keyField] === value) {
return option[nameField];
}
}
} else {
if (src[value]) {
const option = src[value];
} else if (isNumber(value)) {
const index = value as number;
if (arr[index]) {
const option = arr[index];
return option[nameField];
}
}
} else if (isObject(src)) {
const obj = src as Record<string, Record<string, unknown>>;
if (keyField) {
for (let key in src) {
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(src, key)) {
continue;
}
const option = src[key];
const option = obj[key];
if (option[keyField] === value) {
return option[nameField];
}
}
} else {
if (src[value]) {
const option = src[value];
} else if (isNumber(value)) {
const index = value as number;
if (obj[index]) {
const option = obj[index];
return option[nameField];
}
@@ -334,7 +353,7 @@ export function getNameByKeyValue(src, value, keyField, nameField, defaultName)
return defaultName;
}
export function copyObjectTo(fromObject, toObject) {
export function copyObjectTo(fromObject: Record<string, unknown>, toObject: Record<string, unknown>): object {
if (!isObject(fromObject)) {
return toObject;
}
@@ -343,7 +362,7 @@ export function copyObjectTo(fromObject, toObject) {
toObject = {};
}
for (let key in fromObject) {
for (const key in fromObject) {
if (!Object.prototype.hasOwnProperty.call(fromObject, key)) {
continue;
}
@@ -352,9 +371,9 @@ export function copyObjectTo(fromObject, toObject) {
const toValue = toObject[key];
if (isArray(fromValue)) {
toObject[key] = copyArrayTo(fromValue, toValue);
toObject[key] = copyArrayTo(fromValue as unknown[], toValue as unknown[]);
} else if (isObject(fromValue)) {
toObject[key] = copyObjectTo(fromValue, toValue);
toObject[key] = copyObjectTo(fromValue as Record<string, unknown>, toValue as Record<string, unknown>);
} else {
if (fromValue !== toValue) {
toObject[key] = fromValue;
@@ -365,7 +384,7 @@ export function copyObjectTo(fromObject, toObject) {
return toObject;
}
export function copyArrayTo(fromArray, toArray) {
export function copyArrayTo(fromArray: unknown[], toArray: unknown[]) {
if (!isArray(fromArray)) {
return toArray;
}
@@ -381,9 +400,9 @@ export function copyArrayTo(fromArray, toArray) {
const toValue = toArray[i];
if (isArray(fromValue)) {
toArray[i] = copyArrayTo(fromValue, toValue);
toArray[i] = copyArrayTo(fromValue as unknown[], toValue as unknown[]);
} else if (isObject(fromValue)) {
toArray[i] = copyObjectTo(fromValue, toValue);
toArray[i] = copyObjectTo(fromValue as Record<string, unknown>, toValue as Record<string, unknown>);
} else {
if (fromValue !== toValue) {
toArray[i] = fromValue;
@@ -391,9 +410,9 @@ export function copyArrayTo(fromArray, toArray) {
}
} else {
if (isArray(fromValue)) {
toArray.push(copyArrayTo(fromValue, []));
toArray.push(copyArrayTo(fromValue as unknown[], []));
} else if (isObject(fromValue)) {
toArray.push(copyObjectTo(fromValue, {}));
toArray.push(copyObjectTo(fromValue as Record<string, unknown>, {}));
} else {
toArray.push(fromValue);
}
@@ -403,7 +422,7 @@ export function copyArrayTo(fromArray, toArray) {
return toArray;
}
export function arrayContainsFieldValue(array, fieldName, value) {
export function arrayContainsFieldValue(array: Record<string, unknown>[], fieldName: string, value: unknown): boolean {
if (!value || !array || !array.length) {
return false;
}
@@ -417,10 +436,10 @@ export function arrayContainsFieldValue(array, fieldName, value) {
return false;
}
export function objectFieldToArrayItem(object) {
const ret = [];
export function objectFieldToArrayItem(object: object): string[] {
const ret: string[] = [];
for (let field in object) {
for (const field in object) {
if (!Object.prototype.hasOwnProperty.call(object, field)) {
continue;
}
@@ -431,8 +450,8 @@ export function objectFieldToArrayItem(object) {
return ret;
}
export function arrayItemToObjectField(array, value) {
const ret = {};
export function arrayItemToObjectField(array: string[], value: unknown): Record<string, unknown> {
const ret: Record<string, unknown> = {};
for (let i = 0; i < array.length; i++) {
ret[array[i]] = value;
@@ -441,10 +460,10 @@ export function arrayItemToObjectField(array, value) {
return ret;
}
export function categorizedArrayToPlainArray(object) {
const ret = [];
export function categorizedArrayToPlainArray(object: Record<string, unknown[]>): unknown[] {
const ret: unknown[] = [];
for (let field in object) {
for (const field in object) {
if (!Object.prototype.hasOwnProperty.call(object, field)) {
continue;
}
@@ -459,8 +478,8 @@ export function categorizedArrayToPlainArray(object) {
return ret;
}
export function selectAll(filterItemIds, allItemsMap) {
for (let itemId in filterItemIds) {
export function selectAll(filterItemIds: Record<string, boolean>, allItemsMap: { [key: string]: { id: string } }): void {
for (const itemId in filterItemIds) {
if (!Object.prototype.hasOwnProperty.call(filterItemIds, itemId)) {
continue;
}
@@ -473,8 +492,8 @@ export function selectAll(filterItemIds, allItemsMap) {
}
}
export function selectNone(filterItemIds, allItemsMap) {
for (let itemId in filterItemIds) {
export function selectNone(filterItemIds: Record<string, boolean>, allItemsMap: { [key: string]: { id: string } }): void {
for (const itemId in filterItemIds) {
if (!Object.prototype.hasOwnProperty.call(filterItemIds, itemId)) {
continue;
}
@@ -487,8 +506,8 @@ export function selectNone(filterItemIds, allItemsMap) {
}
}
export function selectInvert(filterItemIds, allItemsMap) {
for (let itemId in filterItemIds) {
export function selectInvert(filterItemIds: Record<string, boolean>, allItemsMap: { [key: string]: { id: string } }): void {
for (const itemId in filterItemIds) {
if (!Object.prototype.hasOwnProperty.call(filterItemIds, itemId)) {
continue;
}
@@ -501,7 +520,7 @@ export function selectInvert(filterItemIds, allItemsMap) {
}
}
export function isPrimaryItemHasSecondaryValue(primaryItem, primarySubItemsField, secondaryValueField, secondaryHiddenField, secondaryValue) {
export function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, Record<string, unknown>[]>, primarySubItemsField: string, secondaryValueField: string, secondaryHiddenField: string, secondaryValue: unknown): boolean {
for (let i = 0; i < primaryItem[primarySubItemsField].length; i++) {
const secondaryItem = primaryItem[primarySubItemsField][i];
@@ -519,11 +538,13 @@ export function isPrimaryItemHasSecondaryValue(primaryItem, primarySubItemsField
return false;
}
export function getPrimaryValueBySecondaryValue(items, primarySubItemsField, primaryValueField, primaryHiddenField, secondaryValueField, secondaryHiddenField, secondaryValue) {
export function getPrimaryValueBySecondaryValue(items: Record<string, Record<string, unknown>[]>[] | Record<string, Record<string, Record<string, unknown>[]>>, primarySubItemsField: string, primaryValueField: string, primaryHiddenField: string, secondaryValueField: string, secondaryHiddenField: string, secondaryValue: unknown): unknown {
if (primarySubItemsField) {
if (isArray(items)) {
for (let i = 0; i < items.length; i++) {
const primaryItem = items[i];
const arr = items as Record<string, Record<string, unknown>[]>[];
for (let i = 0; i < arr.length; i++) {
const primaryItem = arr[i];
if (primaryHiddenField && primaryItem[primaryHiddenField]) {
continue;
@@ -538,12 +559,14 @@ export function getPrimaryValueBySecondaryValue(items, primarySubItemsField, pri
}
}
} else {
for (let field in items) {
if (!Object.prototype.hasOwnProperty.call(items, field)) {
const obj = items as Record<string, Record<string, Record<string, unknown>[]>>;
for (const field in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, field)) {
continue;
}
const primaryItem = items[field];
const primaryItem = obj[field];
if (primaryHiddenField && primaryItem[primaryHiddenField]) {
continue;
@@ -563,7 +586,7 @@ export function getPrimaryValueBySecondaryValue(items, primarySubItemsField, pri
return null;
}
export function arrangeArrayWithNewStartIndex(array, startIndex) {
export function arrangeArrayWithNewStartIndex(array: unknown[], startIndex: number): unknown[] {
if (startIndex <= 0 || startIndex >= array.length) {
return array;
}
-83
View File
@@ -1,83 +0,0 @@
import currencyConstants from '@/consts/currency.js';
import { isString, isNumber } from './common.js';
export function getCurrencyFraction(currencyCode) {
const currencyInfo = currencyConstants.all[currencyCode];
if (currencyInfo) {
return currencyInfo.fraction;
}
return null;
}
export function appendCurrencySymbol(value, currencyDisplayType, currencyCode, currencyUnit, currencyName, isPlural) {
if (isNumber(value)) {
value = value.toString();
}
if (!isString(value)) {
return value;
}
const symbol = getAmountPrependAndAppendCurrencySymbol(currencyDisplayType, currencyCode, currencyUnit, currencyName, isPlural);
if (!symbol) {
return value;
}
const separator = currencyDisplayType.separator || '';
if (symbol.prependText) {
value = symbol.prependText + separator + value;
}
if (symbol.appendText) {
value = value + separator + symbol.appendText;
}
return value;
}
export function getAmountPrependAndAppendCurrencySymbol(currencyDisplayType, currencyCode, currencyUnit, currencyName, isPlural) {
if (!currencyDisplayType) {
return null;
}
let symbol = '';
if (currencyDisplayType.symbol === currencyConstants.allCurrencyDisplaySymbol.Symbol) {
const currencyInfo = currencyConstants.all[currencyCode];
if (currencyInfo && currencyInfo.symbol && currencyInfo.symbol.normal) {
symbol = currencyInfo.symbol.normal;
if (isPlural && currencyInfo.symbol.plural) {
symbol = currencyInfo.symbol.plural;
}
}
if (!symbol) {
symbol = currencyConstants.defaultCurrencySymbol;
}
} else if (currencyDisplayType.symbol === currencyConstants.allCurrencyDisplaySymbol.Code) {
symbol = currencyCode;
} else if (currencyDisplayType.symbol === currencyConstants.allCurrencyDisplaySymbol.Unit) {
symbol = currencyUnit;
} else if (currencyDisplayType.symbol === currencyConstants.allCurrencyDisplaySymbol.Name) {
symbol = currencyName;
}
if (currencyDisplayType.location === currencyConstants.allCurrencyDisplayLocation.BeforeAmount) {
return {
prependText: symbol
};
} else if (currencyDisplayType.location === currencyConstants.allCurrencyDisplayLocation.AfterAmount) {
return {
appendText: symbol
};
} else {
return null;
}
}
+80
View File
@@ -0,0 +1,80 @@
import { CurrencyDisplaySymbol, CurrencyDisplayLocation, type CurrencyPrependAndAppendText, CurrencyDisplayType } from '@/core/currency.ts';
import { ALL_CURRENCIES, DEFAULT_CURRENCY_SYMBOL } from '@/consts/currency.ts';
import { isString, isNumber } from './common.ts';
export function getCurrencyFraction(currencyCode: string): number | undefined {
const currencyInfo = ALL_CURRENCIES[currencyCode];
return currencyInfo?.fraction;
}
export function appendCurrencySymbol(value: unknown, currencyDisplayType: CurrencyDisplayType, currencyCode: string, currencyUnit: string, currencyName: string, isPlural: boolean): string | null {
if (isNumber(value)) {
value = (value as number).toString();
}
if (!isString(value)) {
return null;
}
const symbol = getAmountPrependAndAppendCurrencySymbol(currencyDisplayType, currencyCode, currencyUnit, currencyName, isPlural);
if (!symbol) {
return value as string;
}
const separator = currencyDisplayType.separator || '';
let ret = value as string;
if (symbol.prependText) {
ret = symbol.prependText + separator + ret;
}
if (symbol.appendText) {
ret = ret + separator + symbol.appendText;
}
return ret;
}
export function getAmountPrependAndAppendCurrencySymbol(currencyDisplayType: CurrencyDisplayType, currencyCode: string, currencyUnit: string, currencyName: string, isPlural: boolean): CurrencyPrependAndAppendText | null {
if (!currencyDisplayType) {
return null;
}
let symbol = '';
if (currencyDisplayType.symbol === CurrencyDisplaySymbol.Symbol) {
const currencyInfo = ALL_CURRENCIES[currencyCode];
if (currencyInfo && currencyInfo.symbol && currencyInfo.symbol.normal) {
symbol = currencyInfo.symbol.normal;
if (isPlural && currencyInfo.symbol.plural) {
symbol = currencyInfo.symbol.plural;
}
}
if (!symbol) {
symbol = DEFAULT_CURRENCY_SYMBOL;
}
} else if (currencyDisplayType.symbol === CurrencyDisplaySymbol.Code) {
symbol = currencyCode;
} else if (currencyDisplayType.symbol === CurrencyDisplaySymbol.Unit) {
symbol = currencyUnit;
} else if (currencyDisplayType.symbol === CurrencyDisplaySymbol.Name) {
symbol = currencyName;
}
if (currencyDisplayType.location === CurrencyDisplayLocation.BeforeAmount) {
return {
prependText: symbol
};
} else if (currencyDisplayType.location === CurrencyDisplayLocation.AfterAmount) {
return {
appendText: symbol
};
} else {
return null;
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
import moment from 'moment';
import dateTimeConstants from '@/consts/datetime.js';
import { isObject, isString, isNumber } from './common.js';
import { isObject, isString, isNumber } from './common.ts';
export function isYearMonthValid(year, month) {
if (!isNumber(year) || !isNumber(month)) {
+3 -3
View File
@@ -1,6 +1,6 @@
import { isString } from './common.js';
import { isString } from './common.ts';
export function getFileExtension(filename) {
export function getFileExtension(filename: string): string {
if (!filename || !isString(filename)) {
return '';
}
@@ -9,7 +9,7 @@ export function getFileExtension(filename) {
return parts[parts.length - 1];
}
export function isFileExtensionSupported(filename, supportedExtensions) {
export function isFileExtensionSupported(filename: string, supportedExtensions: string): boolean {
if (!supportedExtensions) {
return false;
}
+99 -146
View File
@@ -1,18 +1,23 @@
import moment from 'moment-timezone';
import { defaultLanguage, allLanguages } from '@/locales/index.js';
import { defaultLanguage, allLanguages } from '@/locales/index.ts';
import { TimezoneTypeForStatistics } from '@/core/timezone.ts';
import { CurrencyDisplayType, CurrencySortingType } from '@/core/currency.ts';
import { PresetAmountColor } from '@/core/color.ts';
import { AccountType, AccountCategory } from '@/core/account.ts';
import { CategoryType } from '@/core/category.ts';
import { TransactionEditScopeType, TransactionTagFilterType } from '@/core/transaction.ts';
import { ScheduledTemplateFrequencyType } from '@/core/template.ts';
import numeralConstants from '@/consts/numeral.js';
import datetimeConstants from '@/consts/datetime.js';
import timezoneConstants from '@/consts/timezone.js';
import currencyConstants from '@/consts/currency.js';
import colorConstants from '@/consts/color.js';
import accountConstants from '@/consts/account.js';
import fileConstants from '@/consts/file.js';
import categoryConstants from '@/consts/category.js';
import transactionConstants from '@/consts/transaction.js';
import templateConstants from '@/consts/template.js';
import { UTC_TIMEZONE, ALL_TIMEZONES } from '@/consts/timezone.ts';
import { ALL_CURRENCIES } from '@/consts/currency.ts';
import { SUPPORTED_IMPORT_FILE_TYPES } from '@/consts/file.ts';
import { DEFAULT_EXPENSE_CATEGORIES, DEFAULT_INCOME_CATEGORIES, DEFAULT_TRANSFER_CATEGORIES } from '@/consts/category.ts';
import statisticsConstants from '@/consts/statistics.js';
import apiConstants from '@/consts/api.js';
import { KnownErrorCode, SPECIFIED_API_NOT_FOUND_ERRORS, PARAMETERIZED_ERRORS } from '@/consts/api.ts';
import {
isDefined,
@@ -22,7 +27,7 @@ import {
getNameByKeyValue,
copyObjectTo,
copyArrayTo
} from './common.js';
} from './common.ts';
import {
isPM,
@@ -53,7 +58,7 @@ import {
getCurrencyFraction,
appendCurrencySymbol,
getAmountPrependAndAppendCurrencySymbol
} from './currency.js';
} from './currency.ts';
import {
getCategorizedAccountsMap,
@@ -201,6 +206,21 @@ function getCurrentLanguageDisplayName(i18nGlobal) {
return currentLanguageInfo.displayName;
}
function getLocalizedDisplayNameAndType(nameAndTypes, translateFn) {
const ret = [];
for (let i = 0; i < nameAndTypes.length; i++) {
const nameAndType = nameAndTypes[i];
ret.push({
type: nameAndType.type,
displayName: translateFn(nameAndType.name)
});
}
return ret;
}
function getDefaultCurrency(translateFn) {
return translateFn('default.currency');
}
@@ -214,7 +234,7 @@ function getCurrencyName(currencyCode, translateFn) {
}
function getCurrencyUnitName(currencyCode, isPlural, translateFn) {
const currencyInfo = currencyConstants.all[currencyCode];
const currencyInfo = ALL_CURRENCIES[currencyCode];
if (currencyInfo && currencyInfo.unit) {
if (isPlural) {
@@ -521,17 +541,16 @@ function getDateTimeFormat(translateFn, allFormatMap, allFormatArray, localeForm
function getAllTimezones(includeSystemDefault, translateFn) {
const defaultTimezoneOffset = getBrowserTimezoneOffset();
const defaultTimezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes();
const allTimezones = timezoneConstants.all;
const allTimezoneInfos = [];
for (let i = 0; i < allTimezones.length; i++) {
const utcOffset = (allTimezones[i].timezoneName !== timezoneConstants.utcTimezoneName ? getTimezoneOffset(allTimezones[i].timezoneName) : '');
const displayName = translateFn(`timezone.${allTimezones[i].displayName}`);
for (let i = 0; i < ALL_TIMEZONES.length; i++) {
const utcOffset = (ALL_TIMEZONES[i].timezoneName !== UTC_TIMEZONE.timezoneName ? getTimezoneOffset(ALL_TIMEZONES[i].timezoneName) : '');
const displayName = translateFn(`timezone.${ALL_TIMEZONES[i].displayName}`);
allTimezoneInfos.push({
name: allTimezones[i].timezoneName,
name: ALL_TIMEZONES[i].timezoneName,
utcOffset: utcOffset,
utcOffsetMinutes: getTimezoneOffsetMinutes(allTimezones[i].timezoneName),
utcOffsetMinutes: getTimezoneOffsetMinutes(ALL_TIMEZONES[i].timezoneName),
displayName: displayName,
displayNameWithUtcOffset: `(UTC${utcOffset}) ${displayName}`
});
@@ -595,11 +614,10 @@ function getTimezoneDifferenceDisplayText(utcOffset, translateFn) {
}
function getAllCurrencies(translateFn) {
const allCurrencyCodes = currencyConstants.all;
const allCurrencies = [];
for (let currencyCode in allCurrencyCodes) {
if (!Object.prototype.hasOwnProperty.call(allCurrencyCodes, currencyCode)) {
for (let currencyCode in ALL_CURRENCIES) {
if (!Object.prototype.hasOwnProperty.call(ALL_CURRENCIES, currencyCode)) {
continue;
}
@@ -772,12 +790,12 @@ function getAllTimezoneTypesUsedForStatistics(currentTimezone, translateFn) {
return [
{
displayName: translateFn('Application Timezone') + ` (UTC${currentTimezoneOffset})`,
type: timezoneConstants.allTimezoneTypesUsedForStatistics.ApplicationTimezone
displayName: translateFn(TimezoneTypeForStatistics.ApplicationTimezone.name) + ` (UTC${currentTimezoneOffset})`,
type: TimezoneTypeForStatistics.ApplicationTimezone.type
},
{
displayName: translateFn('Transaction Timezone'),
type: timezoneConstants.allTimezoneTypesUsedForStatistics.TransactionTimezone
displayName: translateFn(TimezoneTypeForStatistics.TransactionTimezone.name),
type: TimezoneTypeForStatistics.TransactionTimezone.type
}
];
}
@@ -851,10 +869,10 @@ function getAllDigitGroupingTypes(translateFn) {
function getAllCurrencyDisplayTypes(userStore, settingsStore, translateFn) {
const defaultCurrencyDisplayTypeName = translateFn('default.currencyDisplayType');
let defaultCurrencyDisplayType = currencyConstants.allCurrencyDisplayType[defaultCurrencyDisplayTypeName];
let defaultCurrencyDisplayType = CurrencyDisplayType.parse(defaultCurrencyDisplayTypeName);
if (!defaultCurrencyDisplayType) {
defaultCurrencyDisplayType = currencyConstants.defaultCurrencyDisplayType;
defaultCurrencyDisplayType = CurrencyDisplayType.Default;
}
const defaultCurrency = userStore.currentUserDefaultCurrency;
@@ -863,12 +881,14 @@ function getAllCurrencyDisplayTypes(userStore, settingsStore, translateFn) {
const defaultSampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, translateFn, userStore, settingsStore, false, defaultCurrencyDisplayType);
ret.push({
type: currencyConstants.defaultCurrencyDisplayTypeValue,
type: CurrencyDisplayType.LanguageDefaultType,
displayName: `${translateFn('Language Default')} (${defaultSampleValue})`
});
for (let i = 0; i < currencyConstants.allCurrencyDisplayTypeArray.length; i++) {
const type = currencyConstants.allCurrencyDisplayTypeArray[i];
const allCurrencyDisplayTypes = CurrencyDisplayType.values();
for (let i = 0; i < allCurrencyDisplayTypes.length; i++) {
const type = allCurrencyDisplayTypes[i];
const sampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, translateFn, userStore, settingsStore, false, type);
const displayName = `${translateFn(type.name)} (${sampleValue})`
@@ -882,22 +902,7 @@ function getAllCurrencyDisplayTypes(userStore, settingsStore, translateFn) {
}
function getAllCurrencySortingTypes(translateFn) {
const allCurrencySortingTypes = [];
for (const sortingTypeField in currencyConstants.allCurrencySortingTypes) {
if (!Object.prototype.hasOwnProperty.call(currencyConstants.allCurrencySortingTypes, sortingTypeField)) {
continue;
}
const sortingType = currencyConstants.allCurrencySortingTypes[sortingTypeField];
allCurrencySortingTypes.push({
type: sortingType.type,
displayName: translateFn(sortingType.name)
});
}
return allCurrencySortingTypes;
return getLocalizedDisplayNameAndType(CurrencySortingType.values(), translateFn);
}
function getCurrentDecimalSeparator(translateFn, decimalSeparator) {
@@ -970,15 +975,15 @@ function getFormattedAmount(value, translateFn, userStore, currencyCode) {
}
function getCurrentCurrencyDisplayType(translateFn, userStore) {
let currencyDisplayType = currencyConstants.allCurrencyDisplayTypeMap[userStore.currentUserCurrencyDisplayType];
let currencyDisplayType = CurrencyDisplayType.valueOf(userStore.currentUserCurrencyDisplayType);
if (!currencyDisplayType) {
const defaultCurrencyDisplayTypeName = translateFn('default.currencyDisplayType');
currencyDisplayType = currencyConstants.allCurrencyDisplayType[defaultCurrencyDisplayTypeName];
currencyDisplayType = CurrencyDisplayType.parse(defaultCurrencyDisplayTypeName);
}
if (!currencyDisplayType) {
currencyDisplayType = currencyConstants.defaultCurrencyDisplayType;
currencyDisplayType = CurrencyDisplayType.Default;
}
return currencyDisplayType;
@@ -1047,65 +1052,57 @@ function getAmountPrependAndAppendText(currencyCode, userStore, settingsStore, i
}
function getAllExpenseIncomeAmountColors(translateFn, expenseOrIncome) {
const allAmountColors = [];
const ret = [];
let defaultAmountName = '';
if (expenseOrIncome === 1) { // expense
defaultAmountName = colorConstants.defaultExpenseAmountColor.name;
defaultAmountName = PresetAmountColor.DefaultExpenseColor.name;
} else if (expenseOrIncome === 2) { // income
defaultAmountName = colorConstants.defaultIncomeAmountColor.name;
defaultAmountName = PresetAmountColor.DefaultIncomeColor.name;
}
if (defaultAmountName) {
defaultAmountName = translateFn('color.amount.' + defaultAmountName);
}
allAmountColors.push({
type: colorConstants.defaultExpenseIncomeAmountValue,
ret.push({
type: PresetAmountColor.SystemDefaultType,
displayName: translateFn('System Default') + (defaultAmountName ? ` (${defaultAmountName})` : '')
});
for (let i = 0; i < colorConstants.allAmountColorsArray.length; i++) {
const amountColor = colorConstants.allAmountColorsArray[i];
const allPresetAmountColors = PresetAmountColor.values();
allAmountColors.push({
for (let i = 0; i < allPresetAmountColors.length; i++) {
const amountColor = allPresetAmountColors[i];
ret.push({
type: amountColor.type,
displayName: translateFn('color.amount.' + amountColor.name)
});
}
return allAmountColors;
return ret;
}
function getAllAccountCategories(translateFn) {
const allAccountCategories = [];
const ret = [];
const allCategories = AccountCategory.values();
for (let i = 0; i < accountConstants.allCategories.length; i++) {
const accountCategory = accountConstants.allCategories[i];
for (let i = 0; i < allCategories.length; i++) {
const accountCategory = allCategories[i];
allAccountCategories.push({
id: accountCategory.id,
ret.push({
type: accountCategory.type,
displayName: translateFn(accountCategory.name),
defaultAccountIconId: accountCategory.defaultAccountIconId
});
}
return allAccountCategories;
return ret;
}
function getAllAccountTypes(translateFn) {
const allAccountTypes = [];
for (let i = 0; i < accountConstants.allAccountTypesArray.length; i++) {
const accountType = accountConstants.allAccountTypesArray[i];
allAccountTypes.push({
id: accountType.id,
displayName: translateFn(accountType.name)
});
}
return allAccountTypes;
return getLocalizedDisplayNameAndType(AccountType.values(), translateFn);
}
function getAllCategoricalChartTypes(translateFn) {
@@ -1202,60 +1199,15 @@ function getAllStatisticsDateAggregationTypes(translateFn) {
}
function getAllTransactionEditScopeTypes(translateFn) {
const allEditScopeTypes = [];
for (const typeName in transactionConstants.allTransactionEditScopeTypes) {
if (!Object.prototype.hasOwnProperty.call(transactionConstants.allTransactionEditScopeTypes, typeName)) {
continue;
}
const editScopeType = transactionConstants.allTransactionEditScopeTypes[typeName];
allEditScopeTypes.push({
type: editScopeType.type,
displayName: translateFn(editScopeType.name)
});
}
return allEditScopeTypes;
return getLocalizedDisplayNameAndType(TransactionEditScopeType.values(), translateFn);
}
function getAllTransactionTagFilterTypes(translateFn) {
const allTagFilterTypes = [];
for (const typeName in transactionConstants.allTransactionTagFilterTypes) {
if (!Object.prototype.hasOwnProperty.call(transactionConstants.allTransactionTagFilterTypes, typeName)) {
continue;
}
const tagFilterType = transactionConstants.allTransactionTagFilterTypes[typeName];
allTagFilterTypes.push({
type: tagFilterType.type,
displayName: translateFn(tagFilterType.name)
});
}
return allTagFilterTypes;
return getLocalizedDisplayNameAndType(TransactionTagFilterType.values(), translateFn);
}
function getAllTransactionScheduledFrequencyTypes(translateFn) {
const allScheduledFrequencyTypes = [];
for (const typeName in templateConstants.allTemplateScheduledFrequencyTypes) {
if (!Object.prototype.hasOwnProperty.call(templateConstants.allTemplateScheduledFrequencyTypes, typeName)) {
continue;
}
const frequencyType = templateConstants.allTemplateScheduledFrequencyTypes[typeName];
allScheduledFrequencyTypes.push({
type: frequencyType.type,
displayName: translateFn(frequencyType.name)
});
}
return allScheduledFrequencyTypes;
return getLocalizedDisplayNameAndType(ScheduledTemplateFrequencyType.values(), translateFn);
}
function getAllTransactionDefaultCategories(categoryType, locale, translateFn) {
@@ -1263,7 +1215,7 @@ function getAllTransactionDefaultCategories(categoryType, locale, translateFn) {
const categoryTypes = [];
if (categoryType === 0) {
for (let i = categoryConstants.allCategoryTypes.Income; i <= categoryConstants.allCategoryTypes.Transfer; i++) {
for (let i = CategoryType.Income; i <= CategoryType.Transfer; i++) {
categoryTypes.push(i);
}
} else {
@@ -1275,12 +1227,12 @@ function getAllTransactionDefaultCategories(categoryType, locale, translateFn) {
const categoryType = categoryTypes[i];
let defaultCategories = [];
if (categoryType === categoryConstants.allCategoryTypes.Income) {
defaultCategories = copyArrayTo(categoryConstants.defaultIncomeCategories, []);
} else if (categoryType === categoryConstants.allCategoryTypes.Expense) {
defaultCategories = copyArrayTo(categoryConstants.defaultExpenseCategories, []);
} else if (categoryType === categoryConstants.allCategoryTypes.Transfer) {
defaultCategories = copyArrayTo(categoryConstants.defaultTransferCategories, []);
if (categoryType === CategoryType.Income) {
defaultCategories = copyArrayTo(DEFAULT_INCOME_CATEGORIES, []);
} else if (categoryType === CategoryType.Expense) {
defaultCategories = copyArrayTo(DEFAULT_EXPENSE_CATEGORIES, []);
} else if (categoryType === CategoryType.Transfer) {
defaultCategories = copyArrayTo(DEFAULT_TRANSFER_CATEGORIES, []);
}
for (let j = 0; j < defaultCategories.length; j++) {
@@ -1330,15 +1282,15 @@ function getAllDisplayExchangeRates(settingsStore, exchangeRatesData, translateF
});
}
if (settingsStore.appSettings.currencySortByInExchangeRatesPage === currencyConstants.allCurrencySortingTypes.Name.type) {
if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.Name.type) {
availableExchangeRates.sort(function(c1, c2) {
return c1.currencyDisplayName.localeCompare(c2.currencyDisplayName);
});
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === currencyConstants.allCurrencySortingTypes.CurrencyCode.type) {
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.CurrencyCode.type) {
availableExchangeRates.sort(function(c1, c2) {
return c1.currencyCode.localeCompare(c2.currencyCode);
});
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === currencyConstants.allCurrencySortingTypes.ExchangeRate.type) {
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.ExchangeRate.type) {
availableExchangeRates.sort(function(c1, c2) {
const rate1 = parseFloat(c1.rate);
const rate2 = parseFloat(c2.rate);
@@ -1359,8 +1311,8 @@ function getAllDisplayExchangeRates(settingsStore, exchangeRatesData, translateF
function getAllSupportedImportFileTypes(i18nGlobal, translateFn) {
const allSupportedImportFileTypes = [];
for (let i = 0; i < fileConstants.supportedImportFileTypes.length; i++) {
const fileType = fileConstants.supportedImportFileTypes[i];
for (let i = 0; i < SUPPORTED_IMPORT_FILE_TYPES.length; i++) {
const fileType = SUPPORTED_IMPORT_FILE_TYPES[i];
let document = {
language: '',
displayLanguageName: '',
@@ -1434,16 +1386,17 @@ function getEnableDisableOptions(translateFn) {
function getCategorizedAccountsWithDisplayBalance(allVisibleAccounts, showAccountBalance, defaultCurrency, userStore, settingsStore, exchangeRatesStore, translateFn) {
const ret = [];
const allCategories = AccountCategory.values();
const categorizedAccounts = copyObjectTo(getCategorizedAccountsMap(allVisibleAccounts), {});
for (let i = 0; i < accountConstants.allCategories.length; i++) {
const category = accountConstants.allCategories[i];
for (let i = 0; i < allCategories.length; i++) {
const category = allCategories[i];
if (!categorizedAccounts[category.id]) {
if (!categorizedAccounts[category.type]) {
continue;
}
const accountCategory = categorizedAccounts[category.id];
const accountCategory = categorizedAccounts[category.type];
if (accountCategory.accounts) {
for (let i = 0; i < accountCategory.accounts.length; i++) {
@@ -1527,20 +1480,20 @@ function joinMultiText(textArray, translateFn) {
}
function getLocalizedError(error) {
if (error.errorCode === apiConstants.apiNotFoundErrorCode && apiConstants.specifiedApiNotFoundErrors[error.path]) {
if (error.errorCode === KnownErrorCode.ApiNotFound && SPECIFIED_API_NOT_FOUND_ERRORS[error.path]) {
return {
message: `${apiConstants.specifiedApiNotFoundErrors[error.path].message}`
message: `${SPECIFIED_API_NOT_FOUND_ERRORS[error.path].message}`
};
}
if (error.errorCode !== apiConstants.validatorErrorCode) {
if (error.errorCode !== KnownErrorCode.ValidatorError) {
return {
message: `error.${error.errorMessage}`
};
}
for (let i = 0; i < apiConstants.parameterizedErrors.length; i++) {
const errorInfo = apiConstants.parameterizedErrors[i];
for (let i = 0; i < PARAMETERIZED_ERRORS.length; i++) {
const errorInfo = PARAMETERIZED_ERRORS[i];
const matches = error.errorMessage.match(errorInfo.regex);
if (matches && matches.length === errorInfo.parameters.length + 1) {
+5 -3
View File
@@ -1,8 +1,10 @@
export function getIconsInRows(allIconInfos, itemPerRow) {
const ret = [];
import type { IconInfo, IconInfoWithId } from '@/core/icon.ts';
export function getIconsInRows(allIconInfos: IconInfo[], itemPerRow: number): IconInfoWithId[][] {
const ret: IconInfoWithId[][] = [];
let rowCount = 0;
for (let iconInfoId in allIconInfos) {
for (const iconInfoId in allIconInfos) {
if (!Object.prototype.hasOwnProperty.call(allIconInfos, iconInfoId)) {
continue;
}
-8
View File
@@ -1,8 +0,0 @@
export default {
getLicense: () => {
return __EZBOOKKEEPING_LICENSE__; // eslint-disable-line
},
getThirdPartyLicenses: () => {
return __EZBOOKKEEPING_THIRD_PARTY_LICENSES__ || []; // eslint-disable-line
}
};
+7
View File
@@ -0,0 +1,7 @@
export function getLicense(): string {
return __EZBOOKKEEPING_LICENSE__;
}
export function getThirdPartyLicenses(): string[] {
return __EZBOOKKEEPING_THIRD_PARTY_LICENSES__ || [];
}
+2 -2
View File
@@ -1,10 +1,10 @@
import { asyncLoadAssets } from '@/lib/misc.js';
import { asyncLoadAssets } from '@/lib/misc.ts';
import services from '@/lib/services.js';
import {
getAmapSecurityVerificationMethod,
getAmapApiExternalProxyUrl,
getAmapApplicationSecret
} from '@/lib/server_settings.js';
} from '@/lib/server_settings.ts';
import logger from '@/lib/logger.js';
const amapHolder = {
+1 -1
View File
@@ -1,4 +1,4 @@
import { asyncLoadAssets } from '@/lib/misc.js';
import { asyncLoadAssets } from '@/lib/misc.ts';
import services from '@/lib/services.js';
import logger from '@/lib/logger.js';
+1 -1
View File
@@ -1,4 +1,4 @@
import { asyncLoadAssets } from '@/lib/misc.js';
import { asyncLoadAssets } from '@/lib/misc.ts';
import services from '@/lib/services.js';
const googleMapHolder = {
+10 -10
View File
@@ -1,7 +1,7 @@
import mapConstants from '@/consts/map.js';
import { LEAFLET_TILE_SOURCES } from '@/consts/map.ts';
import {
getMapProvider
} from '@/lib/server_settings.js';
} from '@/lib/server_settings.ts';
import {
loadLeafletMapAssets,
@@ -45,8 +45,8 @@ import {
export function getMapWebsite() {
if (getMapProvider() === 'custom') {
return '';
} else if (mapConstants.leafletTileSources[getMapProvider()]) {
return mapConstants.leafletTileSources[getMapProvider()].website;
} else if (LEAFLET_TILE_SOURCES[getMapProvider()]) {
return LEAFLET_TILE_SOURCES[getMapProvider()].website;
} else if (getMapProvider() === 'googlemap') {
return getGoogleMapWebsite();
} else if (getMapProvider() === 'baidumap') {
@@ -57,7 +57,7 @@ export function getMapWebsite() {
}
export function loadMapAssets(language) {
if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') {
if (LEAFLET_TILE_SOURCES[getMapProvider()] || getMapProvider() === 'custom') {
return loadLeafletMapAssets(language);
} else if (getMapProvider() === 'googlemap') {
return loadGoogleMapAssets(language);
@@ -69,7 +69,7 @@ export function loadMapAssets(language) {
}
export function createMapHolder() {
if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') {
if (LEAFLET_TILE_SOURCES[getMapProvider()] || getMapProvider() === 'custom') {
return createLeafletMapHolder(getMapProvider());
} else if (getMapProvider() === 'googlemap') {
return createGoogleMapHolder(getMapProvider());
@@ -87,7 +87,7 @@ export function initMapInstance(mapHolder, mapContainer, options) {
return;
}
if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') {
if (LEAFLET_TILE_SOURCES[getMapProvider()] || getMapProvider() === 'custom') {
createLeafletMapInstance(mapHolder, mapContainer, options);
} else if (mapHolder.mapProvider === 'googlemap') {
createGoogleMapInstance(mapHolder, mapContainer, options);
@@ -103,7 +103,7 @@ export function setMapCenterTo(mapHolder, center, zoomLevel) {
return;
}
if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') {
if (LEAFLET_TILE_SOURCES[getMapProvider()] || getMapProvider() === 'custom') {
setLeafletMapCenterTo(mapHolder, center, zoomLevel);
} else if (mapHolder.mapProvider === 'googlemap') {
setGoogleMapCenterTo(mapHolder, center, zoomLevel);
@@ -119,7 +119,7 @@ export function setMapCenterMarker(mapHolder, position) {
return;
}
if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') {
if (LEAFLET_TILE_SOURCES[getMapProvider()] || getMapProvider() === 'custom') {
setLeafletMapCenterMaker(mapHolder, position);
} else if (mapHolder.mapProvider === 'googlemap') {
setGoogleMapCenterMaker(mapHolder, position);
@@ -135,7 +135,7 @@ export function removeMapCenterMarker(mapHolder) {
return;
}
if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') {
if (LEAFLET_TILE_SOURCES[getMapProvider()] || getMapProvider() === 'custom') {
removeLeafletMapCenterMaker(mapHolder);
} else if (mapHolder.mapProvider === 'googlemap') {
removeGoogleMapCenterMaker(mapHolder);
+4 -4
View File
@@ -1,4 +1,4 @@
import mapConstants from '@/consts/map.js';
import { LEAFLET_TILE_SOURCES } from '@/consts/map.ts';
import {
isMapDataFetchProxyEnabled,
getCustomMapTileLayerUrl,
@@ -9,7 +9,7 @@ import {
getCustomMapDefaultZoomLevel,
getTomTomMapAPIKey,
getTianDiTuMapAPIKey
} from '@/lib/server_settings.js';
} from '@/lib/server_settings.ts';
import services from '@/lib/services.js';
const leafletHolder = {
@@ -24,7 +24,7 @@ export function loadLeafletMapAssets() {
}
export function createLeafletMapHolder(mapProvider) {
const mapTileSource = mapConstants.leafletTileSources[mapProvider];
const mapTileSource = LEAFLET_TILE_SOURCES[mapProvider];
if (mapProvider !== 'custom' && !mapTileSource) {
return null;
@@ -60,7 +60,7 @@ export function createLeafletMapInstance(mapHolder, mapContainer, options) {
let mapTileSource = null;
if (mapHolder.mapProvider !== 'custom') {
mapTileSource = Object.assign({}, mapConstants.leafletTileSources[mapHolder.mapProvider]);
mapTileSource = Object.assign({}, LEAFLET_TILE_SOURCES[mapHolder.mapProvider]);
} else {
mapTileSource = createCustomMapSource();
}
-229
View File
@@ -1,229 +0,0 @@
import Clipboard from 'clipboard';
import CryptoJS from 'crypto-js';
import uaParser from 'ua-parser-js';
import { base64encode } from './common.js';
export function asyncLoadAssets(type, assetUrl) {
return new Promise(function (resolve, reject) {
let addElement = false;
let el = null;
if (type === 'js') {
el = document.querySelector('script[src="' + assetUrl + '"]');
} else if (type === 'css') {
el = document.querySelector('link[href="' + assetUrl + '"]');
} else {
reject({
type: type,
assetUrl: assetUrl,
error: 'notsupport'
});
return;
}
if (!el) {
if (type === 'js') {
el = document.createElement('script');
el.setAttribute('type', 'text/javascript');
el.setAttribute('async', 'true');
el.setAttribute('src', assetUrl);
} else if (type === 'css') {
el = document.createElement('link');
el.setAttribute('rel', 'stylesheet');
el.setAttribute('type', 'text/css');
el.setAttribute('href', assetUrl);
}
addElement = true;
} else if (el.hasAttribute('data-loaded')) {
resolve({
type: type,
assetUrl: assetUrl
});
return;
}
el.addEventListener('load', () => {
el.setAttribute('data-loaded', true);
resolve({
type: type,
assetUrl: assetUrl
});
});
el.addEventListener('error', () => {
reject({
type: type,
assetUrl: assetUrl,
error: 'error'
});
});
el.addEventListener('abort', () => {
reject({
type: type,
assetUrl: assetUrl,
error: 'abort'
});
});
if (addElement) {
document.head.appendChild(el);
}
});
}
export function generateRandomString() {
let baseString = 'ebk_' + new Date().getTime();
if (crypto && crypto.getRandomValues) {
const randoms = new Uint8Array(256);
crypto.getRandomValues(randoms);
baseString += '_' + base64encode(randoms);
} else {
baseString += '_' + Math.random();
}
return CryptoJS.SHA256(baseString).toString();
}
export function generateRandomUUID() {
const randomString = generateRandomString();
// convert hash string to UUID Version 8
const uuid = randomString.substring(0, 8) + '-'
+ randomString.substring(8, 12) + '-'
+ '8' + randomString.substring(13, 16) + '-'
+ (0x8 | (parseInt(randomString.charAt(16), 16) & 0x3)).toString(16) + randomString.substring(17, 20) + '-'
+ randomString.substring(20, 32);
return uuid;
}
export function isSessionUserAgentCreatedByCli(ua) {
return ua === 'ezbookkeeping Cli';
}
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(uaInfo) {
if (!uaInfo) {
return '';
}
let result = '';
if (uaInfo.device && uaInfo.device.model) {
result = uaInfo.device.model;
} else if (uaInfo.os && uaInfo.os.name) {
result = uaInfo.os.name;
if (uaInfo.os.version) {
result += ' ' + uaInfo.os.version;
}
}
if (uaInfo.browser && 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 parseSessionInfo(token) {
const isCreatedByCli = isSessionUserAgentCreatedByCli(token.userAgent);
const uaInfo = parseUserAgent(token.userAgent);
let deviceType = '';
if (isCreatedByCli) {
deviceType = 'cli';
} else {
if (uaInfo && uaInfo.device) {
if (uaInfo.device.type === 'mobile') {
deviceType = 'phone';
} else if (uaInfo.device.type === 'wearable') {
deviceType = 'wearable';
} else if (uaInfo.device.type === 'tablet') {
deviceType = 'tablet';
} else if (uaInfo.device.type === 'smarttv') {
deviceType = 'tv';
} else {
deviceType = 'default';
}
} else {
deviceType = 'default';
}
}
return {
tokenId: token.tokenId,
isCurrent: token.isCurrent,
deviceType: deviceType,
deviceInfo: isCreatedByCli ? token.userAgent : parseDeviceInfo(uaInfo),
createdByCli: isCreatedByCli,
lastSeen: token.lastSeen
}
}
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;
};
}
+112
View File
@@ -0,0 +1,112 @@
import CryptoJS from 'crypto-js';
import { base64encode } from './common.ts';
export interface AsyncLoadAssetsResult {
readonly type: string;
readonly assetUrl: string;
}
export function asyncLoadAssets(type: string, assetUrl: string): Promise<AsyncLoadAssetsResult> {
return new Promise(function (resolve, reject) {
let addElement = false;
let el = null;
if (type === 'js') {
el = document.querySelector('script[src="' + assetUrl + '"]');
} else if (type === 'css') {
el = document.querySelector('link[href="' + assetUrl + '"]');
} else {
reject({
type: type,
assetUrl: assetUrl,
error: 'notsupport'
});
return;
}
if (!el) {
if (type === 'js') {
el = document.createElement('script');
el.setAttribute('type', 'text/javascript');
el.setAttribute('async', 'true');
el.setAttribute('src', assetUrl);
} else if (type === 'css') {
el = document.createElement('link');
el.setAttribute('rel', 'stylesheet');
el.setAttribute('type', 'text/css');
el.setAttribute('href', assetUrl);
}
addElement = true;
} else if (el.hasAttribute('data-loaded')) {
resolve({
type: type,
assetUrl: assetUrl
});
return;
}
if (!el) {
reject({
type: type,
assetUrl: assetUrl,
error: 'unexpected'
});
return;
}
el.addEventListener('load', () => {
el.setAttribute('data-loaded', 'true');
resolve({
type: type,
assetUrl: assetUrl
});
});
el.addEventListener('error', () => {
reject({
type: type,
assetUrl: assetUrl,
error: 'error'
});
});
el.addEventListener('abort', () => {
reject({
type: type,
assetUrl: assetUrl,
error: 'abort'
});
});
if (addElement) {
document.head.appendChild(el);
}
});
}
export function generateRandomString(): string {
let baseString = 'ebk_' + new Date().getTime();
if (crypto && crypto.getRandomValues) {
const randoms = new Uint8Array(256);
crypto.getRandomValues(randoms);
baseString += '_' + base64encode(randoms.buffer);
} else {
baseString += '_' + Math.random();
}
return CryptoJS.SHA256(baseString).toString();
}
export function generateRandomUUID(): string {
const randomString = generateRandomString();
// convert hash string to UUID Version 8
const uuid = randomString.substring(0, 8) + '-'
+ randomString.substring(8, 12) + '-'
+ '8' + randomString.substring(13, 16) + '-'
+ (0x8 | (parseInt(randomString.charAt(16), 16) & 0x3)).toString(16) + randomString.substring(17, 20) + '-'
+ randomString.substring(20, 32);
return uuid;
}
+1 -1
View File
@@ -1,6 +1,6 @@
import numeralConstants from '@/consts/numeral.js';
import { isString, isNumber, removeAll } from './common.js';
import { isString, isNumber, removeAll } from './common.ts';
export function appendDigitGroupingSymbol(value, options) {
if (isNumber(value)) {
-109
View File
@@ -1,109 +0,0 @@
const serverSettingsGlobalVariableName = 'EZBOOKKEEPING_SERVER_SETTINGS';
function getServerSetting(key) {
const settings = window[serverSettingsGlobalVariableName] || {};
return settings[key];
}
export function isUserRegistrationEnabled() {
return getServerSetting('r') === 1;
}
export function isUserForgetPasswordEnabled() {
return getServerSetting('f') === 1;
}
export function isUserVerifyEmailEnabled() {
return getServerSetting('v') === 1;
}
export function isTransactionPicturesEnabled() {
return getServerSetting('p') === 1;
}
export function isUserScheduledTransactionEnabled() {
return getServerSetting('s') === 1;
}
export function isDataExportingEnabled() {
return getServerSetting('e') === 1;
}
export function isDataImportingEnabled() {
return getServerSetting('i') === 1;
}
export function getLoginPageTips() {
return getServerSetting('lpt');
}
export function getMapProvider() {
return getServerSetting('m');
}
export function isMapDataFetchProxyEnabled() {
return getServerSetting('mp') === 1;
}
export function getCustomMapTileLayerUrl() {
return getServerSetting('cmsu');
}
export function getCustomMapAnnotationLayerUrl() {
return getServerSetting('cmau');
}
export function isCustomMapAnnotationLayerDataFetchProxyEnabled() {
return getServerSetting('cmap') === 1;
}
export function getCustomMapMinZoomLevel() {
const zoomLevelSettings = (getServerSetting('cmzl') || '').split('-');
return (zoomLevelSettings && zoomLevelSettings[0]) ? parseInt(zoomLevelSettings[0]) : 1;
}
export function getCustomMapMaxZoomLevel() {
const zoomLevelSettings = (getServerSetting('cmzl') || '').split('-');
return (zoomLevelSettings && zoomLevelSettings[1]) ? parseInt(zoomLevelSettings[1]) : 18;
}
export function getCustomMapDefaultZoomLevel() {
const zoomLevelSettings = (getServerSetting('cmzl') || '').split('-');
return (zoomLevelSettings && zoomLevelSettings[2]) ? parseInt(zoomLevelSettings[2]) : 14;
}
export function getTomTomMapAPIKey() {
return getServerSetting('tmak');
}
export function getTianDiTuMapAPIKey() {
return getServerSetting('tdak');
}
export function getGoogleMapAPIKey() {
return getServerSetting('gmak');
}
export function getBaiduMapAK() {
return getServerSetting('bmak');
}
export function getAmapApplicationKey() {
return getServerSetting('amak');
}
export function getAmapSecurityVerificationMethod() {
return getServerSetting('amsv');
}
export function getAmapApiExternalProxyUrl() {
return getServerSetting('amep');
}
export function getAmapApplicationSecret() {
return getServerSetting('amas');
}
export function getExchangeRatesRequestTimeout() {
return getServerSetting('errt');
}
+107
View File
@@ -0,0 +1,107 @@
function getServerSetting(key: string): string | number | boolean | undefined | null {
const settings = window.EZBOOKKEEPING_SERVER_SETTINGS || {};
return settings[key];
}
export function isUserRegistrationEnabled(): boolean {
return getServerSetting('r') === 1;
}
export function isUserForgetPasswordEnabled(): boolean {
return getServerSetting('f') === 1;
}
export function isUserVerifyEmailEnabled(): boolean {
return getServerSetting('v') === 1;
}
export function isTransactionPicturesEnabled(): boolean {
return getServerSetting('p') === 1;
}
export function isUserScheduledTransactionEnabled(): boolean {
return getServerSetting('s') === 1;
}
export function isDataExportingEnabled(): boolean {
return getServerSetting('e') === 1;
}
export function isDataImportingEnabled(): boolean {
return getServerSetting('i') === 1;
}
export function getLoginPageTips(): string {
return getServerSetting('lpt') as string;
}
export function getMapProvider(): string {
return getServerSetting('m') as string;
}
export function isMapDataFetchProxyEnabled(): boolean {
return getServerSetting('mp') === 1;
}
export function getCustomMapTileLayerUrl(): string {
return getServerSetting('cmsu') as string;
}
export function getCustomMapAnnotationLayerUrl(): string {
return getServerSetting('cmau') as string;
}
export function isCustomMapAnnotationLayerDataFetchProxyEnabled(): boolean {
return getServerSetting('cmap') === 1;
}
export function getCustomMapMinZoomLevel(): number {
const zoomLevelSettings = (getServerSetting('cmzl') as string || '').split('-');
return (zoomLevelSettings && zoomLevelSettings[0]) ? parseInt(zoomLevelSettings[0]) : 1;
}
export function getCustomMapMaxZoomLevel(): number {
const zoomLevelSettings = (getServerSetting('cmzl') as string || '').split('-');
return (zoomLevelSettings && zoomLevelSettings[1]) ? parseInt(zoomLevelSettings[1]) : 18;
}
export function getCustomMapDefaultZoomLevel(): number {
const zoomLevelSettings = (getServerSetting('cmzl') as string || '').split('-');
return (zoomLevelSettings && zoomLevelSettings[2]) ? parseInt(zoomLevelSettings[2]) : 14;
}
export function getTomTomMapAPIKey(): string {
return getServerSetting('tmak') as string;
}
export function getTianDiTuMapAPIKey(): string {
return getServerSetting('tdak') as string;
}
export function getGoogleMapAPIKey(): string {
return getServerSetting('gmak') as string;
}
export function getBaiduMapAK(): string {
return getServerSetting('bmak') as string;
}
export function getAmapApplicationKey(): string {
return getServerSetting('amak') as string;
}
export function getAmapSecurityVerificationMethod(): string {
return getServerSetting('amsv') as string;
}
export function getAmapApiExternalProxyUrl(): string {
return getServerSetting('amep') as string;
}
export function getAmapApplicationSecret(): string {
return getServerSetting('amas') as string;
}
export function getExchangeRatesRequestTimeout(): number {
return getServerSetting('errt') as number;
}
+29 -18
View File
@@ -1,25 +1,36 @@
import axios from 'axios';
import apiConstants from '@/consts/api.js';
import {
BASE_API_URL_PATH,
BASE_QRCODE_PATH,
BASE_PROXY_URL_PATH,
BASE_AMAP_API_PROXY_URL_PATH,
DEFAULT_API_TIMEOUT,
DEFAULT_UPLOAD_API_TIMEOUT,
DEFAULT_IMPORT_API_TIMEOUT,
GOOGLE_MAP_JAVASCRIPT_URL,
BAIDU_MAP_JAVASCRIPT_URL,
AMAP_JAVASCRIPT_URL
} from '@/consts/api.ts';
import userState from './userstate.js';
import {
isDefined,
isBoolean
} from './common.js';
} from './common.ts';
import {
getGoogleMapAPIKey,
getBaiduMapAK,
getAmapApplicationKey,
getExchangeRatesRequestTimeout
} from './server_settings.js';
} from './server_settings.ts';
import { getTimezoneOffsetMinutes } from './datetime.js';
import { generateRandomUUID } from './misc.js';
import { generateRandomUUID } from './misc.ts';
let needBlockRequest = false;
let blockedRequests = [];
axios.defaults.baseURL = apiConstants.baseApiUrlPath;
axios.defaults.timeout = apiConstants.defaultTimeout;
axios.defaults.baseURL = BASE_API_URL_PATH;
axios.defaults.timeout = DEFAULT_API_TIMEOUT;
axios.interceptors.request.use(config => {
const token = userState.getToken();
@@ -202,7 +213,7 @@ export default {
return axios.postForm('v1/users/avatar/update.json', {
avatar: avatarFile
}, {
timeout: apiConstants.uploadTimeout
timeout: DEFAULT_UPLOAD_API_TIMEOUT
});
},
removeAvatar: () => {
@@ -471,7 +482,7 @@ export default {
fileType: fileType,
file: importFile
}, {
timeout: apiConstants.uploadTimeout
timeout: DEFAULT_UPLOAD_API_TIMEOUT
});
},
importTransactions: ({ transactions, clientSessionId }) => {
@@ -479,7 +490,7 @@ export default {
transactions: transactions,
clientSessionId: clientSessionId
}, {
timeout: apiConstants.importTimeout
timeout: DEFAULT_IMPORT_API_TIMEOUT
});
},
uploadTransactionPicture: ({ pictureFile, clientSessionId }) => {
@@ -487,7 +498,7 @@ export default {
picture: pictureFile,
clientSessionId: clientSessionId
}, {
timeout: apiConstants.uploadTimeout
timeout: DEFAULT_UPLOAD_API_TIMEOUT
});
},
removeUnusedTransactionPicture: ({ id }) => {
@@ -639,15 +650,15 @@ export default {
getLatestExchangeRates: ({ ignoreError }) => {
return axios.get('v1/exchange_rates/latest.json', {
ignoreError: !!ignoreError,
timeout: getExchangeRatesRequestTimeout() || apiConstants.defaultTimeout
timeout: getExchangeRatesRequestTimeout() || DEFAULT_API_TIMEOUT
});
},
generateQrCodeUrl: (qrCodeName) => {
return `${apiConstants.baseQrcodePath}/${qrCodeName}.png`;
return `${BASE_QRCODE_PATH}/${qrCodeName}.png`;
},
generateMapProxyTileImageUrl: (mapProvider, language) => {
const token = userState.getToken();
let url = `${apiConstants.baseProxyUrlPath}/map/tile/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`;
let url = `${BASE_PROXY_URL_PATH}/map/tile/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`;
if (language) {
url = url + `&language=${language}`;
@@ -657,7 +668,7 @@ export default {
},
generateMapProxyAnnotationImageUrl: (mapProvider, language) => {
const token = userState.getToken();
let url = `${apiConstants.baseProxyUrlPath}/map/annotation/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`;
let url = `${BASE_PROXY_URL_PATH}/map/annotation/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`;
if (language) {
url = url + `&language=${language}`;
@@ -666,7 +677,7 @@ export default {
return url;
},
generateGoogleMapJavascriptUrl: (language, callbackFnName) => {
let url = `${apiConstants.googleMapJavascriptUrl}?key=${getGoogleMapAPIKey()}&libraries=core,marker&callback=${callbackFnName}`;
let url = `${GOOGLE_MAP_JAVASCRIPT_URL}?key=${getGoogleMapAPIKey()}&libraries=core,marker&callback=${callbackFnName}`;
if (language) {
url = url + `&language=${language}`;
@@ -675,13 +686,13 @@ export default {
return url;
},
generateBaiduMapJavascriptUrl: (callbackFnName) => {
return `${apiConstants.baiduMapJavascriptUrl}&ak=${getBaiduMapAK()}&callback=${callbackFnName}`;
return `${BAIDU_MAP_JAVASCRIPT_URL}&ak=${getBaiduMapAK()}&callback=${callbackFnName}`;
},
generateAmapJavascriptUrl: (callbackFnName) => {
return `${apiConstants.amapJavascriptUrl}&key=${getAmapApplicationKey()}&plugin=AMap.ToolBar&callback=${callbackFnName}`;
return `${AMAP_JAVASCRIPT_URL}&key=${getAmapApplicationKey()}&plugin=AMap.ToolBar&callback=${callbackFnName}`;
},
generateAmapApiInternalProxyUrl: () => {
return `${window.location.origin}${apiConstants.baseAmapApiProxyUrlPath}`;
return `${window.location.origin}${BASE_AMAP_API_PROXY_URL_PATH}`;
},
getInternalAvatarUrlWithToken(avatarUrl, disableBrowserCache) {
if (!avatarUrl) {
+116
View File
@@ -0,0 +1,116 @@
import uaParser from 'ua-parser-js';
import { CliUserAgent, type TokenInfoResponse, SessionInfo } from '@/models/token.ts';
interface UserAgentInfo {
device: {
vendor?: string;
model?: string;
type?: string;
};
os: {
name?: string;
version?: string;
};
browser: {
name?: string;
version?: string;
};
}
function parseUserAgent(ua: string): UserAgentInfo {
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 isSessionUserAgentCreatedByCli(ua: string): boolean {
return ua === CliUserAgent;
}
function parseDeviceInfo(uaInfo: UserAgentInfo): string {
if (!uaInfo) {
return '';
}
let result = '';
if (uaInfo.device && uaInfo.device.model) {
result = uaInfo.device.model;
} else if (uaInfo.os && uaInfo.os.name) {
result = uaInfo.os.name;
if (uaInfo.os.version) {
result += ' ' + uaInfo.os.version;
}
}
if (uaInfo.browser && 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 parseSessionInfo(token: TokenInfoResponse): SessionInfo {
const isCreatedByCli = isSessionUserAgentCreatedByCli(token.userAgent);
const uaInfo = parseUserAgent(token.userAgent);
let deviceType = '';
if (isCreatedByCli) {
deviceType = 'cli';
} else {
if (uaInfo && uaInfo.device) {
if (uaInfo.device.type === 'mobile') {
deviceType = 'phone';
} else if (uaInfo.device.type === 'wearable') {
deviceType = 'wearable';
} else if (uaInfo.device.type === 'tablet') {
deviceType = 'tablet';
} else if (uaInfo.device.type === 'smarttv') {
deviceType = 'tv';
} else {
deviceType = 'default';
}
} else {
deviceType = 'default';
}
}
return SessionInfo.of(
token.tokenId,
token.isCurrent,
deviceType,
isCreatedByCli ? token.userAgent : parseDeviceInfo(uaInfo),
isCreatedByCli,
token.lastSeen
);
}
+5 -5
View File
@@ -1,5 +1,5 @@
import timezoneConstants from '@/consts/timezone.js';
import currencyConstants from '@/consts/currency.js';
import { TimezoneTypeForStatistics } from '@/core/timezone.ts';
import { CurrencySortingType } from '@/core/currency.ts';
import statisticsConstants from '@/consts/statistics.js';
const settingsLocalStorageKey = 'ebk_app_settings';
@@ -15,15 +15,15 @@ const defaultSettings = {
autoSaveTransactionDraft: 'disabled',
autoGetCurrentGeoLocation: false,
showAmountInHomePage: true,
timezoneUsedForStatisticsInHomePage: timezoneConstants.defaultTimezoneTypesUsedForStatistics,
timezoneUsedForStatisticsInHomePage: TimezoneTypeForStatistics.Default.type,
itemsCountInTransactionListPage: 15,
showTotalAmountInTransactionListPage: true,
showTagInTransactionListPage: true,
showAccountBalance: true,
currencySortByInExchangeRatesPage: currencyConstants.defaultCurrencySortingType,
currencySortByInExchangeRatesPage: CurrencySortingType.Default.type,
statistics: {
defaultChartDataType: statisticsConstants.defaultChartDataType,
defaultTimezoneType: timezoneConstants.defaultTimezoneTypesUsedForStatistics,
defaultTimezoneType: TimezoneTypeForStatistics.Default.type,
defaultAccountFilter: {},
defaultTransactionCategoryFilter: {},
defaultSortingType: statisticsConstants.defaultSortingType,
+21 -21
View File
@@ -1,8 +1,8 @@
import categoryConstants from '@/consts/category.js';
import transactionConstants from '@/consts/transaction.js';
import { CategoryType } from '@/core/category.ts';
import { TransactionType } from '@/core/transaction.ts';
import {
isNumber
} from './common.js';
} from './common.ts';
import {
getBrowserTimezoneOffsetMinutes,
getDummyUnixTimeForLocalUsage
@@ -32,48 +32,48 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC
}
}
if (allCategories[categoryConstants.allCategoryTypes.Expense] &&
allCategories[categoryConstants.allCategoryTypes.Expense].length) {
if (allCategories[CategoryType.Expense] &&
allCategories[CategoryType.Expense].length) {
if (options.categoryId && options.categoryId !== '0') {
if (isSubCategoryIdAvailable(allCategories[categoryConstants.allCategoryTypes.Expense], options.categoryId)) {
if (isSubCategoryIdAvailable(allCategories[CategoryType.Expense], options.categoryId)) {
transaction.expenseCategory = options.categoryId;
} else {
transaction.expenseCategory = getFirstAvailableSubCategoryId(allCategories[categoryConstants.allCategoryTypes.Expense], options.categoryId);
transaction.expenseCategory = getFirstAvailableSubCategoryId(allCategories[CategoryType.Expense], options.categoryId);
}
}
if (!transaction.expenseCategory) {
transaction.expenseCategory = getFirstAvailableCategoryId(allCategories[categoryConstants.allCategoryTypes.Expense]);
transaction.expenseCategory = getFirstAvailableCategoryId(allCategories[CategoryType.Expense]);
}
}
if (allCategories[categoryConstants.allCategoryTypes.Income] &&
allCategories[categoryConstants.allCategoryTypes.Income].length) {
if (allCategories[CategoryType.Income] &&
allCategories[CategoryType.Income].length) {
if (options.categoryId && options.categoryId !== '0') {
if (isSubCategoryIdAvailable(allCategories[categoryConstants.allCategoryTypes.Income], options.categoryId)) {
if (isSubCategoryIdAvailable(allCategories[CategoryType.Income], options.categoryId)) {
transaction.incomeCategory = options.categoryId;
} else {
transaction.incomeCategory = getFirstAvailableSubCategoryId(allCategories[categoryConstants.allCategoryTypes.Income], options.categoryId);
transaction.incomeCategory = getFirstAvailableSubCategoryId(allCategories[CategoryType.Income], options.categoryId);
}
}
if (!transaction.incomeCategory) {
transaction.incomeCategory = getFirstAvailableCategoryId(allCategories[categoryConstants.allCategoryTypes.Income]);
transaction.incomeCategory = getFirstAvailableCategoryId(allCategories[CategoryType.Income]);
}
}
if (allCategories[categoryConstants.allCategoryTypes.Transfer] &&
allCategories[categoryConstants.allCategoryTypes.Transfer].length) {
if (allCategories[CategoryType.Transfer] &&
allCategories[CategoryType.Transfer].length) {
if (options.categoryId && options.categoryId !== '0') {
if (isSubCategoryIdAvailable(allCategories[categoryConstants.allCategoryTypes.Transfer], options.categoryId)) {
if (isSubCategoryIdAvailable(allCategories[CategoryType.Transfer], options.categoryId)) {
transaction.transferCategory = options.categoryId;
} else {
transaction.transferCategory = getFirstAvailableSubCategoryId(allCategories[categoryConstants.allCategoryTypes.Transfer], options.categoryId);
transaction.transferCategory = getFirstAvailableSubCategoryId(allCategories[CategoryType.Transfer], options.categoryId);
}
}
if (!transaction.transferCategory) {
transaction.transferCategory = getFirstAvailableCategoryId(allCategories[categoryConstants.allCategoryTypes.Transfer]);
transaction.transferCategory = getFirstAvailableCategoryId(allCategories[CategoryType.Transfer]);
}
}
@@ -128,11 +128,11 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC
transaction.type = transaction2.type;
if (transaction.type === transactionConstants.allTransactionTypes.Expense) {
if (transaction.type === TransactionType.Expense) {
transaction.expenseCategory = transaction2.categoryId || '';
} else if (transaction.type === transactionConstants.allTransactionTypes.Income) {
} else if (transaction.type === TransactionType.Income) {
transaction.incomeCategory = transaction2.categoryId || '';
} else if (transaction.type === transactionConstants.allTransactionTypes.Transfer) {
} else if (transaction.type === TransactionType.Transfer) {
transaction.transferCategory = transaction2.categoryId || '';
}
+25 -17
View File
@@ -1,23 +1,25 @@
import colorConstants from '@/consts/color.js';
import { ThemeType } from '@/core/theme.ts';
export function getSystemTheme() {
import { type AmountColor, PresetAmountColor } from '@/core/color.ts';
export function getSystemTheme(): ThemeType {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
return ThemeType.Dark;
} else {
return 'light';
return ThemeType.Light;
}
}
export function getExpenseAndIncomeAmountColor(expenseAmountColorType, incomeAmountColorType, isDarkMode) {
let expenseAmountColor = expenseAmountColorType ? colorConstants.allAmountColorTypesMap[expenseAmountColorType] : null;
let incomeAmountColor = incomeAmountColorType ? colorConstants.allAmountColorTypesMap[incomeAmountColorType] : null;
export function getExpenseAndIncomeAmountColor(expenseAmountColorType: number, incomeAmountColorType: number, isDarkMode: boolean): AmountColor {
let expenseAmountColor = expenseAmountColorType ? PresetAmountColor.valueOf(expenseAmountColorType) : null;
let incomeAmountColor = incomeAmountColorType ? PresetAmountColor.valueOf(incomeAmountColorType) : null;
if (!expenseAmountColor) {
expenseAmountColor = colorConstants.defaultExpenseAmountColor;
expenseAmountColor = PresetAmountColor.DefaultExpenseColor;
}
if (!incomeAmountColor) {
incomeAmountColor = colorConstants.defaultIncomeAmountColor;
incomeAmountColor = PresetAmountColor.DefaultIncomeColor;
}
if (isDarkMode) {
@@ -33,22 +35,28 @@ export function getExpenseAndIncomeAmountColor(expenseAmountColorType, incomeAmo
}
}
export function setExpenseAndIncomeAmountColor(expenseAmountColorType, incomeAmountColorType) {
let expenseAmountColor = expenseAmountColorType ? colorConstants.allAmountColorTypesMap[expenseAmountColorType] : null;
let incomeAmountColor = incomeAmountColorType ? colorConstants.allAmountColorTypesMap[incomeAmountColorType] : null;
export function setExpenseAndIncomeAmountColor(expenseAmountColorType: number, incomeAmountColorType: number): void {
let expenseAmountColor = expenseAmountColorType ? PresetAmountColor.valueOf(expenseAmountColorType) : null;
let incomeAmountColor = incomeAmountColorType ? PresetAmountColor.valueOf(incomeAmountColorType) : null;
if (!expenseAmountColor) {
expenseAmountColor = colorConstants.defaultExpenseAmountColor;
expenseAmountColor = PresetAmountColor.DefaultExpenseColor;
}
if (!incomeAmountColor) {
incomeAmountColor = colorConstants.defaultIncomeAmountColor;
incomeAmountColor = PresetAmountColor.DefaultIncomeColor;
}
const htmlElement = document.querySelector('html');
for (let i = 0; i < colorConstants.allAmountColorsArray.length; i++) {
const amountColor = colorConstants.allAmountColorsArray[i];
if (!htmlElement) {
return;
}
const allPresetAmountColors = PresetAmountColor.values();
for (let i = 0; i < allPresetAmountColors.length; i++) {
const amountColor = allPresetAmountColors[i];
if (amountColor.type === expenseAmountColor.type) {
if (!htmlElement.classList.contains(amountColor.expenseClassName)) {
@@ -68,7 +76,7 @@ export function setExpenseAndIncomeAmountColor(expenseAmountColorType, incomeAmo
}
}
export function startDownloadFile(fileName, fileData) {
export function startDownloadFile(fileName: string, fileData: Blob): void {
const dataObjectUrl = URL.createObjectURL(fileData);
const dataLink = document.createElement('a');
+12 -9
View File
@@ -1,8 +1,8 @@
import { f7, f7ready } from 'framework7-vue';
import fontConstants from '@/consts/font.js';
import { isEnableAnimate } from './settings.js';
import { translateError } from './i18n.js';
import { FontSize, FONT_SIZE_PREVIEW_CLASSNAME_PREFIX } from '@/core/font.ts';
import { isEnableAnimate } from '../settings.js';
import { translateError } from '../i18n.js';
export function showAlert(message, confirmCallback, translateFn) {
f7ready((f7) => {
@@ -126,9 +126,10 @@ export function autoChangeTextareaSize(el) {
export function setAppFontSize(type) {
const htmlElement = elements('html');
const allFontSizes = FontSize.values();
for (let i = 0; i < fontConstants.allFontSizeArray.length; i++) {
const fontSizeType = fontConstants.allFontSizeArray[i];
for (let i = 0; i < allFontSizes.length; i++) {
const fontSizeType = allFontSizes[i];
if (fontSizeType.type === type) {
if (!htmlElement.hasClass(fontSizeType.className)) {
@@ -141,15 +142,17 @@ export function setAppFontSize(type) {
}
export function getFontSizePreviewClassName(type) {
for (let i = 0; i < fontConstants.allFontSizeArray.length; i++) {
const fontSizeType = fontConstants.allFontSizeArray[i];
const allFontSizes = FontSize.values();
for (let i = 0; i < allFontSizes.length; i++) {
const fontSizeType = allFontSizes[i];
if (fontSizeType.type === type) {
return fontConstants.fontSizePreviewClassNamePrefix + fontSizeType.className;
return FONT_SIZE_PREVIEW_CLASSNAME_PREFIX + fontSizeType.className;
}
}
return fontConstants.fontSizePreviewClassNamePrefix + fontConstants.defaultFontSize.className;
return FONT_SIZE_PREVIEW_CLASSNAME_PREFIX + FontSize.Default.className;
}
export function scrollToSelectedItem(parentEl, containerSelector, selectedItemSelector) {
+1 -1
View File
@@ -1,6 +1,6 @@
import CryptoJS from 'crypto-js';
import { isString, isObject } from './common.js';
import { isString, isObject } from './common.ts';
import { isEnableApplicationLock } from './settings.js';
import logger from './logger.js';
+9 -9
View File
@@ -1,11 +1,11 @@
export function isProduction() {
return process.env.NODE_ENV === 'production';
export function isProduction(): boolean {
return __EZBOOKKEEPING_IS_PRODUCTION__;
}
export function getVersion() {
export function getVersion(): string {
const isRelease = !getBuildTime();
const commitHash = __EZBOOKKEEPING_BUILD_COMMIT_HASH__; // eslint-disable-line
let version = __EZBOOKKEEPING_VERSION__; // eslint-disable-line
const commitHash = __EZBOOKKEEPING_BUILD_COMMIT_HASH__;
let version = __EZBOOKKEEPING_VERSION__;
if (version && (!isRelease || !isProduction())) {
version += '-dev';
@@ -22,18 +22,18 @@ export function getVersion() {
return version;
}
export function getBuildTime() {
return __EZBOOKKEEPING_BUILD_UNIX_TIME__; // eslint-disable-line
export function getBuildTime(): string {
return __EZBOOKKEEPING_BUILD_UNIX_TIME__;
}
export function getMobileVersionPath() {
export function getMobileVersionPath(): string {
if (isProduction()) {
return '../mobile';
} else {
return 'mobile.html';
}
}
export function getDesktopVersionPath() {
export function getDesktopVersionPath(): string {
if (isProduction()) {
return '../desktop';
} else {
+2 -2
View File
@@ -6,10 +6,10 @@ import {
arrayBufferToString,
base64encode,
base64decode
} from './common.js';
} from './common.ts';
import {
generateRandomString
} from './misc.js';
} from './misc.ts';
const publicKeyCredentialCreationOptionsBaseTemplate = {
attestation: "none",
+10 -2
View File
@@ -2,10 +2,18 @@ import en from './en.json';
import vi from './vi.json';
import zhHans from './zh_Hans.json';
export const defaultLanguage = 'en';
interface LanguageInfo {
name: string,
displayName: string,
alternativeLanguageTag: string,
aliases?: string[],
content: object
}
export const defaultLanguage: string = 'en';
// To add new languages, please refer to https://ezbookkeeping.mayswind.net/translating
export const allLanguages = {
export const allLanguages: Record<string, LanguageInfo> = {
'en': {
name: 'English',
displayName: 'English',
+2 -2
View File
@@ -79,7 +79,7 @@ import 'line-awesome/dist/line-awesome/css/line-awesome.css';
import VueDatePicker from '@vuepic/vue-datepicker';
import '@vuepic/vue-datepicker/dist/main.css';
import { getVersion, getBuildTime } from '@/lib/version.js';
import { getVersion, getBuildTime } from '@/lib/version.ts';
import userstate from '@/lib/userstate.js';
import {
getI18nOptions,
@@ -93,7 +93,7 @@ import {
showLoading,
hideLoading,
routeBackOnError
} from '@/lib/ui.mobile.js';
} from '@/lib/ui/mobile.js';
import PinCodeInput from '@/components/common/PinCodeInput.vue';
import MapView from '@/components/common/MapView.vue';

Some files were not shown because too many files have changed in this diff Show More