From 3bb7f5abf40fccd5b27608a1d1a7dd6c359833f6 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Thu, 22 Jan 2026 23:58:04 +0800 Subject: [PATCH] support exporting data when checking pending import data --- src/locales/de.json | 3 +- src/locales/en.json | 3 +- src/locales/es.json | 3 +- src/locales/fr.json | 3 +- src/locales/it.json | 3 +- src/locales/ja.json | 3 +- src/locales/kn.json | 3 +- src/locales/ko.json | 3 +- src/locales/nl.json | 3 +- src/locales/pt_BR.json | 3 +- src/locales/ru.json | 3 +- src/locales/sl.json | 3 +- src/locales/ta.json | 3 +- src/locales/th.json | 3 +- src/locales/tr.json | 3 +- src/locales/uk.json | 3 +- src/locales/vi.json | 3 +- src/locales/zh_Hans.json | 3 +- src/locales/zh_Hant.json | 3 +- .../tabs/ImportTransactionCheckDataTab.vue | 129 +++++++++++++++++- 20 files changed, 163 insertions(+), 23 deletions(-) diff --git a/src/locales/de.json b/src/locales/de.json index b42b0864..1f6a6ce3 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/en.json b/src/locales/en.json index 91862c2a..0c424986 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/es.json b/src/locales/es.json index 7671780c..78284965 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregoriano", diff --git a/src/locales/fr.json b/src/locales/fr.json index bbfcb18b..7f680916 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Grégorien", diff --git a/src/locales/it.json b/src/locales/it.json index e4221a9b..9f28ed78 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/ja.json b/src/locales/ja.json index c6a4be26..a63b23ff 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/kn.json b/src/locales/kn.json index 62f2d3eb..4ec4ae70 100644 --- a/src/locales/kn.json +++ b/src/locales/kn.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "ಗ್ರೆಗೋರಿಯನ್", diff --git a/src/locales/ko.json b/src/locales/ko.json index 80ac30c5..c38df914 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/nl.json b/src/locales/nl.json index 9e2bf633..08cf76a1 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 20f95185..86e54de5 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/ru.json b/src/locales/ru.json index 0b59c8c6..fd95adff 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/sl.json b/src/locales/sl.json index b9ff3b04..9bd9ade5 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorijanski", diff --git a/src/locales/ta.json b/src/locales/ta.json index a27be5b6..062cc125 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "கிரிகோரியன்", diff --git a/src/locales/th.json b/src/locales/th.json index d622d8cb..493d2be7 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "เกรกอเรียน", diff --git a/src/locales/tr.json b/src/locales/tr.json index 4974e02d..86a775e9 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_mutabakat_ekstreleri", "defaultImportDataMappingFileName": "ezBookkeeping_ice_aktarim_eslemesi", "defaultImportHandlingScript": "ezBookkeeping_isleme_betigi", - "defaultImportReplaceRuleFileName": "ezBookkeeping_ice_aktarim_degistirme_kurali" + "defaultImportReplaceRuleFileName": "ezBookkeeping_ice_aktarim_degistirme_kurali", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Miladi", diff --git a/src/locales/uk.json b/src/locales/uk.json index 0979f234..020cc27e 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/vi.json b/src/locales/vi.json index 921f7c58..6ae408fd 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements", "defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping", "defaultImportHandlingScript": "ezBookkeeping_handling_script", - "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule" + "defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule", + "defaultImportCheckResultFileName": "ezBookkeeping_import_check_result" }, "calendar": { "Gregorian": "Gregorian", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 2cec4310..8458ac9e 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_对账单", "defaultImportDataMappingFileName": "ezBookkeeping_导入数据映射文件", "defaultImportHandlingScript": "ezBookkeeping_导入处理脚本", - "defaultImportReplaceRuleFileName": "ezBookkeeping_导入替换规则文件" + "defaultImportReplaceRuleFileName": "ezBookkeeping_导入替换规则文件", + "defaultImportCheckResultFileName": "ezBookkeeping_导入检查结果" }, "calendar": { "Gregorian": "公历", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index 49a1844e..a9d77de4 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -149,7 +149,8 @@ "exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_對帳單", "defaultImportDataMappingFileName": "ezBookkeeping_匯入資料對應檔案", "defaultImportHandlingScript": "ezBookkeeping_匯入處理腳本", - "defaultImportReplaceRuleFileName": "ezBookkeeping_匯入替換規則檔案" + "defaultImportReplaceRuleFileName": "ezBookkeeping_匯入替換規則檔案", + "defaultImportCheckResultFileName": "ezBookkeeping_匯入檢查結果" }, "calendar": { "Gregorian": "公曆", diff --git a/src/views/desktop/transactions/import/tabs/ImportTransactionCheckDataTab.vue b/src/views/desktop/transactions/import/tabs/ImportTransactionCheckDataTab.vue index 9a821e36..d93c807d 100644 --- a/src/views/desktop/transactions/import/tabs/ImportTransactionCheckDataTab.vue +++ b/src/views/desktop/transactions/import/tabs/ImportTransactionCheckDataTab.vue @@ -419,6 +419,8 @@ import { type NameValue, type NameNumeralValue, itemAndIndex, reversed, keys } f import { type NumeralSystem, AmountFilterType } from '@/core/numeral.ts'; import { CategoryType } from '@/core/category.ts'; import { TransactionType } from '@/core/transaction.ts'; +import { KnownFileType } from '@/core/file.ts'; +import { ImportTransactionColumnType } from '@/core/import_transaction.ts'; import { Account, type CategorizedAccountWithDisplayBalance } from '@/models/account.ts'; import type { TransactionCategory } from '@/models/transaction_category.ts'; @@ -428,6 +430,7 @@ import { ImportTransaction } from '@/models/imported_transaction.ts'; import { isString, isNumber, + replaceAll, objectFieldToArrayItem } from '@/lib/common.ts'; import { @@ -437,15 +440,14 @@ import { parseDateTimeFromUnixTimeWithTimezoneOffset } from '@/lib/datetime.ts'; import { formatCoordinate } from '@/lib/coordinate.ts'; -import { - getAccountMapByName -} from '@/lib/account.ts'; +import { getAccountMapByName } from '@/lib/account.ts'; import { transactionTypeToCategoryType, getSecondaryTransactionMapByName, getTransactionPrimaryCategoryName, getTransactionSecondaryCategoryName } from '@/lib/category.ts'; +import { startDownloadFile } from '@/lib/ui/common.ts'; import { mdiCheck, @@ -461,7 +463,9 @@ import { mdiShapePlusOutline, mdiPencilBoxMultipleOutline, mdiNumericPositive1, - mdiNumericNegative1 + mdiNumericNegative1, + mdiComma, + mdiKeyboardTab } from '@mdi/js'; type SnackBarType = InstanceType; @@ -504,6 +508,8 @@ const { tt, getCurrentNumeralSystemType, formatDateTimeToLongDateTime, + formatDateTimeToGregorianDefaultDateTime, + formatAmountToWesternArabicNumeralsWithoutDigitGrouping, formatAmountToLocalizedNumeralsWithCurrency, getCategorizedAccountsWithDisplayBalance } = useI18n(); @@ -937,6 +943,19 @@ const toolMenus = computed(() => [ title: tt('Batch Convert Selected Amounts to Negative Values'), disabled: isEditing.value || selectedImportTransactionCount.value < 1, onClick: () => convertTransactionAmountSign(-1) + }, + { + prependIcon: mdiComma, + title: tt('Export to CSV (Comma-separated values) File'), + disabled: isEditing.value || selectedImportTransactionCount.value < 1, + divider: true, + onClick: () => exportData(KnownFileType.CSV) + }, + { + prependIcon: mdiKeyboardTab, + title: tt('Export to TSV (Tab-separated values) File'), + disabled: isEditing.value || selectedImportTransactionCount.value < 1, + onClick: () => exportData(KnownFileType.TSV) } ]); @@ -1320,6 +1339,20 @@ function getDisplayTimezone(transaction: ImportTransaction): string { return `UTC${getUtcOffsetByUtcOffsetMinutes(transaction.utcOffset)}`; } +function getDisplayTransactionType(transaction: ImportTransaction): string { + if (transaction.type === TransactionType.ModifyBalance) { + return tt('Modify Balance'); + } else if (transaction.type === TransactionType.Income) { + return tt('Income'); + } else if (transaction.type === TransactionType.Expense) { + return tt('Expense'); + } else if (transaction.type === TransactionType.Transfer) { + return tt('Transfer'); + } else { + return tt('Unknown'); + } +} + function getDisplayCurrency(value: number, currencyCode: string): string { return formatAmountToLocalizedNumeralsWithCurrency(value, currencyCode); } @@ -2079,6 +2112,94 @@ function changeCustomDateFilter(minTime: number, maxTime: number): void { showCustomDateRangeDialog.value = false; } +function exportData(fileType: KnownFileType): void { + if (!props.importTransactions || props.importTransactions.length < 1 || selectedImportTransactionCount.value < 1) { + return; + } + + let separator = ','; + + if (fileType === KnownFileType.TSV) { + separator = '\t'; + } + + const header = [ + tt(ImportTransactionColumnType.TransactionTime.name), + tt(ImportTransactionColumnType.TransactionTimezone.name), + tt(ImportTransactionColumnType.TransactionType.name), + tt(ImportTransactionColumnType.Category.name), + tt(ImportTransactionColumnType.AccountName.name), + tt(ImportTransactionColumnType.AccountCurrency.name), + tt(ImportTransactionColumnType.Amount.name), + tt(ImportTransactionColumnType.RelatedAccountName.name), + tt(ImportTransactionColumnType.RelatedAccountCurrency.name), + tt(ImportTransactionColumnType.RelatedAmount.name), + tt(ImportTransactionColumnType.GeographicLocation.name), + tt(ImportTransactionColumnType.Tags.name), + tt(ImportTransactionColumnType.Description.name) + ].join(separator) + '\n'; + + const transactions = props.importTransactions ?? []; + const rows = transactions.filter(transaction => transaction.selected).map(transaction => { + const transactionTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset); + const type = getDisplayTransactionType(transaction); + const accountName = transaction.sourceAccountId && transaction.sourceAccountId !== '0' && allAccountsMap.value[transaction.sourceAccountId] ? (allAccountsMap.value[transaction.sourceAccountId]?.name ?? transaction.originalSourceAccountName) : transaction.originalSourceAccountName; + const amountCurrency = transaction.sourceAccountId && transaction.sourceAccountId !== '0' && allAccountsMap.value[transaction.sourceAccountId] ? (allAccountsMap.value[transaction.sourceAccountId]?.currency ?? transaction.originalSourceAccountCurrency) : transaction.originalSourceAccountCurrency; + const amount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.sourceAmount); + const geographicLocation = transaction.geoLocation ? `${transaction.geoLocation.longitude} ${transaction.geoLocation.latitude}` : ''; + let categoryName = transaction.categoryId && transaction.categoryId !== '0' && allCategoriesMap.value[transaction.categoryId] ? (allCategoriesMap.value[transaction.categoryId]?.name ?? transaction.originalCategoryName) : transaction.originalCategoryName; + let relatedAccountName: string | undefined = undefined; + let relatedAccountCurrency: string | undefined = undefined; + let relatedAmount: string | undefined = undefined; + + if (transaction.type === TransactionType.ModifyBalance) { + categoryName = ''; + } else if (transaction.type === TransactionType.Transfer) { + relatedAccountName = transaction.destinationAccountId && transaction.destinationAccountId !== '0' && allAccountsMap.value[transaction.destinationAccountId] ? (allAccountsMap.value[transaction.destinationAccountId]?.name ?? transaction.originalDestinationAccountName) : transaction.originalDestinationAccountName; + relatedAccountCurrency = transaction.destinationAccountId && transaction.destinationAccountId !== '0' && allAccountsMap.value[transaction.destinationAccountId] ? (allAccountsMap.value[transaction.destinationAccountId]?.currency ?? transaction.originalDestinationAccountCurrency) : transaction.originalDestinationAccountCurrency; + relatedAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.destinationAmount); + } + + const tagNames: string[] = []; + + if (transaction.tagIds && transaction.tagIds.length > 0) { + for (const [tagId, index] of itemAndIndex(transaction.tagIds)) { + let tagName = ''; + + if (tagId && tagId !== '0' && allTagsMap.value[tagId]) { + tagName = allTagsMap.value[tagId]!.name; + } else if (transaction.originalTagNames && transaction.originalTagNames[index]) { + tagName = transaction.originalTagNames[index] as string; + } + + if (tagName) { + tagName = replaceAll(tagName, separator, ' '); + tagName = replaceAll(tagName, ';', ' '); + tagNames.push(tagName); + } + } + } + + return [ + formatDateTimeToGregorianDefaultDateTime(transactionTime), + getUtcOffsetByUtcOffsetMinutes(transaction.utcOffset), + type, + replaceAll(categoryName, separator, ' '), + replaceAll(accountName, separator, ' '), + amountCurrency, + amount, + replaceAll(relatedAccountName ?? '', separator, ' '), + relatedAccountCurrency ?? '', + relatedAmount ?? '', + geographicLocation, + tagNames.join(';'), + replaceAll(transaction.comment || '', separator, ' ') + ].join(separator); + }); + + startDownloadFile(fileType.formatFileName(tt('dataExport.defaultImportCheckResultFileName')), fileType.createBlob(header + rows.join('\n'))); +} + function onShowDateRangeError(message: string): void { snackbar.value?.showError(message); }