diff --git a/src/consts/category.ts b/src/consts/category.ts index d9a3f3db..85109ab3 100644 --- a/src/consts/category.ts +++ b/src/consts/category.ts @@ -1,17 +1,4 @@ -import type { ColorValue } from '@/core/color.ts'; - -export interface PresetCategory { - readonly name: string; - readonly categoryIconId: string; - readonly color: ColorValue; - readonly subCategories: PresetSubCategory[]; -} - -export interface PresetSubCategory { - readonly name: string; - readonly categoryIconId: string; - readonly color: ColorValue; -} +import type { PresetCategory } from '@/core/category.ts'; export const DEFAULT_EXPENSE_CATEGORIES: PresetCategory[] = [ { diff --git a/src/core/category.ts b/src/core/category.ts index d73df798..33c6f419 100644 --- a/src/core/category.ts +++ b/src/core/category.ts @@ -1,5 +1,41 @@ +import type { ColorValue } from '@/core/color.ts'; + export enum CategoryType { Income = 1, Expense = 2, Transfer = 3 } + +export const ALL_CATEGORY_TYPES: CategoryType[] = [ + CategoryType.Income, + CategoryType.Expense, + CategoryType.Transfer +]; + +export interface PresetCategory { + readonly name: string; + readonly categoryIconId: string; + readonly color: ColorValue; + readonly subCategories: PresetSubCategory[]; +} + +export interface PresetSubCategory { + readonly name: string; + readonly categoryIconId: string; + readonly color: ColorValue; +} + +export interface LocalizedPresetCategory { + readonly name: string; + readonly type: CategoryType; + readonly icon: string; + readonly color: ColorValue; + readonly subCategories: LocalizedPresetSubCategory[]; +} + +export interface LocalizedPresetSubCategory { + readonly name: string; + readonly type: CategoryType; + readonly icon: string; + readonly color: ColorValue; +} diff --git a/src/locales/helpers.ts b/src/locales/helpers.ts index e8596d44..35621af4 100644 --- a/src/locales/helpers.ts +++ b/src/locales/helpers.ts @@ -1,7 +1,7 @@ import { useI18n as useVueI18n } from 'vue-i18n'; import moment from 'moment-timezone'; -import type { TypeAndName, TypeAndDisplayName, LocalizedSwitchOption } from '@/core/base.ts'; +import type { PartialRecord, TypeAndName, TypeAndDisplayName, LocalizedSwitchOption } from '@/core/base.ts'; import { type LanguageInfo, type LanguageOption, ALL_LANGUAGES, DEFAULT_LANGUAGE } from '@/locales/index.ts'; @@ -49,6 +49,14 @@ import { AccountCategory } from '@/core/account.ts'; +import { + type PresetCategory, + type LocalizedPresetCategory, + type LocalizedPresetSubCategory, + CategoryType, + ALL_CATEGORY_TYPES +} from '@/core/category.ts'; + import { TransactionEditScopeType, TransactionTagFilterType @@ -72,6 +80,7 @@ import type { ErrorResponse } from '@/core/api.ts'; import { UTC_TIMEZONE, ALL_TIMEZONES } from '@/consts/timezone.ts'; import { ALL_CURRENCIES } from '@/consts/currency.ts'; +import { DEFAULT_EXPENSE_CATEGORIES, DEFAULT_INCOME_CATEGORIES, DEFAULT_TRANSFER_CATEGORIES } from '@/consts/category.ts'; import { KnownErrorCode, SPECIFIED_API_NOT_FOUND_ERRORS, PARAMETERIZED_ERRORS } from '@/consts/api.ts'; import type { LatestExchangeRateResponse, LocalizedLatestExchangeRate } from '@/models/exchange_rate.ts'; @@ -81,7 +90,8 @@ import { isObject, isString, isNumber, - isBoolean + isBoolean, + copyArrayTo } from '@/lib/common.ts'; import { @@ -842,6 +852,61 @@ export function useI18n() { return ret; } + function getAllTransactionDefaultCategories(categoryType: 0 | CategoryType, locale: string): PartialRecord { + const allCategories: PartialRecord = {}; + const categoryTypes: CategoryType[] = []; + + if (categoryType === 0) { + categoryTypes.push(...ALL_CATEGORY_TYPES); + } else { + categoryTypes.push(categoryType); + } + + for (let i = 0; i < categoryTypes.length; i++) { + const categories: LocalizedPresetCategory[] = []; + const categoryType = categoryTypes[i]; + let defaultCategories: PresetCategory[] = []; + + if (categoryType === CategoryType.Income) { + defaultCategories = copyArrayTo(DEFAULT_INCOME_CATEGORIES, []); + } else if (categoryType === CategoryType.Expense) { + defaultCategories = copyArrayTo(DEFAULT_EXPENSE_CATEGORIES, []); + } else if (categoryType === CategoryType.Transfer) { + defaultCategories = copyArrayTo(DEFAULT_TRANSFER_CATEGORIES, []); + } + + for (let j = 0; j < defaultCategories.length; j++) { + const category = defaultCategories[j]; + + const submitCategory: LocalizedPresetCategory = { + name: t('category.' + category.name, {}, { locale: locale }), + type: categoryType, + icon: category.categoryIconId, + color: category.color, + subCategories: [] + }; + + for (let k = 0; k < category.subCategories.length; k++) { + const subCategory = category.subCategories[k]; + const submitSubCategory: LocalizedPresetSubCategory = { + name: t('category.' + subCategory.name, {}, { locale: locale }), + type: categoryType, + icon: subCategory.categoryIconId, + color: subCategory.color + }; + + submitCategory.subCategories.push(submitSubCategory); + } + + categories.push(submitCategory); + } + + allCategories[categoryType] = categories; + } + + return allCategories; + } + function getAllDisplayExchangeRates(exchangeRatesData?: LatestExchangeRateResponse): LocalizedLatestExchangeRate[] { const availableExchangeRates: LocalizedLatestExchangeRate[] = []; @@ -1269,6 +1334,7 @@ export function useI18n() { getAllTransactionEditScopeTypes: () => getLocalizedDisplayNameAndType(TransactionEditScopeType.values()), getAllTransactionTagFilterTypes: () => getLocalizedDisplayNameAndType(TransactionTagFilterType.values()), getAllTransactionScheduledFrequencyTypes: () => getLocalizedDisplayNameAndType(ScheduledTemplateFrequencyType.values()), + getAllTransactionDefaultCategories, getAllDisplayExchangeRates, // get localized info getMonthShortName, diff --git a/src/models/transaction_category.ts b/src/models/transaction_category.ts index f12c33ad..f6fbb325 100644 --- a/src/models/transaction_category.ts +++ b/src/models/transaction_category.ts @@ -1,4 +1,4 @@ -import { CategoryType } from '@/core/category.ts'; +import { type LocalizedPresetCategory, CategoryType } from '@/core/category.ts'; import { DEFAULT_CATEGORY_ICON_ID } from '@/consts/icon.ts'; import { DEFAULT_CATEGORY_COLOR } from '@/consts/color.ts'; @@ -131,16 +131,7 @@ export interface TransactionCategoryCreateRequest { } export interface TransactionCategoryCreateBatchRequest { - readonly categories: TransactionCategoryCreateWithSubCategories[]; -} - -export interface TransactionCategoryCreateWithSubCategories { - readonly name: string; - readonly type: number; - readonly icon: string; - readonly color: string; - readonly comment: string; - readonly subCategories: TransactionCategoryCreateRequest[]; + readonly categories: LocalizedPresetCategory[]; } export interface TransactionCategoryModifyRequest { diff --git a/src/views/mobile/categories/PresetPage.vue b/src/views/mobile/categories/PresetPage.vue index a8686840..2a96e8dd 100644 --- a/src/views/mobile/categories/PresetPage.vue +++ b/src/views/mobile/categories/PresetPage.vue @@ -1,11 +1,11 @@ -