diff --git a/src/components/base/AccountBalanceTrendsChartBase.ts b/src/components/base/AccountBalanceTrendsChartBase.ts index c74750f3..e0ded109 100644 --- a/src/components/base/AccountBalanceTrendsChartBase.ts +++ b/src/components/base/AccountBalanceTrendsChartBase.ts @@ -69,9 +69,7 @@ export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTren let minUnixTimeClosingBalance = 0; let maxUnixTimeClosingBalance = 0; - for (let i = 0; i < props.items.length; i++) { - const item = props.items[i]; - + for (const item of props.items) { if (item.time < minUnixTime) { minUnixTime = item.time; minUnixTimeOpeningBalance = item.accountOpeningBalance; @@ -120,8 +118,7 @@ export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTren const dayDataItemsMap: Record = {}; - for (let i = 0; i < props.items.length; i++) { - const dateItem = props.items[i]; + for (const dateItem of props.items) { let dateRangeMinUnixTime = 0; if (props.dateAggregationType === ChartDateAggregationType.Year.type) { @@ -149,8 +146,7 @@ export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTren let lastMedianBalance = lastClosingBalance; let lastAverageBalance = lastClosingBalance; - for (let i = 0; i < allDateRanges.value.length; i++) { - const dateRange = allDateRanges.value[i]; + for (const dateRange of allDateRanges.value) { const dataItems = dayDataItemsMap[dateRange.minUnixTime]; let displayDate = ''; @@ -176,11 +172,11 @@ export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTren return data1.time - data2.time; }); - const openingBalance = dataItems[0].accountOpeningBalance; - const closingBalance = dataItems[dataItems.length - 1].accountClosingBalance; + const openingBalance = dataItems[0]!.accountOpeningBalance; + const closingBalance = dataItems[dataItems.length - 1]!.accountClosingBalance; const minimumBalance = Math.min(...dataItems.map(item => item.accountClosingBalance)); const maximumBalance = Math.max(...dataItems.map(item => item.accountClosingBalance)); - const medianBalance = dataItems[Math.floor(dataItems.length / 2)].accountClosingBalance; + const medianBalance = dataItems[Math.floor(dataItems.length / 2)]!.accountClosingBalance; const averageBalance = Math.trunc(sumAmounts(dataItems.map(item => item.accountClosingBalance)) / dataItems.length); if (props.account.isAsset) { diff --git a/src/components/base/DateRangeSelectionBase.ts b/src/components/base/DateRangeSelectionBase.ts index aaea3236..e55fc6fe 100644 --- a/src/components/base/DateRangeSelectionBase.ts +++ b/src/components/base/DateRangeSelectionBase.ts @@ -56,11 +56,11 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) const firstDayOfWeek = computed(() => userStore.currentUserFirstDayOfWeek); const beginDateTime = computed(() => { - const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[0]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); + const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[0] as Date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); return formatUnixTimeToLongDateTime(actualBeginUnixTime); }); const endDateTime = computed(() => { - const actualEndUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[1]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); + const actualEndUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[1] as Date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); return formatUnixTimeToLongDateTime(actualEndUnixTime); }); const presetRanges = computed(() => { diff --git a/src/components/base/ItemIconBase.ts b/src/components/base/ItemIconBase.ts index e73b93af..83fe4020 100644 --- a/src/components/base/ItemIconBase.ts +++ b/src/components/base/ItemIconBase.ts @@ -42,11 +42,13 @@ export function useItemIconBase(props: CommonIconProps) { iconId = iconId.toString(); } - if (!ALL_ACCOUNT_ICONS[iconId]) { + const iconInfo = ALL_ACCOUNT_ICONS[iconId]; + + if (!iconInfo) { return DEFAULT_ACCOUNT_ICON.icon; } - return ALL_ACCOUNT_ICONS[iconId].icon; + return iconInfo.icon; } function getCategoryIcon(iconId: string | number): string { @@ -54,11 +56,13 @@ export function useItemIconBase(props: CommonIconProps) { iconId = iconId.toString(); } - if (!ALL_CATEGORY_ICONS[iconId]) { + const iconInfo = ALL_CATEGORY_ICONS[iconId]; + + if (!iconInfo) { return DEFAULT_CATEGORY_ICON.icon; } - return ALL_CATEGORY_ICONS[iconId].icon; + return iconInfo.icon; } function getAccountIconStyle(color?: ColorValue, defaultColor?: ColorStyleValue, additionalColorAttr?: string): Record { diff --git a/src/components/base/MonthRangeSelectionBase.ts b/src/components/base/MonthRangeSelectionBase.ts index 7b1e5e74..5c52257d 100644 --- a/src/components/base/MonthRangeSelectionBase.ts +++ b/src/components/base/MonthRangeSelectionBase.ts @@ -57,8 +57,8 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps maxDate ]); - const beginDateTime = computed(() => formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthFirstUnixTime(dateRange.value[0]))); - const endDateTime = computed(() => formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthLastUnixTime(dateRange.value[1]))); + const beginDateTime = computed(() => formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthFirstUnixTime(dateRange.value[0] as Year0BasedMonth))); + const endDateTime = computed(() => formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthLastUnixTime(dateRange.value[1] as Year0BasedMonth))); function getFinalMonthRange(): { minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | '' } | null { if (!dateRange.value[0] || !dateRange.value[1]) { @@ -69,8 +69,8 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps throw new Error('Date is too early'); } - const minYearMonth = getYearMonthStringFromYear0BasedMonthObject(dateRange.value[0]); - const maxYearMonth = getYearMonthStringFromYear0BasedMonthObject(dateRange.value[1]); + const minYearMonth = getYearMonthStringFromYear0BasedMonthObject(dateRange.value[0] as Year0BasedMonth); + const maxYearMonth = getYearMonthStringFromYear0BasedMonthObject(dateRange.value[1] as Year0BasedMonth); return { minYearMonth, diff --git a/src/components/common/DateTimePicker.vue b/src/components/common/DateTimePicker.vue index c317aca7..9e6acbb4 100644 --- a/src/components/common/DateTimePicker.vue +++ b/src/components/common/DateTimePicker.vue @@ -146,7 +146,7 @@ function getDisplayYear(year: number): string { function getDisplayMonth(month: number): string { if (isArray(dateTime.value)) { - return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0].getFullYear(), month + 1, 1).getUnixTime(), actualNumeralSystem.value); + return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0]!.getFullYear(), month + 1, 1).getUnixTime(), actualNumeralSystem.value); } else if (dateTime.value) { return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value.getFullYear(), month + 1, 1).getUnixTime(), actualNumeralSystem.value); } else { diff --git a/src/components/common/MonthPicker.vue b/src/components/common/MonthPicker.vue index e8d0875c..01a11a95 100644 --- a/src/components/common/MonthPicker.vue +++ b/src/components/common/MonthPicker.vue @@ -102,7 +102,7 @@ function getDisplayYear(year: number): string { function getDisplayMonth(month: number): string { if (isArray(dateTime.value)) { - return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0].year, month + 1, 1).getUnixTime()); + return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0]!.year, month + 1, 1).getUnixTime()); } else { return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value.year, month + 1, 1).getUnixTime()); } diff --git a/src/components/desktop/AccountBalanceTrendsChart.vue b/src/components/desktop/AccountBalanceTrendsChart.vue index 271d388d..b279a5f4 100644 --- a/src/components/desktop/AccountBalanceTrendsChart.vue +++ b/src/components/desktop/AccountBalanceTrendsChart.vue @@ -8,11 +8,15 @@ import { useTheme } from 'vuetify'; import type { CallbackDataParams } from 'echarts/types/dist/shared'; import { useI18n } from '@/locales/helpers.ts'; -import { type CommonAccountBalanceTrendsChartProps, useAccountBalanceTrendsChartBase } from '@/components/base/AccountBalanceTrendsChartBase.ts' +import { + type AccountBalanceTrendsChartItem, + type CommonAccountBalanceTrendsChartProps, + useAccountBalanceTrendsChartBase +} from '@/components/base/AccountBalanceTrendsChartBase.ts' import { useUserStore } from '@/stores/user.ts'; -import type { NameValue } from '@/core/base.ts'; +import { type NameValue, itemAndIndex } from '@/core/base.ts'; import { TextDirection } from '@/core/text.ts'; import type { ColorStyleValue } from '@/core/color.ts'; import { ThemeType } from '@/core/theme.ts'; @@ -83,9 +87,7 @@ const allSeries = computed(() => { series.itemStyle.borderColor0 = expenseIncomeAmountColor.expenseAmountColor; } - for (let i = 0; i < allDataItems.value.length; i++) { - const item = allDataItems.value[i]; - + for (const item of allDataItems.value) { if (props.type === AccountBalanceTrendChartType.Candlestick.type) { series.data.push([ item.openingBalance, @@ -110,13 +112,12 @@ const yAxisWidth = computed(() => { return width; } - for (let i = 0; i < allSeries.value.length; i++) { - for (let j = 0; j < allSeries.value[i].data.length; j++) { - const data = allSeries.value[i].data[j]; + for (const series of allSeries.value) { + for (const data of series.data) { let value: number; if (isArray(data)) { - value = data[1]; // for candlestick, use closing balance + value = data[1] as number; // for candlestick, use closing balance } else { value = data as number; // for line or bar chart } @@ -172,8 +173,8 @@ const chartOptions = computed(() => { }, formatter: (params: CallbackDataParams[]) => { if (props.type === AccountBalanceTrendChartType.Candlestick.type) { - const dataIndex = params[0].dataIndex; - const dataItem = allDataItems.value[dataIndex]; + const dataIndex = params[0]!.dataIndex; + const dataItem = allDataItems.value[dataIndex] as AccountBalanceTrendsChartItem; const displayItems: NameValue[] = [ { name: tt('Opening Balance'), @@ -201,20 +202,20 @@ const chartOptions = computed(() => { } ]; - let tooltip = `${params[0].name} ${props.legendName}
`; + let tooltip = `${params[0]!.name} ${props.legendName}
`; - for (let i = 0; i < displayItems.length; i++) { - tooltip += `
` - + `${displayItems[i].name}${displayItems[i].value}
` + for (const [displayItem, index] of itemAndIndex(displayItems)) { + tooltip += `
` + + `${displayItem.name}${displayItem.value}
` + `
`; } return tooltip; } else { - const amount = params[0].data as number; + const amount = params[0]!.data as number; const value = formatAmountToLocalizedNumeralsWithCurrency(amount, props.account.currency); - return `${params[0].name}
` + return `${params[0]!.name}
` + '
' + `${props.legendName}${value}
` + '
'; diff --git a/src/components/desktop/MonthlyTrendsChart.vue b/src/components/desktop/MonthlyTrendsChart.vue index e219c371..187454b8 100644 --- a/src/components/desktop/MonthlyTrendsChart.vue +++ b/src/components/desktop/MonthlyTrendsChart.vue @@ -14,6 +14,7 @@ import { type CommonMonthlyTrendsChartProps, type MonthlyTrendsBarChartClickEven import { useUserStore } from '@/stores/user.ts'; +import { itemAndIndex } from '@/core/base.ts'; import { TextDirection } from '@/core/text.ts'; import { type Year1BasedMonth, DateRangeScene } from '@/core/datetime.ts'; import type { ColorStyleValue } from '@/core/color.ts'; @@ -100,8 +101,7 @@ const isDarkMode = computed(() => theme.global.name.value === ThemeType const itemsMap = computed>>(() => { const map: Record> = {}; - for (let i = 0; i < props.items.length; i++) { - const item = props.items[i]; + for (const item of props.items) { let id: string = ''; if (props.idField && item[props.idField]) { @@ -135,9 +135,7 @@ const itemsMap = computed>>(() => { const allDisplayDateRanges = computed(() => { const allDisplayDateRanges: string[] = []; - for (let i = 0; i < allDateRanges.value.length; i++) { - const dateRange = allDateRanges.value[i]; - + for (const dateRange of allDateRanges.value) { if (props.dateAggregationType === ChartDateAggregationType.Year.type) { allDisplayDateRanges.push(formatUnixTimeToGregorianLikeShortYear(dateRange.minUnixTime)); } else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type && 'year' in dateRange) { @@ -155,9 +153,7 @@ const allDisplayDateRanges = computed(() => { const allSeries = computed(() => { const allSeries: MonthlyTrendsChartDataItem[] = []; - for (let i = 0; i < props.items.length; i++) { - const item = props.items[i]; - + for (const [item, index] of itemAndIndex(props.items)) { if (props.hiddenField && item[props.hiddenField]) { continue; } @@ -165,8 +161,7 @@ const allSeries = computed(() => { const allAmounts: number[] = []; const dateRangeAmountMap: Record = {}; - for (let j = 0; j < item.items.length; j++) { - const dataItem = item.items[j]; + for (const dataItem of item.items) { let dateRangeKey = ''; if (props.dateAggregationType === ChartDateAggregationType.Year.type) { @@ -189,8 +184,7 @@ const allSeries = computed(() => { dateRangeAmountMap[dateRangeKey] = dataItems; } - for (let j = 0; j < allDateRanges.value.length; j++) { - const dateRange = allDateRanges.value[j]; + for (const dateRange of allDateRanges.value) { let dateRangeKey = ''; if (props.dateAggregationType === ChartDateAggregationType.Year.type) { @@ -207,9 +201,7 @@ const allSeries = computed(() => { const dataItems = dateRangeAmountMap[dateRangeKey]; if (isArray(dataItems)) { - for (let i = 0; i < dataItems.length; i++) { - const dataItem = dataItems[i]; - + for (const dataItem of dataItems) { if (isNumber(dataItem[props.valueField])) { amount += dataItem[props.valueField] as number; } @@ -223,7 +215,7 @@ const allSeries = computed(() => { id: (props.idField && item[props.idField]) ? item[props.idField] as string : getItemName(item[props.nameField] as string), name: (props.idField && item[props.idField]) ? item[props.idField] as string : getItemName(item[props.nameField] as string), itemStyle: { - color: getDisplayColor(props.colorField && item[props.colorField] ? item[props.colorField] as string : DEFAULT_CHART_COLORS[i % DEFAULT_CHART_COLORS.length]), + color: getDisplayColor(props.colorField && item[props.colorField] ? item[props.colorField] as string : DEFAULT_CHART_COLORS[index % DEFAULT_CHART_COLORS.length]), }, selected: true, type: 'line', @@ -253,10 +245,9 @@ const yAxisWidth = computed(() => { return width; } - for (let i = 0; i < allSeries.value.length; i++) { - for (let j = 0; j < allSeries.value[i].data.length; j++) { - const value = allSeries.value[i].data[j]; + for (const series of allSeries.value) { + for (const value of series.data) { if (value > maxValue) { maxValue = value; } @@ -311,12 +302,12 @@ const chartOptions = computed(() => { let totalAmount = 0; const displayItems: MonthlyTrendsChartTooltipItem[] = []; - for (let i = 0; i < params.length; i++) { - const id = params[i].seriesId as string; + for (const param of params) { + const id = param.seriesId as string; const name = itemsMap.value[id] && props.nameField && itemsMap.value[id][props.nameField] ? getItemName(itemsMap.value[id][props.nameField] as string) : id; - const color = params[i].color; + const color = param.color; const displayOrders = itemsMap.value[id] && props.displayOrdersField && itemsMap.value[id][props.displayOrdersField] ? itemsMap.value[id][props.displayOrdersField] as number[] : [0]; - const amount = params[i].data as number; + const amount = param.data as number; displayItems.push({ name: name, @@ -330,9 +321,7 @@ const chartOptions = computed(() => { sortStatisticsItems(displayItems, props.sortingType); - for (let i = 0; i < displayItems.length; i++) { - const item = displayItems[i]; - + for (const item of displayItems) { if (displayItems.length === 1 || item.totalAmount !== 0) { const value = formatAmountToLocalizedNumeralsWithCurrency(item.totalAmount, props.defaultCurrency); tooltip += '
'; @@ -349,7 +338,7 @@ const chartOptions = computed(() => { + '' + tooltip; } - if (params.length && params[0].name) { + if (params.length && params[0] && params[0].name) { tooltip = `${params[0].name}
` + tooltip; } @@ -410,9 +399,14 @@ function clickItem(e: ECElementEvent): void { } const id = e.seriesId as string; - const item = itemsMap.value[id]; + const item = itemsMap.value[id] as Record; const itemId = props.idField ? item[props.idField] as string : ''; const dateRange = allDateRanges.value[e.dataIndex]; + + if (!dateRange) { + return; + } + let minUnixTime = dateRange.minUnixTime; let maxUnixTime = dateRange.maxUnixTime; @@ -450,16 +444,16 @@ function exportData(): { headers: string[], data: string[][] } { headers.push(tt('Date')); - for (let i = 0; i < allSeries.value.length; i++) { - const id = allSeries.value[i].id; + for (const series of allSeries.value) { + const id = series.id; const name = itemsMap.value[id] && props.nameField && itemsMap.value[id][props.nameField] ? getItemName(itemsMap.value[id][props.nameField] as string) : id; headers.push(name); } - for (let i = 0; i < allDisplayDateRanges.value.length; i++) { + for (const [displayDateRange, index] of itemAndIndex(allDisplayDateRanges.value)) { const row: string[] = []; - row.push(allDisplayDateRanges.value[i]); - row.push(...allSeries.value.map(item => formatAmountToWesternArabicNumeralsWithoutDigitGrouping(item.data[i]))); + row.push(displayDateRange); + row.push(...allSeries.value.map(item => formatAmountToWesternArabicNumeralsWithoutDigitGrouping(item.data[index] ?? 0))); data.push(row); } diff --git a/src/components/mobile/DateTimeSelectionSheet.vue b/src/components/mobile/DateTimeSelectionSheet.vue index 6fe1750f..e76f0af2 100644 --- a/src/components/mobile/DateTimeSelectionSheet.vue +++ b/src/components/mobile/DateTimeSelectionSheet.vue @@ -252,8 +252,8 @@ function getTimerPickerItemStyle(textualValue: string, textualCurrentValue: stri return ''; } - const minValue = parseInt(values[0].value); - const maxValue = parseInt(values[values.length - 1].value); + const minValue = parseInt(values[0]!.value); + const maxValue = parseInt(values[values.length - 1]!.value); const value = parseInt(textualValue, 10); const currentValue = parseInt(textualCurrentValue, 10); let valueDiff = value - currentValue; @@ -327,7 +327,7 @@ function scrollToSelectedItem(itemsClass: string, itemClass: string, value: stri } for (let i = 0; i < itemElements.length; i++) { - const itemElement = itemElements[i]; + const itemElement = itemElements[i] as HTMLElement; if ('offsetHeight' in itemsElement && 'offsetTop' in itemElement && 'offsetHeight' in itemElement && (!itemElement.hasAttribute('data-items-index') || itemElement.getAttribute('data-items-index') === '1') diff --git a/src/components/mobile/MonthlyTrendsBarChart.vue b/src/components/mobile/MonthlyTrendsBarChart.vue index 8ead7f3b..083ea24d 100644 --- a/src/components/mobile/MonthlyTrendsBarChart.vue +++ b/src/components/mobile/MonthlyTrendsBarChart.vue @@ -95,6 +95,7 @@ import { type CommonMonthlyTrendsChartProps, type MonthlyTrendsBarChartClickEven import { useUserStore } from '@/stores/user.ts'; +import { itemAndIndex } from '@/core/base.ts'; import { type Year1BasedMonth, type UnixTimeRange, DateRangeScene } from '@/core/datetime.ts'; import type { ColorStyleValue } from '@/core/color.ts'; import { ChartDateAggregationType } from '@/core/statistics.ts'; @@ -173,9 +174,7 @@ const allDisplayDataItems = computed(() => { const allDateRangeItemsMap: Record = {}; const legends: TrendsBarChartLegend[] = []; - for (let i = 0; i < props.items.length; i++) { - const item = props.items[i]; - + for (const [item, index] of itemAndIndex(props.items)) { if (props.hiddenField && item[props.hiddenField]) { continue; } @@ -185,7 +184,7 @@ const allDisplayDataItems = computed(() => { const legend: TrendsBarChartLegend = { id: id, name: (props.nameField && item[props.nameField]) ? getItemName(item[props.nameField] as string) : id, - color: getDisplayColor(props.colorField && item[props.colorField] ? item[props.colorField] as string : DEFAULT_CHART_COLORS[i % DEFAULT_CHART_COLORS.length]), + color: getDisplayColor(props.colorField && item[props.colorField] ? item[props.colorField] as string : DEFAULT_CHART_COLORS[index % DEFAULT_CHART_COLORS.length]), displayOrders: (props.displayOrdersField && item[props.displayOrdersField]) ? item[props.displayOrdersField] as number[] : [0] }; @@ -197,8 +196,7 @@ const allDisplayDataItems = computed(() => { const dateRangeItemMap: Record = {}; - for (let j = 0; j < item.items.length; j++) { - const dataItem = item.items[j]; + for (const dataItem of item.items) { let dateRangeKey = ''; if (props.dateAggregationType === ChartDateAggregationType.Year.type) { @@ -216,7 +214,7 @@ const allDisplayDataItems = computed(() => { } if (dateRangeItemMap[dateRangeKey]) { - dateRangeItemMap[dateRangeKey].totalAmount += (props.valueField && isNumber(dataItem[props.valueField])) ? dataItem[props.valueField] as number : 0; + dateRangeItemMap[dateRangeKey]!.totalAmount += (props.valueField && isNumber(dataItem[props.valueField])) ? dataItem[props.valueField] as number : 0; } else { const allDataItems: MonthlyTrendsBarChartDataAmount[] = allDateRangeItemsMap[dateRangeKey] || []; const finalDataItem: MonthlyTrendsBarChartDataAmount = Object.assign({}, legend, { @@ -233,8 +231,7 @@ const allDisplayDataItems = computed(() => { const finalDataItems: MonthlyTrendsBarChartDataItem[] = []; let maxTotalAmount = 0; - for (let i = 0; i < allDateRanges.value.length; i++) { - const dateRange = allDateRanges.value[i]; + for (const dateRange of allDateRanges.value) { let dateRangeKey = ''; if (props.dateAggregationType === ChartDateAggregationType.Year.type) { @@ -265,12 +262,12 @@ const allDisplayDataItems = computed(() => { sortStatisticsItems(dataItems, props.sortingType); - for (let j = 0; j < dataItems.length; j++) { - if (dataItems[j].totalAmount > 0) { - totalPositiveAmount += dataItems[j].totalAmount; + for (const dataItem of dataItems) { + if (dataItem.totalAmount > 0) { + totalPositiveAmount += dataItem.totalAmount; } - totalAmount += dataItems[j].totalAmount; + totalAmount += dataItem.totalAmount; } if (totalAmount > maxTotalAmount) { @@ -289,11 +286,11 @@ const allDisplayDataItems = computed(() => { finalDataItems.push(finalDataItem); } - for (let i = 0; i < finalDataItems.length; i++) { - if (maxTotalAmount > 0 && finalDataItems[i].totalAmount > 0) { - finalDataItems[i].percent = 100.0 * finalDataItems[i].totalAmount / maxTotalAmount; + for (const finalDataItem of finalDataItems) { + if (maxTotalAmount > 0 && finalDataItem.totalAmount > 0) { + finalDataItem.percent = 100.0 * finalDataItem.totalAmount / maxTotalAmount; } else { - finalDataItems[i].percent = 0.0; + finalDataItem.percent = 0.0; } } @@ -306,9 +303,7 @@ const allDisplayDataItems = computed(() => { function clickItem(item: MonthlyTrendsBarChartDataItem): void { let itemId = ''; - for (let i = 0; i < props.items.length; i++) { - const item = props.items[i]; - + for (const item of props.items) { if (!props.hiddenField || item[props.hiddenField]) { continue; } diff --git a/src/components/mobile/TransactionTagSelectionSheet.vue b/src/components/mobile/TransactionTagSelectionSheet.vue index 8ec7b8c2..98b92dc1 100644 --- a/src/components/mobile/TransactionTagSelectionSheet.vue +++ b/src/components/mobile/TransactionTagSelectionSheet.vue @@ -143,8 +143,8 @@ const allTags = computed(() => { const noAvailableTag = computed(() => { if (transactionTagsStore.allTransactionTags) { - for (let i = 0; i < transactionTagsStore.allTransactionTags.length; i++) { - if (!transactionTagsStore.allTransactionTags[i].hidden) { + for (const transactionTag of transactionTagsStore.allTransactionTags) { + if (!transactionTag.hidden) { return false; } } diff --git a/src/lib/account.ts b/src/lib/account.ts index 478ae626..2d7c2544 100644 --- a/src/lib/account.ts +++ b/src/lib/account.ts @@ -1,3 +1,4 @@ +import { itemAndIndex, keys, keysIfValueEquals, values } from '@/core/base.ts'; import { AccountType, AccountCategory } from '@/core/account.ts'; import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts'; import { type AccountBalance, type CategorizedAccount, type AccountCategoriesWithVisibleCount, Account } from '@/models/account.ts'; @@ -5,9 +6,7 @@ import { type AccountBalance, type CategorizedAccount, type AccountCategoriesWit export function getCategorizedAccountsMap(allAccounts: Account[]): Record { const ret: Record = {}; - for (let i = 0; i < allAccounts.length; i++) { - const account = allAccounts[i]; - + for (const account of allAccounts) { if (!ret[account.category]) { const categoryInfo = AccountCategory.valueOf(account.category); @@ -21,8 +20,10 @@ export function getCategorizedAccountsMap(allAccounts: Account[]): Record = {}; const allVisibleSubAccountCounts: Record = {}; const allFirstVisibleSubAccountIndexes: Record = {}; let allVisibleAccountCount = 0; let firstVisibleAccountIndex = -1; - for (let j = 0; j < allAccounts.length; j++) { - const account = allAccounts[j]; - + for (const [account, accountIndex] of itemAndIndex(allAccounts)) { if (!account.hidden) { allVisibleAccountCount++; if (firstVisibleAccountIndex === -1) { - firstVisibleAccountIndex = j; + firstVisibleAccountIndex = accountIndex; } } @@ -105,14 +102,12 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap: R let visibleSubAccountCount = 0; let firstVisibleSubAccountIndex = -1; - for (let k = 0; k < account.subAccounts.length; k++) { - const subAccount = account.subAccounts[k]; - + for (const [subAccount, subAccountIndex] of itemAndIndex(account.subAccounts)) { if (!subAccount.hidden) { visibleSubAccountCount++; if (firstVisibleSubAccountIndex === -1) { - firstVisibleSubAccountIndex = k; + firstVisibleSubAccountIndex = subAccountIndex; } } } @@ -147,16 +142,14 @@ export function getAllFilteredAccountsBalance(categorizedAccounts: Record, allAccountsMap: Record, skipHiddenAccount: boolean): void { - for (const accountId in filterAccountIds) { - if (!Object.prototype.hasOwnProperty.call(filterAccountIds, accountId)) { - continue; - } - + for (const accountId of keys(filterAccountIds)) { const account = allAccountsMap[accountId]; if (skipHiddenAccount && account && account.hidden) { @@ -284,11 +264,7 @@ export function selectAll(filterAccountIds: Record, allAccounts } export function selectNone(filterAccountIds: Record, allAccountsMap: Record, skipHiddenAccount: boolean): void { - for (const accountId in filterAccountIds) { - if (!Object.prototype.hasOwnProperty.call(filterAccountIds, accountId)) { - continue; - } - + for (const accountId of keys(filterAccountIds)) { const account = allAccountsMap[accountId]; if (skipHiddenAccount && account && account.hidden) { @@ -302,11 +278,7 @@ export function selectNone(filterAccountIds: Record, allAccount } export function selectInvert(filterAccountIds: Record, allAccountsMap: Record, skipHiddenAccount: boolean): void { - for (const accountId in filterAccountIds) { - if (!Object.prototype.hasOwnProperty.call(filterAccountIds, accountId)) { - continue; - } - + for (const accountId of keys(filterAccountIds)) { const account = allAccountsMap[accountId]; if (skipHiddenAccount && account && account.hidden) { @@ -324,8 +296,7 @@ export function isAccountOrSubAccountsAllChecked(account: Account, filterAccount return !filterAccountIds[account.id]; } - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (const subAccount of account.subAccounts) { if (filterAccountIds[subAccount.id]) { return false; } @@ -341,8 +312,7 @@ export function isAccountOrSubAccountsHasButNotAllChecked(account: Account, filt let checkedCount = 0; - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (const subAccount of account.subAccounts) { if (!filterAccountIds[subAccount.id]) { checkedCount++; } diff --git a/src/lib/color.ts b/src/lib/color.ts index 94c34ff1..c6bea1f2 100644 --- a/src/lib/color.ts +++ b/src/lib/color.ts @@ -20,8 +20,8 @@ export function getColorsInRows(allColorValues: ColorValue[], itemPerRow: number ret[++rowCount] = []; } - ret[rowCount].push({ - color: allColorValues[i] + ret[rowCount]!.push({ + color: allColorValues[i] as ColorValue }); } diff --git a/src/lib/evaluator.ts b/src/lib/evaluator.ts index 40a42a34..f8fbf362 100644 --- a/src/lib/evaluator.ts +++ b/src/lib/evaluator.ts @@ -4,12 +4,15 @@ import { replaceAll } from './common.ts'; import logger from './logger.ts'; +type Operator = '+' | '-' | '*' | '/'; +type OperatorAndParenthesis = Operator | '(' | ')'; + const maxAllowedDecimalCount = 6; const normalizeFactor: number = 1000000; const normalizedDecimalsMaxZeroString: string = '000000'; const normalizedNumberToAmountFactor: number = 10000; // 1000000 / 100 -const operatorPriority: Record = { +const operatorPriority: Record = { '+': 1, '-': 1, '*': 2, @@ -48,20 +51,20 @@ function checkNumberRange(num: number): void { function toPostfixExprTokens(expr: string): string[] | null { const finalTokens: string[] = []; - const operatorStack: string[] = []; + const operatorStack: OperatorAndParenthesis[] = []; let currentNumberBuilder = ''; let isLastTokenOperator = true; expr = replaceAll(expr, ' ', ''); for (let i = 0; i < expr.length; i++) { - const ch = expr[i]; + const ch = expr[i] as string; // number if ('0' <= ch && ch <= '9' || ch === '.') { currentNumberBuilder += ch; continue - } else if (ch === '-' && i + 1 < expr.length && '0' <= expr[i + 1] && expr[i + 1] <= '9' && currentNumberBuilder.length === 0 && isLastTokenOperator) { + } else if (ch === '-' && i + 1 < expr.length && '0' <= (expr[i + 1] as string) && (expr[i + 1] as string) <= '9' && currentNumberBuilder.length === 0 && isLastTokenOperator) { currentNumberBuilder += ch; continue } @@ -84,13 +87,15 @@ function toPostfixExprTokens(expr: string): string[] | null { } while (operatorStack.length > 0) { - const topOperator = operatorStack[operatorStack.length - 1]; + const topOperator = operatorStack[operatorStack.length - 1] as OperatorAndParenthesis; if (topOperator === '(') { break; } - if (operatorPriority[topOperator] >= operatorPriority[ch]) { + const isCurrentOperator = topOperator === '+' || topOperator === '-' || topOperator === '*' || topOperator === '/'; + + if (isCurrentOperator && operatorPriority[topOperator] >= operatorPriority[ch]) { finalTokens.push(topOperator); operatorStack.pop(); } else { @@ -154,7 +159,7 @@ function evaluatePostfixExpr(tokens: string[]): number | null { const stack: number[] = []; for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; + const token = tokens[i] as string; switch (token) { case '+': @@ -211,7 +216,7 @@ function evaluatePostfixExpr(tokens: string[]): number | null { return null; } - return stack[0]; + return stack[0] as number; } export function evaluateExpressionToAmount(expr: string): number | undefined { if (!expr) { diff --git a/src/lib/numeral.ts b/src/lib/numeral.ts index d5ac878f..e227c6ba 100644 --- a/src/lib/numeral.ts +++ b/src/lib/numeral.ts @@ -13,8 +13,8 @@ import { isDefined, isString, isNumber, replaceAll, removeAll } from './common.t export function sumAmounts(amounts: number[]): number { let sum = 0; - for (let i = 0; i < amounts.length; i++) { - sum += amounts[i]; + for (const amount of amounts) { + sum += amount; } return sum; @@ -292,7 +292,7 @@ export function formatExchangeRateAmount(exchangeRateAmount: number, options: Nu } } -export function getAdaptiveDisplayAmountRate(amount1: number, amount2: number, fromExchangeRate: { rate: string }, toExchangeRate: { rate: string }, options: NumberFormatOptions): string | null { +export function getAdaptiveDisplayAmountRate(amount1: number, amount2: number, options: NumberFormatOptions, fromExchangeRate?: { rate: string }, toExchangeRate?: { rate: string }): string | null { const numeralSystem = options.numeralSystem || NumeralSystem.Default; if (!amount1 || !amount2 || amount1 === amount2) { diff --git a/src/lib/settings.ts b/src/lib/settings.ts index 6ba4376d..c9514701 100644 --- a/src/lib/settings.ts +++ b/src/lib/settings.ts @@ -1,3 +1,5 @@ +import { keys } from '@/core/base.ts'; + import type { ApplicationSettingKey, ApplicationSettingValue, @@ -28,11 +30,7 @@ function getStoredApplicationSettings(): BaseApplicationSetting { export function getApplicationSettings(): ApplicationSettings { const storedApplicationSettings = getStoredApplicationSettings(); - for (const key in storedApplicationSettings) { - if (!Object.prototype.hasOwnProperty.call(storedApplicationSettings, key)) { - continue; - } - + for (const key of keys(storedApplicationSettings)) { if (typeof(DEFAULT_APPLICATION_SETTINGS[key]) === 'object') { storedApplicationSettings[key] = Object.assign({}, DEFAULT_APPLICATION_SETTINGS[key], storedApplicationSettings[key]); } diff --git a/src/lib/tag.ts b/src/lib/tag.ts index 03d15fae..8200638c 100644 --- a/src/lib/tag.ts +++ b/src/lib/tag.ts @@ -1,8 +1,9 @@ +import { reversed } from '@/core/base.ts'; import { TransactionTag } from '@/models/transaction_tag.ts'; export function isNoAvailableTag(tags: TransactionTag[], showHidden: boolean): boolean { - for (let i = 0; i < tags.length; i++) { - if (showHidden || !tags[i].hidden) { + for (const tag of tags) { + if (showHidden || !tag.hidden) { return false; } } @@ -13,8 +14,8 @@ export function isNoAvailableTag(tags: TransactionTag[], showHidden: boolean): b export function getAvailableTagCount(tags: TransactionTag[], showHidden: boolean): number { let count = 0; - for (let i = 0; i < tags.length; i++) { - if (showHidden || !tags[i].hidden) { + for (const tag of tags) { + if (showHidden || !tag.hidden) { count++; } } @@ -23,9 +24,9 @@ export function getAvailableTagCount(tags: TransactionTag[], showHidden: boolean } export function getFirstShowingId(tags: TransactionTag[], showHidden: boolean): string | null { - for (let i = 0; i < tags.length; i++) { - if (showHidden || !tags[i].hidden) { - return tags[i].id; + for (const tag of tags) { + if (showHidden || !tag.hidden) { + return tag.id; } } @@ -33,9 +34,9 @@ export function getFirstShowingId(tags: TransactionTag[], showHidden: boolean): } export function getLastShowingId(tags: TransactionTag[], showHidden: boolean): string | null { - for (let i = tags.length - 1; i >= 0; i--) { - if (showHidden || !tags[i].hidden) { - return tags[i].id; + for (const tag of reversed(tags)) { + if (showHidden || !tag.hidden) { + return tag.id; } } diff --git a/src/lib/template.ts b/src/lib/template.ts index 40d9e313..004a909a 100644 --- a/src/lib/template.ts +++ b/src/lib/template.ts @@ -1,8 +1,9 @@ +import { reversed } from '@/core/base.ts'; import { TransactionTemplate } from '@/models/transaction_template.ts'; export function isNoAvailableTemplate(templates: TransactionTemplate[], showHidden: boolean): boolean { - for (let i = 0; i < templates.length; i++) { - if (showHidden || !templates[i].hidden) { + for (const template of templates) { + if (showHidden || !template.hidden) { return false; } } @@ -13,8 +14,8 @@ export function isNoAvailableTemplate(templates: TransactionTemplate[], showHidd export function getAvailableTemplateCount(templates: TransactionTemplate[], showHidden: boolean): number { let count = 0; - for (let i = 0; i < templates.length; i++) { - if (showHidden || !templates[i].hidden) { + for (const template of templates) { + if (showHidden || !template.hidden) { count++; } } @@ -23,9 +24,9 @@ export function getAvailableTemplateCount(templates: TransactionTemplate[], show } export function getFirstShowingId(templates: TransactionTemplate[], showHidden: boolean): string | null { - for (let i = 0; i < templates.length; i++) { - if (showHidden || !templates[i].hidden) { - return templates[i].id; + for (const template of templates) { + if (showHidden || !template.hidden) { + return template.id; } } @@ -33,9 +34,9 @@ export function getFirstShowingId(templates: TransactionTemplate[], showHidden: } export function getLastShowingId(templates: TransactionTemplate[], showHidden: boolean): string | null { - for (let i = templates.length - 1; i >= 0; i--) { - if (showHidden || !templates[i].hidden) { - return templates[i].id; + for (const template of reversed(templates)) { + if (showHidden || !template.hidden) { + return template.id; } } diff --git a/src/lib/transaction.ts b/src/lib/transaction.ts index 20cc7769..578d2d15 100644 --- a/src/lib/transaction.ts +++ b/src/lib/transaction.ts @@ -39,7 +39,7 @@ export function setTransactionModelByTransaction(transaction: Transaction, trans } if (!options.type && options.categoryId && options.categoryId !== '0' && allCategoriesMap[options.categoryId]) { - const category = allCategoriesMap[options.categoryId]; + const category = allCategoriesMap[options.categoryId] as TransactionCategory; const type = categoryTypeToTransactionType(category.type); if (isNumber(type)) { @@ -102,8 +102,8 @@ export function setTransactionModelByTransaction(transaction: Transaction, trans if (allVisibleAccounts.length) { if (options.accountId && options.accountId !== '0') { - for (let i = 0; i < allVisibleAccounts.length; i++) { - if (allVisibleAccounts[i].id === options.accountId) { + for (const account of allVisibleAccounts) { + if (account.id === options.accountId) { transaction.sourceAccountId = options.accountId; transaction.destinationAccountId = options.accountId; break; @@ -115,7 +115,7 @@ export function setTransactionModelByTransaction(transaction: Transaction, trans if (defaultAccountId && allAccountsMap[defaultAccountId] && !allAccountsMap[defaultAccountId].hidden) { transaction.sourceAccountId = defaultAccountId; } else { - transaction.sourceAccountId = allVisibleAccounts[0].id; + transaction.sourceAccountId = allVisibleAccounts[0]!.id; } } @@ -123,7 +123,7 @@ export function setTransactionModelByTransaction(transaction: Transaction, trans if (defaultAccountId && allAccountsMap[defaultAccountId] && !allAccountsMap[defaultAccountId].hidden) { transaction.destinationAccountId = defaultAccountId; } else { - transaction.destinationAccountId = allVisibleAccounts[0].id; + transaction.destinationAccountId = allVisibleAccounts[0]!.id; } } } @@ -132,8 +132,7 @@ export function setTransactionModelByTransaction(transaction: Transaction, trans const tagIds = options.tagIds.split(','); const finalTagIds = []; - for (let i = 0; i < tagIds.length; i++) { - const tagId = tagIds[i]; + for (const tagId of tagIds) { const tag = allTagsMap[tagId]; if (tag && !tag.hidden) { diff --git a/src/locales/helpers.ts b/src/locales/helpers.ts index 82ccd422..9c512636 100644 --- a/src/locales/helpers.ts +++ b/src/locales/helpers.ts @@ -21,6 +21,11 @@ import { DEFAULT_CONTENT as PERSIAN_CALENDAR_DEFAULT_CONTENT } from '@/locales/calendar/persian/index.ts'; +import { + entries, + keys +} from '@/core/base.ts'; + import { TextDirection } from '@/core/text.ts'; @@ -257,12 +262,7 @@ export function getI18nOptions(): object { messages: (function () { const messages: Record = {}; - for (const languageKey in ALL_LANGUAGES) { - if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) { - continue; - } - - const languageInfo = ALL_LANGUAGES[languageKey]; + for (const [languageKey, languageInfo] of entries(ALL_LANGUAGES)) { messages[languageKey] = languageInfo.content; } @@ -274,13 +274,7 @@ export function getI18nOptions(): object { export function getRtlLocales(): Record { const rtlLocales: Record = {}; - for (const languageKey in ALL_LANGUAGES) { - if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) { - continue; - } - - const languageInfo = ALL_LANGUAGES[languageKey]; - + for (const [languageKey, languageInfo] of entries(ALL_LANGUAGES)) { if (languageInfo.textDirection === 'rtl') { rtlLocales[languageKey] = true; } @@ -346,7 +340,7 @@ export function useI18n() { // fallback to use marco language tag if (languageTagParts.length > 1) { - browserLanguage = languageTagParts[0]; + browserLanguage = languageTagParts[0] as string; // try to match marco language tag with full language tag in i18n file if (ALL_LANGUAGES[browserLanguage]) { @@ -373,24 +367,19 @@ export function useI18n() { } function getLanguageKeyFromLanguageAlias(alias: string): string | null { - for (const languageKey in ALL_LANGUAGES) { - if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) { - continue; - } - + for (const [languageKey, languageInfo] of entries(ALL_LANGUAGES)) { if (languageKey.toLowerCase() === alias.toLowerCase()) { return languageKey; } - const langInfo = ALL_LANGUAGES[languageKey]; - const aliases = langInfo.aliases; + const aliases = languageInfo.aliases; if (!aliases || aliases.length < 1) { continue; } - for (let i = 0; i < aliases.length; i++) { - if (aliases[i].toLowerCase() === alias.toLowerCase()) { + for (const aliasName of aliases) { + if (aliasName.toLowerCase() === alias.toLowerCase()) { return languageKey; } } @@ -400,16 +389,12 @@ export function useI18n() { } function getLanguageKeyFromMarcoLanguageTag(languageTag: string): string | null { - for (const languageKey in ALL_LANGUAGES) { - if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) { - continue; - } - + for (const languageKey of keys(ALL_LANGUAGES)) { if (languageKey.indexOf('-') < 0) { continue; } - const marcoLanguageTag = languageKey.split('-')[0]; + const marcoLanguageTag = languageKey.split('-')[0] as string; if (marcoLanguageTag.toLowerCase() === languageTag.toLowerCase()) { return languageKey; @@ -422,7 +407,7 @@ export function useI18n() { function getLocalizedError(error: ErrorResponse): LocalizedError { if (error.errorCode === KnownErrorCode.ApiNotFound && SPECIFIED_API_NOT_FOUND_ERRORS[error.path]) { return { - message: `${SPECIFIED_API_NOT_FOUND_ERRORS[error.path].message}` + message: `${SPECIFIED_API_NOT_FOUND_ERRORS[error.path]!.message}` }; } @@ -432,8 +417,7 @@ export function useI18n() { }; } - for (let i = 0; i < PARAMETERIZED_ERRORS.length; i++) { - const errorInfo = PARAMETERIZED_ERRORS[i]; + for (const errorInfo of PARAMETERIZED_ERRORS) { const matches = error.errorMessage.match(errorInfo.regex); if (matches && matches.length === errorInfo.parameters.length + 1) { @@ -443,7 +427,7 @@ export function useI18n() { return { key: param.field, localized: param.localized, - value: matches[index + 1] + value: matches[index + 1] as string } }) }; @@ -459,9 +443,7 @@ export function useI18n() { const localizedParameters: Record = {}; if (parameters) { - for (let i = 0; i < parameters.length; i++) { - const parameter = parameters[i]; - + for (const parameter of parameters) { if (parameter.localized) { localizedParameters[parameter.key] = t(`parameter.${parameter.value}`); } else { @@ -520,8 +502,7 @@ export function useI18n() { const allCurrencyDisplayTypes = CurrencyDisplayType.values(); - for (let i = 0; i < allCurrencyDisplayTypes.length; i++) { - const type = allCurrencyDisplayTypes[i]; + for (const type of allCurrencyDisplayTypes) { const sampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, type, numeralSystem, decimalSeparator); const displayName = `${t(type.name)} (${sampleValue})` @@ -534,7 +515,7 @@ export function useI18n() { return ret; } - function getAllLocalizedCalendarTypes(allTypeAndNameArray: CalendarDisplayType[] | DateDisplayType[], localeDefaultType: CalendarDisplayType | DateDisplayType | undefined, systemDefaultType: CalendarDisplayType | DateDisplayType, languageDefaultValue: number): TypeAndDisplayName[] { + function getAllLocalizedCalendarTypes(allCalendarDisplayTypeArray: CalendarDisplayType[] | DateDisplayType[], localeDefaultType: CalendarDisplayType | DateDisplayType | undefined, systemDefaultType: CalendarDisplayType | DateDisplayType, languageDefaultValue: number): TypeAndDisplayName[] { let defaultType: TypeAndName | undefined = localeDefaultType; if (!defaultType) { @@ -548,12 +529,10 @@ export function useI18n() { displayName: `${t('Language Default')} (${t('calendar.' + defaultType.name)})` }); - for (let i = 0; i < allTypeAndNameArray.length; i++) { - const type = allTypeAndNameArray[i]; - + for (const calendarDisplayType of allCalendarDisplayTypeArray) { ret.push({ - type: type.type, - displayName: t('calendar.' + type.name) + type: calendarDisplayType.type, + displayName: t('calendar.' + calendarDisplayType.name) }); } @@ -563,12 +542,10 @@ export function useI18n() { function getLocalizedDisplayNameAndType(typeAndNames: TypeAndName[]): TypeAndDisplayName[] { const ret: TypeAndDisplayName[] = []; - for (let i = 0; i < typeAndNames.length; i++) { - const nameAndType = typeAndNames[i]; - + for (const typeAndName of typeAndNames) { ret.push({ - type: nameAndType.type, - displayName: t(nameAndType.name) + type: typeAndName.type, + displayName: t(typeAndName.name) }); } @@ -583,12 +560,10 @@ export function useI18n() { displayName: t('System Default') + (defaultType.name ? ` (${t(defaultType.name)})` : '') }); - for (let i = 0; i < typeAndNames.length; i++) { - const nameAndType = typeAndNames[i]; - + for (const typeAndName of typeAndNames) { ret.push({ - type: nameAndType.type, - displayName: t(nameAndType.name) + type: typeAndName.type, + displayName: t(typeAndName.name) }); } @@ -610,13 +585,11 @@ export function useI18n() { displayName: `${t('Language Default')} (${defaultSeparatorType.symbol})` }); - for (let i = 0; i < allSeparatorArray.length; i++) { - const type = allSeparatorArray[i]; - + for (const separator of allSeparatorArray) { ret.push({ - type: type.type, - symbol: type.symbol, - displayName: `${t('numeral.' + type.name)} (${type.symbol})` + type: separator.type, + symbol: separator.symbol, + displayName: `${t('numeral.' + separator.name)} (${separator.symbol})` }); } @@ -627,9 +600,7 @@ export function useI18n() { const ret: TypeAndDisplayName[] = []; const allTypes: ChartDateAggregationType[] = ChartDateAggregationType.values(); - for (let i = 0; i < allTypes.length; i++) { - const type = allTypes[i]; - + for (const type of allTypes) { ret.push({ type: type.type, displayName: t(fullName ? type.fullName : `granularity.${type.shortName}`) @@ -643,8 +614,7 @@ export function useI18n() { const ret = []; const allMonths = Month.values(); - for (let i = 0; i < allMonths.length; i++) { - const month = allMonths[i]; + for (const month of allMonths) { ret.push(t(`datetime.${month.name}.${type}`)); } @@ -655,8 +625,7 @@ export function useI18n() { const ret = []; const allWeekDays = WeekDay.values(); - for (let i = 0; i < allWeekDays.length; i++) { - const weekDay = allWeekDays[i]; + for (const weekDay of allWeekDays) { ret.push(t(`datetime.${weekDay.name}.${type}`)); } @@ -952,17 +921,12 @@ export function useI18n() { function getAllLanguageOptions(includeSystemDefault: boolean): LanguageOption[] { const ret: LanguageOption[] = []; - for (const languageTag in ALL_LANGUAGES) { - if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageTag)) { - continue; - } - - const languageInfo = ALL_LANGUAGES[languageTag]; + for (const [languageKey, languageInfo] of entries(ALL_LANGUAGES)) { const displayName = languageInfo.displayName; const languageNameInCurrentLanguage = getLanguageDisplayName(languageInfo.name); ret.push({ - languageTag: languageTag, + languageTag: languageKey, displayName: languageNameInCurrentLanguage, nativeDisplayName: displayName }); @@ -996,11 +960,7 @@ export function useI18n() { function getAllCurrencies(): LocalizedCurrencyInfo[] { const allCurrencies: LocalizedCurrencyInfo[] = []; - for (const currencyCode in ALL_CURRENCIES) { - if (!Object.prototype.hasOwnProperty.call(ALL_CURRENCIES, currencyCode)) { - continue; - } - + for (const currencyCode of keys(ALL_CURRENCIES)) { const localizedCurrencyInfo: LocalizedCurrencyInfo = { currencyCode: currencyCode, displayName: getCurrencyName(currencyCode) @@ -1020,9 +980,7 @@ export function useI18n() { const allMeridiemIndicators = MeridiemIndicator.values(); const localizedMeridiemIndicatorNames = []; - for (let i = 0; i < allMeridiemIndicators.length; i++) { - const indicator = allMeridiemIndicators[i]; - + for (const indicator of allMeridiemIndicators) { localizedMeridiemIndicatorNames.push({ name: t(`datetime.${indicator.name}.content`), value: indicator.name @@ -1061,7 +1019,7 @@ export function useI18n() { } for (let i = firstDayOfWeek; i < allWeekDays.length; i++) { - const weekDay = allWeekDays[i]; + const weekDay = allWeekDays[i] as WeekDay; ret.push({ type: weekDay.type, @@ -1070,7 +1028,7 @@ export function useI18n() { } for (let i = 0; i < firstDayOfWeek; i++) { - const weekDay = allWeekDays[i]; + const weekDay = allWeekDays[i] as WeekDay; ret.push({ type: weekDay.type, @@ -1092,8 +1050,7 @@ export function useI18n() { displayName: `${t('Language Default')} (${formatCurrentTime(defaultFormat, dateTimeFormatOptions)})` }); - for (let i = 0; i < allFormatArray.length; i++) { - const formatType = allFormatArray[i]; + for (const formatType of allFormatArray) { const format = t(`format.${type}.${formatType.key}`); ret.push({ @@ -1110,9 +1067,7 @@ export function useI18n() { const ret: LocalizedDateRange[] = []; const allDateRanges = DateRange.values(); - for (let i = 0; i < allDateRanges.length; i++) { - const dateRange = allDateRanges[i]; - + for (const dateRange of allDateRanges) { if (!dateRange.isAvailableForScene(scene)) { continue; } @@ -1158,9 +1113,7 @@ export function useI18n() { }); } - for (let i = 0; i < recentDateRanges.length; i++) { - const recentDateRange = recentDateRanges[i]; - + for (const recentDateRange of recentDateRanges) { allRecentMonthDateRanges.push({ dateType: recentDateRange.dateType, minTime: recentDateRange.minTime, @@ -1190,14 +1143,14 @@ export function useI18n() { const defaultTimezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes(); const allTimezoneInfos: LocalizedTimezoneInfo[] = []; - for (let i = 0; i < ALL_TIMEZONES.length; i++) { - const utcOffset = (ALL_TIMEZONES[i].timezoneName !== UTC_TIMEZONE.timezoneName ? numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(ALL_TIMEZONES[i].timezoneName)) : ''); - const displayName = t(`timezone.${ALL_TIMEZONES[i].displayName}`); + for (const timezoneInfo of ALL_TIMEZONES) { + const utcOffset = (timezoneInfo.timezoneName !== UTC_TIMEZONE.timezoneName ? numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(timezoneInfo.timezoneName)) : ''); + const displayName = t(`timezone.${timezoneInfo.displayName}`); allTimezoneInfos.push({ - name: ALL_TIMEZONES[i].timezoneName, + name: timezoneInfo.timezoneName, utcOffset: utcOffset, - utcOffsetMinutes: getTimezoneOffsetMinutes(ALL_TIMEZONES[i].timezoneName), + utcOffsetMinutes: getTimezoneOffsetMinutes(timezoneInfo.timezoneName), displayName: displayName, displayNameWithUtcOffset: `(UTC${utcOffset}) ${displayName}` }); @@ -1269,9 +1222,7 @@ export function useI18n() { const allFiscalYearFormats = FiscalYearFormat.values(); - for (let i = 0; i < allFiscalYearFormats.length; i++) { - const fiscalYearFormat = allFiscalYearFormats[i]; - + for (const fiscalYearFormat of allFiscalYearFormats) { ret.push({ type: fiscalYearFormat.type, displayName: formatTimeRangeToGregorianLikeFiscalYearFormat(fiscalYearFormat, currentFiscalYearRange, numeralSystem, calendarType), @@ -1298,9 +1249,7 @@ export function useI18n() { const allNumeralSystemTypes = NumeralSystem.values(); - for (let i = 0; i < allNumeralSystemTypes.length; i++) { - const type = allNumeralSystemTypes[i]; - + for (const type of allNumeralSystemTypes) { ret.push({ type: type.type, displayName: `${t('numeral.' + type.name)} (${type.textualAllDigits})` @@ -1329,8 +1278,7 @@ export function useI18n() { const allDigitGroupingTypes = DigitGroupingType.values(); const numberCharacters = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits('123456789').split(''); - for (let i = 0; i < allDigitGroupingTypes.length; i++) { - const type = allDigitGroupingTypes[i]; + for (const type of allDigitGroupingTypes) { const sampleValue = type.format(numberCharacters, digitGroupingSymbol); ret.push({ @@ -1364,9 +1312,7 @@ export function useI18n() { const allPresetAmountColors = PresetAmountColor.values(); - for (let i = 0; i < allPresetAmountColors.length; i++) { - const amountColor = allPresetAmountColors[i]; - + for (const amountColor of allPresetAmountColors) { ret.push({ type: amountColor.type, displayName: t('color.amount.' + amountColor.name) @@ -1380,9 +1326,7 @@ export function useI18n() { const ret: LocalizedAccountCategory[] = []; const allCategories = AccountCategory.values(); - for (let i = 0; i < allCategories.length; i++) { - const accountCategory = allCategories[i]; - + for (const accountCategory of allCategories) { ret.push({ type: accountCategory.type, displayName: t(accountCategory.name), @@ -1403,9 +1347,8 @@ export function useI18n() { categoryTypes.push(categoryType); } - for (let i = 0; i < categoryTypes.length; i++) { + for (const categoryType of categoryTypes) { const categories: LocalizedPresetCategory[] = []; - const categoryType = categoryTypes[i]; let defaultCategories: PresetCategory[] = []; if (categoryType === CategoryType.Income) { @@ -1416,9 +1359,7 @@ export function useI18n() { defaultCategories = DEFAULT_TRANSFER_CATEGORIES; } - for (let j = 0; j < defaultCategories.length; j++) { - const category = defaultCategories[j]; - + for (const category of defaultCategories) { const submitCategory: LocalizedPresetCategory = { name: t('category.' + category.name, {}, { locale: locale }), type: categoryType, @@ -1427,8 +1368,7 @@ export function useI18n() { subCategories: [] }; - for (let k = 0; k < category.subCategories.length; k++) { - const subCategory = category.subCategories[k]; + for (const subCategory of category.subCategories) { const submitSubCategory: LocalizedPresetSubCategory = { name: t('category.' + subCategory.name, {}, { locale: locale }), type: categoryType, @@ -1455,9 +1395,7 @@ export function useI18n() { return availableExchangeRates; } - for (let i = 0; i < exchangeRatesData.exchangeRates.length; i++) { - const exchangeRate = exchangeRatesData.exchangeRates[i]; - + for (const exchangeRate of exchangeRatesData.exchangeRates) { availableExchangeRates.push({ currencyCode: exchangeRate.currency, currencyDisplayName: getCurrencyName(exchangeRate.currency), @@ -1494,16 +1432,13 @@ export function useI18n() { function getAllSupportedImportFileCagtegoryAndTypes(): LocalizedImportFileCategoryAndTypes[] { const allSupportedImportFileCategoryAndTypes: LocalizedImportFileCategoryAndTypes[] = []; - for (let i = 0; i < SUPPORTED_IMPORT_FILE_CATEGORY_AND_TYPES.length; i++) { - const categoryAndTypes = SUPPORTED_IMPORT_FILE_CATEGORY_AND_TYPES[i]; - + for (const categoryAndTypes of SUPPORTED_IMPORT_FILE_CATEGORY_AND_TYPES) { const localizedCategoryAndTypes: LocalizedImportFileCategoryAndTypes = { displayCategoryName: t(categoryAndTypes.categoryName), fileTypes: [] }; - for (let j = 0; j < categoryAndTypes.fileTypes.length; j++) { - const fileType = categoryAndTypes.fileTypes[j]; + for (const fileType of categoryAndTypes.fileTypes) { let document: LocalizedImportFileDocument | undefined; if (fileType.document) { @@ -1517,7 +1452,7 @@ export function useI18n() { if (SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE[documentLanguage] === documentLanguage) { documentAnchor = t(`document.anchor.export_and_import.${fileType.document.anchor}`); } else if (SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE[documentLanguage]) { - documentLanguage = SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE[documentLanguage]; + documentLanguage = SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE[documentLanguage] as string; documentAnchor = t(`document.anchor.export_and_import.${fileType.document.anchor}`, {}, { locale: documentLanguage }); } else { documentLanguage = DEFAULT_DOCUMENT_LANGUAGE_FOR_IMPORT_FILE; @@ -1528,8 +1463,8 @@ export function useI18n() { documentAnchor = fileType.document.anchor; } - if (documentLanguage && documentLanguage !== getCurrentLanguageTag()) { - documentDisplayLanguageName = getLanguageDisplayName(ALL_LANGUAGES[documentLanguage].name); + if (documentLanguage && documentLanguage !== getCurrentLanguageTag() && ALL_LANGUAGES[documentLanguage]) { + documentDisplayLanguageName = getLanguageDisplayName((ALL_LANGUAGES[documentLanguage] as LanguageInfo).name); } if (documentLanguage) { @@ -1556,8 +1491,7 @@ export function useI18n() { const subTypes: LocalizedImportFileTypeSubType[] = []; if (fileType.subTypes) { - for (let k = 0; k < fileType.subTypes.length; k++) { - const subType = fileType.subTypes[k]; + for (const subType of fileType.subTypes) { const localizedSubType: LocalizedImportFileTypeSubType = { type: subType.type, displayName: t(subType.name), @@ -1571,8 +1505,7 @@ export function useI18n() { const supportedEncodings: LocalizedImportFileTypeSupportedEncodings[] = []; if (fileType.supportedEncodings) { - for (let k = 0; k < fileType.supportedEncodings.length; k++) { - const encoding = fileType.supportedEncodings[k]; + for (const encoding of fileType.supportedEncodings) { const localizedEncoding: LocalizedImportFileTypeSupportedEncodings = { encoding: encoding, displayName: t(`encoding.${encoding}`) @@ -1638,7 +1571,7 @@ export function useI18n() { if (monthDays.length === 1) { return t('format.misc.monthDay', { - ordinal: getMonthdayOrdinal(monthDays[0]) + ordinal: getMonthdayOrdinal(monthDays[0] as number) }); } else { return t('format.misc.monthDays', { @@ -1657,16 +1590,14 @@ export function useI18n() { firstDayOfWeek = WeekDay.DefaultFirstDay.type; } - for (let i = 0; i < weekdayTypes.length; i++) { - weekdayTypesMap[weekdayTypes[i]] = true; + for (const weekdayType of weekdayTypes) { + weekdayTypesMap[weekdayType] = true; } const allWeekDays = getAllWeekDays(firstDayOfWeek); const finalWeekdayNames = []; - for (let i = 0; i < allWeekDays.length; i++) { - const weekDay = allWeekDays[i]; - + for (const weekDay of allWeekDays) { if (weekdayTypesMap[weekDay.type]) { finalWeekdayNames.push(weekDay.displayName); } @@ -1894,9 +1825,7 @@ export function useI18n() { const dateTimeFormatOptions = getDateTimeFormatOptions(); const gregorianLikeDateTimeFormatOptions = getDateTimeFormatOptions({ calendarType: gregorianLikeCalendarType }); - for (let i = 0; i < allDateRanges.length; i++) { - const dateRange = allDateRanges[i]; - + for (const dateRange of allDateRanges) { if (dateRange && dateRange.type !== DateRange.Custom.type && dateRange.type === dateType && dateRange.name) { return t(dateRange.name); } @@ -1984,8 +1913,7 @@ export function useI18n() { const ret: CalendarAlternateDate[] = []; - for (let i = 0; i < chineseDates.length; i++) { - const chineseDate = chineseDates[i]; + for (const chineseDate of chineseDates) { const alternateDate = getChineseCalendarAlternateDisplayDate(chineseDate); ret.push(alternateDate); } @@ -2117,11 +2045,9 @@ export function useI18n() { return formatExchangeRateAmount(value, numberFormatOptions); } - function getAdaptiveAmountRate(amount1: number, amount2: number, fromExchangeRate: { - rate: string - }, toExchangeRate: { rate: string }): string | null { + function getAdaptiveAmountRate(amount1: number, amount2: number, fromExchangeRate?: { rate: string }, toExchangeRate?: { rate: string }): string | null { const numberFormatOptions = getNumberFormatOptions({}); - return getAdaptiveDisplayAmountRate(amount1, amount2, fromExchangeRate, toExchangeRate, numberFormatOptions); + return getAdaptiveDisplayAmountRate(amount1, amount2, numberFormatOptions, fromExchangeRate, toExchangeRate); } function getAmountPrependAndAppendText(currencyCode: string, isPlural: boolean): CurrencyPrependAndAppendText | null { @@ -2137,19 +2063,17 @@ export function useI18n() { const allCategories = AccountCategory.values(); const categorizedAccounts: Record = getCategorizedAccountsMap(Account.cloneAccounts(allVisibleAccounts)); - for (let i = 0; i < allCategories.length; i++) { - const category = allCategories[i]; + for (const category of allCategories) { + const accountCategory = categorizedAccounts[category.type]; - if (!categorizedAccounts[category.type]) { + if (!accountCategory) { continue; } - const accountCategory = categorizedAccounts[category.type]; const accountsWithDisplayBalance: AccountWithDisplayBalance[] = []; if (accountCategory.accounts) { - for (let i = 0; i < accountCategory.accounts.length; i++) { - const account = accountCategory.accounts[i]; + for (const account of accountCategory.accounts) { let accountWithDisplaceBalance: AccountWithDisplayBalance; if (showAccountBalance && account.isAsset) { @@ -2171,24 +2095,24 @@ export function useI18n() { let totalBalance = 0; let hasUnCalculatedAmount = false; - for (let i = 0; i < accountsBalance.length; i++) { - if (accountsBalance[i].currency === defaultCurrency) { - if (accountsBalance[i].isAsset) { - totalBalance += accountsBalance[i].balance; - } else if (accountsBalance[i].isLiability) { - totalBalance -= accountsBalance[i].balance; + for (const accountBalance of accountsBalance) { + if (accountBalance.currency === defaultCurrency) { + if (accountBalance.isAsset) { + totalBalance += accountBalance.balance; + } else if (accountBalance.isLiability) { + totalBalance -= accountBalance.balance; } } else { - const balance = exchangeRatesStore.getExchangedAmount(accountsBalance[i].balance, accountsBalance[i].currency, defaultCurrency); + const balance = exchangeRatesStore.getExchangedAmount(accountBalance.balance, accountBalance.currency, defaultCurrency); if (!isNumber(balance)) { hasUnCalculatedAmount = true; continue; } - if (accountsBalance[i].isAsset) { + if (accountBalance.isAsset) { totalBalance += Math.trunc(balance); - } else if (accountsBalance[i].isLiability) { + } else if (accountBalance.isLiability) { totalBalance -= Math.trunc(balance); } } diff --git a/src/models/account.ts b/src/models/account.ts index 3149ad7e..8d94b0bb 100644 --- a/src/models/account.ts +++ b/src/models/account.ts @@ -108,7 +108,7 @@ export class Account implements AccountInfoResponse { } for (let i = 0; i < this.subAccounts.length; i++) { - if (!this.subAccounts[i].equals(other.subAccounts[i])) { + if (!(this.subAccounts[i] as Account).equals(other.subAccounts[i] as Account)) { return false; } } @@ -137,9 +137,9 @@ export class Account implements AccountInfoResponse { public setSuitableIcon(oldCategory: number, newCategory: number): void { const allCategories = AccountCategory.values(); - for (let i = 0; i < allCategories.length; i++) { - if (allCategories[i].type === oldCategory) { - if (this.icon !== allCategories[i].defaultAccountIconId) { + for (const category of allCategories) { + if (category.type === oldCategory) { + if (this.icon !== category.defaultAccountIconId) { return; } else { break; @@ -147,9 +147,9 @@ export class Account implements AccountInfoResponse { } } - for (let i = 0; i < allCategories.length; i++) { - if (allCategories[i].type === newCategory) { - this.icon = allCategories[i].defaultAccountIconId; + for (const category of allCategories) { + if (category.type === newCategory) { + this.icon = category.defaultAccountIconId; } } } @@ -231,9 +231,7 @@ export class Account implements AccountInfoResponse { return null; } - for (let i = 0; i < this.subAccounts.length; i++) { - const subAccount = this.subAccounts[i]; - + for (const subAccount of this.subAccounts) { if (subAccountId && subAccountId === subAccount.id) { return subAccount.id; } @@ -255,9 +253,7 @@ export class Account implements AccountInfoResponse { return false; } - for (let i = 0; i < this.subAccounts.length; i++) { - const subAccount = this.subAccounts[i]; - + for (const subAccount of this.subAccounts) { if (subAccountId && subAccountId === subAccount.id) { return subAccount.hidden; } @@ -279,9 +275,7 @@ export class Account implements AccountInfoResponse { return null; } - for (let i = 0; i < this.subAccounts.length; i++) { - const subAccount = this.subAccounts[i]; - + for (const subAccount of this.subAccounts) { if (subAccountId && subAccountId === subAccount.id) { return subAccount.comment; } @@ -303,9 +297,7 @@ export class Account implements AccountInfoResponse { return null; } - for (let i = 0; i < this.subAccounts.length; i++) { - const subAccount = this.subAccounts[i]; - + for (const subAccount of this.subAccounts) { if (subAccountId && subAccountId === subAccount.id) { return subAccount; } @@ -322,9 +314,7 @@ export class Account implements AccountInfoResponse { return null; } - for (let i = 0; i < this.subAccounts.length; i++) { - const subAccount = this.subAccounts[i]; - + for (const subAccount of this.subAccounts) { if (subAccountId && subAccountId === subAccount.id) { return subAccount; } @@ -341,9 +331,7 @@ export class Account implements AccountInfoResponse { const subAccountCurrenciesMap: Record = {}; const subAccountCurrencies: string[] = []; - for (let i = 0; i < this.subAccounts.length; i++) { - const subAccount = this.subAccounts[i]; - + for (const subAccount of this.subAccounts) { if (!showHidden && subAccount.hidden) { continue; } @@ -508,7 +496,7 @@ export class Account implements AccountInfoResponse { if (account1.parentId && account1.parentId !== '0') { if (allAccountsMap && allAccountsMap[account1.parentId]) { - account1DisplayOrder = allAccountsMap[account1.parentId].displayOrder; + account1DisplayOrder = (allAccountsMap[account1.parentId] as Account).displayOrder; } else { account1DisplayOrder = null; } @@ -516,7 +504,7 @@ export class Account implements AccountInfoResponse { if (account2.parentId && account2.parentId !== '0') { if (allAccountsMap && allAccountsMap[account2.parentId]) { - account2DisplayOrder = allAccountsMap[account2.parentId].displayOrder; + account2DisplayOrder = (allAccountsMap[account2.parentId] as Account).displayOrder; } else { account2DisplayOrder = null; } diff --git a/src/models/transaction.ts b/src/models/transaction.ts index 6be61bdd..f0847e5b 100644 --- a/src/models/transaction.ts +++ b/src/models/transaction.ts @@ -1,4 +1,4 @@ -import type { PartialRecord } from '@/core/base.ts'; +import { type PartialRecord, itemAndIndex } from '@/core/base.ts'; import type { Year1BasedMonth, TextualYearMonthDay, StartEndTime, WeekDay } from '@/core/datetime.ts'; import { type Coordinate, getNormalizedCoordinate } from '@/core/coordinate.ts'; import { TransactionType } from '@/core/transaction.ts'; @@ -185,9 +185,9 @@ export class Transaction implements TransactionInfoResponse { return; } - for (let i = 0; i < this._pictures.length; i++) { - if (this._pictures[i].pictureId === pictureInfo.pictureId) { - this._pictures.splice(i, 1); + for (const [picture, index] of itemAndIndex(this._pictures)) { + if (picture.pictureId === pictureInfo.pictureId) { + this._pictures.splice(index, 1); } } } diff --git a/src/models/transaction_category.ts b/src/models/transaction_category.ts index 5605a94d..e2e1e07a 100644 --- a/src/models/transaction_category.ts +++ b/src/models/transaction_category.ts @@ -1,3 +1,4 @@ +import { entries } from '@/core/base.ts'; import type { ColorValue } from '@/core/color.ts'; import { CategoryType } from '@/core/category.ts'; import { DEFAULT_CATEGORY_ICON_ID } from '@/consts/icon.ts'; @@ -58,7 +59,7 @@ export class TransactionCategory implements TransactionCategoryInfoResponse { } for (let i = 0; i < this.subCategories.length; i++) { - if (!this.subCategories[i].equals(other.subCategories[i])) { + if (!(this.subCategories[i] as TransactionCategory).equals(other.subCategories[i] as TransactionCategory)) { return false; } } @@ -132,12 +133,8 @@ export class TransactionCategory implements TransactionCategoryInfoResponse { public static ofMap(categoriesByType: Record): Record { const ret: Record = {}; - for (const categoryType in categoriesByType) { - if (!Object.prototype.hasOwnProperty.call(categoriesByType, categoryType)) { - continue; - } - - ret[categoryType] = TransactionCategory.ofMulti(categoriesByType[categoryType]); + for (const [categoryType, categories] of entries(categoriesByType)) { + ret[parseInt(categoryType)] = TransactionCategory.ofMulti(categories); } return ret; diff --git a/src/stores/exchangeRates.ts b/src/stores/exchangeRates.ts index c474edbe..a9a5728e 100644 --- a/src/stores/exchangeRates.ts +++ b/src/stores/exchangeRates.ts @@ -1,7 +1,7 @@ import { ref, computed } from 'vue'; import { defineStore } from 'pinia'; -import type { BeforeResolveFunction } from '@/core/base.ts'; +import { type BeforeResolveFunction, itemAndIndex } from '@/core/base.ts'; import type { UserCustomExchangeRateUpdateResponse, @@ -65,15 +65,14 @@ export const useExchangeRatesStore = defineStore('exchangeRates', () => { return exchangeRateMap; } - for (let i = 0; i < latestExchangeRates.value.data.exchangeRates.length; i++) { - const exchangeRate = latestExchangeRates.value.data.exchangeRates[i]; + for (const exchangeRate of latestExchangeRates.value.data.exchangeRates) { exchangeRateMap[exchangeRate.currency] = exchangeRate; } return exchangeRateMap; }); - function updateExchangeRateToLatestExchangeRateList(exchangeRate: LatestExchangeRate, updateTime: number): void { + function updateExchangeRateToLatestExchangeRateList(latestExchangeRate: LatestExchangeRate, updateTime: number): void { if (!latestExchangeRates.value || !latestExchangeRates.value.data || !latestExchangeRates.value.data.exchangeRates) { return; } @@ -81,16 +80,16 @@ export const useExchangeRatesStore = defineStore('exchangeRates', () => { const exchangeRates = latestExchangeRates.value.data.exchangeRates; let changed = false; - for (let i = 0; i < exchangeRates.length; i++) { - if (exchangeRates[i].currency === exchangeRate.currency) { - exchangeRates.splice(i, 1, exchangeRate); + for (const [exchangeRate, index] of itemAndIndex(exchangeRates)) { + if (exchangeRate.currency === latestExchangeRate.currency) { + exchangeRates.splice(index, 1, latestExchangeRate); changed = true; break; } } if (!changed) { - exchangeRates.push(exchangeRate); + exchangeRates.push(latestExchangeRate); changed = true; } @@ -109,9 +108,9 @@ export const useExchangeRatesStore = defineStore('exchangeRates', () => { const exchangeRates = latestExchangeRates.value.data.exchangeRates; let changed = false; - for (let i = 0; i < exchangeRates.length; i++) { - if (exchangeRates[i].currency === currency) { - exchangeRates.splice(i, 1); + for (const [exchangeRate, index] of itemAndIndex(exchangeRates)) { + if (exchangeRate.currency === currency) { + exchangeRates.splice(index, 1); changed = true; break; } @@ -262,8 +261,7 @@ export const useExchangeRatesStore = defineStore('exchangeRates', () => { const exchangeRates = latestExchangeRates.value.data.exchangeRates; const exchangeRateMap: Record = {}; - for (let i = 0; i < exchangeRates.length; i++) { - const exchangeRate = exchangeRates[i]; + for (const exchangeRate of exchangeRates) { exchangeRateMap[exchangeRate.currency] = exchangeRate; } diff --git a/src/stores/setting.ts b/src/stores/setting.ts index 19143954..2948af30 100644 --- a/src/stores/setting.ts +++ b/src/stores/setting.ts @@ -1,6 +1,10 @@ import { ref, computed } from 'vue'; import { defineStore } from 'pinia'; +import { + values +} from '@/core/base.ts'; + import { type ApplicationSettingValue, type ApplicationSettingSubValue, @@ -39,13 +43,15 @@ export const useSettingsStore = defineStore('settings', () => { function updateApplicationSettingsValueAndAppSettingsFromCloudSetting(key: string, value: string | number | boolean | Record): void { const keyItems = key.split('.'); + const keyFirstPart = keyItems[0] as string; if (keyItems.length === 1) { - updateApplicationSettingsValue(keyItems[0], value); - appSettings.value[keyItems[0]] = value; + updateApplicationSettingsValue(keyFirstPart, value); + appSettings.value[keyFirstPart] = value; } else if (keyItems.length === 2) { - updateApplicationSettingsSubValue(keyItems[0], keyItems[1], value); - (appSettings.value[keyItems[0]] as Record)[keyItems[1]] = value; + const subKey = keyItems[1] as string; + updateApplicationSettingsSubValue(keyFirstPart, subKey, value); + (appSettings.value[keyFirstPart] as Record)[subKey] = value; } else { logger.warn(`cannot load application cloud setting "${key}", because it has invalid key format`); } @@ -60,10 +66,12 @@ export const useSettingsStore = defineStore('settings', () => { } const keyItems = key.split('.'); - let value: ApplicationSettingValue | ApplicationSettingSubValue = appSettings.value[key]; + let value: ApplicationSettingValue | ApplicationSettingSubValue = appSettings.value[key] as (ApplicationSettingValue | ApplicationSettingSubValue); if (keyItems.length === 2) { - value = (appSettings.value[keyItems[0]] as Record)[keyItems[1]]; + const primaryKey = keyItems[0] as string; + const subKey = keyItems[1] as string; + value = (appSettings.value[primaryKey] as Record)[subKey] as ApplicationSettingSubValue; } else if (keyItems.length > 2) { logger.warn(`cannot get application cloud setting "${key}", because it has invalid key format`); return null; @@ -313,8 +321,7 @@ export const useSettingsStore = defineStore('settings', () => { const settings: ApplicationCloudSetting[] = []; - for (let i = 0; i < applicationSettingKeys.length; i++) { - const settingKey = applicationSettingKeys[i]; + for (const settingKey of applicationSettingKeys) { const cloudSetting = createUserApplicationCloudSetting(settingKey); if (cloudSetting) { @@ -333,9 +340,7 @@ export const useSettingsStore = defineStore('settings', () => { syncedAppSettings.value = arrayItemToObjectField(cloudSettings.map(item => item.settingKey), true); - for (let i = 0; i < cloudSettings.length; i++) { - const setting = cloudSettings[i]; - + for (const setting of cloudSettings) { if (!setting || !setting.settingKey) { continue; } @@ -371,13 +376,7 @@ export const useSettingsStore = defineStore('settings', () => { let isValid = isObject(map); if (isValid) { - for (const key in map) { - if (!Object.prototype.hasOwnProperty.call(map, key)) { - continue; - } - - const value = map[key]; - + for (const value of values(map)) { if (!isBoolean(value)) { isValid = false; break; diff --git a/src/stores/transaction.ts b/src/stores/transaction.ts index 32580892..ea6d78c7 100644 --- a/src/stores/transaction.ts +++ b/src/stores/transaction.ts @@ -140,11 +140,9 @@ export const useTransactionsStore = defineStore('transactions', () => { const allFilterTagIdsCount = computed(() => countSplitItems(transactionsFilter.value.tagIds, ',')); const noTransaction = computed(() => { - for (let i = 0; i < transactions.value.length; i++) { - const transactionMonthList = transactions.value[i]; - - for (let j = 0; j < transactionMonthList.items.length; j++) { - if (transactionMonthList.items[j]) { + for (const transactionMonthList of transactions.value) { + for (const transaction of transactionMonthList.items) { + if (transaction) { return false; } } diff --git a/src/stores/transactionTag.ts b/src/stores/transactionTag.ts index c10698a3..5aaa824c 100644 --- a/src/stores/transactionTag.ts +++ b/src/stores/transactionTag.ts @@ -1,7 +1,7 @@ import { ref, computed } from 'vue'; import { defineStore } from 'pinia'; -import type { BeforeResolveFunction } from '@/core/base.ts'; +import { type BeforeResolveFunction, itemAndIndex } from '@/core/base.ts'; import { type TransactionTagCreateBatchRequest, @@ -49,37 +49,37 @@ export const useTransactionTagsStore = defineStore('transactionTags', () => { allTransactionTagsMap.value[tag.id] = tag; } - function updateTagInTransactionTagList(tag: TransactionTag): void { - for (let i = 0; i < allTransactionTags.value.length; i++) { - if (allTransactionTags.value[i].id === tag.id) { - allTransactionTags.value.splice(i, 1, tag); + function updateTagInTransactionTagList(currentTag: TransactionTag): void { + for (const [transactionTag, index] of itemAndIndex(allTransactionTags.value)) { + if (transactionTag.id === currentTag.id) { + allTransactionTags.value.splice(index, 1, currentTag); break; } } - allTransactionTagsMap.value[tag.id] = tag; + allTransactionTagsMap.value[currentTag.id] = currentTag; } function updateTagDisplayOrderInTransactionTagList({ from, to }: { from: number, to: number }): void { - allTransactionTags.value.splice(to, 0, allTransactionTags.value.splice(from, 1)[0]); + allTransactionTags.value.splice(to, 0, allTransactionTags.value.splice(from, 1)[0] as TransactionTag); } function updateTagVisibilityInTransactionTagList({ tag, hidden }: { tag: TransactionTag, hidden: boolean }): void { if (allTransactionTagsMap.value[tag.id]) { - allTransactionTagsMap.value[tag.id].hidden = hidden; + allTransactionTagsMap.value[tag.id]!.hidden = hidden; } } - function removeTagFromTransactionTagList(tag: TransactionTag): void { - for (let i = 0; i < allTransactionTags.value.length; i++) { - if (allTransactionTags.value[i].id === tag.id) { - allTransactionTags.value.splice(i, 1); + function removeTagFromTransactionTagList(currentTag: TransactionTag): void { + for (const [transactionTag, index] of itemAndIndex(allTransactionTags.value)) { + if (transactionTag.id === currentTag.id) { + allTransactionTags.value.splice(index, 1); break; } } - if (allTransactionTagsMap.value[tag.id]) { - delete allTransactionTagsMap.value[tag.id]; + if (allTransactionTagsMap.value[currentTag.id]) { + delete allTransactionTagsMap.value[currentTag.id]; } } @@ -223,16 +223,16 @@ export const useTransactionTagsStore = defineStore('transactionTags', () => { function changeTagDisplayOrder({ tagId, from, to }: { tagId: string, from: number, to: number }): Promise { return new Promise((resolve, reject) => { - let tag: TransactionTag | null = null; + let currentTag: TransactionTag | null = null; - for (let i = 0; i < allTransactionTags.value.length; i++) { - if (allTransactionTags.value[i].id === tagId) { - tag = allTransactionTags.value[i]; + for (const transactionTag of allTransactionTags.value) { + if (transactionTag.id === tagId) { + currentTag = transactionTag; break; } } - if (!tag || !allTransactionTags.value[to]) { + if (!currentTag || !allTransactionTags.value[to]) { reject({ message: 'Unable to move tag' }); return; } @@ -250,10 +250,10 @@ export const useTransactionTagsStore = defineStore('transactionTags', () => { function updateTagDisplayOrders(): Promise { const newDisplayOrders: TransactionTagNewDisplayOrderRequest[] = []; - for (let i = 0; i < allTransactionTags.value.length; i++) { + for (const [transactionTag, index] of itemAndIndex(allTransactionTags.value)) { newDisplayOrders.push({ - id: allTransactionTags.value[i].id, - displayOrder: i + 1 + id: transactionTag.id, + displayOrder: index + 1 }); } diff --git a/src/views/base/settings/AccountFilterSettingPageBase.ts b/src/views/base/settings/AccountFilterSettingPageBase.ts index 9e34ccc2..48eb0669 100644 --- a/src/views/base/settings/AccountFilterSettingPageBase.ts +++ b/src/views/base/settings/AccountFilterSettingPageBase.ts @@ -6,6 +6,7 @@ import { useTransactionsStore } from '@/stores/transaction.ts'; import { useStatisticsStore } from '@/stores/statistics.ts'; import { useOverviewStore } from '@/stores/overview.ts'; +import { keys, keysIfValueEquals, values } from '@/core/base.ts'; import type { Account, AccountCategoriesWithVisibleCount } from '@/models/account.ts'; import { @@ -65,13 +66,7 @@ export function useAccountFilterSettingPageBase(type?: AccountFilterType) { function loadFilterAccountIds(): boolean { const allAccountIds: Record = {}; - for (const accountId in accountsStore.allAccountsMap) { - if (!Object.prototype.hasOwnProperty.call(accountsStore.allAccountsMap, accountId)) { - continue; - } - - const account = accountsStore.allAccountsMap[accountId]; - + for (const account of values(accountsStore.allAccountsMap)) { if (!allowHiddenAccount.value && account.hidden) { continue; } @@ -93,11 +88,7 @@ export function useAccountFilterSettingPageBase(type?: AccountFilterType) { filterAccountIds.value = Object.assign(allAccountIds, settingsStore.appSettings.overviewAccountFilterInHomePage); return true; } else if (type === 'transactionListCurrent') { - for (const accountId in transactionsStore.allFilterAccountIds) { - if (!Object.prototype.hasOwnProperty.call(transactionsStore.allFilterAccountIds, accountId)) { - continue; - } - + for (const accountId of keysIfValueEquals(transactionsStore.allFilterAccountIds, true)) { const account = accountsStore.allAccountsMap[accountId]; if (account) { @@ -120,11 +111,7 @@ export function useAccountFilterSettingPageBase(type?: AccountFilterType) { let finalAccountIds = ''; let changed = true; - for (const accountId in filterAccountIds.value) { - if (!Object.prototype.hasOwnProperty.call(filterAccountIds.value, accountId)) { - continue; - } - + for (const accountId of keys(filterAccountIds.value)) { const account = accountsStore.allAccountsMap[accountId]; if (!account) { diff --git a/src/views/base/settings/AppCloudSyncPageBase.ts b/src/views/base/settings/AppCloudSyncPageBase.ts index 293c2e0e..02469b3f 100644 --- a/src/views/base/settings/AppCloudSyncPageBase.ts +++ b/src/views/base/settings/AppCloudSyncPageBase.ts @@ -2,6 +2,7 @@ import { ref, computed } from 'vue'; import { useSettingsStore } from '@/stores/setting.ts'; +import { keysIfValueEquals } from '@/core/base.ts'; import type { ApplicationCloudSetting } from '@/core/setting.ts'; export interface CategorizedApplicationCloudSettingItems { @@ -101,14 +102,8 @@ export function useAppCloudSyncBase() { const isEnableCloudSync = computed(() => settingsStore.enableApplicationCloudSync); const hasEnabledApplicationCloudSettings = computed(() => { - for (const key in enabledApplicationCloudSettings.value) { - if (!Object.prototype.hasOwnProperty.call(enabledApplicationCloudSettings.value, key)) { - continue; - } - - if (enabledApplicationCloudSettings.value[key]) { - return true; - } + for (const _ of keysIfValueEquals(enabledApplicationCloudSettings.value, true)) { + return true; } return false; @@ -117,22 +112,15 @@ export function useAppCloudSyncBase() { const enabledApplicationCloudSettingKeys = computed(() => { const keys: string[] = []; - for (const key in enabledApplicationCloudSettings.value) { - if (!Object.prototype.hasOwnProperty.call(enabledApplicationCloudSettings.value, key)) { - continue; - } - - if (enabledApplicationCloudSettings.value[key]) { - keys.push(key); - } + for (const key of keysIfValueEquals(enabledApplicationCloudSettings.value, true)) { + keys.push(key); } return keys; }); function isAllSettingsSelected(categorizedItems: CategorizedApplicationCloudSettingItems): boolean { - for (let i = 0; i < categorizedItems.items.length; i++) { - const item = categorizedItems.items[i]; + for (const item of categorizedItems.items) { if (!enabledApplicationCloudSettings.value[item.settingKey]) { return false; } @@ -144,8 +132,7 @@ export function useAppCloudSyncBase() { function hasSettingSelectedButNotAllChecked(categorizedItems: CategorizedApplicationCloudSettingItems): boolean { let checkedCount = 0; - for (let i = 0; i < categorizedItems.items.length; i++) { - const item = categorizedItems.items[i]; + for (const item of categorizedItems.items) { if (!enabledApplicationCloudSettings.value[item.settingKey]) { checkedCount++; } @@ -155,40 +142,30 @@ export function useAppCloudSyncBase() { } function updateSettingsSelected(categorizedItems: CategorizedApplicationCloudSettingItems, value: boolean): void { - for (let i = 0; i < categorizedItems.items.length; i++) { - const item = categorizedItems.items[i]; + for (const item of categorizedItems.items) { enabledApplicationCloudSettings.value[item.settingKey] = value; } } function selectAllSettings(): void { - for (let i = 0; i < ALL_APPLICATION_CLOUD_SETTINGS.length; i++) { - const categorizedItems = ALL_APPLICATION_CLOUD_SETTINGS[i]; - - for (let j = 0; j < categorizedItems.items.length; j++) { - const item = categorizedItems.items[j]; + for (const categorizedItems of ALL_APPLICATION_CLOUD_SETTINGS) { + for (const item of categorizedItems.items) { enabledApplicationCloudSettings.value[item.settingKey] = true; } } } function selectNoneSettings(): void { - for (let i = 0; i < ALL_APPLICATION_CLOUD_SETTINGS.length; i++) { - const categorizedItems = ALL_APPLICATION_CLOUD_SETTINGS[i]; - - for (let j = 0; j < categorizedItems.items.length; j++) { - const item = categorizedItems.items[j]; + for (const categorizedItems of ALL_APPLICATION_CLOUD_SETTINGS) { + for (const item of categorizedItems.items) { enabledApplicationCloudSettings.value[item.settingKey] = false; } } } function selectInvertSettings(): void { - for (let i = 0; i < ALL_APPLICATION_CLOUD_SETTINGS.length; i++) { - const categorizedItems = ALL_APPLICATION_CLOUD_SETTINGS[i]; - - for (let j = 0; j < categorizedItems.items.length; j++) { - const item = categorizedItems.items[j]; + for (const categorizedItems of ALL_APPLICATION_CLOUD_SETTINGS) { + for (const item of categorizedItems.items) { enabledApplicationCloudSettings.value[item.settingKey] = !enabledApplicationCloudSettings.value[item.settingKey]; } } diff --git a/src/views/base/settings/AppSettingsPageBase.ts b/src/views/base/settings/AppSettingsPageBase.ts index 3dc6f566..f7118472 100644 --- a/src/views/base/settings/AppSettingsPageBase.ts +++ b/src/views/base/settings/AppSettingsPageBase.ts @@ -9,7 +9,7 @@ import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts'; import { useOverviewStore } from '@/stores/overview.ts'; import { useStatisticsStore } from '@/stores/statistics.ts'; -import type { NameValue, TypeAndDisplayName } from '@/core/base.ts'; +import { type NameValue, type TypeAndDisplayName, keysIfValueEquals, values } from '@/core/base.ts'; import type { LocalizedTimezoneInfo } from '@/core/timezone.ts'; import { CategoryType } from '@/core/category.ts'; import type { Account } from '@/models/account.ts'; @@ -145,12 +145,8 @@ export function useAppSettingPageBase() { let hasExcludeAccount = false; - for (const accountId in excludeAccountIds) { - if (!Object.prototype.hasOwnProperty.call(excludeAccountIds, accountId)) { - continue; - } - - if (excludeAccountIds[accountId] && accountsStore.allAccountsMap[accountId]) { + for (const accountId of keysIfValueEquals(excludeAccountIds, true)) { + if (accountsStore.allAccountsMap[accountId]) { hasExcludeAccount = true; break; } @@ -162,9 +158,7 @@ export function useAppSettingPageBase() { let allAccountExcluded = true; - for (let i = 0; i < allAccounts.length; i++) { - const account = allAccounts[i]; - + for (const account of allAccounts) { if (!excludeAccountIds[account.id]) { allAccountExcluded = false; break; @@ -185,12 +179,8 @@ export function useAppSettingPageBase() { let hasExcludeTransactionCategory = false; - for (const transactionCategoryId in excludeTransactionCategoryIds) { - if (!Object.prototype.hasOwnProperty.call(excludeTransactionCategoryIds, transactionCategoryId)) { - continue; - } - - if (excludeTransactionCategoryIds[transactionCategoryId] && transactionCategoriesStore.allTransactionCategoriesMap[transactionCategoryId]) { + for (const transactionCategoryId of keysIfValueEquals(excludeTransactionCategoryIds, true)) { + if (transactionCategoriesStore.allTransactionCategoriesMap[transactionCategoryId]) { hasExcludeTransactionCategory = true; break; } @@ -202,13 +192,7 @@ export function useAppSettingPageBase() { let allTransactionCategoryExcluded = true; - for (const transactionCategoryId in transactionCategoriesStore.allTransactionCategoriesMap) { - if (!Object.prototype.hasOwnProperty.call(transactionCategoriesStore.allTransactionCategoriesMap, transactionCategoryId)) { - continue; - } - - const transactionCategory = transactionCategoriesStore.allTransactionCategoriesMap[transactionCategoryId]; - + for (const transactionCategory of values(transactionCategoriesStore.allTransactionCategoriesMap)) { if (transactionCategory.type !== CategoryType.Income && transactionCategory.type !== CategoryType.Expense) { continue; } diff --git a/src/views/base/settings/TransactionTagFilterSettingPageBase.ts b/src/views/base/settings/TransactionTagFilterSettingPageBase.ts index c2b7ec7a..d42a33d6 100644 --- a/src/views/base/settings/TransactionTagFilterSettingPageBase.ts +++ b/src/views/base/settings/TransactionTagFilterSettingPageBase.ts @@ -6,7 +6,7 @@ import { useTransactionTagsStore } from '@/stores/transactionTag.ts'; import { useTransactionsStore } from '@/stores/transaction.ts'; import { useStatisticsStore } from '@/stores/statistics.ts'; -import type { TypeAndDisplayName } from '@/core/base.ts'; +import { type TypeAndDisplayName, keys, keysIfValueEquals, values } from '@/core/base.ts'; import { TransactionTagFilterType } from '@/core/transaction.ts'; import type { TransactionTag } from '@/models/transaction_tag.ts'; @@ -44,20 +44,14 @@ export function useTransactionTagFilterSettingPageBase(type?: string) { function loadFilterTagIds(): boolean { const allTransactionTagIds: Record = {}; - for (const transactionTagId in transactionTagsStore.allTransactionTagsMap) { - if (!Object.prototype.hasOwnProperty.call(transactionTagsStore.allTransactionTagsMap, transactionTagId)) { - continue; - } - - const transactionTag = transactionTagsStore.allTransactionTagsMap[transactionTagId]; + for (const transactionTag of values(transactionTagsStore.allTransactionTagsMap)) { allTransactionTagIds[transactionTag.id] = true; } if (type === 'statisticsCurrent') { const transactionTagIds = statisticsStore.transactionStatisticsFilter.tagIds ? statisticsStore.transactionStatisticsFilter.tagIds.split(',') : []; - for (let i = 0; i < transactionTagIds.length; i++) { - const transactionTagId = transactionTagIds[i]; + for (const transactionTagId of transactionTagIds) { const transactionTag = transactionTagsStore.allTransactionTagsMap[transactionTagId]; if (transactionTag) { @@ -68,11 +62,7 @@ export function useTransactionTagFilterSettingPageBase(type?: string) { tagFilterType.value = statisticsStore.transactionStatisticsFilter.tagFilterType; return true; } else if (type === 'transactionListCurrent') { - for (const transactionTagId in transactionsStore.allFilterTagIds) { - if (!Object.prototype.hasOwnProperty.call(transactionsStore.allFilterTagIds, transactionTagId)) { - continue; - } - + for (const transactionTagId of keysIfValueEquals(transactionsStore.allFilterTagIds, true)) { const transactionTag = transactionTagsStore.allTransactionTagsMap[transactionTagId]; if (transactionTag) { @@ -91,11 +81,7 @@ export function useTransactionTagFilterSettingPageBase(type?: string) { let finalTagIds = ''; let changed = true; - for (const transactionTagId in filterTagIds.value) { - if (!Object.prototype.hasOwnProperty.call(filterTagIds.value, transactionTagId)) { - continue; - } - + for (const transactionTagId of keys(filterTagIds.value)) { const transactionTag = transactionTagsStore.allTransactionTagsMap[transactionTagId]; if (!transactionTag) { diff --git a/src/views/base/transactions/TransactionListPageBase.ts b/src/views/base/transactions/TransactionListPageBase.ts index d3b88005..88b2c5ab 100644 --- a/src/views/base/transactions/TransactionListPageBase.ts +++ b/src/views/base/transactions/TransactionListPageBase.ts @@ -9,7 +9,7 @@ import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts'; import { useTransactionTagsStore } from '@/stores/transactionTag.ts'; import { type TransactionListFilter, type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts'; -import type { TypeAndName } from '@/core/base.ts'; +import { type TypeAndName, entries } from '@/core/base.ts'; import type { NumeralSystem } from '@/core/numeral.ts'; import { type TextualYearMonthDay, type Year0BasedMonth, type LocalizedDateRange, type WeekDayValue, DateRange, DateRangeScene } from '@/core/datetime.ts'; import { AccountType } from '@/core/account.ts'; @@ -113,16 +113,12 @@ export function useTransactionListPageBase() { const allPrimaryCategories = computed>(() => { const primaryCategories: Record = {}; - for (const categoryType in transactionCategoriesStore.allTransactionCategories) { - if (!Object.prototype.hasOwnProperty.call(transactionCategoriesStore.allTransactionCategories, categoryType)) { - continue; - } - + for (const [categoryType, categories] of entries(transactionCategoriesStore.allTransactionCategories)) { if (query.value.type && categoryTypeToTransactionType(parseInt(categoryType)) !== query.value.type) { continue; } - primaryCategories[categoryType] = transactionCategoriesStore.allTransactionCategories[categoryType]; + primaryCategories[categoryType] = categories; } return primaryCategories; @@ -131,17 +127,13 @@ export function useTransactionListPageBase() { const allAvailableCategoriesCount = computed(() => { let totalCount = 0; - for (const categoryType in transactionCategoriesStore.allTransactionCategories) { - if (!Object.prototype.hasOwnProperty.call(transactionCategoriesStore.allTransactionCategories, categoryType)) { - continue; - } - + for (const [categoryType, categories] of entries(transactionCategoriesStore.allTransactionCategories)) { if (query.value.type && categoryTypeToTransactionType(parseInt(categoryType)) !== query.value.type) { continue; } - if (transactionCategoriesStore.allTransactionCategories[categoryType]) { - totalCount += transactionCategoriesStore.allTransactionCategories[categoryType].length; + if (categories) { + totalCount += categories.length; } } @@ -229,7 +221,7 @@ export function useTransactionListPageBase() { const displayAmount: string[] = []; for (let i = 1; i < amountFilterItems.length; i++) { - displayAmount.push(formatAmountToLocalizedNumeralsWithCurrency(parseInt(amountFilterItems[i]), false)); + displayAmount.push(formatAmountToLocalizedNumeralsWithCurrency(parseInt(amountFilterItems[i] as string), false)); } return displayAmount.join(' ~ '); @@ -249,9 +241,9 @@ export function useTransactionListPageBase() { const currentYear = currentMonthMinDate.getGregorianCalendarYear(); const currentMonth = currentMonthMinDate.getGregorianCalendarMonth(); - for (let i = 0; i < allTransactions.length; i++) { - if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) { - return allTransactions[i]; + for (const transactionMonth of allTransactions) { + if (transactionMonth.year === currentYear && transactionMonth.month === currentMonth) { + return transactionMonth; } } diff --git a/src/views/desktop/common/cards/AccountFilterSettingsCard.vue b/src/views/desktop/common/cards/AccountFilterSettingsCard.vue index 896a3023..ddfd3acd 100644 --- a/src/views/desktop/common/cards/AccountFilterSettingsCard.vue +++ b/src/views/desktop/common/cards/AccountFilterSettingsCard.vue @@ -111,7 +111,7 @@ v-if="(showHidden || !account.hidden) && account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])">