use for-of statements to replace for and for-in

This commit is contained in:
MaysWind
2025-09-14 17:18:01 +08:00
parent 4700446ca0
commit 1a8ce7d58d
29 changed files with 455 additions and 579 deletions
@@ -151,14 +151,8 @@ function updateFrequencyValue(value: number, selected: boolean | null): void {
frequencyValue.value = sortNumbersArray(newFrequencyValues); frequencyValue.value = sortNumbersArray(newFrequencyValues);
} }
function isFrequencyValueSelected(value: number): boolean { function isFrequencyValueSelected(currentValue: number): boolean {
for (let i = 0; i < frequencyValue.value.length; i++) { return frequencyValue.value.indexOf(currentValue) >= 0;
if (frequencyValue.value[i] === value) {
return true;
}
}
return false;
} }
function onMenuStateChanged(state: boolean): void { function onMenuStateChanged(state: boolean): void {
@@ -56,6 +56,7 @@ import {
useAccountBalanceTrendsChartBase useAccountBalanceTrendsChartBase
} from '@/components/base/AccountBalanceTrendsChartBase.ts' } from '@/components/base/AccountBalanceTrendsChartBase.ts'
import { itemAndIndex } from '@/core/base.ts';
import type { ColorStyleValue } from '@/core/color.ts'; import type { ColorStyleValue } from '@/core/color.ts';
import { DEFAULT_CHART_COLORS } from '@/consts/color.ts'; import { DEFAULT_CHART_COLORS } from '@/consts/color.ts';
@@ -88,15 +89,13 @@ const allVirtualListItems = computed<MobileAccountBalanceTrendsChartItem[]>(() =
const ret: MobileAccountBalanceTrendsChartItem[] = []; const ret: MobileAccountBalanceTrendsChartItem[] = [];
let maxClosingBalance = 0; let maxClosingBalance = 0;
for (let i = 0; i < allDataItems.value.length; i++) { for (const [dataItem, index] of itemAndIndex(allDataItems.value)) {
const dataItem = allDataItems.value[i];
if (dataItem.closingBalance > maxClosingBalance) { if (dataItem.closingBalance > maxClosingBalance) {
maxClosingBalance = dataItem.closingBalance; maxClosingBalance = dataItem.closingBalance;
} }
const finalDataItem: MobileAccountBalanceTrendsChartItem = { const finalDataItem: MobileAccountBalanceTrendsChartItem = {
index: i, index: index,
displayDate: dataItem.displayDate, displayDate: dataItem.displayDate,
openingBalance: dataItem.openingBalance, openingBalance: dataItem.openingBalance,
closingBalance: dataItem.closingBalance, closingBalance: dataItem.closingBalance,
@@ -104,18 +103,18 @@ const allVirtualListItems = computed<MobileAccountBalanceTrendsChartItem[]>(() =
averageBalance: dataItem.averageBalance, averageBalance: dataItem.averageBalance,
minimumBalance: dataItem.minimumBalance, minimumBalance: dataItem.minimumBalance,
maximumBalance: dataItem.maximumBalance, maximumBalance: dataItem.maximumBalance,
color: `#${DEFAULT_CHART_COLORS[0]}`, color: `#${DEFAULT_CHART_COLORS[0] as string}`,
percent: 0.0 percent: 0.0
}; };
ret.push(finalDataItem); ret.push(finalDataItem);
} }
for (let i = 0; i < ret.length; i++) { for (const item of ret) {
if (maxClosingBalance > 0 && ret[i].closingBalance > 0) { if (maxClosingBalance > 0 && item.closingBalance > 0) {
ret[i].percent = 100.0 * ret[i].closingBalance / maxClosingBalance; item.percent = 100.0 * item.closingBalance / maxClosingBalance;
} else { } else {
ret[i].percent = 0.0; item.percent = 0.0;
} }
} }
@@ -72,6 +72,7 @@ import { type CommonScheduleFrequencySelectionProps, useScheduleFrequencySelecti
import { useUserStore } from '@/stores/user.ts'; import { useUserStore } from '@/stores/user.ts';
import { itemAndIndex } from '@/core/base.ts';
import { type WeekDayValue } from '@/core/datetime.ts'; import { type WeekDayValue } from '@/core/datetime.ts';
import { ScheduledTemplateFrequencyType } from '@/core/template.ts'; import { ScheduledTemplateFrequencyType } from '@/core/template.ts';
import { sortNumbersArray } from '@/lib/common.ts'; import { sortNumbersArray } from '@/lib/common.ts';
@@ -117,20 +118,20 @@ function changeFrequencyType(value: number): void {
} }
function changeFrequencyValue(e: Event): void { function changeFrequencyValue(e: Event): void {
const value = parseInt((e.target as HTMLInputElement).value); const currentValue = parseInt((e.target as HTMLInputElement).value);
if ((e.target as HTMLInputElement).checked) { if ((e.target as HTMLInputElement).checked) {
for (let i = 0; i < currentFrequencyValue.value.length; i++) { for (const value of currentFrequencyValue.value) {
if (currentFrequencyValue.value[i] === value) { if (value === currentValue) {
return; return;
} }
} }
currentFrequencyValue.value.push(value); currentFrequencyValue.value.push(currentValue);
} else { } else {
for (let i = 0; i < currentFrequencyValue.value.length; i++) { for (const [value, index] of itemAndIndex(currentFrequencyValue.value)) {
if (currentFrequencyValue.value[i] === value) { if (value === currentValue) {
currentFrequencyValue.value.splice(i, 1); currentFrequencyValue.value.splice(index, 1);
break; break;
} }
} }
@@ -103,9 +103,7 @@ function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, unknown>): b
const lowerCaseFilterContent = filterContent.value?.toLowerCase() ?? ''; const lowerCaseFilterContent = filterContent.value?.toLowerCase() ?? '';
for (let i = 0; i < subItems.length; i++) { for (const secondaryItem of subItems) {
const secondaryItem = subItems[i];
if (props.secondaryHiddenField && (secondaryItem as Record<string, unknown>)[props.secondaryHiddenField]) { if (props.secondaryHiddenField && (secondaryItem as Record<string, unknown>)[props.secondaryHiddenField]) {
continue; continue;
} }
+46 -30
View File
@@ -1,4 +1,4 @@
import type { TypeAndName, TypeAndDisplayName } from './base.ts'; import { type TypeAndName, type TypeAndDisplayName, entries, keys } from './base.ts';
import { KnownAmountFormat } from './numeral.ts'; import { KnownAmountFormat } from './numeral.ts';
import { KnownDateTimeFormat } from './datetime.ts'; import { KnownDateTimeFormat } from './datetime.ts';
import { KnownDateTimezoneFormat } from './timezone.ts'; import { KnownDateTimezoneFormat } from './timezone.ts';
@@ -92,9 +92,9 @@ export class ImportTransactionDataMapping {
this.dataColumnMapping[columnType] = columnIndex; this.dataColumnMapping[columnType] = columnIndex;
} }
for (const otherColumnType in this.dataColumnMapping) { for (const otherColumnType of keys(this.dataColumnMapping)) {
if (otherColumnType !== columnType.toString() && this.dataColumnMapping[otherColumnType] === columnIndex) { if (otherColumnType !== columnType.toString() && this.dataColumnMapping[parseInt(otherColumnType)] === columnIndex) {
delete this.dataColumnMapping[otherColumnType]; delete this.dataColumnMapping[parseInt(otherColumnType)];
} }
} }
} }
@@ -119,16 +119,22 @@ export class ImportTransactionDataMapping {
const allTypeMap: Record<string, boolean> = {}; const allTypeMap: Record<string, boolean> = {};
const allTypes: string[] = []; const allTypes: string[] = [];
const typeColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.TransactionType.type]; const typeColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.TransactionType.type] as number;
const startIndex = this.includeHeader ? 1 : 0; const startIndex = this.includeHeader ? 1 : 0;
for (let i = startIndex; i < fileData.length; i++) { for (let i = startIndex; i < fileData.length; i++) {
if (fileData[i].length <= typeColumnIndex) { const items = fileData[i];
if (!items) {
continue; continue;
} }
const type = fileData[i][typeColumnIndex]; if (items.length <= typeColumnIndex) {
continue;
}
const type = items[typeColumnIndex];
if (type && !allTypeMap[type]) { if (type && !allTypeMap[type]) {
allTypes.push(type); allTypes.push(type);
@@ -150,13 +156,7 @@ export class ImportTransactionDataMapping {
return result; return result;
} }
for (const name in this.transactionTypeMapping) { for (const [name, type] of entries(this.transactionTypeMapping)) {
if (!Object.prototype.hasOwnProperty.call(this.transactionTypeMapping, name)) {
continue;
}
const type = this.transactionTypeMapping[name];
if (TransactionType.ModifyBalance <= type && type <= TransactionType.Transfer) { if (TransactionType.ModifyBalance <= type && type <= TransactionType.Transfer) {
result[name] = type; result[name] = type;
} }
@@ -171,16 +171,22 @@ export class ImportTransactionDataMapping {
} }
const allDateTimes: string[] = []; const allDateTimes: string[] = [];
const dateTimeColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.TransactionTime.type]; const dateTimeColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.TransactionTime.type] as number;
const startIndex = this.includeHeader ? 1 : 0; const startIndex = this.includeHeader ? 1 : 0;
for (let i = startIndex; i < fileData.length; i++) { for (let i = startIndex; i < fileData.length; i++) {
if (fileData[i].length <= dateTimeColumnIndex) { const items = fileData[i];
if (!items) {
continue; continue;
} }
const dateTime = fileData[i][dateTimeColumnIndex]; if (items.length <= dateTimeColumnIndex) {
continue;
}
const dateTime = items[dateTimeColumnIndex];
if (dateTime) { if (dateTime) {
allDateTimes.push(dateTime); allDateTimes.push(dateTime);
@@ -193,7 +199,7 @@ export class ImportTransactionDataMapping {
return undefined; return undefined;
} }
return detectedFormats[0].format; return detectedFormats[0]!.format;
} }
public parseFileAutoDetectedTimezoneFormat(fileData: string[][] | undefined): string | undefined { public parseFileAutoDetectedTimezoneFormat(fileData: string[][] | undefined): string | undefined {
@@ -202,16 +208,22 @@ export class ImportTransactionDataMapping {
} }
const allTimezones: string[] = []; const allTimezones: string[] = [];
const timezoneColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.TransactionTimezone.type]; const timezoneColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.TransactionTimezone.type] as number;
const startIndex = this.includeHeader ? 1 : 0; const startIndex = this.includeHeader ? 1 : 0;
for (let i = startIndex; i < fileData.length; i++) { for (let i = startIndex; i < fileData.length; i++) {
if (fileData[i].length <= timezoneColumnIndex) { const items = fileData[i];
if (!items) {
continue; continue;
} }
const timezone = fileData[i][timezoneColumnIndex]; if (items.length <= timezoneColumnIndex) {
continue;
}
const timezone = items[timezoneColumnIndex];
if (timezone) { if (timezone) {
allTimezones.push(timezone); allTimezones.push(timezone);
@@ -224,7 +236,7 @@ export class ImportTransactionDataMapping {
return undefined; return undefined;
} }
return detectedFormats[0].value; return detectedFormats[0]!.value;
} }
public parseFileAutoDetectedAmountFormat(fileData: string[][] | undefined): string | undefined { public parseFileAutoDetectedAmountFormat(fileData: string[][] | undefined): string | undefined {
@@ -233,16 +245,22 @@ export class ImportTransactionDataMapping {
} }
const allAmounts: string[] = []; const allAmounts: string[] = [];
const amountColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.Amount.type]; const amountColumnIndex = this.dataColumnMapping[ImportTransactionColumnType.Amount.type] as number;
const startIndex = this.includeHeader ? 1 : 0; const startIndex = this.includeHeader ? 1 : 0;
for (let i = startIndex; i < fileData.length; i++) { for (let i = startIndex; i < fileData.length; i++) {
if (fileData[i].length <= amountColumnIndex) { const items = fileData[i];
if (!items) {
continue; continue;
} }
const amount = fileData[i][amountColumnIndex]; if (items.length <= amountColumnIndex) {
continue;
}
const amount = items[amountColumnIndex];
if (amount) { if (amount) {
allAmounts.push(amount); allAmounts.push(amount);
@@ -255,7 +273,7 @@ export class ImportTransactionDataMapping {
return undefined; return undefined;
} }
return detectedFormats[0].type; return detectedFormats[0]!.type;
} }
public reset(): void { public reset(): void {
@@ -382,8 +400,7 @@ export class ImportTransactionReplaceRules {
public toJson(): string { public toJson(): string {
const result: unknown[] = []; const result: unknown[] = [];
for (let i = 0; i < this.rules.length; i++) { for (const rule of this.rules) {
const rule = this.rules[i];
result.push(rule.toJsonObject()); result.push(rule.toJsonObject());
} }
@@ -407,8 +424,7 @@ export class ImportTransactionReplaceRules {
const result = new ImportTransactionReplaceRules([]); const result = new ImportTransactionReplaceRules([]);
for (let i = 0; i < root.length; i++) { for (const rule of root) {
const rule = root[i];
const replaceRule = ImportTransactionReplaceRule.parse(rule); const replaceRule = ImportTransactionReplaceRule.parse(rule);
if (replaceRule) { if (replaceRule) {
@@ -3,6 +3,8 @@ import path from 'path';
import { describe, expect, test } from '@jest/globals'; import { describe, expect, test } from '@jest/globals';
import { DEFAULT_CONTENT } from '@/locales/calendar/chinese/index.ts'; import { DEFAULT_CONTENT } from '@/locales/calendar/chinese/index.ts';
import { itemAndIndex, entries } from '@/core/base.ts';
import type { ChineseCalendarLocaleData } from '@/core/calendar.ts'; import type { ChineseCalendarLocaleData } from '@/core/calendar.ts';
import { import {
type ChineseYearMonthDayInfo, type ChineseYearMonthDayInfo,
@@ -90,12 +92,12 @@ describe('getChineseYearMonthAllDayInfos', () => {
allMonthChineseDays[`${currentYear}-${currentMonth}`] = currentMonthChineseDays; allMonthChineseDays[`${currentYear}-${currentMonth}`] = currentMonthChineseDays;
allMonthSolarTermNames[`${currentYear}-${currentMonth}`] = currentMonthSolarTermNames; allMonthSolarTermNames[`${currentYear}-${currentMonth}`] = currentMonthSolarTermNames;
for (const yearMonth in allMonthChineseDays) { for (const [yearMonth, monthChineseDays] of entries(allMonthChineseDays)) {
test(`returns correct chinese all dates in month for ${yearMonth}`, () => { test(`returns correct chinese all dates in month for ${yearMonth}`, () => {
const [yearStr, monthStr] = yearMonth.split('-'); const [yearStr, monthStr] = yearMonth.split('-');
const year = parseInt(yearStr as string); const year = parseInt(yearStr as string);
const month = parseInt(monthStr as string); const month = parseInt(monthStr as string);
const expectedChineseMonthOrDays = allMonthChineseDays[yearMonth] as string[]; const expectedChineseMonthOrDays = monthChineseDays;
const expectedSolarTermNames = allMonthSolarTermNames[yearMonth] as string[]; const expectedSolarTermNames = allMonthSolarTermNames[yearMonth] as string[];
const actualChineseDates: ChineseYearMonthDayInfo[] | undefined = getChineseYearMonthAllDayInfos({ const actualChineseDates: ChineseYearMonthDayInfo[] | undefined = getChineseYearMonthAllDayInfos({
@@ -106,13 +108,12 @@ describe('getChineseYearMonthAllDayInfos', () => {
expect(actualChineseDates).toBeDefined(); expect(actualChineseDates).toBeDefined();
if (actualChineseDates) { if (actualChineseDates) {
for (let i = 0; i < actualChineseDates.length; i++) { for (const [actualChineseDate, index] of itemAndIndex(actualChineseDates)) {
const actualChineseDate = actualChineseDates[i];
const chineseMonthOrDay: string | undefined = actualChineseDate?.day === 1 ? `${actualChineseDate?.month}${ordinalSuffix[actualChineseDate?.month - 1] ?? 'th'} Lunar Month`.toLowerCase() : actualChineseDate?.day.toString(); const chineseMonthOrDay: string | undefined = actualChineseDate?.day === 1 ? `${actualChineseDate?.month}${ordinalSuffix[actualChineseDate?.month - 1] ?? 'th'} Lunar Month`.toLowerCase() : actualChineseDate?.day.toString();
expect(actualChineseDate).toBeDefined(); expect(actualChineseDate).toBeDefined();
expect(chineseMonthOrDay).toBe(expectedChineseMonthOrDays[i]); expect(chineseMonthOrDay).toBe(expectedChineseMonthOrDays[index]);
expect(actualChineseDate?.solarTermName).toBe(expectedSolarTermNames[i]); expect(actualChineseDate?.solarTermName).toBe(expectedSolarTermNames[index]);
} }
} }
}); });
+2 -2
View File
@@ -71,7 +71,7 @@ export function localizedPresetCategoriesToTransactionCategoryCreateWithSubCateg
return categories; return categories;
} }
export function getSecondaryTransactionMapByName(allCategories: TransactionCategory[]): Record<string, TransactionCategory> { export function getSecondaryTransactionMapByName(allCategories?: TransactionCategory[]): Record<string, TransactionCategory> {
const ret: Record<string, TransactionCategory> = {}; const ret: Record<string, TransactionCategory> = {};
if (!allCategories) { if (!allCategories) {
@@ -274,7 +274,7 @@ export function isSubCategoryIdAvailable(categories: TransactionCategory[], cate
return false; return false;
} }
export function getFirstAvailableCategoryId(categories: TransactionCategory[]): string { export function getFirstAvailableCategoryId(categories?: TransactionCategory[]): string {
if (!categories || !categories.length) { if (!categories || !categories.length) {
return ''; return '';
} }
+11 -15
View File
@@ -431,8 +431,8 @@ export function countSplitItems(str: string | undefined | null, separator: strin
const items = str.split(separator); const items = str.split(separator);
let count = 0; let count = 0;
for (let i = 0; i < items.length; i++) { for (const item of items) {
if (items[i]) { if (item) {
count++; count++;
} }
} }
@@ -483,9 +483,13 @@ export function selectInvert(filterItemIds: Record<string, boolean>, allItemsMap
} }
export function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, Record<string, unknown>[]>, primarySubItemsField: string, secondaryValueField: string | undefined, secondaryHiddenField: string | undefined, secondaryValue: unknown): boolean { export function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, Record<string, unknown>[]>, primarySubItemsField: string, secondaryValueField: string | undefined, secondaryHiddenField: string | undefined, secondaryValue: unknown): boolean {
for (let i = 0; i < primaryItem[primarySubItemsField].length; i++) { const secondaryItems = primaryItem[primarySubItemsField];
const secondaryItem = primaryItem[primarySubItemsField][i];
if (!secondaryItems || secondaryItems.length < 1) {
return false;
}
for (const secondaryItem of secondaryItems) {
if (secondaryHiddenField && secondaryItem[secondaryHiddenField]) { if (secondaryHiddenField && secondaryItem[secondaryHiddenField]) {
continue; continue;
} }
@@ -500,14 +504,12 @@ export function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, Recor
return false; return false;
} }
export function getPrimaryValueBySecondaryValue<T>(items: Record<string, Record<string, T>[]>[] | Record<string, Record<string, Record<string, T>[]>>, primarySubItemsField: string | undefined, primaryValueField: string | undefined, primaryHiddenField: string | undefined, secondaryValueField: string | undefined, secondaryHiddenField: string | undefined, secondaryValue: T): Record<string, T>[] | Record<string, Record<string, T>[]> | null { export function getPrimaryValueBySecondaryValue<T>(items: Record<string, Record<string, T>[]>[] | Record<string, Record<string, Record<string, T>[]>>, primarySubItemsField: string | undefined, primaryValueField: string | undefined, primaryHiddenField: string | undefined, secondaryValueField: string | undefined, secondaryHiddenField: string | undefined, secondaryValue: T): Record<string, T>[] | Record<string, Record<string, T>[]> | null | undefined {
if (primarySubItemsField) { if (primarySubItemsField) {
if (isArray(items)) { if (isArray(items)) {
const arr = items as Record<string, Record<string, T>[]>[]; const arr = items as Record<string, Record<string, T>[]>[];
for (let i = 0; i < arr.length; i++) { for (const primaryItem of arr) {
const primaryItem = arr[i];
if (primaryHiddenField && primaryItem[primaryHiddenField]) { if (primaryHiddenField && primaryItem[primaryHiddenField]) {
continue; continue;
} }
@@ -523,13 +525,7 @@ export function getPrimaryValueBySecondaryValue<T>(items: Record<string, Record<
} else { } else {
const obj = items as Record<string, Record<string, Record<string, T>[]>>; const obj = items as Record<string, Record<string, Record<string, T>[]>>;
for (const field in obj) { for (const primaryItem of values(obj)) {
if (!Object.prototype.hasOwnProperty.call(obj, field)) {
continue;
}
const primaryItem = obj[field];
if (primaryHiddenField && primaryItem[primaryHiddenField]) { if (primaryHiddenField && primaryItem[primaryHiddenField]) {
continue; continue;
} }
+1 -3
View File
@@ -224,9 +224,7 @@ export class LeafletMapInstance implements MapInstance {
private getFinalUrlFormat(urlFormat: string, urlExtraParams: LeafletTileSourceExtraParam[], options: MapInstanceInitOptions) { private getFinalUrlFormat(urlFormat: string, urlExtraParams: LeafletTileSourceExtraParam[], options: MapInstanceInitOptions) {
const params: string[] = []; const params: string[] = [];
for (let i = 0; i < urlExtraParams.length; i++) { for (const param of urlExtraParams) {
const param = urlExtraParams[i];
if (param.paramValueType === 'tomtom_key') { if (param.paramValueType === 'tomtom_key') {
params.push(param.paramName + '=' + getTomTomMapAPIKey()); params.push(param.paramName + '=' + getTomTomMapAPIKey());
} else if (param.paramValueType === 'tianditu_key') { } else if (param.paramValueType === 'tianditu_key') {
+6 -6
View File
@@ -221,7 +221,7 @@ export class Account implements AccountInfoResponse {
}; };
} }
public getAccountOrSubAccountId(subAccountId: string): string | null { public getAccountOrSubAccountId(subAccountId?: string): string | null {
if (this.type === AccountType.SingleAccount.type) { if (this.type === AccountType.SingleAccount.type) {
return this.id; return this.id;
} else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) { } else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) {
@@ -243,7 +243,7 @@ export class Account implements AccountInfoResponse {
} }
} }
public isAccountOrSubAccountHidden(subAccountId: string): boolean { public isAccountOrSubAccountHidden(subAccountId?: string): boolean {
if (this.type === AccountType.SingleAccount.type) { if (this.type === AccountType.SingleAccount.type) {
return this.hidden; return this.hidden;
} else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) { } else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) {
@@ -265,7 +265,7 @@ export class Account implements AccountInfoResponse {
} }
} }
public getAccountOrSubAccountComment(subAccountId: string): string | null { public getAccountOrSubAccountComment(subAccountId?: string): string | null {
if (this.type === AccountType.SingleAccount.type) { if (this.type === AccountType.SingleAccount.type) {
return this.comment; return this.comment;
} else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) { } else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) {
@@ -287,7 +287,7 @@ export class Account implements AccountInfoResponse {
} }
} }
public getAccountOrSubAccount(subAccountId: string): Account | null { public getAccountOrSubAccount(subAccountId?: string): Account | null {
if (this.type === AccountType.SingleAccount.type) { if (this.type === AccountType.SingleAccount.type) {
return this; return this;
} else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) { } else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) {
@@ -309,7 +309,7 @@ export class Account implements AccountInfoResponse {
} }
} }
public getSubAccount(subAccountId: string): Account | null { public getSubAccount(subAccountId?: string): Account | null {
if (!this.subAccounts || !this.subAccounts.length) { if (!this.subAccounts || !this.subAccounts.length) {
return null; return null;
} }
@@ -323,7 +323,7 @@ export class Account implements AccountInfoResponse {
return null; return null;
} }
public getSubAccountCurrencies(showHidden: boolean, subAccountId: string): string[] { public getSubAccountCurrencies(showHidden: boolean, subAccountId?: string): string[] {
if (!this.subAccounts || !this.subAccounts.length) { if (!this.subAccounts || !this.subAccounts.length) {
return []; return [];
} }
+3 -3
View File
@@ -140,15 +140,15 @@ export class Transaction implements TransactionInfoResponse {
} }
} }
public setCategory(category: TransactionCategory): void { public setCategory(category?: TransactionCategory): void {
this._category = category; this._category = category;
} }
public setSourceAccount(sourceAccount: Account): void { public setSourceAccount(sourceAccount?: Account): void {
this._sourceAccount = sourceAccount; this._sourceAccount = sourceAccount;
} }
public setDestinationAccount(destinationAccount: Account): void { public setDestinationAccount(destinationAccount?: Account): void {
this._destinationAccount = destinationAccount; this._destinationAccount = destinationAccount;
} }
+132 -180
View File
@@ -5,7 +5,7 @@ import { useSettingsStore } from './setting.ts';
import { useUserStore } from './user.ts'; import { useUserStore } from './user.ts';
import { useExchangeRatesStore } from './exchangeRates.ts'; import { useExchangeRatesStore } from './exchangeRates.ts';
import type { BeforeResolveFunction } from '@/core/base.ts'; import { type BeforeResolveFunction, itemAndIndex, reversed, entries, values } from '@/core/base.ts';
import type { HiddenAmount, NumberWithSuffix } from '@/core/numeral.ts'; import type { HiddenAmount, NumberWithSuffix } from '@/core/numeral.ts';
import { AccountType, AccountCategory } from '@/core/account.ts'; import { AccountType, AccountCategory } from '@/core/account.ts';
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts'; import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
@@ -36,15 +36,12 @@ export const useAccountsStore = defineStore('accounts', () => {
const allPlainAccounts = computed<Account[]>(() => { const allPlainAccounts = computed<Account[]>(() => {
const allAccountsList: Account[] = []; const allAccountsList: Account[] = [];
for (let i = 0; i < allAccounts.value.length; i++) { for (const account of allAccounts.value) {
const account = allAccounts.value[i];
if (account.type === AccountType.SingleAccount.type) { if (account.type === AccountType.SingleAccount.type) {
allAccountsList.push(account); allAccountsList.push(account);
} else if (account.type === AccountType.MultiSubAccounts.type) { } else if (account.type === AccountType.MultiSubAccounts.type) {
if (account.subAccounts) { if (account.subAccounts) {
for (let j = 0; j < account.subAccounts.length; j++) { for (const subAccount of account.subAccounts) {
const subAccount = account.subAccounts[j];
allAccountsList.push(subAccount); allAccountsList.push(subAccount);
} }
} }
@@ -57,17 +54,14 @@ export const useAccountsStore = defineStore('accounts', () => {
const allMixedPlainAccounts = computed<Account[]>(() => { const allMixedPlainAccounts = computed<Account[]>(() => {
const allAccountsList: Account[] = []; const allAccountsList: Account[] = [];
for (let i = 0; i < allAccounts.value.length; i++) { for (const account of allAccounts.value) {
const account = allAccounts.value[i];
if (account.type === AccountType.SingleAccount.type) { if (account.type === AccountType.SingleAccount.type) {
allAccountsList.push(account); allAccountsList.push(account);
} else if (account.type === AccountType.MultiSubAccounts.type) { } else if (account.type === AccountType.MultiSubAccounts.type) {
allAccountsList.push(account); allAccountsList.push(account);
if (account.subAccounts) { if (account.subAccounts) {
for (let j = 0; j < account.subAccounts.length; j++) { for (const subAccount of account.subAccounts) {
const subAccount = account.subAccounts[j];
allAccountsList.push(subAccount); allAccountsList.push(subAccount);
} }
} }
@@ -80,9 +74,7 @@ export const useAccountsStore = defineStore('accounts', () => {
const allVisiblePlainAccounts = computed<Account[]>(() => { const allVisiblePlainAccounts = computed<Account[]>(() => {
const allVisibleAccounts: Account[] = []; const allVisibleAccounts: Account[] = [];
for (let i = 0; i < allAccounts.value.length; i++) { for (const account of allAccounts.value) {
const account = allAccounts.value[i];
if (account.hidden) { if (account.hidden) {
continue; continue;
} }
@@ -91,8 +83,7 @@ export const useAccountsStore = defineStore('accounts', () => {
allVisibleAccounts.push(account); allVisibleAccounts.push(account);
} else if (account.type === AccountType.MultiSubAccounts.type) { } else if (account.type === AccountType.MultiSubAccounts.type) {
if (account.subAccounts) { if (account.subAccounts) {
for (let j = 0; j < account.subAccounts.length; j++) { for (const subAccount of account.subAccounts) {
const subAccount = account.subAccounts[j];
if (subAccount.hidden) { if (subAccount.hidden) {
continue; continue;
@@ -110,12 +101,8 @@ export const useAccountsStore = defineStore('accounts', () => {
const allAvailableAccountsCount = computed<number>(() => { const allAvailableAccountsCount = computed<number>(() => {
let allAccountCount = 0; let allAccountCount = 0;
for (const category in allCategorizedAccountsMap.value) { for (const categorizedAccounts of values(allCategorizedAccountsMap.value)) {
if (!Object.prototype.hasOwnProperty.call(allCategorizedAccountsMap.value, category)) { allAccountCount += categorizedAccounts.accounts.length;
continue;
}
allAccountCount += allCategorizedAccountsMap.value[category].accounts.length;
} }
return allAccountCount; return allAccountCount;
@@ -124,15 +111,11 @@ export const useAccountsStore = defineStore('accounts', () => {
const allVisibleAccountsCount = computed<number>(() => { const allVisibleAccountsCount = computed<number>(() => {
let shownAccountCount = 0; let shownAccountCount = 0;
for (const category in allCategorizedAccountsMap.value) { for (const categorizedAccounts of values(allCategorizedAccountsMap.value)) {
if (!Object.prototype.hasOwnProperty.call(allCategorizedAccountsMap.value, category)) { const accountList = categorizedAccounts.accounts;
continue;
}
const accountList = allCategorizedAccountsMap.value[category].accounts; for (const account of accountList) {
if (!account.hidden) {
for (let i = 0; i < accountList.length; i++) {
if (!accountList[i].hidden) {
shownAccountCount++; shownAccountCount++;
} }
} }
@@ -145,13 +128,11 @@ export const useAccountsStore = defineStore('accounts', () => {
allAccounts.value = accounts; allAccounts.value = accounts;
allAccountsMap.value = {}; allAccountsMap.value = {};
for (let i = 0; i < accounts.length; i++) { for (const account of accounts) {
const account = accounts[i];
allAccountsMap.value[account.id] = account; allAccountsMap.value[account.id] = account;
if (account.subAccounts) { if (account.subAccounts) {
for (let j = 0; j < account.subAccounts.length; j++) { for (const subAccount of account.subAccounts) {
const subAccount = account.subAccounts[j];
allAccountsMap.value[subAccount.id] = subAccount; allAccountsMap.value[subAccount.id] = subAccount;
} }
} }
@@ -160,51 +141,49 @@ export const useAccountsStore = defineStore('accounts', () => {
allCategorizedAccountsMap.value = getCategorizedAccountsMap(accounts); allCategorizedAccountsMap.value = getCategorizedAccountsMap(accounts);
} }
function addAccountToAccountList(account: Account): void { function addAccountToAccountList(currentAccount: Account): void {
const newAccountCategory = AccountCategory.valueOf(account.category); const newAccountCategory = AccountCategory.valueOf(currentAccount.category);
let insertIndexToAllList = allAccounts.value.length; let insertIndexToAllList = allAccounts.value.length;
if (newAccountCategory) { if (newAccountCategory) {
for (let i = 0; i < allAccounts.value.length; i++) { for (const [account, index] of itemAndIndex(allAccounts.value)) {
const accountCategory = AccountCategory.valueOf(allAccounts.value[i].category); const accountCategory = AccountCategory.valueOf(account.category);
if (accountCategory && accountCategory.displayOrder > newAccountCategory.displayOrder) { if (accountCategory && accountCategory.displayOrder > newAccountCategory.displayOrder) {
insertIndexToAllList = i; insertIndexToAllList = index;
break; break;
} }
} }
} }
allAccounts.value.splice(insertIndexToAllList, 0, account); allAccounts.value.splice(insertIndexToAllList, 0, currentAccount);
allAccountsMap.value[account.id] = account; allAccountsMap.value[currentAccount.id] = currentAccount;
if (account.subAccounts) { if (currentAccount.subAccounts) {
for (let i = 0; i < account.subAccounts.length; i++) { for (const subAccount of currentAccount.subAccounts) {
const subAccount = account.subAccounts[i];
allAccountsMap.value[subAccount.id] = subAccount; allAccountsMap.value[subAccount.id] = subAccount;
} }
} }
if (allCategorizedAccountsMap.value[account.category]) { if (allCategorizedAccountsMap.value[currentAccount.category]) {
const accountList = allCategorizedAccountsMap.value[account.category].accounts; const accountList = allCategorizedAccountsMap.value[currentAccount.category]!.accounts;
accountList.push(account); accountList.push(currentAccount);
} else { } else {
allCategorizedAccountsMap.value = getCategorizedAccountsMap(allAccounts.value); allCategorizedAccountsMap.value = getCategorizedAccountsMap(allAccounts.value);
} }
} }
function updateAccountToAccountList(oldAccount: Account, newAccount: Account): void { function updateAccountToAccountList(oldAccount: Account, newAccount: Account): void {
for (let i = 0; i < allAccounts.value.length; i++) { for (const [account, index] of itemAndIndex(allAccounts.value)) {
if (allAccounts.value[i].id === newAccount.id) { if (account.id === newAccount.id) {
allAccounts.value.splice(i, 1, newAccount); allAccounts.value.splice(index, 1, newAccount);
break; break;
} }
} }
if (oldAccount.subAccounts) { if (oldAccount.subAccounts) {
for (let i = 0; i < oldAccount.subAccounts.length; i++) { for (const subAccount of oldAccount.subAccounts) {
const subAccount = oldAccount.subAccounts[i];
if (allAccountsMap.value[subAccount.id]) { if (allAccountsMap.value[subAccount.id]) {
delete allAccountsMap.value[subAccount.id]; delete allAccountsMap.value[subAccount.id];
} }
@@ -214,18 +193,17 @@ export const useAccountsStore = defineStore('accounts', () => {
allAccountsMap.value[newAccount.id] = newAccount; allAccountsMap.value[newAccount.id] = newAccount;
if (newAccount.subAccounts) { if (newAccount.subAccounts) {
for (let i = 0; i < newAccount.subAccounts.length; i++) { for (const subAccount of newAccount.subAccounts) {
const subAccount = newAccount.subAccounts[i];
allAccountsMap.value[subAccount.id] = subAccount; allAccountsMap.value[subAccount.id] = subAccount;
} }
} }
if (allCategorizedAccountsMap.value[newAccount.category]) { if (allCategorizedAccountsMap.value[newAccount.category]) {
const accountList = allCategorizedAccountsMap.value[newAccount.category].accounts; const accountList = allCategorizedAccountsMap.value[newAccount.category]!.accounts;
for (let i = 0; i < accountList.length; i++) { for (const [account, index] of itemAndIndex(accountList)) {
if (accountList[i].id === newAccount.id) { if (account.id === newAccount.id) {
accountList.splice(i, 1, newAccount); accountList.splice(index, 1, newAccount);
break; break;
} }
} }
@@ -237,12 +215,12 @@ export const useAccountsStore = defineStore('accounts', () => {
let toAccount = null; let toAccount = null;
if (allCategorizedAccountsMap.value[account.category]) { if (allCategorizedAccountsMap.value[account.category]) {
const accountList = allCategorizedAccountsMap.value[account.category].accounts; const accountList = allCategorizedAccountsMap.value[account.category]!.accounts;
if (updateListOrder) { if (updateListOrder) {
fromAccount = accountList[from]; fromAccount = accountList[from];
toAccount = accountList[to]; toAccount = accountList[to];
accountList.splice(to, 0, accountList.splice(from, 1)[0]); accountList.splice(to, 0, accountList.splice(from, 1)[0] as Account);
} else { } else {
fromAccount = accountList[to]; fromAccount = accountList[to];
@@ -258,94 +236,93 @@ export const useAccountsStore = defineStore('accounts', () => {
let globalFromIndex = -1; let globalFromIndex = -1;
let globalToIndex = -1; let globalToIndex = -1;
for (let i = 0; i < allAccounts.value.length; i++) { for (const [account, index] of itemAndIndex(allAccounts.value)) {
if (allAccounts.value[i].id === fromAccount.id) { if (account.id === fromAccount.id) {
globalFromIndex = i; globalFromIndex = index;
} else if (allAccounts.value[i].id === toAccount.id) { } else if (account.id === toAccount.id) {
globalToIndex = i; globalToIndex = index;
} }
} }
if (globalFromIndex >= 0 && globalToIndex >= 0) { if (globalFromIndex >= 0 && globalToIndex >= 0) {
allAccounts.value.splice(globalToIndex, 0, allAccounts.value.splice(globalFromIndex, 1)[0]); allAccounts.value.splice(globalToIndex, 0, allAccounts.value.splice(globalFromIndex, 1)[0] as Account);
} }
} }
} }
function updateAccountVisibilityInAccountList({ account, hidden }: { account: Account, hidden: boolean }): void { function updateAccountVisibilityInAccountList({ account, hidden }: { account: Account, hidden: boolean }): void {
if (allAccountsMap.value[account.id]) { if (allAccountsMap.value[account.id]) {
allAccountsMap.value[account.id].visible = !hidden; allAccountsMap.value[account.id]!.visible = !hidden;
} }
} }
function removeAccountFromAccountList(account: Account): void { function removeAccountFromAccountList(currentAccount: Account): void {
for (let i = 0; i < allAccounts.value.length; i++) { for (const [account, index] of itemAndIndex(allAccounts.value)) {
if (allAccounts.value[i].id === account.id) { if (account.id === currentAccount.id) {
allAccounts.value.splice(i, 1); allAccounts.value.splice(index, 1);
break; break;
} }
} }
if (allAccountsMap.value[account.id] && allAccountsMap.value[account.id].subAccounts) { if (allAccountsMap.value[currentAccount.id] && allAccountsMap.value[currentAccount.id]!.subAccounts) {
const subAccounts = allAccountsMap.value[account.id].subAccounts as Account[]; const subAccounts = allAccountsMap.value[currentAccount.id]!.subAccounts as Account[];
for (let i = 0; i < subAccounts.length; i++) { for (const subAccount of subAccounts) {
const subAccount = subAccounts[i];
if (allAccountsMap.value[subAccount.id]) { if (allAccountsMap.value[subAccount.id]) {
delete allAccountsMap.value[subAccount.id]; delete allAccountsMap.value[subAccount.id];
} }
} }
} }
if (allAccountsMap.value[account.id]) { if (allAccountsMap.value[currentAccount.id]) {
delete allAccountsMap.value[account.id]; delete allAccountsMap.value[currentAccount.id];
} }
if (allCategorizedAccountsMap.value[account.category]) { if (allCategorizedAccountsMap.value[currentAccount.category]) {
const accountList = allCategorizedAccountsMap.value[account.category].accounts; const accountList = allCategorizedAccountsMap.value[currentAccount.category]!.accounts;
for (let i = 0; i < accountList.length; i++) { for (const [account, index] of itemAndIndex(accountList)) {
if (accountList[i].id === account.id) { if (account.id === currentAccount.id) {
accountList.splice(i, 1); accountList.splice(index, 1);
break; break;
} }
} }
} }
} }
function removeSubAccountFromAccountList(subAccount: Account): void { function removeSubAccountFromAccountList(currentSubAccount: Account): void {
for (let i = 0; i < allAccounts.value.length; i++) { for (const account of allAccounts.value) {
if (allAccounts.value[i].type !== AccountType.MultiSubAccounts.type || !allAccounts.value[i].subAccounts) { if (account.type !== AccountType.MultiSubAccounts.type || !account.subAccounts) {
continue; continue;
} }
const subAccounts = allAccounts.value[i].subAccounts as Account[]; const subAccounts = account.subAccounts as Account[];
for (let j = 0; j < subAccounts.length; j++) { for (const [subAccount, index] of itemAndIndex(subAccounts)) {
if (subAccounts[j].id === subAccount.id) { if (subAccount.id === currentSubAccount.id) {
subAccounts.splice(j, 1); subAccounts.splice(index, 1);
break; break;
} }
} }
} }
if (allAccountsMap.value[subAccount.id]) { if (allAccountsMap.value[currentSubAccount.id]) {
delete allAccountsMap.value[subAccount.id]; delete allAccountsMap.value[currentSubAccount.id];
} }
if (allCategorizedAccountsMap.value[subAccount.category]) { if (allCategorizedAccountsMap.value[currentSubAccount.category]) {
const accountList = allCategorizedAccountsMap.value[subAccount.category].accounts; const accountList = allCategorizedAccountsMap.value[currentSubAccount.category]!.accounts;
for (let i = 0; i < accountList.length; i++) { for (const account of accountList) {
if (accountList[i].type !== AccountType.MultiSubAccounts.type || !accountList[i].subAccounts) { if (account.type !== AccountType.MultiSubAccounts.type || !account.subAccounts) {
continue; continue;
} }
const subAccounts = accountList[i].subAccounts as Account[]; const subAccounts = account.subAccounts as Account[];
for (let j = 0; j < subAccounts.length; j++) { for (const [subAccount, index] of itemAndIndex(subAccounts)) {
if (subAccounts[j].id === subAccount.id) { if (subAccount.id === currentSubAccount.id) {
subAccounts.splice(j, 1); subAccounts.splice(index, 1);
break; break;
} }
} }
@@ -370,24 +347,16 @@ export const useAccountsStore = defineStore('accounts', () => {
subAccounts: {} subAccounts: {}
}; };
for (const category in allCategorizedAccountsMap.value) { for (const [category, categorizedAccounts] of entries(allCategorizedAccountsMap.value)) {
if (!Object.prototype.hasOwnProperty.call(allCategorizedAccountsMap.value, category)) { if (!categorizedAccounts || !categorizedAccounts.accounts) {
continue; continue;
} }
if (!allCategorizedAccountsMap.value[category] || !allCategorizedAccountsMap.value[category].accounts) { const accounts = categorizedAccounts.accounts;
continue;
}
const accounts = allCategorizedAccountsMap.value[category].accounts;
for (let i = 0; i < accounts.length; i++) {
const account = accounts[i];
for (const account of accounts) {
if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) { if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) {
for (let j = 0; j < account.subAccounts.length; j++) { for (const subAccount of account.subAccounts) {
const subAccount = account.subAccounts[j];
if (showHidden || !subAccount.hidden) { if (showHidden || !subAccount.hidden) {
ret.subAccounts[account.id] = subAccount.id; ret.subAccounts[account.id] = subAccount.id;
break; break;
@@ -396,7 +365,7 @@ export const useAccountsStore = defineStore('accounts', () => {
} }
if (showHidden || !account.hidden) { if (showHidden || !account.hidden) {
ret.accounts[category] = account.id; ret.accounts[parseInt(category)] = account.id;
break; break;
} }
} }
@@ -411,24 +380,16 @@ export const useAccountsStore = defineStore('accounts', () => {
subAccounts: {} subAccounts: {}
}; };
for (const category in allCategorizedAccountsMap.value) { for (const [category, categorizedAccounts] of entries(allCategorizedAccountsMap.value)) {
if (!Object.prototype.hasOwnProperty.call(allCategorizedAccountsMap.value, category)) { if (!categorizedAccounts || !categorizedAccounts.accounts) {
continue; continue;
} }
if (!allCategorizedAccountsMap.value[category] || !allCategorizedAccountsMap.value[category].accounts) { const accounts = categorizedAccounts.accounts;
continue;
}
const accounts = allCategorizedAccountsMap.value[category].accounts;
for (let i = accounts.length - 1; i >= 0; i--) {
const account = accounts[i];
for (const account of reversed(accounts)) {
if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) { if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) {
for (let j = account.subAccounts.length - 1; j >= 0; j--) { for (const subAccount of reversed(account.subAccounts)) {
const subAccount = account.subAccounts[j];
if (showHidden || !subAccount.hidden) { if (showHidden || !subAccount.hidden) {
ret.subAccounts[account.id] = subAccount.id; ret.subAccounts[account.id] = subAccount.id;
break; break;
@@ -437,7 +398,7 @@ export const useAccountsStore = defineStore('accounts', () => {
} }
if (showHidden || !account.hidden) { if (showHidden || !account.hidden) {
ret.accounts[category] = account.id; ret.accounts[parseInt(category)] = account.id;
break; break;
} }
} }
@@ -454,9 +415,8 @@ export const useAccountsStore = defineStore('accounts', () => {
const accountIds = accountId.split(','); const accountIds = accountId.split(',');
let mainAccount = null; let mainAccount = null;
for (let i = 0; i < accountIds.length; i++) { for (const accountId of accountIds) {
const id = accountIds[i]; let account = allAccountsMap.value[accountId];
let account = allAccountsMap.value[id];
if (!account) { if (!account) {
return null; return null;
@@ -466,7 +426,11 @@ export const useAccountsStore = defineStore('accounts', () => {
account = allAccountsMap.value[account.parentId]; account = allAccountsMap.value[account.parentId];
} }
if (mainAccount !== null) { if (!account) {
return null;
}
if (mainAccount) {
if (mainAccount.id !== account.id) { if (mainAccount.id !== account.id) {
return null; return null;
} else { } else {
@@ -499,11 +463,11 @@ export const useAccountsStore = defineStore('accounts', () => {
let netAssets = 0; let netAssets = 0;
let hasUnCalculatedAmount = false; let hasUnCalculatedAmount = false;
for (let i = 0; i < accountsBalance.length; i++) { for (const accountBalance of accountsBalance) {
if (accountsBalance[i].currency === userStore.currentUserDefaultCurrency) { if (accountBalance.currency === userStore.currentUserDefaultCurrency) {
netAssets += accountsBalance[i].balance; netAssets += accountBalance.balance;
} else { } else {
const balance = exchangeRatesStore.getExchangedAmount(accountsBalance[i].balance, accountsBalance[i].currency, userStore.currentUserDefaultCurrency); const balance = exchangeRatesStore.getExchangedAmount(accountBalance.balance, accountBalance.currency, userStore.currentUserDefaultCurrency);
if (!isNumber(balance)) { if (!isNumber(balance)) {
hasUnCalculatedAmount = true; hasUnCalculatedAmount = true;
@@ -535,11 +499,11 @@ export const useAccountsStore = defineStore('accounts', () => {
let totalAssets = 0; let totalAssets = 0;
let hasUnCalculatedAmount = false; let hasUnCalculatedAmount = false;
for (let i = 0; i < accountsBalance.length; i++) { for (const accountBalance of accountsBalance) {
if (accountsBalance[i].currency === userStore.currentUserDefaultCurrency) { if (accountBalance.currency === userStore.currentUserDefaultCurrency) {
totalAssets += accountsBalance[i].balance; totalAssets += accountBalance.balance;
} else { } else {
const balance = exchangeRatesStore.getExchangedAmount(accountsBalance[i].balance, accountsBalance[i].currency, userStore.currentUserDefaultCurrency); const balance = exchangeRatesStore.getExchangedAmount(accountBalance.balance, accountBalance.currency, userStore.currentUserDefaultCurrency);
if (!isNumber(balance)) { if (!isNumber(balance)) {
hasUnCalculatedAmount = true; hasUnCalculatedAmount = true;
@@ -571,11 +535,11 @@ export const useAccountsStore = defineStore('accounts', () => {
let totalLiabilities = 0; let totalLiabilities = 0;
let hasUnCalculatedAmount = false; let hasUnCalculatedAmount = false;
for (let i = 0; i < accountsBalance.length; i++) { for (const accountBalance of accountsBalance) {
if (accountsBalance[i].currency === userStore.currentUserDefaultCurrency) { if (accountBalance.currency === userStore.currentUserDefaultCurrency) {
totalLiabilities -= accountsBalance[i].balance; totalLiabilities -= accountBalance.balance;
} else { } else {
const balance = exchangeRatesStore.getExchangedAmount(accountsBalance[i].balance, accountsBalance[i].currency, userStore.currentUserDefaultCurrency); const balance = exchangeRatesStore.getExchangedAmount(accountBalance.balance, accountBalance.currency, userStore.currentUserDefaultCurrency);
if (!isNumber(balance)) { if (!isNumber(balance)) {
hasUnCalculatedAmount = true; hasUnCalculatedAmount = true;
@@ -605,26 +569,26 @@ export const useAccountsStore = defineStore('accounts', () => {
let totalBalance = 0; let totalBalance = 0;
let hasUnCalculatedAmount = false; let hasUnCalculatedAmount = false;
for (let i = 0; i < accountsBalance.length; i++) { for (const accountBalance of accountsBalance) {
if (accountsBalance[i].currency === userStore.currentUserDefaultCurrency) { if (accountBalance.currency === userStore.currentUserDefaultCurrency) {
if (accountsBalance[i].isAsset) { if (accountBalance.isAsset) {
totalBalance += accountsBalance[i].balance; totalBalance += accountBalance.balance;
} else if (accountsBalance[i].isLiability) { } else if (accountBalance.isLiability) {
totalBalance -= accountsBalance[i].balance; totalBalance -= accountBalance.balance;
} else { } else {
totalBalance += accountsBalance[i].balance; totalBalance += accountBalance.balance;
} }
} else { } else {
const balance = exchangeRatesStore.getExchangedAmount(accountsBalance[i].balance, accountsBalance[i].currency, userStore.currentUserDefaultCurrency); const balance = exchangeRatesStore.getExchangedAmount(accountBalance.balance, accountBalance.currency, userStore.currentUserDefaultCurrency);
if (!isNumber(balance)) { if (!isNumber(balance)) {
hasUnCalculatedAmount = true; hasUnCalculatedAmount = true;
continue; continue;
} }
if (accountsBalance[i].isAsset) { if (accountBalance.isAsset) {
totalBalance += Math.trunc(balance); totalBalance += Math.trunc(balance);
} else if (accountsBalance[i].isLiability) { } else if (accountBalance.isLiability) {
totalBalance -= Math.trunc(balance); totalBalance -= Math.trunc(balance);
} else { } else {
totalBalance += Math.trunc(balance); totalBalance += Math.trunc(balance);
@@ -678,9 +642,7 @@ export const useAccountsStore = defineStore('accounts', () => {
const allSubAccountCurrencies: string[] = []; const allSubAccountCurrencies: string[] = [];
let totalBalance = 0; let totalBalance = 0;
for (let i = 0; i < account.subAccounts.length; i++) { for (const subAccount of account.subAccounts) {
const subAccount = account.subAccounts[i];
if (!showHidden && subAccount.hidden) { if (!showHidden && subAccount.hidden) {
continue; continue;
} }
@@ -699,14 +661,12 @@ export const useAccountsStore = defineStore('accounts', () => {
} }
if (allSubAccountCurrencies.length === 1) { if (allSubAccountCurrencies.length === 1) {
resultCurrency = allSubAccountCurrencies[0]; resultCurrency = allSubAccountCurrencies[0] as string;
} }
let hasUnCalculatedAmount = false; let hasUnCalculatedAmount = false;
for (let i = 0; i < account.subAccounts.length; i++) { for (const subAccount of account.subAccounts) {
const subAccount = account.subAccounts[i];
if (!showHidden && subAccount.hidden) { if (!showHidden && subAccount.hidden) {
continue; continue;
} }
@@ -762,17 +722,15 @@ export const useAccountsStore = defineStore('accounts', () => {
} }
function hasAccount(accountCategory: AccountCategory, visibleOnly: boolean): boolean { function hasAccount(accountCategory: AccountCategory, visibleOnly: boolean): boolean {
if (!allCategorizedAccountsMap.value[accountCategory.type] || const categorizedAccounts = allCategorizedAccountsMap.value[accountCategory.type];
!allCategorizedAccountsMap.value[accountCategory.type].accounts ||
!allCategorizedAccountsMap.value[accountCategory.type].accounts.length) { if (!categorizedAccounts || !categorizedAccounts.accounts || !categorizedAccounts.accounts.length) {
return false; return false;
} }
let shownCount = 0; let shownCount = 0;
for (let i = 0; i < allCategorizedAccountsMap.value[accountCategory.type].accounts.length; i++) { for (const account of categorizedAccounts.accounts) {
const account = allCategorizedAccountsMap.value[accountCategory.type].accounts[i];
if (!visibleOnly || !account.hidden) { if (!visibleOnly || !account.hidden) {
shownCount++; shownCount++;
} }
@@ -786,8 +744,8 @@ export const useAccountsStore = defineStore('accounts', () => {
return false; return false;
} }
for (let i = 0; i < account.subAccounts.length; i++) { for (const subAccount of account.subAccounts) {
if (showHidden || !account.subAccounts[i].hidden) { if (showHidden || !subAccount.hidden) {
return true; return true;
} }
} }
@@ -934,8 +892,8 @@ export const useAccountsStore = defineStore('accounts', () => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!account || if (!account ||
!allCategorizedAccountsMap.value[account.category] || !allCategorizedAccountsMap.value[account.category] ||
!allCategorizedAccountsMap.value[account.category].accounts || !allCategorizedAccountsMap.value[account.category]!.accounts ||
!allCategorizedAccountsMap.value[account.category].accounts[to]) { !allCategorizedAccountsMap.value[account.category]!.accounts[to]) {
reject({ message: 'Unable to move account' }); reject({ message: 'Unable to move account' });
return; return;
} }
@@ -953,17 +911,11 @@ export const useAccountsStore = defineStore('accounts', () => {
function updateAccountDisplayOrders(): Promise<boolean> { function updateAccountDisplayOrders(): Promise<boolean> {
const newDisplayOrders: AccountNewDisplayOrderRequest[] = []; const newDisplayOrders: AccountNewDisplayOrderRequest[] = [];
for (const category in allCategorizedAccountsMap.value) { for (const categorizedAccounts of values(allCategorizedAccountsMap.value)) {
if (!Object.prototype.hasOwnProperty.call(allCategorizedAccountsMap.value, category)) { for (const [account, index] of itemAndIndex(categorizedAccounts.accounts)) {
continue;
}
const accountList = allCategorizedAccountsMap.value[category].accounts;
for (let i = 0; i < accountList.length; i++) {
newDisplayOrders.push({ newDisplayOrders.push({
id: accountList[i].id, id: account.id,
displayOrder: i + 1 displayOrder: index + 1
}); });
} }
} }
+9 -30
View File
@@ -7,6 +7,7 @@ import { useAccountsStore } from './account.ts';
import { useTransactionCategoriesStore } from './transactionCategory.ts'; import { useTransactionCategoriesStore } from './transactionCategory.ts';
import { useExchangeRatesStore } from './exchangeRates.ts'; import { useExchangeRatesStore } from './exchangeRates.ts';
import { entries, values } from '@/core/base.ts';
import { type TextualYearMonth, type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts'; import { type TextualYearMonth, type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts';
import { TimezoneTypeForStatistics } from '@/core/timezone.ts'; import { TimezoneTypeForStatistics } from '@/core/timezone.ts';
import { CategoryType } from '@/core/category.ts'; import { CategoryType } from '@/core/category.ts';
@@ -228,9 +229,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
let totalAmount = 0; let totalAmount = 0;
let totalNonNegativeAmount = 0; let totalNonNegativeAmount = 0;
for (let i = 0; i < accountsStore.allPlainAccounts.length; i++) { for (const account of accountsStore.allPlainAccounts) {
const account = accountsStore.allPlainAccounts[i];
if (transactionStatisticsFilter.value.chartDataType === ChartDataType.AccountTotalAssets.type) { if (transactionStatisticsFilter.value.chartDataType === ChartDataType.AccountTotalAssets.type) {
if (!account.isAsset) { if (!account.isAsset) {
continue; continue;
@@ -312,12 +311,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
const allStatisticsItems: TransactionCategoricalAnalysisDataItem[] = []; const allStatisticsItems: TransactionCategoricalAnalysisDataItem[] = [];
if (combinedData && combinedData.items) { if (combinedData && combinedData.items) {
for (const id in combinedData.items) { for (const dataItem of values(combinedData.items)) {
if (!Object.prototype.hasOwnProperty.call(combinedData.items, id)) {
continue;
}
const dataItem = combinedData.items[id];
let percent = 0; let percent = 0;
if (dataItem.totalAmount > 0) { if (dataItem.totalAmount > 0) {
@@ -361,8 +355,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
const finalTrendsData: TransactionStatisticTrendsResponseItemWithInfo[] = []; const finalTrendsData: TransactionStatisticTrendsResponseItemWithInfo[] = [];
if (trendsData && trendsData.length) { if (trendsData && trendsData.length) {
for (let i = 0; i < trendsData.length; i++) { for (const trendItem of trendsData) {
const trendItem = trendsData[i];
const finalTrendItem: TransactionStatisticTrendsResponseItemWithInfo = { const finalTrendItem: TransactionStatisticTrendsResponseItemWithInfo = {
year: trendItem.year, year: trendItem.year,
month: trendItem.month, month: trendItem.month,
@@ -387,16 +380,10 @@ export const useStatisticsStore = defineStore('statistics', () => {
const combinedDataMap: Record<string, WritableTransactionTrendsAnalysisDataItem> = {}; const combinedDataMap: Record<string, WritableTransactionTrendsAnalysisDataItem> = {};
for (let i = 0; i < transactionCategoryTrendsDataWithCategoryAndAccountInfo.value.length; i++) { for (const trendItem of transactionCategoryTrendsDataWithCategoryAndAccountInfo.value) {
const trendItem = transactionCategoryTrendsDataWithCategoryAndAccountInfo.value[i];
const totalAmountItems = getCategoryTotalAmountItems(trendItem.items, transactionStatisticsFilter.value); const totalAmountItems = getCategoryTotalAmountItems(trendItem.items, transactionStatisticsFilter.value);
for (const id in totalAmountItems.items) { for (const [id, item] of entries(totalAmountItems.items)) {
if (!Object.prototype.hasOwnProperty.call(totalAmountItems.items, id)) {
continue;
}
const item = totalAmountItems.items[id];
let combinedData = combinedDataMap[id]; let combinedData = combinedDataMap[id];
if (!combinedData) { if (!combinedData) {
@@ -426,12 +413,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
const totalAmountsTrends: TransactionTrendsAnalysisDataItem[] = []; const totalAmountsTrends: TransactionTrendsAnalysisDataItem[] = [];
for (const id in combinedDataMap) { for (const trendData of values(combinedDataMap)) {
if (!Object.prototype.hasOwnProperty.call(combinedDataMap, id)) {
continue;
}
const trendData = combinedDataMap[id];
totalAmountsTrends.push(trendData); totalAmountsTrends.push(trendData);
} }
@@ -448,8 +430,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
const finalItems: TransactionStatisticResponseItemWithInfo[] = []; const finalItems: TransactionStatisticResponseItemWithInfo[] = [];
const defaultCurrency = userStore.currentUserDefaultCurrency; const defaultCurrency = userStore.currentUserDefaultCurrency;
for (let i = 0; i < items.length; i++) { for (const dataItem of items) {
const dataItem = items[i];
const item: TransactionStatisticResponseItemWithInfo = { const item: TransactionStatisticResponseItemWithInfo = {
categoryId: dataItem.categoryId, categoryId: dataItem.categoryId,
accountId: dataItem.accountId, accountId: dataItem.accountId,
@@ -500,9 +481,7 @@ export const useStatisticsStore = defineStore('statistics', () => {
let totalAmount = 0; let totalAmount = 0;
let totalNonNegativeAmount = 0; let totalNonNegativeAmount = 0;
for (let i = 0; i < items.length; i++) { for (const item of items) {
const item = items[i];
if (!item.primaryAccount || !item.account || !item.primaryCategory || !item.category) { if (!item.primaryAccount || !item.account || !item.primaryCategory || !item.category) {
continue; continue;
} }
+42 -58
View File
@@ -9,7 +9,7 @@ import { useOverviewStore } from './overview.ts';
import { useStatisticsStore } from './statistics.ts'; import { useStatisticsStore } from './statistics.ts';
import { useExchangeRatesStore } from './exchangeRates.ts'; import { useExchangeRatesStore } from './exchangeRates.ts';
import type { BeforeResolveFunction } from '@/core/base.ts'; import { type BeforeResolveFunction, itemAndIndex, entries, keys } from '@/core/base.ts';
import { type TextualYearMonth, DateRange } from '@/core/datetime.ts'; import { type TextualYearMonth, DateRange } from '@/core/datetime.ts';
import { CategoryType } from '@/core/category.ts'; import { CategoryType } from '@/core/category.ts';
import { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts'; import { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts';
@@ -165,8 +165,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
let currentMonthListIndex = -1; let currentMonthListIndex = -1;
let currentMonthList: TransactionMonthList | null = null; let currentMonthList: TransactionMonthList | null = null;
for (let i = 0; i < transactionPageWrapper.items.length; i++) { for (const [item, index] of itemAndIndex(transactionPageWrapper.items)) {
const item = transactionPageWrapper.items[i];
fillTransactionObject(item, currentUtcOffset); fillTransactionObject(item, currentUtcOffset);
const transactionTime = parseDateTimeFromUnixTime(item.time, item.utcOffset, currentUtcOffset); const transactionTime = parseDateTimeFromUnixTime(item.time, item.utcOffset, currentUtcOffset);
@@ -174,8 +173,8 @@ export const useTransactionsStore = defineStore('transactions', () => {
const transactionMonth = transactionTime.getGregorianCalendarMonth(); const transactionMonth = transactionTime.getGregorianCalendarMonth();
const transactionYearDashMonth = transactionTime.getGregorianCalendarYearDashMonth(); const transactionYearDashMonth = transactionTime.getGregorianCalendarYearDashMonth();
if (i === 0 && transactions.value.length > 0) { if (index === 0 && transactions.value.length > 0) {
const lastMonthList = transactions.value[transactions.value.length - 1]; const lastMonthList = transactions.value[transactions.value.length - 1] as TransactionMonthList;
if (lastMonthList.totalAmount.incompleteExpense || lastMonthList.totalAmount.incompleteIncome) { if (lastMonthList.totalAmount.incompleteExpense || lastMonthList.totalAmount.incompleteIncome) {
// calculate the total amount of last month which has incomplete total amount before starting to process a new request // calculate the total amount of last month which has incomplete total amount before starting to process a new request
@@ -186,7 +185,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
if (currentMonthList && currentMonthList.year === transactionYear && currentMonthList.month === transactionMonth) { if (currentMonthList && currentMonthList.year === transactionYear && currentMonthList.month === transactionMonth) {
currentMonthList.items.push(Object.freeze(item)); currentMonthList.items.push(Object.freeze(item));
if (i === transactionPageWrapper.items.length - 1) { if (index === transactionPageWrapper.items.length - 1) {
// calculate the total amount of current month when processing the last transaction item of this request // calculate the total amount of current month when processing the last transaction item of this request
calculateMonthTotalAmount(currentMonthList, defaultCurrency, transactionsFilter.value.accountIds, true); calculateMonthTotalAmount(currentMonthList, defaultCurrency, transactionsFilter.value.accountIds, true);
} }
@@ -194,9 +193,9 @@ export const useTransactionsStore = defineStore('transactions', () => {
} }
for (let j = currentMonthListIndex + 1; j < transactions.value.length; j++) { for (let j = currentMonthListIndex + 1; j < transactions.value.length; j++) {
if (transactions.value[j].year === transactionYear && transactions.value[j].month === transactionMonth) { if (transactions.value[j]!.year === transactionYear && transactions.value[j]!.month === transactionMonth) {
currentMonthListIndex = j; currentMonthListIndex = j;
currentMonthList = transactions.value[j]; currentMonthList = transactions.value[j] as TransactionMonthList;
break; break;
} }
} }
@@ -223,7 +222,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
transactions.value.push(monthList); transactions.value.push(monthList);
currentMonthListIndex = transactions.value.length - 1; currentMonthListIndex = transactions.value.length - 1;
currentMonthList = transactions.value[transactions.value.length - 1]; currentMonthList = transactions.value[transactions.value.length - 1] as TransactionMonthList;
} }
currentMonthList.items.push(Object.freeze(item)); currentMonthList.items.push(Object.freeze(item));
@@ -235,50 +234,48 @@ export const useTransactionsStore = defineStore('transactions', () => {
if (nextTimeSequenceId) { if (nextTimeSequenceId) {
transactionsNextTimeId.value = nextTimeSequenceId; transactionsNextTimeId.value = nextTimeSequenceId;
} else { } else {
calculateMonthTotalAmount(transactions.value[transactions.value.length - 1], defaultCurrency, transactionsFilter.value.accountIds, false); calculateMonthTotalAmount(transactions.value[transactions.value.length - 1] as TransactionMonthList, defaultCurrency, transactionsFilter.value.accountIds, false);
transactionsNextTimeId.value = -1; transactionsNextTimeId.value = -1;
} }
} }
function updateTransactionInTransactionList({ transaction, defaultCurrency }: { transaction: Transaction, defaultCurrency: string }): void { function updateTransactionInTransactionList({ currentTransaction, defaultCurrency }: { currentTransaction: Transaction, defaultCurrency: string }): void {
const currentUtcOffset = getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone); const currentUtcOffset = getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone);
const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); const transactionTime = parseDateTimeFromUnixTime(currentTransaction.time, currentTransaction.utcOffset, currentUtcOffset);
const transactionYear = transactionTime.getGregorianCalendarYear(); const transactionYear = transactionTime.getGregorianCalendarYear();
const transactionMonth = transactionTime.getGregorianCalendarMonth(); const transactionMonth = transactionTime.getGregorianCalendarMonth();
for (let i = 0; i < transactions.value.length; i++) { for (const [transactionMonthList, monthIndex] of itemAndIndex(transactions.value)) {
const transactionMonthList = transactions.value[i];
if (!transactionMonthList.items) { if (!transactionMonthList.items) {
continue; continue;
} }
for (let j = 0; j < transactionMonthList.items.length; j++) { for (const [transaction, transactionIndex] of itemAndIndex(transactionMonthList.items)) {
if (transactionMonthList.items[j].id === transaction.id) { if (transaction.id === currentTransaction.id) {
fillTransactionObject(transaction, currentUtcOffset); fillTransactionObject(currentTransaction, currentUtcOffset);
if (transactionYear !== transactionMonthList.year || if (transactionYear !== transactionMonthList.year ||
transactionMonth !== transactionMonthList.month || transactionMonth !== transactionMonthList.month ||
transaction.gregorianCalendarDayOfMonth !== transactionMonthList.items[j].gregorianCalendarDayOfMonth) { currentTransaction.gregorianCalendarDayOfMonth !== transaction.gregorianCalendarDayOfMonth) {
transactionListStateInvalid.value = true; transactionListStateInvalid.value = true;
return; return;
} }
if ((transactionsFilter.value.categoryIds && !allFilterCategoryIds.value[transaction.categoryId]) || if ((transactionsFilter.value.categoryIds && !allFilterCategoryIds.value[currentTransaction.categoryId]) ||
(transactionsFilter.value.accountIds && !allFilterAccountIds.value[transaction.sourceAccountId] && !allFilterAccountIds.value[transaction.destinationAccountId] && (transactionsFilter.value.accountIds && !allFilterAccountIds.value[currentTransaction.sourceAccountId] && !allFilterAccountIds.value[currentTransaction.destinationAccountId] &&
(!transaction.sourceAccount || !allFilterAccountIds.value[transaction.sourceAccount.parentId]) && (!currentTransaction.sourceAccount || !allFilterAccountIds.value[currentTransaction.sourceAccount.parentId]) &&
(!transaction.destinationAccount || !allFilterAccountIds.value[transaction.destinationAccount.parentId]) (!currentTransaction.destinationAccount || !allFilterAccountIds.value[currentTransaction.destinationAccount.parentId])
) )
) { ) {
transactionMonthList.items.splice(j, 1); transactionMonthList.items.splice(transactionIndex, 1);
} else { } else {
transactionMonthList.items.splice(j, 1, transaction); transactionMonthList.items.splice(transactionIndex, 1, currentTransaction);
} }
if (transactionMonthList.items.length < 1) { if (transactionMonthList.items.length < 1) {
transactions.value.splice(i, 1); transactions.value.splice(monthIndex, 1);
} else { } else {
calculateMonthTotalAmount(transactionMonthList, defaultCurrency, transactionsFilter.value.accountIds, i >= transactions.value.length - 1 && transactionsNextTimeId.value > 0); calculateMonthTotalAmount(transactionMonthList, defaultCurrency, transactionsFilter.value.accountIds, monthIndex >= transactions.value.length - 1 && transactionsNextTimeId.value > 0);
} }
return; return;
@@ -287,26 +284,24 @@ export const useTransactionsStore = defineStore('transactions', () => {
} }
} }
function removeTransactionFromTransactionList({ transaction, defaultCurrency }: { transaction: TransactionInfoResponse, defaultCurrency: string }): void { function removeTransactionFromTransactionList({ currentTransaction, defaultCurrency }: { currentTransaction: TransactionInfoResponse, defaultCurrency: string }): void {
for (let i = 0; i <transactions.value.length; i++) { for (const [transactionMonthList, monthIndex] of itemAndIndex(transactions.value)) {
const transactionMonthList = transactions.value[i];
if (!transactionMonthList.items || if (!transactionMonthList.items ||
transactionMonthList.items[0].time < transaction.time || transactionMonthList.items[0]!.time < currentTransaction.time ||
transactionMonthList.items[transactionMonthList.items.length - 1].time > transaction.time) { transactionMonthList.items[transactionMonthList.items.length - 1]!.time > currentTransaction.time) {
continue; continue;
} }
for (let j = 0; j < transactionMonthList.items.length; j++) { for (const [transaction, transactionIndex] of itemAndIndex(transactionMonthList.items)) {
if (transactionMonthList.items[j].id === transaction.id) { if (transaction.id === currentTransaction.id) {
transactionMonthList.items.splice(j, 1); transactionMonthList.items.splice(transactionIndex, 1);
} }
} }
if (transactionMonthList.items.length < 1) { if (transactionMonthList.items.length < 1) {
transactions.value.splice(i, 1); transactions.value.splice(monthIndex, 1);
} else { } else {
calculateMonthTotalAmount(transactionMonthList, defaultCurrency, transactionsFilter.value.accountIds, i >= transactions.value.length - 1 && transactionsNextTimeId.value > 0); calculateMonthTotalAmount(transactionMonthList, defaultCurrency, transactionsFilter.value.accountIds, monthIndex >= transactions.value.length - 1 && transactionsNextTimeId.value > 0);
} }
} }
} }
@@ -328,16 +323,15 @@ export const useTransactionsStore = defineStore('transactions', () => {
if (accountIds && accountIds !== '0') { if (accountIds && accountIds !== '0') {
const allAccountIdsArray = accountIds.split(','); const allAccountIdsArray = accountIds.split(',');
for (let i = 0; i < allAccountIdsArray.length; i++) { for (const accountId of allAccountIdsArray) {
if (allAccountIdsArray[i]) { if (accountId) {
allAccountIdsMap[allAccountIdsArray[i]] = true; allAccountIdsMap[accountId] = true;
totalAccountIdsCount++; totalAccountIdsCount++;
} }
} }
} }
for (let i = 0; i < transactionMonthList.items.length; i++) { for (const transaction of transactionMonthList.items) {
const transaction = transactionMonthList.items[i];
const transactionDay = isNumber(transaction.gregorianCalendarDayOfMonth) ? transaction.gregorianCalendarDayOfMonth.toString() : '0'; const transactionDay = isNumber(transaction.gregorianCalendarDayOfMonth) ? transaction.gregorianCalendarDayOfMonth.toString() : '0';
let dailyTotalAmount = dailyTotalAmounts[transactionDay]; let dailyTotalAmount = dailyTotalAmounts[transactionDay];
@@ -413,21 +407,11 @@ export const useTransactionsStore = defineStore('transactions', () => {
transactionMonthList.totalAmount.income = Math.trunc(totalIncome); transactionMonthList.totalAmount.income = Math.trunc(totalIncome);
transactionMonthList.totalAmount.incompleteIncome = incomplete || hasUnCalculatedTotalIncome; transactionMonthList.totalAmount.incompleteIncome = incomplete || hasUnCalculatedTotalIncome;
for (const day in transactionMonthList.dailyTotalAmounts) { for (const day of keys(transactionMonthList.dailyTotalAmounts)) {
if (!Object.prototype.hasOwnProperty.call(transactionMonthList.dailyTotalAmounts, day)) {
continue;
}
delete transactionMonthList.dailyTotalAmounts[day]; delete transactionMonthList.dailyTotalAmounts[day];
} }
for (const day in dailyTotalAmounts) { for (const [day, dailyTotalAmount] of entries(dailyTotalAmounts)) {
if (!Object.prototype.hasOwnProperty.call(dailyTotalAmounts, day)) {
continue;
}
const dailyTotalAmount = dailyTotalAmounts[day];
transactionMonthList.dailyTotalAmounts[day] = { transactionMonthList.dailyTotalAmounts[day] = {
expense: Math.trunc(dailyTotalAmount.expense), expense: Math.trunc(dailyTotalAmount.expense),
incompleteExpense: incomplete || dailyTotalAmount.incompleteExpense, incompleteExpense: incomplete || dailyTotalAmount.incompleteExpense,
@@ -1076,7 +1060,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
} }
} else { } else {
updateTransactionInTransactionList({ updateTransactionInTransactionList({
transaction: transaction, currentTransaction: transaction,
defaultCurrency: defaultCurrency defaultCurrency: defaultCurrency
}); });
} }
@@ -1131,13 +1115,13 @@ export const useTransactionsStore = defineStore('transactions', () => {
if (beforeResolve) { if (beforeResolve) {
beforeResolve(() => { beforeResolve(() => {
removeTransactionFromTransactionList({ removeTransactionFromTransactionList({
transaction: transaction, currentTransaction: transaction,
defaultCurrency: defaultCurrency defaultCurrency: defaultCurrency
}); });
}); });
} else { } else {
removeTransactionFromTransactionList({ removeTransactionFromTransactionList({
transaction: transaction, currentTransaction: transaction,
defaultCurrency: defaultCurrency defaultCurrency: defaultCurrency
}); });
} }
+38 -46
View File
@@ -3,6 +3,7 @@ import { defineStore } from 'pinia';
import type { BeforeResolveFunction } from '@/core/base.ts'; import type { BeforeResolveFunction } from '@/core/base.ts';
import { itemAndIndex, values } from '@/core/base.ts';
import { CategoryType } from '@/core/category.ts'; import { CategoryType } from '@/core/category.ts';
import { import {
@@ -53,23 +54,15 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
allTransactionCategories.value = allCategories; allTransactionCategories.value = allCategories;
allTransactionCategoriesMap.value = {}; allTransactionCategoriesMap.value = {};
for (const categoryType in allCategories) { for (const categories of values(allCategories)) {
if (!Object.prototype.hasOwnProperty.call(allCategories, categoryType)) { for (const category of categories) {
continue;
}
const categories = allCategories[categoryType];
for (let i = 0; i < categories.length; i++) {
const category = categories[i];
allTransactionCategoriesMap.value[category.id] = category; allTransactionCategoriesMap.value[category.id] = category;
if (!category.subCategories) { if (!category.subCategories) {
continue; continue;
} }
for (let j = 0; j < category.subCategories.length; j++) { for (const subCategory of category.subCategories) {
const subCategory = category.subCategories[j];
allTransactionCategoriesMap.value[subCategory.id] = subCategory; allTransactionCategoriesMap.value[subCategory.id] = subCategory;
} }
} }
@@ -82,7 +75,7 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
if (!category.parentId || category.parentId === '0') { if (!category.parentId || category.parentId === '0') {
categoryList = allTransactionCategories.value[category.type]; categoryList = allTransactionCategories.value[category.type];
} else if (allTransactionCategoriesMap.value[category.parentId]) { } else if (allTransactionCategoriesMap.value[category.parentId]) {
categoryList = allTransactionCategoriesMap.value[category.parentId].subCategories; categoryList = allTransactionCategoriesMap.value[category.parentId]!.subCategories;
} }
if (categoryList) { if (categoryList) {
@@ -92,33 +85,33 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
allTransactionCategoriesMap.value[category.id] = category; allTransactionCategoriesMap.value[category.id] = category;
} }
function updateCategoryInTransactionCategoryList(category: TransactionCategory, oldCategory: TransactionCategory): boolean { function updateCategoryInTransactionCategoryList(currentCategory: TransactionCategory, oldCategory?: TransactionCategory): boolean {
if (oldCategory && category.parentId !== oldCategory.parentId) { if (oldCategory && currentCategory.parentId !== oldCategory.parentId) {
return false; return false;
} }
let categoryList: TransactionCategory[] | undefined = undefined; let categoryList: TransactionCategory[] | undefined = undefined;
if (!category.parentId || category.parentId === '0') { if (!currentCategory.parentId || currentCategory.parentId === '0') {
categoryList = allTransactionCategories.value[category.type]; categoryList = allTransactionCategories.value[currentCategory.type];
} else if (allTransactionCategoriesMap.value[category.parentId]) { } else if (allTransactionCategoriesMap.value[currentCategory.parentId]) {
categoryList = allTransactionCategoriesMap.value[category.parentId].subCategories; categoryList = allTransactionCategoriesMap.value[currentCategory.parentId]!.subCategories;
} }
if (categoryList) { if (categoryList) {
for (let i = 0; i < categoryList.length; i++) { for (const [category, index] of itemAndIndex(categoryList)) {
if (categoryList[i].id === category.id) { if (category.id === currentCategory.id) {
if (!category.parentId || category.parentId === '0') { if (!currentCategory.parentId || currentCategory.parentId === '0') {
category.subCategories = categoryList[i].subCategories; currentCategory.subCategories = category.subCategories;
} }
categoryList.splice(i, 1, category); categoryList.splice(index, 1, currentCategory);
break; break;
} }
} }
} }
allTransactionCategoriesMap.value[category.id] = category; allTransactionCategoriesMap.value[currentCategory.id] = currentCategory;
return true; return true;
} }
@@ -128,44 +121,43 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
if (!category.parentId || category.parentId === '0') { if (!category.parentId || category.parentId === '0') {
categoryList = allTransactionCategories.value[category.type]; categoryList = allTransactionCategories.value[category.type];
} else if (allTransactionCategoriesMap.value[category.parentId]) { } else if (allTransactionCategoriesMap.value[category.parentId]) {
categoryList = allTransactionCategoriesMap.value[category.parentId].subCategories; categoryList = allTransactionCategoriesMap.value[category.parentId]!.subCategories;
} }
if (categoryList) { if (categoryList) {
categoryList.splice(to, 0, categoryList.splice(from, 1)[0]); categoryList.splice(to, 0, categoryList.splice(from, 1)[0] as TransactionCategory);
} }
} }
function updateCategoryVisibilityInTransactionCategoryList({ category, hidden }: { category: TransactionCategory, hidden: boolean }): void { function updateCategoryVisibilityInTransactionCategoryList({ category, hidden }: { category: TransactionCategory, hidden: boolean }): void {
if (allTransactionCategoriesMap.value[category.id]) { if (allTransactionCategoriesMap.value[category.id]) {
allTransactionCategoriesMap.value[category.id].visible = !hidden; allTransactionCategoriesMap.value[category.id]!.visible = !hidden;
} }
} }
function removeCategoryFromTransactionCategoryList(category: TransactionCategory): void { function removeCategoryFromTransactionCategoryList(currentCategory: TransactionCategory): void {
let categoryList: TransactionCategory[] | undefined = undefined; let categoryList: TransactionCategory[] | undefined = undefined;
if (!category.parentId || category.parentId === '0') { if (!currentCategory.parentId || currentCategory.parentId === '0') {
categoryList = allTransactionCategories.value[category.type]; categoryList = allTransactionCategories.value[currentCategory.type];
} else if (allTransactionCategoriesMap.value[category.parentId]) { } else if (allTransactionCategoriesMap.value[currentCategory.parentId]) {
categoryList = allTransactionCategoriesMap.value[category.parentId].subCategories; categoryList = allTransactionCategoriesMap.value[currentCategory.parentId]!.subCategories;
} }
if (categoryList) { if (categoryList) {
for (let i = 0; i < categoryList.length; i++) { for (const [category, index] of itemAndIndex(categoryList)) {
if (categoryList[i].id === category.id) { if (category.id === currentCategory.id) {
categoryList.splice(i, 1); categoryList.splice(index, 1);
break; break;
} }
} }
} }
if (allTransactionCategoriesMap.value[category.id] && allTransactionCategoriesMap.value[category.id].subCategories) { if (allTransactionCategoriesMap.value[currentCategory.id] && allTransactionCategoriesMap.value[currentCategory.id]!.subCategories) {
const subCategoryList = allTransactionCategoriesMap.value[category.id].subCategories; const subCategoryList = allTransactionCategoriesMap.value[currentCategory.id]!.subCategories;
if (subCategoryList) { if (subCategoryList) {
for (let i = 0; i < subCategoryList.length; i++) { for (const subCategory of subCategoryList) {
const subCategory = subCategoryList[i];
if (allTransactionCategoriesMap.value[subCategory.id]) { if (allTransactionCategoriesMap.value[subCategory.id]) {
delete allTransactionCategoriesMap.value[subCategory.id]; delete allTransactionCategoriesMap.value[subCategory.id];
} }
@@ -173,8 +165,8 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
} }
} }
if (allTransactionCategoriesMap.value[category.id]) { if (allTransactionCategoriesMap.value[currentCategory.id]) {
delete allTransactionCategoriesMap.value[category.id]; delete allTransactionCategoriesMap.value[currentCategory.id];
} }
} }
@@ -403,12 +395,12 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
if (!category.parentId || category.parentId === '0') { if (!category.parentId || category.parentId === '0') {
if (!allTransactionCategories.value[category.type] || if (!allTransactionCategories.value[category.type] ||
!allTransactionCategories.value[category.type][to]) { !allTransactionCategories.value[category.type]![to]) {
reject({ message: 'Unable to move category' }); reject({ message: 'Unable to move category' });
return; return;
} }
} else { } else {
const subCategoryList = allTransactionCategoriesMap.value[category.parentId].subCategories; const subCategoryList = allTransactionCategoriesMap.value[category.parentId]?.subCategories;
if (!subCategoryList || !subCategoryList[to]) { if (!subCategoryList || !subCategoryList[to]) {
reject({ message: 'Unable to move category' }); reject({ message: 'Unable to move category' });
@@ -438,10 +430,10 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
} }
if (categoryList) { if (categoryList) {
for (let i = 0; i < categoryList.length; i++) { for (const [category, index] of itemAndIndex(categoryList)) {
newDisplayOrders.push({ newDisplayOrders.push({
id: categoryList[i].id, id: category.id,
displayOrder: i + 1 displayOrder: index + 1
}); });
} }
} }
+28 -44
View File
@@ -1,7 +1,7 @@
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import type { BeforeResolveFunction } from '@/core/base.ts'; import { type BeforeResolveFunction, itemAndIndex, entries } from '@/core/base.ts';
import { TransactionType } from '@/core/transaction.ts'; import { TransactionType } from '@/core/transaction.ts';
@@ -24,23 +24,16 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
const allVisibleTemplates = computed<Record<number, TransactionTemplate[]>>(() => { const allVisibleTemplates = computed<Record<number, TransactionTemplate[]>>(() => {
const allVisibleTemplates: Record<number, TransactionTemplate[]> = {}; const allVisibleTemplates: Record<number, TransactionTemplate[]> = {};
for (const templateType in allTransactionTemplates.value) { for (const [templateType, allTemplates] of entries(allTransactionTemplates.value)) {
if (!Object.prototype.hasOwnProperty.call(allTransactionTemplates.value, templateType)) {
continue;
}
const allTemplates = allTransactionTemplates.value[templateType];
const visibleTemplates: TransactionTemplate[] = []; const visibleTemplates: TransactionTemplate[] = [];
for (let i = 0; i < allTemplates.length; i++) { for (const template of allTemplates) {
const template = allTemplates[i];
if (!template.hidden) { if (!template.hidden) {
visibleTemplates.push(template); visibleTemplates.push(template);
} }
} }
allVisibleTemplates[templateType] = visibleTemplates; allVisibleTemplates[parseInt(templateType)] = visibleTemplates;
} }
return allVisibleTemplates; return allVisibleTemplates;
@@ -49,12 +42,8 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
const allAvailableTemplatesCount = computed<Record<number, number>>(() => { const allAvailableTemplatesCount = computed<Record<number, number>>(() => {
const allAvailableTemplateCounts: Record<number, number> = {}; const allAvailableTemplateCounts: Record<number, number> = {};
for (const templateType in allTransactionTemplates.value) { for (const [templateType, allTemplates] of entries(allTransactionTemplates.value)) {
if (!Object.prototype.hasOwnProperty.call(allTransactionTemplates.value, templateType)) { allAvailableTemplateCounts[parseInt(templateType)] = allTemplates.length;
continue;
}
allAvailableTemplateCounts[templateType] = allTransactionTemplates.value[templateType].length;
} }
return allAvailableTemplateCounts; return allAvailableTemplateCounts;
@@ -63,12 +52,8 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
const allVisibleTemplatesCount = computed<Record<number, number>>(() => { const allVisibleTemplatesCount = computed<Record<number, number>>(() => {
const allVisibleTemplateCounts: Record<number, number> = {}; const allVisibleTemplateCounts: Record<number, number> = {};
for (const templateType in allVisibleTemplates.value) { for (const [templateType, allTemplates] of entries(allVisibleTemplates.value)) {
if (!Object.prototype.hasOwnProperty.call(allVisibleTemplates.value, templateType)) { allVisibleTemplateCounts[parseInt(templateType)] = allTemplates.length;
continue;
}
allVisibleTemplateCounts[templateType] = allVisibleTemplates.value[templateType].length;
} }
return allVisibleTemplateCounts; return allVisibleTemplateCounts;
@@ -78,8 +63,7 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
allTransactionTemplates.value[templateType] = templates; allTransactionTemplates.value[templateType] = templates;
allTransactionTemplatesMap.value[templateType] = {}; allTransactionTemplatesMap.value[templateType] = {};
for (let i = 0; i < templates.length; i++) { for (const template of templates) {
const template = templates[i];
allTransactionTemplatesMap.value[templateType][template.id] = template; allTransactionTemplatesMap.value[templateType][template.id] = template;
} }
} }
@@ -102,9 +86,9 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
const templateMap = allTransactionTemplatesMap.value[templateType]; const templateMap = allTransactionTemplatesMap.value[templateType];
if (isArray(templates)) { if (isArray(templates)) {
for (let i = 0; i < templates.length; i++) { for (const [template, index] of itemAndIndex(templates)) {
if (templates[i].id === template.id) { if (template.id === template.id) {
templates.splice(i, 1, template); templates.splice(index, 1, template);
break; break;
} }
} }
@@ -119,7 +103,7 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
const templates = allTransactionTemplates.value[templateType]; const templates = allTransactionTemplates.value[templateType];
if (isArray(templates)) { if (isArray(templates)) {
templates.splice(to, 0, templates.splice(from, 1)[0]); templates.splice(to, 0, templates.splice(from, 1)[0] as TransactionTemplate);
} }
} }
@@ -128,27 +112,27 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
if (isObject(templateMap)) { if (isObject(templateMap)) {
if (templateMap[template.id]) { if (templateMap[template.id]) {
templateMap[template.id].hidden = hidden; templateMap[template.id]!.hidden = hidden;
} }
} }
} }
function removeTemplateFromTransactionTemplateList(templateType: number, template: TransactionTemplate): void { function removeTemplateFromTransactionTemplateList(templateType: number, currentTemplate: TransactionTemplate): void {
const templates = allTransactionTemplates.value[templateType]; const templates = allTransactionTemplates.value[templateType];
const templateMap = allTransactionTemplatesMap.value[templateType]; const templateMap = allTransactionTemplatesMap.value[templateType];
if (isArray(templates)) { if (isArray(templates)) {
for (let i = 0; i < templates.length; i++) { for (const [template, index] of itemAndIndex(templates)) {
if (templates[i].id === template.id) { if (template.id === currentTemplate.id) {
templates.splice(i, 1); templates.splice(index, 1);
break; break;
} }
} }
} }
if (isObject(templateMap)) { if (isObject(templateMap)) {
if (templateMap[template.id]) { if (templateMap[currentTemplate.id]) {
delete templateMap[template.id]; delete templateMap[currentTemplate.id];
} }
} }
} }
@@ -298,21 +282,21 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
function changeTemplateDisplayOrder({ templateType, templateId, from, to }: { templateType: number, templateId: string, from: number, to: number }): Promise<void> { function changeTemplateDisplayOrder({ templateType, templateId, from, to }: { templateType: number, templateId: string, from: number, to: number }): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let template: TransactionTemplate | null = null; let currentTemplate: TransactionTemplate | null = null;
if (!isArray(allTransactionTemplates.value[templateType])) { if (!isArray(allTransactionTemplates.value[templateType])) {
reject({ message: 'Unable to move template' }); reject({ message: 'Unable to move template' });
return; return;
} }
for (let i = 0; i < allTransactionTemplates.value[templateType].length; i++) { for (const template of allTransactionTemplates.value[templateType]) {
if (allTransactionTemplates.value[templateType][i].id === templateId) { if (template.id === templateId) {
template = allTransactionTemplates.value[templateType][i]; currentTemplate = template;
break; break;
} }
} }
if (!template || !allTransactionTemplates.value[templateType][to]) { if (!currentTemplate || !allTransactionTemplates.value[templateType][to]) {
reject({ message: 'Unable to move template' }); reject({ message: 'Unable to move template' });
return; return;
} }
@@ -331,10 +315,10 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
const newDisplayOrders: TransactionTemplateNewDisplayOrderRequest[] = []; const newDisplayOrders: TransactionTemplateNewDisplayOrderRequest[] = [];
if (isArray(allTransactionTemplates.value[templateType])) { if (isArray(allTransactionTemplates.value[templateType])) {
for (let i = 0; i < allTransactionTemplates.value[templateType].length; i++) { for (const [template, index] of itemAndIndex(allTransactionTemplates.value[templateType])) {
newDisplayOrders.push({ newDisplayOrders.push({
id: allTransactionTemplates.value[templateType][i].id, id: template.id,
displayOrder: i + 1 displayOrder: index + 1
}); });
} }
} }
@@ -175,8 +175,7 @@ export function useAppCloudSyncBase() {
if (settings && settings.length > 0) { if (settings && settings.length > 0) {
settingsStore.setApplicationSettingsFromCloudSettings(settings); settingsStore.setApplicationSettingsFromCloudSettings(settings);
for (let i = 0; i < settings.length; i++) { for (const setting of settings) {
const setting = settings[i];
if (setting && setting.settingKey) { if (setting && setting.settingKey) {
enabledApplicationCloudSettings.value[setting.settingKey] = true; enabledApplicationCloudSettings.value[setting.settingKey] = true;
} }
+12 -10
View File
@@ -150,8 +150,8 @@
handle=".drag-handle" handle=".drag-handle"
ghost-class="dragging-item" ghost-class="dragging-item"
:disabled="activeAccountCategoryVisibleAccountCount <= 1" :disabled="activeAccountCategoryVisibleAccountCount <= 1"
:list="allCategorizedAccountsMap[activeAccountCategory.type].accounts" :list="allCategorizedAccountsMap[activeAccountCategory.type]!.accounts"
v-if="activeAccountCategory && allCategorizedAccountsMap[activeAccountCategory.type] && allCategorizedAccountsMap[activeAccountCategory.type].accounts && allCategorizedAccountsMap[activeAccountCategory.type].accounts.length" v-if="activeAccountCategory && allCategorizedAccountsMap[activeAccountCategory.type] && allCategorizedAccountsMap[activeAccountCategory.type]!.accounts && allCategorizedAccountsMap[activeAccountCategory.type]!.accounts.length"
@change="onMove" @change="onMove"
> >
<template #item="{ element }"> <template #item="{ element }">
@@ -376,20 +376,24 @@ const activeAccountCategory = computed<AccountCategory | undefined>(() => Accoun
const activeAccountCategoryTotalBalance = computed<string>(() => accountCategoryTotalBalance(activeAccountCategory.value)); const activeAccountCategoryTotalBalance = computed<string>(() => accountCategoryTotalBalance(activeAccountCategory.value));
const activeAccountCategoryVisibleAccountCount = computed<number>(() => { const activeAccountCategoryVisibleAccountCount = computed<number>(() => {
if (!activeAccountCategory.value || !allCategorizedAccountsMap.value[activeAccountCategory.value.type] || !allCategorizedAccountsMap.value[activeAccountCategory.value.type].accounts) { if (!activeAccountCategory.value) {
return 0; return 0;
} }
const accounts = allCategorizedAccountsMap.value[activeAccountCategory.value.type].accounts; const categorizedAccounts = allCategorizedAccountsMap.value[activeAccountCategory.value.type];
if (!categorizedAccounts || !categorizedAccounts.accounts || !categorizedAccounts.accounts.length) {
return 0;
}
if (showHidden.value) { if (showHidden.value) {
return accounts.length; return categorizedAccounts.accounts.length;
} }
let visibleCount = 0; let visibleCount = 0;
for (let i = 0; i < accounts.length; i++) { for (const account of categorizedAccounts.accounts) {
if (!accounts[i].hidden) { if (!account.hidden) {
visibleCount++; visibleCount++;
} }
} }
@@ -407,9 +411,7 @@ function reload(force: boolean): void {
displayOrderModified.value = false; displayOrderModified.value = false;
if (allAccounts.value) { if (allAccounts.value) {
for (let i = 0; i < allAccounts.value.length; i++) { for (const account of allAccounts.value) {
const account = allAccounts.value[i];
if (account.type === AccountType.MultiSubAccounts.type && !activeSubAccount.value[account.id]) { if (account.type === AccountType.MultiSubAccounts.type && !activeSubAccount.value[account.id]) {
activeSubAccount.value[account.id] = ''; activeSubAccount.value[account.id] = '';
} }
@@ -202,6 +202,7 @@ import { useAccountEditPageBaseBase } from '@/views/base/accounts/AccountEditPag
import { useUserStore } from '@/stores/user.ts'; import { useUserStore } from '@/stores/user.ts';
import { useAccountsStore } from '@/stores/account.ts'; import { useAccountsStore } from '@/stores/account.ts';
import { itemAndIndex } from '@/core/base.ts';
import { AccountType } from '@/core/account.ts'; import { AccountType } from '@/core/account.ts';
import { ALL_ACCOUNT_ICONS } from '@/consts/icon.ts'; import { ALL_ACCOUNT_ICONS } from '@/consts/icon.ts';
import { ALL_ACCOUNT_COLORS } from '@/consts/color.ts'; import { ALL_ACCOUNT_COLORS } from '@/consts/color.ts';
@@ -365,11 +366,11 @@ function save(): void {
}); });
} }
function removeSubAccount(subAccount: Account): void { function removeSubAccount(currentSubAccount: Account): void {
confirmDialog.value?.open('Are you sure you want to remove this sub-account?').then(() => { confirmDialog.value?.open('Are you sure you want to remove this sub-account?').then(() => {
for (let i = 0; i < subAccounts.value.length; i++) { for (const [subAccount, index] of itemAndIndex(subAccounts.value)) {
if (subAccounts.value[i] === subAccount) { if (subAccount === currentSubAccount) {
subAccounts.value.splice(i, 1); subAccounts.value.splice(index, 1);
if (currentAccountIndex.value >= subAccounts.value.length) { if (currentAccountIndex.value >= subAccounts.value.length) {
currentAccountIndex.value = subAccounts.value.length - 1; currentAccountIndex.value = subAccounts.value.length - 1;
@@ -162,15 +162,15 @@
<template #item.categoryId="{ item }"> <template #item.categoryId="{ item }">
<div class="d-flex align-center"> <div class="d-flex align-center">
<ItemIcon size="24px" icon-type="category" <ItemIcon size="24px" icon-type="category"
:icon-id="allCategoriesMap[item.categoryId].icon" :icon-id="allCategoriesMap[item.categoryId]?.icon ?? ''"
:color="allCategoriesMap[item.categoryId].color" :color="allCategoriesMap[item.categoryId]?.color ?? ''"
v-if="allCategoriesMap[item.categoryId] && allCategoriesMap[item.categoryId]?.color"></ItemIcon> v-if="allCategoriesMap[item.categoryId] && allCategoriesMap[item.categoryId]?.color"></ItemIcon>
<v-icon size="24" :icon="mdiPencilBoxOutline" v-else-if="!allCategoriesMap[item.categoryId] || !allCategoriesMap[item.categoryId]?.color" /> <v-icon size="24" :icon="mdiPencilBoxOutline" v-else-if="!allCategoriesMap[item.categoryId] || !allCategoriesMap[item.categoryId]?.color" />
<span class="ms-2" v-if="item.type === TransactionType.ModifyBalance"> <span class="ms-2" v-if="item.type === TransactionType.ModifyBalance">
{{ tt('Modify Balance') }} {{ tt('Modify Balance') }}
</span> </span>
<span class="ms-2" v-else-if="item.type !== TransactionType.ModifyBalance && allCategoriesMap[item.categoryId]"> <span class="ms-2" v-else-if="item.type !== TransactionType.ModifyBalance && allCategoriesMap[item.categoryId]">
{{ allCategoriesMap[item.categoryId].name }} {{ allCategoriesMap[item.categoryId]?.name }}
</span> </span>
</div> </div>
</template> </template>
@@ -181,9 +181,9 @@
</template> </template>
<template #item.sourceAccountId="{ item }"> <template #item.sourceAccountId="{ item }">
<div class="d-flex align-center"> <div class="d-flex align-center">
<span v-if="item.sourceAccountId && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId].name }}</span> <span v-if="item.sourceAccountId && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId]?.name }}</span>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon> <v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && allAccountsMap[item.destinationAccountId]">{{ allAccountsMap[item.destinationAccountId].name }}</span> <span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && allAccountsMap[item.destinationAccountId]">{{ allAccountsMap[item.destinationAccountId]?.name }}</span>
</div> </div>
</template> </template>
<template #item.accountBalance="{ item }"> <template #item.accountBalance="{ item }">
@@ -388,12 +388,7 @@ const totalPageCount = computed<number>(() => {
return 1; return 1;
} }
let count = 0; const count = reconciliationStatements.value.transactions.length;
for (let i = 0; i < reconciliationStatements.value.transactions.length; i++) {
count++;
}
return Math.ceil(count / countPerPage.value); return Math.ceil(count / countPerPage.value);
}); });
@@ -422,9 +417,7 @@ function getTablePageOptions(linesCount?: number): NameNumeralValue[] {
const availableCountPerPage = [ 5, 10, 15, 20, 25, 30, 50 ]; const availableCountPerPage = [ 5, 10, 15, 20, 25, 30, 50 ];
for (let i = 0; i < availableCountPerPage.length; i++) { for (const count of availableCountPerPage) {
const count = availableCountPerPage[i];
if (linesCount < count) { if (linesCount < count) {
break; break;
} }
+2 -2
View File
@@ -259,7 +259,7 @@ const primaryCategories = computed<TransactionCategory[]>(() => {
return []; return [];
} }
return transactionCategoriesStore.allTransactionCategories[activeCategoryType.value]; return transactionCategoriesStore.allTransactionCategories[activeCategoryType.value] ?? [];
}); });
const secondaryCategories = computed<TransactionCategory[]>(() => { const secondaryCategories = computed<TransactionCategory[]>(() => {
@@ -267,7 +267,7 @@ const secondaryCategories = computed<TransactionCategory[]>(() => {
return []; return [];
} }
return transactionCategoriesStore.allTransactionCategoriesMap[primaryCategoryId.value].subCategories || []; return transactionCategoriesStore.allTransactionCategoriesMap[primaryCategoryId.value]?.subCategories ?? [];
}); });
const hasSubCategories = computed<boolean>(() => { const hasSubCategories = computed<boolean>(() => {
@@ -78,9 +78,7 @@ const hasAnyData = computed<boolean>(() => {
return false; return false;
} }
for (let i = 0; i < props.data.length; i++) { for (const item of props.data) {
const item = props.data[i];
if (item.incomeAmount > 0 || item.incomeAmount < 0 || item.expenseAmount > 0 || item.expenseAmount < 0) { if (item.incomeAmount > 0 || item.incomeAmount < 0 || item.expenseAmount > 0 || item.expenseAmount < 0) {
return true; return true;
} }
@@ -99,8 +97,7 @@ const chartOptions = computed<object>(() => {
const expenseIncomeAmountColor = getExpenseAndIncomeAmountColor(userStore.currentUserExpenseAmountColor, userStore.currentUserIncomeAmountColor, props.isDarkMode); const expenseIncomeAmountColor = getExpenseAndIncomeAmountColor(userStore.currentUserExpenseAmountColor, userStore.currentUserIncomeAmountColor, props.isDarkMode);
if (props.data) { if (props.data) {
for (let i = 0; i < props.data.length; i++) { for (const item of props.data) {
const item = props.data[i];
const monthShortName = formatUnixTimeToGregorianLikeShortMonth(item.monthStartTime); const monthShortName = formatUnixTimeToGregorianLikeShortMonth(item.monthStartTime);
monthNames.push(monthShortName); monthNames.push(monthShortName);
@@ -145,10 +142,9 @@ const chartOptions = computed<object>(() => {
let incomeAmount: string | null = null; let incomeAmount: string | null = null;
let expenseAmount: string | null = null; let expenseAmount: string | null = null;
for (let i = 0; i < params.length; i++) { for (const param of params) {
const param = params[i];
const dataIndex = param.dataIndex; const dataIndex = param.dataIndex;
const data = props.data[dataIndex]; const data = props.data[dataIndex] as TransactionMonthlyIncomeAndExpenseData;
if (param.seriesId === 'seriesIncome') { if (param.seriesId === 'seriesIncome') {
incomeAmount = getDisplayIncomeAmount(data); incomeAmount = getDisplayIncomeAmount(data);
@@ -160,7 +156,7 @@ const chartOptions = computed<object>(() => {
return `<table>` + return `<table>` +
`<thead>` + `<thead>` +
`<tr>` + `<tr>` +
`<td colspan="2" class="text-start">${params[0].name}</td>` + `<td colspan="2" class="text-start">${params[0]?.name}</td>` +
`</tr>` + `</tr>` +
`</thead>` + `</thead>` +
`<tbody>` + `<tbody>` +
+25 -28
View File
@@ -261,7 +261,7 @@
</v-list-item> </v-list-item>
<v-list-group :key="category.id" v-for="category in categories"> <v-list-group :key="category.id" v-for="category in categories">
<template #activator="{ props }" v-if="!category.hidden || query.categoryIds === category.id || (allCategories[query.categoryIds] && allCategories[query.categoryIds].parentId === category.id)"> <template #activator="{ props }" v-if="!category.hidden || query.categoryIds === category.id || (allCategories[query.categoryIds] && allCategories[query.categoryIds]!.parentId === category.id)">
<v-divider /> <v-divider />
<v-list-item class="text-sm" density="compact" <v-list-item class="text-sm" density="compact"
:class="getCategoryListItemCheckedClass(category, queryAllFilterCategoryIds)" :class="getCategoryListItemCheckedClass(category, queryAllFilterCategoryIds)"
@@ -402,12 +402,12 @@
</v-list-item> </v-list-item>
<template :key="account.id" <template :key="account.id"
v-for="account in allAccounts"> v-for="account in allAccounts">
<v-divider v-if="(!account.hidden && (!allAccountsMap[account.parentId] || !allAccountsMap[account.parentId].hidden)) || query.accountIds === account.id" /> <v-divider v-if="(!account.hidden && (!allAccountsMap[account.parentId] || !allAccountsMap[account.parentId]!.hidden)) || query.accountIds === account.id" />
<v-list-item class="text-sm" density="compact" <v-list-item class="text-sm" density="compact"
:value="account.id" :value="account.id"
:class="{ 'list-item-selected': query.accountIds === account.id, 'item-in-multiple-selection': queryAllFilterAccountIdsCount > 1 && queryAllFilterAccountIds[account.id] }" :class="{ 'list-item-selected': query.accountIds === account.id, 'item-in-multiple-selection': queryAllFilterAccountIdsCount > 1 && queryAllFilterAccountIds[account.id] }"
:append-icon="(query.accountIds === account.id ? mdiCheck : undefined)" :append-icon="(query.accountIds === account.id ? mdiCheck : undefined)"
v-if="(!account.hidden && (!allAccountsMap[account.parentId] || !allAccountsMap[account.parentId].hidden)) || query.accountIds === account.id"> v-if="(!account.hidden && (!allAccountsMap[account.parentId] || !allAccountsMap[account.parentId]!.hidden)) || query.accountIds === account.id">
<v-list-item-title class="cursor-pointer" <v-list-item-title class="cursor-pointer"
@click="changeAccountFilter(account.id)"> @click="changeAccountFilter(account.id)">
<div class="d-flex align-center"> <div class="d-flex align-center">
@@ -527,7 +527,7 @@
:class="{ 'disabled': loading, 'has-bottom-border': idx < transactions.length - 1 }" :class="{ 'disabled': loading, 'has-bottom-border': idx < transactions.length - 1 }"
v-for="(transaction, idx) in transactions"> v-for="(transaction, idx) in transactions">
<tr class="transaction-list-row-date no-hover text-sm" <tr class="transaction-list-row-date no-hover text-sm"
v-if="pageType === TransactionListPageType.List.type && (idx === 0 || (idx > 0 && (transaction.gregorianCalendarYearDashMonthDashDay !== transactions[idx - 1].gregorianCalendarYearDashMonthDashDay)))"> v-if="pageType === TransactionListPageType.List.type && (idx === 0 || (idx > 0 && (transaction.gregorianCalendarYearDashMonthDashDay !== transactions[idx - 1]!.gregorianCalendarYearDashMonthDashDay)))">
<td :colspan="showTagInTransactionListPage ? 6 : 5" class="font-weight-bold"> <td :colspan="showTagInTransactionListPage ? 6 : 5" class="font-weight-bold">
<div class="d-flex align-center"> <div class="d-flex align-center">
<span>{{ getDisplayLongDate(transaction) }}</span> <span>{{ getDisplayLongDate(transaction) }}</span>
@@ -579,7 +579,7 @@
</td> </td>
<td class="transaction-table-column-tags" v-if="showTagInTransactionListPage"> <td class="transaction-table-column-tags" v-if="showTagInTransactionListPage">
<v-chip class="transaction-tag" size="small" :prepend-icon="mdiPound" <v-chip class="transaction-tag" size="small" :prepend-icon="mdiPound"
:text="allTransactionTags[tagId].name" :text="allTransactionTags[tagId]?.name"
:key="tagId" :key="tagId"
v-for="tagId in transaction.tagIds"/> v-for="tagId in transaction.tagIds"/>
<v-chip class="transaction-tag" size="small" <v-chip class="transaction-tag" size="small"
@@ -669,7 +669,11 @@ import { useTransactionsStore } from '@/stores/transaction.ts';
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.ts'; import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.ts';
import { useDesktopPageStore } from '@/stores/desktopPage.ts'; import { useDesktopPageStore } from '@/stores/desktopPage.ts';
import type { NameNumeralValue, TypeAndDisplayName } from '@/core/base.ts'; import {
type NameNumeralValue,
type TypeAndDisplayName,
keys
} from '@/core/base.ts';
import { import {
type Year0BasedMonth, type Year0BasedMonth,
type LocalizedRecentMonthDateRange, type LocalizedRecentMonthDateRange,
@@ -884,8 +888,7 @@ const allPageCounts = computed<NameNumeralValue[]>(() => {
const pageCounts: NameNumeralValue[] = []; const pageCounts: NameNumeralValue[] = [];
const availableCountPerPage: number[] = [ 5, 10, 15, 20, 25, 30, 50 ]; const availableCountPerPage: number[] = [ 5, 10, 15, 20, 25, 30, 50 ];
for (let i = 0; i < availableCountPerPage.length; i++) { for (const count of availableCountPerPage) {
const count = availableCountPerPage[i];
pageCounts.push({ value: count, name: numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(count.toString()) }); pageCounts.push({ value: count, name: numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(count.toString()) });
} }
@@ -903,11 +906,11 @@ const allTransactionTagFilterTypes = computed<TransactionTemplateWithIcon[]>(()
const allTagFilterTypes: TypeAndDisplayName[] = getAllTransactionTagFilterTypes(); const allTagFilterTypes: TypeAndDisplayName[] = getAllTransactionTagFilterTypes();
const allTagFilterTypesWithIcon: TransactionTemplateWithIcon[] = []; const allTagFilterTypesWithIcon: TransactionTemplateWithIcon[] = [];
for (let i = 0; i < allTagFilterTypes.length; i++) { for (const tagFilterType of allTagFilterTypes) {
allTagFilterTypesWithIcon.push({ allTagFilterTypesWithIcon.push({
type: allTagFilterTypes[i].type, type: tagFilterType.type,
displayName: allTagFilterTypes[i].displayName, displayName: tagFilterType.displayName,
icon: tagFilterIconMap[allTagFilterTypes[i].type] icon: tagFilterIconMap[tagFilterType.type] ?? ''
}); });
} }
@@ -948,9 +951,7 @@ const transactions = computed<Transaction[]>(() => {
const transactions :Transaction[] = []; const transactions :Transaction[] = [];
for (let i = 0; i < transactionData.items.length; i++) { for (const transaction of transactionData.items) {
const transaction = transactionData.items[i];
if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) { if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) {
transactions.push(transaction); transactions.push(transaction);
} }
@@ -972,7 +973,7 @@ const recentDateRangeIndex = computed<number>({
value = 0; value = 0;
} }
changeDateFilter(recentMonthDateRanges.value[value]); changeDateFilter(recentMonthDateRanges.value[value] as LocalizedRecentMonthDateRange);
} }
}); });
@@ -1089,8 +1090,8 @@ function getCategoryListItemCheckedClass(category: TransactionCategory, queryCat
} }
if (category.subCategories) { if (category.subCategories) {
for (let i = 0; i < category.subCategories.length; i++) { for (const subCategory of category.subCategories) {
if (queryCategoryIds && queryCategoryIds[category.subCategories[i].id]) { if (queryCategoryIds && queryCategoryIds[subCategory.id]) {
return { return {
'list-item-selected': true, 'list-item-selected': true,
'has-children-item-selected': true 'has-children-item-selected': true
@@ -1382,7 +1383,7 @@ function changeCustomMonthDateFilter(yearMonth: Year0BasedMonth): void {
} }
function shiftDateRange(startTime: number, endTime: number, scale: number): void { function shiftDateRange(startTime: number, endTime: number, scale: number): void {
if (recentMonthDateRanges.value[recentDateRangeIndex.value].dateType === DateRange.All.type) { if (recentMonthDateRanges.value[recentDateRangeIndex.value]?.dateType === DateRange.All.type) {
return; return;
} }
@@ -1421,11 +1422,7 @@ function changeTypeFilter(type: number): void {
if (type && query.value.categoryIds) { if (type && query.value.categoryIds) {
newCategoryFilter = ''; newCategoryFilter = '';
for (const categoryId in queryAllFilterCategoryIds.value) { for (const categoryId of keys(queryAllFilterCategoryIds.value)) {
if (!Object.prototype.hasOwnProperty.call(queryAllFilterCategoryIds.value, categoryId)) {
continue;
}
const category = allCategories.value[categoryId]; const category = allCategories.value[categoryId];
if (category && category.type === transactionTypeToCategoryType(type)) { if (category && category.type === transactionTypeToCategoryType(type)) {
@@ -1680,13 +1677,13 @@ function scrollAmountMenuToSelectedItem(opened: boolean): void {
if (isString(query.value.amountFilter)) { if (isString(query.value.amountFilter)) {
try { try {
const filterItems = query.value.amountFilter.split(':'); const filterItems = query.value.amountFilter.split(':');
const amountCount = getAmountFilterParameterCount(filterItems[0]); const amountCount = getAmountFilterParameterCount(filterItems[0] as string);
if (filterItems.length === 2 && amountCount === 1) { if (filterItems.length === 2 && amountCount === 1) {
amount1 = parseInt(filterItems[1]); amount1 = parseInt(filterItems[1] as string);
} else if (filterItems.length === 3 && amountCount === 2) { } else if (filterItems.length === 3 && amountCount === 2) {
amount1 = parseInt(filterItems[1]); amount1 = parseInt(filterItems[1] as string);
amount2 = parseInt(filterItems[2]); amount2 = parseInt(filterItems[2] as string);
} }
} catch (ex) { } catch (ex) {
logger.warn('cannot parse amount from filter value, original value is ' + query.value.amountFilter, ex); logger.warn('cannot parse amount from filter value, original value is ' + query.value.amountFilter, ex);
@@ -93,11 +93,11 @@
<div class="d-flex align-center" v-if="editingTransaction !== item || item.type === TransactionType.ModifyBalance"> <div class="d-flex align-center" v-if="editingTransaction !== item || item.type === TransactionType.ModifyBalance">
<span v-if="item.type === TransactionType.ModifyBalance">-</span> <span v-if="item.type === TransactionType.ModifyBalance">-</span>
<ItemIcon size="24px" icon-type="category" <ItemIcon size="24px" icon-type="category"
:icon-id="allCategoriesMap[item.categoryId].icon" :icon-id="allCategoriesMap[item.categoryId]?.icon ?? ''"
:color="allCategoriesMap[item.categoryId].color" :color="allCategoriesMap[item.categoryId]?.color ?? ''"
v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]"></ItemIcon> v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]"></ItemIcon>
<span class="ms-2" v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]"> <span class="ms-2" v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]">
{{ allCategoriesMap[item.categoryId].name }} {{ allCategoriesMap[item.categoryId]?.name }}
</span> </span>
<div class="text-error font-italic" v-else-if="item.type !== TransactionType.ModifyBalance && (!item.categoryId || item.categoryId === '0' || !allCategoriesMap[item.categoryId])"> <div class="text-error font-italic" v-else-if="item.type !== TransactionType.ModifyBalance && (!item.categoryId || item.categoryId === '0' || !allCategoriesMap[item.categoryId])">
<v-icon class="me-1" :icon="mdiAlertOutline"/> <v-icon class="me-1" :icon="mdiAlertOutline"/>
@@ -166,13 +166,13 @@
</template> </template>
<template #item.actualSourceAccountName="{ item }"> <template #item.actualSourceAccountName="{ item }">
<div class="d-flex align-center" v-if="editingTransaction !== item"> <div class="d-flex align-center" v-if="editingTransaction !== item">
<span v-if="item.sourceAccountId && item.sourceAccountId !== '0' && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId].name }}</span> <span v-if="item.sourceAccountId && item.sourceAccountId !== '0' && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId]?.name }}</span>
<div class="text-error font-italic" v-else> <div class="text-error font-italic" v-else>
<v-icon class="me-1" :icon="mdiAlertOutline"/> <v-icon class="me-1" :icon="mdiAlertOutline"/>
<span>{{ item.originalSourceAccountName }}</span> <span>{{ item.originalSourceAccountName }}</span>
</div> </div>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon> <v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && item.destinationAccountId !== '0' && allAccountsMap[item.destinationAccountId]">{{allAccountsMap[item.destinationAccountId].name }}</span> <span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && item.destinationAccountId !== '0' && allAccountsMap[item.destinationAccountId]">{{allAccountsMap[item.destinationAccountId]?.name }}</span>
<div class="text-error font-italic" v-else-if="item.type === TransactionType.Transfer && (!item.destinationAccountId || item.destinationAccountId === '0' || !allAccountsMap[item.destinationAccountId])"> <div class="text-error font-italic" v-else-if="item.type === TransactionType.Transfer && (!item.destinationAccountId || item.destinationAccountId === '0' || !allAccountsMap[item.destinationAccountId])">
<v-icon class="me-1" :icon="mdiAlertOutline"/> <v-icon class="me-1" :icon="mdiAlertOutline"/>
<span>{{ item.originalDestinationAccountName }}</span> <span>{{ item.originalDestinationAccountName }}</span>
@@ -252,7 +252,7 @@
<v-chip :class="{ 'font-italic': !isTagValid(editingTags, index) }" <v-chip :class="{ 'font-italic': !isTagValid(editingTags, index) }"
:prepend-icon="isTagValid(editingTags, index) ? mdiPound : mdiAlertOutline" :prepend-icon="isTagValid(editingTags, index) ? mdiPound : mdiAlertOutline"
:color="isTagValid(editingTags, index) ? 'default' : 'error'" :color="isTagValid(editingTags, index) ? 'default' : 'error'"
:text="isTagValid(editingTags, index) ? allTagsMap[editingTags[index]].name : item.originalTagNames[index]" :text="isTagValid(editingTags, index) ? allTagsMap[editingTags[index] as string]?.name : item.originalTagNames[index]"
v-bind="props"/> v-bind="props"/>
</template> </template>
@@ -1153,7 +1153,7 @@ function getTransactionDisplayAmount(transaction: ImportTransaction): string {
let currency = transaction.originalSourceAccountCurrency || defaultCurrency.value; let currency = transaction.originalSourceAccountCurrency || defaultCurrency.value;
if (transaction.sourceAccountId && transaction.sourceAccountId !== '0' && allAccountsMap.value[transaction.sourceAccountId]) { if (transaction.sourceAccountId && transaction.sourceAccountId !== '0' && allAccountsMap.value[transaction.sourceAccountId]) {
currency = allAccountsMap.value[transaction.sourceAccountId].currency; currency = allAccountsMap.value[transaction.sourceAccountId]!.currency;
} }
return getDisplayCurrency(transaction.sourceAmount, currency); return getDisplayCurrency(transaction.sourceAmount, currency);
@@ -1167,7 +1167,7 @@ function getTransactionDisplayDestinationAmount(transaction: ImportTransaction):
let currency = transaction.originalDestinationAccountCurrency || defaultCurrency.value; let currency = transaction.originalDestinationAccountCurrency || defaultCurrency.value;
if (transaction.destinationAccountId && transaction.destinationAccountId !== '0' && allAccountsMap.value[transaction.destinationAccountId]) { if (transaction.destinationAccountId && transaction.destinationAccountId !== '0' && allAccountsMap.value[transaction.destinationAccountId]) {
currency = allAccountsMap.value[transaction.destinationAccountId].currency; currency = allAccountsMap.value[transaction.destinationAccountId]!.currency;
} }
return getDisplayCurrency(transaction.destinationAmount, currency); return getDisplayCurrency(transaction.destinationAmount, currency);
@@ -1425,15 +1425,15 @@ function updateTransactionData(transaction: ImportTransaction): void {
transaction.valid = transaction.isTransactionValid(); transaction.valid = transaction.isTransactionValid();
if (transaction.categoryId && allCategoriesMap.value[transaction.categoryId]) { if (transaction.categoryId && allCategoriesMap.value[transaction.categoryId]) {
transaction.actualCategoryName = allCategoriesMap.value[transaction.categoryId].name; transaction.actualCategoryName = allCategoriesMap.value[transaction.categoryId]!.name;
} }
if (transaction.sourceAccountId && allAccountsMap.value[transaction.sourceAccountId]) { if (transaction.sourceAccountId && allAccountsMap.value[transaction.sourceAccountId]) {
transaction.actualSourceAccountName = allAccountsMap.value[transaction.sourceAccountId].name; transaction.actualSourceAccountName = allAccountsMap.value[transaction.sourceAccountId]!.name;
} }
if (transaction.destinationAccountId && allAccountsMap.value[transaction.destinationAccountId]) { if (transaction.destinationAccountId && allAccountsMap.value[transaction.destinationAccountId]) {
transaction.actualDestinationAccountName = allAccountsMap.value[transaction.destinationAccountId].name; transaction.actualDestinationAccountName = allAccountsMap.value[transaction.destinationAccountId]!.name;
} }
} }
@@ -358,15 +358,16 @@ const parsedFileLinesHeaders = computed<object[]>(() => {
} }
} }
const headers: object[] = []; const firstLine: string[] = props.parsedFileData && props.parsedFileData.length > 0 ? (props.parsedFileData[0] as string[]) : [];
const headers: object[] = [];
headers.push({ key: 'index', value: 'index', title: '#', sortable: true, nowrap: true }); headers.push({ key: 'index', value: 'index', title: '#', sortable: true, nowrap: true });
for (let i = 0; i < maxColumnCount; i++) { for (let i = 0; i < maxColumnCount; i++) {
let title = `#${i + 1}`; let title = `#${i + 1}`;
if (parsedFileDataColumnMapping.value.includeHeader && props.parsedFileData && props.parsedFileData[0][i]) { if (parsedFileDataColumnMapping.value.includeHeader && firstLine && firstLine[i]) {
title = props.parsedFileData[0][i] as string; title = firstLine[i] as string;
} }
headers.push({ key: i.toString(), value: `column${i + 1}`, title: title, sortable: true, nowrap: true }); headers.push({ key: i.toString(), value: `column${i + 1}`, title: title, sortable: true, nowrap: true });
+20 -19
View File
@@ -370,7 +370,7 @@
<template #default> <template #default>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<div class="list-item-subitem no-chevron"> <div class="list-item-subitem no-chevron">
<a class="item-link" href="#" @click="subAccountContexts[idx].showIconSelectionSheet = true"> <a class="item-link" href="#" @click="subAccountContexts[idx]!.showIconSelectionSheet = true">
<div class="item-content"> <div class="item-content">
<div class="item-inner"> <div class="item-inner">
<div class="item-header"> <div class="item-header">
@@ -387,12 +387,12 @@
<icon-selection-sheet :all-icon-infos="ALL_ACCOUNT_ICONS" <icon-selection-sheet :all-icon-infos="ALL_ACCOUNT_ICONS"
:color="subAccount.color" :color="subAccount.color"
v-model:show="subAccountContexts[idx].showIconSelectionSheet" v-model:show="subAccountContexts[idx]!.showIconSelectionSheet"
v-model="subAccount.icon" v-model="subAccount.icon"
></icon-selection-sheet> ></icon-selection-sheet>
</div> </div>
<div class="list-item-subitem no-chevron"> <div class="list-item-subitem no-chevron">
<a class="item-link" href="#" @click="subAccountContexts[idx].showColorSelectionSheet = true"> <a class="item-link" href="#" @click="subAccountContexts[idx]!.showColorSelectionSheet = true">
<div class="item-content"> <div class="item-content">
<div class="item-inner"> <div class="item-inner">
<div class="item-header"> <div class="item-header">
@@ -408,7 +408,7 @@
</a> </a>
<color-selection-sheet :all-color-infos="ALL_ACCOUNT_COLORS" <color-selection-sheet :all-color-infos="ALL_ACCOUNT_COLORS"
v-model:show="subAccountContexts[idx].showColorSelectionSheet" v-model:show="subAccountContexts[idx]!.showColorSelectionSheet"
v-model="subAccount.color" v-model="subAccount.color"
></color-selection-sheet> ></color-selection-sheet>
</div> </div>
@@ -422,7 +422,7 @@
:class="{ 'disabled': editAccountId && !isNewAccount(subAccount) }" :class="{ 'disabled': editAccountId && !isNewAccount(subAccount) }"
:header="tt('Currency')" :header="tt('Currency')"
:no-chevron="!!editAccountId && !isNewAccount(subAccount)" :no-chevron="!!editAccountId && !isNewAccount(subAccount)"
@click="subAccountContexts[idx].showCurrencyPopup = true" @click="subAccountContexts[idx]!.showCurrencyPopup = true"
> >
<template #title> <template #title>
<div class="no-padding no-margin"> <div class="no-padding no-margin">
@@ -438,7 +438,7 @@
:filter-placeholder="tt('Currency')" :filter-placeholder="tt('Currency')"
:filter-no-items-text="tt('No results')" :filter-no-items-text="tt('No results')"
:items="allCurrencies" :items="allCurrencies"
v-model:show="subAccountContexts[idx].showCurrencyPopup" v-model:show="subAccountContexts[idx]!.showCurrencyPopup"
v-model="subAccount.currency"> v-model="subAccount.currency">
</list-item-selection-popup> </list-item-selection-popup>
</f7-list-item> </f7-list-item>
@@ -449,13 +449,13 @@
:class="{ 'disabled': editAccountId && !isNewAccount(subAccount) }" :class="{ 'disabled': editAccountId && !isNewAccount(subAccount) }"
:header="account.isLiability ? tt('Sub-account Outstanding Balance') : tt('Sub-account Balance')" :header="account.isLiability ? tt('Sub-account Outstanding Balance') : tt('Sub-account Balance')"
:title="formatAccountDisplayBalance(subAccount)" :title="formatAccountDisplayBalance(subAccount)"
@click="subAccountContexts[idx].showBalanceSheet = true" @click="subAccountContexts[idx]!.showBalanceSheet = true"
> >
<number-pad-sheet :min-value="TRANSACTION_MIN_AMOUNT" <number-pad-sheet :min-value="TRANSACTION_MIN_AMOUNT"
:max-value="TRANSACTION_MAX_AMOUNT" :max-value="TRANSACTION_MAX_AMOUNT"
:currency="subAccount.currency" :currency="subAccount.currency"
:flip-negative="account.isLiability" :flip-negative="account.isLiability"
v-model:show="subAccountContexts[idx].showBalanceSheet" v-model:show="subAccountContexts[idx]!.showBalanceSheet"
v-model="subAccount.balance" v-model="subAccount.balance"
></number-pad-sheet> ></number-pad-sheet>
</f7-list-item> </f7-list-item>
@@ -467,15 +467,15 @@
v-if="!editAccountId || isNewAccount(subAccount)" v-if="!editAccountId || isNewAccount(subAccount)"
> >
<template #header> <template #header>
<div class="account-edit-balancetime-header" @click="showDateTimeDialog(subAccountContexts[idx], 'time')">{{ tt('Sub-account Balance Time') }}</div> <div class="account-edit-balancetime-header" @click="showDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ tt('Sub-account Balance Time') }}</div>
</template> </template>
<template #title> <template #title>
<div class="account-edit-balancetime-title"> <div class="account-edit-balancetime-title">
<div @click="showDateTimeDialog(subAccountContexts[idx], 'date')">{{ formatAccountBalanceDate(subAccount) }}</div>&nbsp;<div class="account-edit-balancetime-time" @click="showDateTimeDialog(subAccountContexts[idx], 'time')">{{ formatAccountBalanceTime(subAccount) }}</div> <div @click="showDateTimeDialog(subAccountContexts[idx] as AccountContext, 'date')">{{ formatAccountBalanceDate(subAccount) }}</div>&nbsp;<div class="account-edit-balancetime-time" @click="showDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ formatAccountBalanceTime(subAccount) }}</div>
</div> </div>
</template> </template>
<date-time-selection-sheet :init-mode="subAccountContexts[idx].balanceDateTimeSheetMode" <date-time-selection-sheet :init-mode="subAccountContexts[idx]!.balanceDateTimeSheetMode"
v-model:show="subAccountContexts[idx].showBalanceDateTimeSheet" v-model:show="subAccountContexts[idx]!.showBalanceDateTimeSheet"
v-model="subAccount.balanceTime"> v-model="subAccount.balanceTime">
</date-time-selection-sheet> </date-time-selection-sheet>
</f7-list-item> </f7-list-item>
@@ -526,6 +526,7 @@ import { useAccountEditPageBaseBase } from '@/views/base/accounts/AccountEditPag
import { useAccountsStore } from '@/stores/account.ts'; import { useAccountsStore } from '@/stores/account.ts';
import { itemAndIndex } from '@/core/base.ts';
import type { LocalizedCurrencyInfo } from '@/core/currency.ts'; import type { LocalizedCurrencyInfo } from '@/core/currency.ts';
import { AccountType } from '@/core/account.ts'; import { AccountType } from '@/core/account.ts';
import { ALL_ACCOUNT_ICONS } from '@/consts/icon.ts'; import { ALL_ACCOUNT_ICONS } from '@/consts/icon.ts';
@@ -709,14 +710,14 @@ function addSubAccountAndContext(): void {
} }
} }
function removeSubAccount(subAccount: Account | null, confirm: boolean): void { function removeSubAccount(currentSubAccount: Account | null, confirm: boolean): void {
if (!subAccount) { if (!currentSubAccount) {
showAlert('An error occurred'); showAlert('An error occurred');
return; return;
} }
if (!confirm) { if (!confirm) {
subAccountToDelete.value = subAccount; subAccountToDelete.value = currentSubAccount;
showDeleteActionSheet.value = true; showDeleteActionSheet.value = true;
return; return;
} }
@@ -724,10 +725,10 @@ function removeSubAccount(subAccount: Account | null, confirm: boolean): void {
showDeleteActionSheet.value = false; showDeleteActionSheet.value = false;
subAccountToDelete.value = null; subAccountToDelete.value = null;
for (let i = 0; i < subAccounts.value.length; i++) { for (const [subAccount, index] of itemAndIndex(subAccounts.value)) {
if (subAccounts.value[i] === subAccount) { if (subAccount === currentSubAccount) {
subAccounts.value.splice(i, 1); subAccounts.value.splice(index, 1);
subAccountContexts.value.splice(i, 1); subAccountContexts.value.splice(index, 1);
} }
} }
} }
+2 -2
View File
@@ -140,13 +140,13 @@ const categories = computed<TransactionCategory[]>(() => {
return []; return [];
} }
return transactionCategoriesStore.allTransactionCategories[categoryType.value]; return transactionCategoriesStore.allTransactionCategories[categoryType.value] ?? [];
} else if (primaryCategoryId.value && primaryCategoryId.value !== '' && primaryCategoryId.value !== '0') { } else if (primaryCategoryId.value && primaryCategoryId.value !== '' && primaryCategoryId.value !== '0') {
if (!transactionCategoriesStore.allTransactionCategoriesMap || !transactionCategoriesStore.allTransactionCategoriesMap[primaryCategoryId.value]) { if (!transactionCategoriesStore.allTransactionCategoriesMap || !transactionCategoriesStore.allTransactionCategoriesMap[primaryCategoryId.value]) {
return []; return [];
} }
return transactionCategoriesStore.allTransactionCategoriesMap[primaryCategoryId.value].subCategories || []; return transactionCategoriesStore.allTransactionCategoriesMap[primaryCategoryId.value]?.subCategories ?? [];
} else { } else {
return []; return [];
} }
+4 -4
View File
@@ -684,9 +684,9 @@ const transactionPictures = computed<Record<string, string | undefined>[]>(() =>
return thumbs; return thumbs;
} }
for (let i = 0; i < transaction.value.pictures.length; i++) { for (const picture of transaction.value.pictures) {
thumbs.push({ thumbs.push({
url: getTransactionPictureUrl(transaction.value.pictures[i]) url: getTransactionPictureUrl(picture)
}); });
} }
@@ -700,8 +700,8 @@ const transactionThumbs = computed<(string | undefined)[]>(() => {
return thumbs; return thumbs;
} }
for (let i = 0; i < transaction.value.pictures.length; i++) { for (const picture of transaction.value.pictures) {
thumbs.push(getTransactionPictureUrl(transaction.value.pictures[i])); thumbs.push(getTransactionPictureUrl(picture));
} }
return thumbs; return thumbs;
+13 -21
View File
@@ -200,7 +200,7 @@
v-for="(transaction, idx) in transactionMonthList.items" v-for="(transaction, idx) in transactionMonthList.items"
> >
<template #media> <template #media>
<div class="display-flex flex-direction-column transaction-date" :style="getTransactionDateStyle(transaction, idx > 0 ? transactionMonthList.items[idx - 1] : null)"> <div class="display-flex flex-direction-column transaction-date" :style="getTransactionDateStyle(transaction, idx > 0 ? transactionMonthList.items[idx - 1] : undefined)">
<span class="transaction-day full-line flex-direction-column"> <span class="transaction-day full-line flex-direction-column">
{{ getCalendarDisplayDayOfMonthFromUnixTime(transaction.time) }} {{ getCalendarDisplayDayOfMonthFromUnixTime(transaction.time) }}
</span> </span>
@@ -252,7 +252,7 @@
<div class="item-footer"> <div class="item-footer">
<div class="transaction-tags" v-if="showTagInTransactionListPage && transaction.tagIds && transaction.tagIds.length"> <div class="transaction-tags" v-if="showTagInTransactionListPage && transaction.tagIds && transaction.tagIds.length">
<f7-chip media-text-color="var(--f7-chip-text-color)" class="transaction-tag" <f7-chip media-text-color="var(--f7-chip-text-color)" class="transaction-tag"
:text="allTransactionTags[tagId].name" :text="allTransactionTags[tagId]?.name"
:key="tagId" :key="tagId"
v-for="tagId in transaction.tagIds"> v-for="tagId in transaction.tagIds">
<template #media> <template #media>
@@ -373,7 +373,7 @@
:class="getCategoryListItemCheckedClass(category, queryAllFilterCategoryIds)" :class="getCategoryListItemCheckedClass(category, queryAllFilterCategoryIds)"
:key="category.id" :key="category.id"
v-for="category in categories" v-for="category in categories"
v-show="!category.hidden || query.categoryIds === category.id || (allCategories[query.categoryIds] && allCategories[query.categoryIds].parentId === category.id)" v-show="!category.hidden || query.categoryIds === category.id || (allCategories[query.categoryIds] && allCategories[query.categoryIds]?.parentId === category.id)"
> >
<template #media> <template #media>
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon> <ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
@@ -439,7 +439,7 @@
:class="{ 'list-item-selected': query.accountIds === account.id, 'item-in-multiple-selection': queryAllFilterAccountIdsCount > 1 && queryAllFilterAccountIds[account.id] }" :class="{ 'list-item-selected': query.accountIds === account.id, 'item-in-multiple-selection': queryAllFilterAccountIdsCount > 1 && queryAllFilterAccountIds[account.id] }"
:key="account.id" :key="account.id"
v-for="account in allAccounts" v-for="account in allAccounts"
v-show="(!account.hidden && (!allAccountsMap[account.parentId] || !allAccountsMap[account.parentId].hidden)) || query.accountIds === account.id" v-show="(!account.hidden && (!allAccountsMap[account.parentId] || !allAccountsMap[account.parentId]!.hidden)) || query.accountIds === account.id"
@click="changeAccountFilter(account.id)" @click="changeAccountFilter(account.id)"
> >
<template #media> <template #media>
@@ -597,7 +597,7 @@ import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
import { useTransactionTagsStore } from '@/stores/transactionTag.ts'; import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts'; import { type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts';
import type { TypeAndDisplayName } from '@/core/base.ts'; import { type TypeAndDisplayName, keys } from '@/core/base.ts';
import { TextDirection } from '@/core/text.ts'; import { TextDirection } from '@/core/text.ts';
import { import {
type TextualYearMonth, type TextualYearMonth,
@@ -742,9 +742,7 @@ const transactions = computed<TransactionMonthList[]>(() => {
const transactions :Transaction[] = []; const transactions :Transaction[] = [];
for (let i = 0; i < transactionData.items.length; i++) { for (const transaction of transactionData.items) {
const transaction = transactionData.items[i];
if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) { if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) {
transactions.push(transaction); transactions.push(transaction);
} }
@@ -778,7 +776,7 @@ const noTransaction = computed<boolean>(() => {
if (pageType.value === TransactionListPageType.List.type) { if (pageType.value === TransactionListPageType.List.type) {
return transactionsStore.noTransaction; return transactionsStore.noTransaction;
} else if (pageType.value === TransactionListPageType.Calendar.type) { } else if (pageType.value === TransactionListPageType.Calendar.type) {
return !transactions.value || !transactions.value.length || !transactions.value[0].items || !transactions.value[0].items.length; return !transactions.value || !transactions.value.length || !transactions.value[0]!.items || !transactions.value[0]!.items.length;
} else { } else {
return true; return true;
} }
@@ -832,8 +830,7 @@ function setTransactionMonthListHeights(reset: boolean): Promise<unknown> {
if (transactions.value && transactions.value.length) { if (transactions.value && transactions.value.length) {
const heights: Record<string, number> = getElementActualHeights('.transaction-month-list'); const heights: Record<string, number> = getElementActualHeights('.transaction-month-list');
for (let i = 0; i < transactions.value.length - 1; i++) { for (const transactionMonthList of transactions.value) {
const transactionMonthList = transactions.value[i];
const yearDashMonth = transactionMonthList.yearDashMonth; const yearDashMonth = transactionMonthList.yearDashMonth;
const domId = getTransactionMonthListDomId(yearDashMonth); const domId = getTransactionMonthListDomId(yearDashMonth);
const height = heights[domId]; const height = heights[domId];
@@ -851,8 +848,7 @@ function setTransactionInvisibleYearMonthList(): void {
return; return;
} }
for (let i = 0; i < transactions.value.length - 1; i++) { for (const transactionMonthList of transactions.value) {
const transactionMonthList = transactions.value[i];
const yearDashMonth = transactionMonthList.yearDashMonth; const yearDashMonth = transactionMonthList.yearDashMonth;
const titleDomId = getTransactionMonthTitleDomId(yearDashMonth); const titleDomId = getTransactionMonthTitleDomId(yearDashMonth);
@@ -875,7 +871,7 @@ function setTransactionInvisibleYearMonthList(): void {
} }
} }
function getTransactionDateStyle(transaction: Transaction, previousTransaction: Transaction | null): Record<string, string> { function getTransactionDateStyle(transaction: Transaction, previousTransaction: Transaction | undefined): Record<string, string> {
if (!previousTransaction || transaction.gregorianCalendarDayOfMonth !== previousTransaction.gregorianCalendarDayOfMonth) { if (!previousTransaction || transaction.gregorianCalendarDayOfMonth !== previousTransaction.gregorianCalendarDayOfMonth) {
return {}; return {};
} }
@@ -893,8 +889,8 @@ function getCategoryListItemCheckedClass(category: TransactionCategory, queryCat
} }
if (category.subCategories) { if (category.subCategories) {
for (let i = 0; i < category.subCategories.length; i++) { for (const subCategory of category.subCategories) {
if (queryCategoryIds && queryCategoryIds[category.subCategories[i].id]) { if (queryCategoryIds && queryCategoryIds[subCategory.id]) {
return { return {
'list-item-checked': true 'list-item-checked': true
}; };
@@ -1208,11 +1204,7 @@ function changeTypeFilter(type: number): void {
if (type && query.value.categoryIds) { if (type && query.value.categoryIds) {
newCategoryFilter = ''; newCategoryFilter = '';
for (const categoryId in queryAllFilterCategoryIds.value) { for (const categoryId of keys(queryAllFilterCategoryIds.value)) {
if (!Object.prototype.hasOwnProperty.call(queryAllFilterCategoryIds.value, categoryId)) {
continue;
}
const category = allCategories.value[categoryId]; const category = allCategories.value[categoryId];
if (category && category.type === transactionTypeToCategoryType(type)) { if (category && category.type === transactionTypeToCategoryType(type)) {