migrate transaction category store to composition API and typescript
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import { TransactionType } from '@/core/transaction.ts';
|
import { TransactionType } from '@/core/transaction.ts';
|
||||||
|
import { type TransactionCategoriesWithVisibleCount, TransactionCategory } from '@/models/transaction_category.ts';
|
||||||
|
|
||||||
export function setCategoryModelByAnotherCategory(category, category2) {
|
export function setCategoryModelByAnotherCategory(category: TransactionCategory, category2: TransactionCategory): void {
|
||||||
category.id = category2.id;
|
category.id = category2.id;
|
||||||
category.type = category2.type;
|
category.type = category2.type;
|
||||||
category.parentId = category2.parentId;
|
category.parentId = category2.parentId;
|
||||||
@@ -12,7 +13,7 @@ export function setCategoryModelByAnotherCategory(category, category2) {
|
|||||||
category.visible = !category2.hidden;
|
category.visible = !category2.hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transactionTypeToCategoryType(transactionType) {
|
export function transactionTypeToCategoryType(transactionType: TransactionType): CategoryType | null {
|
||||||
if (transactionType === TransactionType.Income) {
|
if (transactionType === TransactionType.Income) {
|
||||||
return CategoryType.Income;
|
return CategoryType.Income;
|
||||||
} else if (transactionType === TransactionType.Expense) {
|
} else if (transactionType === TransactionType.Expense) {
|
||||||
@@ -24,7 +25,7 @@ export function transactionTypeToCategoryType(transactionType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function categoryTypeToTransactionType(categoryType) {
|
export function categoryTypeToTransactionType(categoryType: CategoryType): TransactionType | null {
|
||||||
if (categoryType === CategoryType.Income) {
|
if (categoryType === CategoryType.Income) {
|
||||||
return TransactionType.Income;
|
return TransactionType.Income;
|
||||||
} else if (categoryType === CategoryType.Expense) {
|
} else if (categoryType === CategoryType.Expense) {
|
||||||
@@ -36,14 +37,20 @@ export function categoryTypeToTransactionType(categoryType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTransactionPrimaryCategoryName(categoryId, allCategories) {
|
export function getTransactionPrimaryCategoryName(categoryId: string, allCategories: TransactionCategory[]): string {
|
||||||
if (!allCategories) {
|
if (!allCategories) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < allCategories.length; i++) {
|
for (let i = 0; i < allCategories.length; i++) {
|
||||||
for (let j = 0; j < allCategories[i].subCategories.length; j++) {
|
const subCategoryList = allCategories[i].secondaryCategories;
|
||||||
const subCategory = allCategories[i].subCategories[j];
|
|
||||||
|
if (!subCategoryList) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < subCategoryList.length; j++) {
|
||||||
|
const subCategory = subCategoryList[j];
|
||||||
if (subCategory.id === categoryId) {
|
if (subCategory.id === categoryId) {
|
||||||
return allCategories[i].name;
|
return allCategories[i].name;
|
||||||
}
|
}
|
||||||
@@ -53,14 +60,20 @@ export function getTransactionPrimaryCategoryName(categoryId, allCategories) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTransactionSecondaryCategoryName(categoryId, allCategories) {
|
export function getTransactionSecondaryCategoryName(categoryId: string, allCategories: TransactionCategory[]): string {
|
||||||
if (!allCategories) {
|
if (!allCategories) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < allCategories.length; i++) {
|
for (let i = 0; i < allCategories.length; i++) {
|
||||||
for (let j = 0; j < allCategories[i].subCategories.length; j++) {
|
const subCategoryList = allCategories[i].secondaryCategories;
|
||||||
const subCategory = allCategories[i].subCategories[j];
|
|
||||||
|
if (!subCategoryList) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < subCategoryList.length; j++) {
|
||||||
|
const subCategory = subCategoryList[j];
|
||||||
if (subCategory.id === categoryId) {
|
if (subCategory.id === categoryId) {
|
||||||
return subCategory.name;
|
return subCategory.name;
|
||||||
}
|
}
|
||||||
@@ -70,12 +83,12 @@ export function getTransactionSecondaryCategoryName(categoryId, allCategories) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function allTransactionCategoriesWithVisibleCount(allTransactionCategories, allowCategoryTypes) {
|
export function allTransactionCategoriesWithVisibleCount(allTransactionCategories: Record<number, TransactionCategory[]>, allowCategoryTypes: Record<number, boolean>): Record<number, TransactionCategoriesWithVisibleCount> {
|
||||||
const ret = {};
|
const ret: Record<string, TransactionCategoriesWithVisibleCount> = {};
|
||||||
const hasAllowCategoryTypes = allowCategoryTypes
|
const hasAllowCategoryTypes = allowCategoryTypes
|
||||||
&& (allowCategoryTypes[CategoryType.Income.toString()]
|
&& (allowCategoryTypes[CategoryType.Income]
|
||||||
|| allowCategoryTypes[CategoryType.Expense.toString()]
|
|| allowCategoryTypes[CategoryType.Expense]
|
||||||
|| allowCategoryTypes[CategoryType.Transfer.toString()]);
|
|| allowCategoryTypes[CategoryType.Transfer]);
|
||||||
|
|
||||||
const allCategoryTypes = [ CategoryType.Income, CategoryType.Expense, CategoryType.Transfer ];
|
const allCategoryTypes = [ CategoryType.Income, CategoryType.Expense, CategoryType.Transfer ];
|
||||||
|
|
||||||
@@ -90,10 +103,10 @@ export function allTransactionCategoriesWithVisibleCount(allTransactionCategorie
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const allCategories = allTransactionCategories[categoryType];
|
const allCategories: TransactionCategory[] = allTransactionCategories[categoryType];
|
||||||
const allSubCategories = {};
|
const allSubCategories: Record<string, TransactionCategory[]> = {};
|
||||||
const allVisibleSubCategoryCounts = {};
|
const allVisibleSubCategoryCounts: Record<string, number> = {};
|
||||||
const allFirstVisibleSubCategoryIndexes = {};
|
const allFirstVisibleSubCategoryIndexes: Record<string, number> = {};
|
||||||
let allVisibleCategoryCount = 0;
|
let allVisibleCategoryCount = 0;
|
||||||
let firstVisibleCategoryIndex = -1;
|
let firstVisibleCategoryIndex = -1;
|
||||||
|
|
||||||
@@ -108,12 +121,12 @@ export function allTransactionCategoriesWithVisibleCount(allTransactionCategorie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category.subCategories) {
|
if (category.secondaryCategories) {
|
||||||
let visibleSubCategoryCount = 0;
|
let visibleSubCategoryCount = 0;
|
||||||
let firstVisibleSubCategoryIndex = -1;
|
let firstVisibleSubCategoryIndex = -1;
|
||||||
|
|
||||||
for (let k = 0; k < category.subCategories.length; k++) {
|
for (let k = 0; k < category.secondaryCategories.length; k++) {
|
||||||
const subCategory = category.subCategories[k];
|
const subCategory = category.secondaryCategories[k];
|
||||||
|
|
||||||
if (!subCategory.hidden) {
|
if (!subCategory.hidden) {
|
||||||
visibleSubCategoryCount++;
|
visibleSubCategoryCount++;
|
||||||
@@ -124,16 +137,16 @@ export function allTransactionCategoriesWithVisibleCount(allTransactionCategorie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category.subCategories.length > 0) {
|
if (category.secondaryCategories.length > 0) {
|
||||||
allSubCategories[category.id] = category.subCategories;
|
allSubCategories[category.id] = category.secondaryCategories;
|
||||||
allVisibleSubCategoryCounts[category.id] = visibleSubCategoryCount;
|
allVisibleSubCategoryCounts[category.id] = visibleSubCategoryCount;
|
||||||
allFirstVisibleSubCategoryIndexes[category.id] = firstVisibleSubCategoryIndex;
|
allFirstVisibleSubCategoryIndexes[category.id] = firstVisibleSubCategoryIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret[categoryType.toString()] = {
|
ret[categoryType] = {
|
||||||
type: categoryType.toString(),
|
type: categoryType,
|
||||||
allCategories: allCategories,
|
allCategories: allCategories,
|
||||||
allVisibleCategoryCount: allVisibleCategoryCount,
|
allVisibleCategoryCount: allVisibleCategoryCount,
|
||||||
firstVisibleCategoryIndex: firstVisibleCategoryIndex,
|
firstVisibleCategoryIndex: firstVisibleCategoryIndex,
|
||||||
@@ -146,9 +159,9 @@ export function allTransactionCategoriesWithVisibleCount(allTransactionCategorie
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function allVisiblePrimaryTransactionCategoriesByType(allTransactionCategories, categoryType) {
|
export function allVisiblePrimaryTransactionCategoriesByType(allTransactionCategories: Record<number, TransactionCategory[]>, categoryType: number): TransactionCategory[] {
|
||||||
const allCategories = allTransactionCategories[categoryType];
|
const allCategories = allTransactionCategories[categoryType];
|
||||||
const visibleCategories = [];
|
const visibleCategories: TransactionCategory[] = [];
|
||||||
|
|
||||||
if (!allCategories) {
|
if (!allCategories) {
|
||||||
return visibleCategories;
|
return visibleCategories;
|
||||||
@@ -167,14 +180,14 @@ export function allVisiblePrimaryTransactionCategoriesByType(allTransactionCateg
|
|||||||
return visibleCategories;
|
return visibleCategories;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFinalCategoryIdsByFilteredCategoryIds(allTransactionCategoriesMap, filteredCategoryIds) {
|
export function getFinalCategoryIdsByFilteredCategoryIds(allTransactionCategoriesMap: Record<number, TransactionCategory>, filteredCategoryIds: Record<string, boolean>): string {
|
||||||
let finalCategoryIds = '';
|
let finalCategoryIds = '';
|
||||||
|
|
||||||
if (!allTransactionCategoriesMap) {
|
if (!allTransactionCategoriesMap) {
|
||||||
return finalCategoryIds;
|
return finalCategoryIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let categoryId in allTransactionCategoriesMap) {
|
for (const categoryId in allTransactionCategoriesMap) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(allTransactionCategoriesMap, categoryId)) {
|
if (!Object.prototype.hasOwnProperty.call(allTransactionCategoriesMap, categoryId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -195,7 +208,7 @@ export function getFinalCategoryIdsByFilteredCategoryIds(allTransactionCategorie
|
|||||||
return finalCategoryIds;
|
return finalCategoryIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSubCategoryIdAvailable(categories, categoryId) {
|
export function isSubCategoryIdAvailable(categories: TransactionCategory[], categoryId: string): boolean {
|
||||||
if (!categories || !categories.length) {
|
if (!categories || !categories.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -207,8 +220,14 @@ export function isSubCategoryIdAvailable(categories, categoryId) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = 0; j < primaryCategory.subCategories.length; j++) {
|
const subCategoryList = primaryCategory.secondaryCategories;
|
||||||
const secondaryCategory = primaryCategory.subCategories[j];
|
|
||||||
|
if (!subCategoryList) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < subCategoryList.length; j++) {
|
||||||
|
const secondaryCategory = subCategoryList[j];
|
||||||
|
|
||||||
if (secondaryCategory.hidden) {
|
if (secondaryCategory.hidden) {
|
||||||
continue;
|
continue;
|
||||||
@@ -223,7 +242,7 @@ export function isSubCategoryIdAvailable(categories, categoryId) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFirstAvailableCategoryId(categories) {
|
export function getFirstAvailableCategoryId(categories: TransactionCategory[]): string {
|
||||||
if (!categories || !categories.length) {
|
if (!categories || !categories.length) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -235,8 +254,14 @@ export function getFirstAvailableCategoryId(categories) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = 0; j < primaryCategory.subCategories.length; j++) {
|
const subCategoryList = primaryCategory.secondaryCategories;
|
||||||
const secondaryCategory = primaryCategory.subCategories[j];
|
|
||||||
|
if (!subCategoryList) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < subCategoryList.length; j++) {
|
||||||
|
const secondaryCategory = subCategoryList[j];
|
||||||
|
|
||||||
if (secondaryCategory.hidden) {
|
if (secondaryCategory.hidden) {
|
||||||
continue;
|
continue;
|
||||||
@@ -249,7 +274,7 @@ export function getFirstAvailableCategoryId(categories) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFirstAvailableSubCategoryId(categories, categoryId) {
|
export function getFirstAvailableSubCategoryId(categories: TransactionCategory[], categoryId: string): string {
|
||||||
if (!categories || !categories.length) {
|
if (!categories || !categories.length) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -261,8 +286,14 @@ export function getFirstAvailableSubCategoryId(categories, categoryId) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = 0; j < primaryCategory.subCategories.length; j++) {
|
const subCategoryList = primaryCategory.secondaryCategories;
|
||||||
const secondaryCategory = primaryCategory.subCategories[j];
|
|
||||||
|
if (!subCategoryList) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < subCategoryList.length; j++) {
|
||||||
|
const secondaryCategory = subCategoryList[j];
|
||||||
|
|
||||||
if (secondaryCategory.hidden) {
|
if (secondaryCategory.hidden) {
|
||||||
continue;
|
continue;
|
||||||
@@ -277,7 +308,7 @@ export function getFirstAvailableSubCategoryId(categories, categoryId) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNoAvailableCategory(categories, showHidden) {
|
export function isNoAvailableCategory(categories: TransactionCategory[], showHidden: boolean): boolean {
|
||||||
for (let i = 0; i < categories.length; i++) {
|
for (let i = 0; i < categories.length; i++) {
|
||||||
if (showHidden || !categories[i].hidden) {
|
if (showHidden || !categories[i].hidden) {
|
||||||
return false;
|
return false;
|
||||||
@@ -287,7 +318,7 @@ export function isNoAvailableCategory(categories, showHidden) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAvailableCategoryCount(categories, showHidden) {
|
export function getAvailableCategoryCount(categories: TransactionCategory[], showHidden: boolean): number {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
for (let i = 0; i < categories.length; i++) {
|
for (let i = 0; i < categories.length; i++) {
|
||||||
@@ -299,7 +330,7 @@ export function getAvailableCategoryCount(categories, showHidden) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFirstShowingId(categories, showHidden) {
|
export function getFirstShowingId(categories: TransactionCategory[], showHidden: boolean): string | null {
|
||||||
for (let i = 0; i < categories.length; i++) {
|
for (let i = 0; i < categories.length; i++) {
|
||||||
if (showHidden || !categories[i].hidden) {
|
if (showHidden || !categories[i].hidden) {
|
||||||
return categories[i].id;
|
return categories[i].id;
|
||||||
@@ -309,7 +340,7 @@ export function getFirstShowingId(categories, showHidden) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLastShowingId(categories, showHidden) {
|
export function getLastShowingId(categories: TransactionCategory[], showHidden: boolean): string | null {
|
||||||
for (let i = categories.length - 1; i >= 0; i--) {
|
for (let i = categories.length - 1; i >= 0; i--) {
|
||||||
if (showHidden || !categories[i].hidden) {
|
if (showHidden || !categories[i].hidden) {
|
||||||
return categories[i].id;
|
return categories[i].id;
|
||||||
@@ -319,8 +350,8 @@ export function getLastShowingId(categories, showHidden) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasAnyAvailableCategory(allTransactionCategories, showHidden) {
|
export function hasAnyAvailableCategory(allTransactionCategories: Record<number, TransactionCategoriesWithVisibleCount>, showHidden: boolean): boolean {
|
||||||
for (let type in allTransactionCategories) {
|
for (const type in allTransactionCategories) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(allTransactionCategories, type)) {
|
if (!Object.prototype.hasOwnProperty.call(allTransactionCategories, type)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -341,10 +372,10 @@ export function hasAnyAvailableCategory(allTransactionCategories, showHidden) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasAvailableCategory(allTransactionCategories, showHidden) {
|
export function hasAvailableCategory(allTransactionCategories: Record<number, TransactionCategoriesWithVisibleCount>, showHidden: boolean): Record<number, boolean> {
|
||||||
const result = {};
|
const result: Record<number, boolean> = {};
|
||||||
|
|
||||||
for (let type in allTransactionCategories) {
|
for (const type in allTransactionCategories) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(allTransactionCategories, type)) {
|
if (!Object.prototype.hasOwnProperty.call(allTransactionCategories, type)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -361,19 +392,19 @@ export function hasAvailableCategory(allTransactionCategories, showHidden) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectSubCategories(filterCategoryIds, category, value) {
|
export function selectSubCategories(filterCategoryIds: Record<string, boolean>, category: TransactionCategory, value: boolean): void {
|
||||||
if (!category || !category.subCategories || !category.subCategories.length) {
|
if (!category || !category.secondaryCategories || !category.secondaryCategories.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < category.subCategories.length; i++) {
|
for (let i = 0; i < category.secondaryCategories.length; i++) {
|
||||||
const subCategory = category.subCategories[i];
|
const subCategory = category.secondaryCategories[i];
|
||||||
filterCategoryIds[subCategory.id] = value;
|
filterCategoryIds[subCategory.id] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectAll(filterCategoryIds, allTransactionCategoriesMap) {
|
export function selectAll(filterCategoryIds: Record<string, boolean>, allTransactionCategoriesMap: Record<string, TransactionCategory>): void {
|
||||||
for (let categoryId in filterCategoryIds) {
|
for (const categoryId in filterCategoryIds) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(filterCategoryIds, categoryId)) {
|
if (!Object.prototype.hasOwnProperty.call(filterCategoryIds, categoryId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -386,8 +417,8 @@ export function selectAll(filterCategoryIds, allTransactionCategoriesMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectNone(filterCategoryIds, allTransactionCategoriesMap) {
|
export function selectNone(filterCategoryIds: Record<string, boolean>, allTransactionCategoriesMap: Record<string, TransactionCategory>): void {
|
||||||
for (let categoryId in filterCategoryIds) {
|
for (const categoryId in filterCategoryIds) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(filterCategoryIds, categoryId)) {
|
if (!Object.prototype.hasOwnProperty.call(filterCategoryIds, categoryId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -400,8 +431,8 @@ export function selectNone(filterCategoryIds, allTransactionCategoriesMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectInvert(filterCategoryIds, allTransactionCategoriesMap) {
|
export function selectInvert(filterCategoryIds: Record<string, boolean>, allTransactionCategoriesMap: Record<string, TransactionCategory>): void {
|
||||||
for (let categoryId in filterCategoryIds) {
|
for (const categoryId in filterCategoryIds) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(filterCategoryIds, categoryId)) {
|
if (!Object.prototype.hasOwnProperty.call(filterCategoryIds, categoryId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -414,13 +445,13 @@ export function selectInvert(filterCategoryIds, allTransactionCategoriesMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCategoryOrSubCategoriesAllChecked(category, filterCategoryIds) {
|
export function isCategoryOrSubCategoriesAllChecked(category: TransactionCategory, filterCategoryIds: Record<string, boolean>): boolean {
|
||||||
if (!category.subCategories) {
|
if (!category.secondaryCategories || category.secondaryCategories.length < 1) {
|
||||||
return !filterCategoryIds[category.id];
|
return !filterCategoryIds[category.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < category.subCategories.length; i++) {
|
for (let i = 0; i < category.secondaryCategories.length; i++) {
|
||||||
const subCategory = category.subCategories[i];
|
const subCategory = category.secondaryCategories[i];
|
||||||
if (filterCategoryIds[subCategory.id]) {
|
if (filterCategoryIds[subCategory.id]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -429,9 +460,13 @@ export function isCategoryOrSubCategoriesAllChecked(category, filterCategoryIds)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSubCategoriesAllChecked(category, filterCategoryIds) {
|
export function isSubCategoriesAllChecked(category: TransactionCategory, filterCategoryIds: Record<string, boolean>): boolean {
|
||||||
for (let i = 0; i < category.subCategories.length; i++) {
|
if (!category.secondaryCategories || category.secondaryCategories.length < 1) {
|
||||||
const subCategory = category.subCategories[i];
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < category.secondaryCategories.length; i++) {
|
||||||
|
const subCategory = category.secondaryCategories[i];
|
||||||
if (filterCategoryIds[subCategory.id]) {
|
if (filterCategoryIds[subCategory.id]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -440,15 +475,19 @@ export function isSubCategoriesAllChecked(category, filterCategoryIds) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSubCategoriesHasButNotAllChecked(category, filterCategoryIds) {
|
export function isSubCategoriesHasButNotAllChecked(category: TransactionCategory, filterCategoryIds: Record<string, boolean>): boolean {
|
||||||
let checkedCount = 0;
|
let checkedCount = 0;
|
||||||
|
|
||||||
for (let i = 0; i < category.subCategories.length; i++) {
|
if (!category.secondaryCategories || category.secondaryCategories.length < 1) {
|
||||||
const subCategory = category.subCategories[i];
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < category.secondaryCategories.length; i++) {
|
||||||
|
const subCategory = category.secondaryCategories[i];
|
||||||
if (!filterCategoryIds[subCategory.id]) {
|
if (!filterCategoryIds[subCategory.id]) {
|
||||||
checkedCount++;
|
checkedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkedCount > 0 && checkedCount < category.subCategories.length;
|
return checkedCount > 0 && checkedCount < category.secondaryCategories.length;
|
||||||
}
|
}
|
||||||
+2
-2
@@ -445,8 +445,8 @@ export default {
|
|||||||
removeUnusedTransactionPicture: (req: TransactionPictureUnusedDeleteRequest): ApiResponsePromise<boolean> => {
|
removeUnusedTransactionPicture: (req: TransactionPictureUnusedDeleteRequest): ApiResponsePromise<boolean> => {
|
||||||
return axios.post<ApiResponse<boolean>>('v1/transaction/pictures/remove_unused.json', req);
|
return axios.post<ApiResponse<boolean>>('v1/transaction/pictures/remove_unused.json', req);
|
||||||
},
|
},
|
||||||
getAllTransactionCategories: (): ApiResponsePromise<TransactionCategoryInfoResponse[]> => {
|
getAllTransactionCategories: (): ApiResponsePromise<Record<number, TransactionCategoryInfoResponse[]>> => {
|
||||||
return axios.get<ApiResponse<TransactionCategoryInfoResponse[]>>('v1/transaction/categories/list.json');
|
return axios.get<ApiResponse<Record<number, TransactionCategoryInfoResponse[]>>>('v1/transaction/categories/list.json');
|
||||||
},
|
},
|
||||||
getTransactionCategory: (req: { id: string }): ApiResponsePromise<TransactionCategoryInfoResponse> => {
|
getTransactionCategory: (req: { id: string }): ApiResponsePromise<TransactionCategoryInfoResponse> => {
|
||||||
return axios.get<ApiResponse<TransactionCategoryInfoResponse>>('v1/transaction/categories/get.json?id=' + req.id);
|
return axios.get<ApiResponse<TransactionCategoryInfoResponse>>('v1/transaction/categories/get.json?id=' + req.id);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
isSubCategoryIdAvailable,
|
isSubCategoryIdAvailable,
|
||||||
getFirstAvailableCategoryId,
|
getFirstAvailableCategoryId,
|
||||||
getFirstAvailableSubCategoryId
|
getFirstAvailableSubCategoryId
|
||||||
} from './category.js';
|
} from './category.ts';
|
||||||
|
|
||||||
function getDisplayAmount(amount, currency, hideAmount, formatAmountWithCurrencyFunc) {
|
function getDisplayAmount(amount, currency, hideAmount, formatAmountWithCurrencyFunc) {
|
||||||
if (hideAmount) {
|
if (hideAmount) {
|
||||||
|
|||||||
@@ -1,3 +1,125 @@
|
|||||||
|
import { CategoryType } from '@/core/category.ts';
|
||||||
|
import { DEFAULT_CATEGORY_ICON_ID } from '@/consts/icon.ts';
|
||||||
|
import { DEFAULT_CATEGORY_COLOR } from '@/consts/color.ts';
|
||||||
|
|
||||||
|
export class TransactionCategory implements TransactionCategoryInfoResponse {
|
||||||
|
public id: string;
|
||||||
|
public name: string;
|
||||||
|
public parentId: string;
|
||||||
|
public type: number;
|
||||||
|
public icon: string;
|
||||||
|
public color: string;
|
||||||
|
public comment: string;
|
||||||
|
public displayOrder: number;
|
||||||
|
public visible: boolean;
|
||||||
|
public secondaryCategories?: TransactionCategory[];
|
||||||
|
|
||||||
|
private constructor(id: string, name: string, parentId: string, type: number, icon: string, color: string, comment: string, displayOrder: number, visible: boolean, secondaryCategories?: TransactionCategory[]) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.parentId = parentId;
|
||||||
|
this.type = type;
|
||||||
|
this.icon = icon;
|
||||||
|
this.color = color;
|
||||||
|
this.comment = comment;
|
||||||
|
this.displayOrder = displayOrder;
|
||||||
|
this.visible = visible;
|
||||||
|
|
||||||
|
if (secondaryCategories) {
|
||||||
|
this.secondaryCategories = secondaryCategories;
|
||||||
|
} else if (!secondaryCategories && (!parentId || parentId === '0')) {
|
||||||
|
this.secondaryCategories = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get hidden(): boolean {
|
||||||
|
return !this.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
get subCategories(): TransactionCategoryInfoResponse[] | undefined {
|
||||||
|
if (typeof this.secondaryCategories === 'undefined') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ret: TransactionCategoryInfoResponse[] = [];
|
||||||
|
|
||||||
|
if (this.secondaryCategories) {
|
||||||
|
for (const subCategory of this.secondaryCategories) {
|
||||||
|
ret.push(subCategory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toCreateRequest(clientSessionId: string): TransactionCategoryCreateRequest {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
type: this.type,
|
||||||
|
parentId: this.parentId,
|
||||||
|
icon: this.icon,
|
||||||
|
color: this.color,
|
||||||
|
comment: this.comment,
|
||||||
|
clientSessionId: clientSessionId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public toModifyRequest(): TransactionCategoryModifyRequest {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
parentId: this.parentId,
|
||||||
|
icon: this.icon,
|
||||||
|
color: this.color,
|
||||||
|
comment: this.comment,
|
||||||
|
hidden: !this.visible
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static of(categoryResponse: TransactionCategoryInfoResponse): TransactionCategory {
|
||||||
|
return new TransactionCategory(
|
||||||
|
categoryResponse.id,
|
||||||
|
categoryResponse.name,
|
||||||
|
categoryResponse.parentId,
|
||||||
|
categoryResponse.type,
|
||||||
|
categoryResponse.icon,
|
||||||
|
categoryResponse.color,
|
||||||
|
categoryResponse.comment,
|
||||||
|
categoryResponse.displayOrder,
|
||||||
|
!categoryResponse.hidden,
|
||||||
|
categoryResponse.subCategories ? TransactionCategory.ofMany(categoryResponse.subCategories) : undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ofMany(categoryResponses: TransactionCategoryInfoResponse[]): TransactionCategory[] {
|
||||||
|
const tags: TransactionCategory[] = [];
|
||||||
|
|
||||||
|
for (const tagResponse of categoryResponses) {
|
||||||
|
tags.push(TransactionCategory.of(tagResponse));
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ofMap(categoriesByType: Record<number, TransactionCategoryInfoResponse[]>): Record<number, TransactionCategory[]> {
|
||||||
|
const ret: Record<number, TransactionCategory[]> = {};
|
||||||
|
|
||||||
|
for (const categoryType in categoriesByType) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(categoriesByType, categoryType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[categoryType] = TransactionCategory.ofMany(categoriesByType[categoryType]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static createNewCategory(type?: CategoryType, parentId?: string): TransactionCategory {
|
||||||
|
return new TransactionCategory('', '', parentId || '0', type || CategoryType.Income, DEFAULT_CATEGORY_ICON_ID, DEFAULT_CATEGORY_COLOR, '', 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface TransactionCategoryCreateRequest {
|
export interface TransactionCategoryCreateRequest {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly type: number;
|
readonly type: number;
|
||||||
@@ -61,3 +183,13 @@ export interface TransactionCategoryInfoResponse {
|
|||||||
readonly hidden: boolean;
|
readonly hidden: boolean;
|
||||||
readonly subCategories?: TransactionCategoryInfoResponse[];
|
readonly subCategories?: TransactionCategoryInfoResponse[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TransactionCategoriesWithVisibleCount {
|
||||||
|
readonly type: number;
|
||||||
|
readonly allCategories: TransactionCategory[];
|
||||||
|
readonly allVisibleCategoryCount: number;
|
||||||
|
readonly firstVisibleCategoryIndex: number;
|
||||||
|
readonly allSubCategories: Record<string, TransactionCategory[]>;
|
||||||
|
readonly allVisibleSubCategoryCounts: Record<string, number>;
|
||||||
|
readonly allFirstVisibleSubCategoryIndexes: Record<string, number>;
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { useSettingsStore } from './setting.ts';
|
import { useSettingsStore } from './setting.ts';
|
||||||
import { useUserStore } from './user.ts';
|
import { useUserStore } from './user.ts';
|
||||||
import { useAccountsStore } from './account.js';
|
import { useAccountsStore } from './account.js';
|
||||||
import { useTransactionCategoriesStore } from './transactionCategory.js';
|
import { useTransactionCategoriesStore } from './transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from './transactionTag.ts';
|
import { useTransactionTagsStore } from './transactionTag.ts';
|
||||||
import { useTransactionTemplatesStore } from './transactionTemplate.js';
|
import { useTransactionTemplatesStore } from './transactionTemplate.js';
|
||||||
import { useTransactionsStore } from './transaction.js';
|
import { useTransactionsStore } from './transaction.js';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { useSettingsStore } from './setting.ts';
|
import { useSettingsStore } from './setting.ts';
|
||||||
import { useUserStore } from './user.ts';
|
import { useUserStore } from './user.ts';
|
||||||
import { useAccountsStore } from './account.js';
|
import { useAccountsStore } from './account.js';
|
||||||
import { useTransactionCategoriesStore } from './transactionCategory.js';
|
import { useTransactionCategoriesStore } from './transactionCategory.ts';
|
||||||
import { useExchangeRatesStore } from './exchangeRates.ts';
|
import { useExchangeRatesStore } from './exchangeRates.ts';
|
||||||
|
|
||||||
import { DateRangeScene, DateRange } from '@/core/datetime';
|
import { DateRangeScene, DateRange } from '@/core/datetime';
|
||||||
@@ -43,7 +43,7 @@ import {
|
|||||||
} from '@/lib/account.js';
|
} from '@/lib/account.js';
|
||||||
import {
|
import {
|
||||||
getFinalCategoryIdsByFilteredCategoryIds
|
getFinalCategoryIdsByFilteredCategoryIds
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
import {
|
import {
|
||||||
sortStatisticsItems
|
sortStatisticsItems
|
||||||
} from '@/lib/statistics.ts';
|
} from '@/lib/statistics.ts';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { useSettingsStore } from './setting.ts';
|
import { useSettingsStore } from './setting.ts';
|
||||||
import { useUserStore } from './user.ts';
|
import { useUserStore } from './user.ts';
|
||||||
import { useAccountsStore } from './account.js';
|
import { useAccountsStore } from './account.js';
|
||||||
import { useTransactionCategoriesStore } from './transactionCategory.js';
|
import { useTransactionCategoriesStore } from './transactionCategory.ts';
|
||||||
import { useOverviewStore } from './overview.ts';
|
import { useOverviewStore } from './overview.ts';
|
||||||
import { useStatisticsStore } from './statistics.js';
|
import { useStatisticsStore } from './statistics.js';
|
||||||
import { useExchangeRatesStore } from './exchangeRates.ts';
|
import { useExchangeRatesStore } from './exchangeRates.ts';
|
||||||
@@ -39,7 +39,7 @@ import {
|
|||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
import { getAmountWithDecimalNumberCount } from '@/lib/numeral.ts';
|
import { getAmountWithDecimalNumberCount } from '@/lib/numeral.ts';
|
||||||
import { getCurrencyFraction } from '@/lib/currency.ts';
|
import { getCurrencyFraction } from '@/lib/currency.ts';
|
||||||
import { getFirstAvailableCategoryId } from '@/lib/category.js';
|
import { getFirstAvailableCategoryId } from '@/lib/category.ts';
|
||||||
|
|
||||||
const emptyTransactionResult = {
|
const emptyTransactionResult = {
|
||||||
items: [],
|
items: [],
|
||||||
|
|||||||
@@ -1,533 +0,0 @@
|
|||||||
import { defineStore } from 'pinia';
|
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
|
||||||
import { DEFAULT_CATEGORY_ICON_ID } from '@/consts/icon.ts';
|
|
||||||
import { DEFAULT_CATEGORY_COLOR } from '@/consts/color.ts';
|
|
||||||
import { isEquals } from '@/lib/common.ts';
|
|
||||||
import services from '@/lib/services.ts';
|
|
||||||
import logger from '@/lib/logger.ts';
|
|
||||||
|
|
||||||
function loadTransactionCategoryList(state, allCategories) {
|
|
||||||
state.allTransactionCategories = allCategories;
|
|
||||||
state.allTransactionCategoriesMap = {};
|
|
||||||
|
|
||||||
for (let categoryType in allCategories) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(allCategories, categoryType)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const categories = allCategories[categoryType];
|
|
||||||
|
|
||||||
for (let i = 0; i < categories.length; i++) {
|
|
||||||
const category = categories[i];
|
|
||||||
state.allTransactionCategoriesMap[category.id] = category;
|
|
||||||
|
|
||||||
for (let j = 0; j < category.subCategories.length; j++) {
|
|
||||||
const subCategory = category.subCategories[j];
|
|
||||||
state.allTransactionCategoriesMap[subCategory.id] = subCategory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addCategoryToTransactionCategoryList(state, category) {
|
|
||||||
let categoryList = null;
|
|
||||||
|
|
||||||
if (!category.parentId || category.parentId === '0') {
|
|
||||||
categoryList = state.allTransactionCategories[category.type];
|
|
||||||
} else if (state.allTransactionCategoriesMap[category.parentId]) {
|
|
||||||
categoryList = state.allTransactionCategoriesMap[category.parentId].subCategories;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (categoryList) {
|
|
||||||
categoryList.push(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.allTransactionCategoriesMap[category.id] = category;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCategoryInTransactionCategoryList(state, category, oldCategory) {
|
|
||||||
if (oldCategory && category.parentId !== oldCategory.parentId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let categoryList = null;
|
|
||||||
|
|
||||||
if (!category.parentId || category.parentId === '0') {
|
|
||||||
categoryList = state.allTransactionCategories[category.type];
|
|
||||||
} else if (state.allTransactionCategoriesMap[category.parentId]) {
|
|
||||||
categoryList = state.allTransactionCategoriesMap[category.parentId].subCategories;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (categoryList) {
|
|
||||||
for (let i = 0; i < categoryList.length; i++) {
|
|
||||||
if (categoryList[i].id === category.id) {
|
|
||||||
if (!category.parentId || category.parentId === '0') {
|
|
||||||
category.subCategories = categoryList[i].subCategories;
|
|
||||||
}
|
|
||||||
|
|
||||||
categoryList.splice(i, 1, category);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.allTransactionCategoriesMap[category.id] = category;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCategoryDisplayOrderInCategoryList(state, { category, from, to }) {
|
|
||||||
let categoryList = null;
|
|
||||||
|
|
||||||
if (!category.parentId || category.parentId === '0') {
|
|
||||||
categoryList = state.allTransactionCategories[category.type];
|
|
||||||
} else if (state.allTransactionCategoriesMap[category.parentId]) {
|
|
||||||
categoryList = state.allTransactionCategoriesMap[category.parentId].subCategories;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (categoryList) {
|
|
||||||
categoryList.splice(to, 0, categoryList.splice(from, 1)[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCategoryVisibilityInTransactionCategoryList(state, { category, hidden }) {
|
|
||||||
if (state.allTransactionCategoriesMap[category.id]) {
|
|
||||||
state.allTransactionCategoriesMap[category.id].hidden = hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeCategoryFromTransactionCategoryList(state, category) {
|
|
||||||
let categoryList = null;
|
|
||||||
|
|
||||||
if (!category.parentId || category.parentId === '0') {
|
|
||||||
categoryList = state.allTransactionCategories[category.type];
|
|
||||||
} else if (state.allTransactionCategoriesMap[category.parentId]) {
|
|
||||||
categoryList = state.allTransactionCategoriesMap[category.parentId].subCategories;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (categoryList) {
|
|
||||||
for (let i = 0; i < categoryList.length; i++) {
|
|
||||||
if (categoryList[i].id === category.id) {
|
|
||||||
categoryList.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.allTransactionCategoriesMap[category.id] && state.allTransactionCategoriesMap[category.id].subCategories) {
|
|
||||||
const subCategories = state.allTransactionCategoriesMap[category.id].subCategories;
|
|
||||||
|
|
||||||
for (let i = 0; i < subCategories.length; i++) {
|
|
||||||
const subCategory = subCategories[i];
|
|
||||||
if (state.allTransactionCategoriesMap[subCategory.id]) {
|
|
||||||
delete state.allTransactionCategoriesMap[subCategory.id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.allTransactionCategoriesMap[category.id]) {
|
|
||||||
delete state.allTransactionCategoriesMap[category.id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useTransactionCategoriesStore = defineStore('transactionCategories', {
|
|
||||||
state: () => ({
|
|
||||||
allTransactionCategories: {},
|
|
||||||
allTransactionCategoriesMap: {},
|
|
||||||
transactionCategoryListStateInvalid: true,
|
|
||||||
}),
|
|
||||||
actions: {
|
|
||||||
generateNewTransactionCategoryModel(type, parentId) {
|
|
||||||
return {
|
|
||||||
type: type || CategoryType.Income,
|
|
||||||
name: '',
|
|
||||||
parentId: parentId || '0',
|
|
||||||
icon: DEFAULT_CATEGORY_ICON_ID,
|
|
||||||
color: DEFAULT_CATEGORY_COLOR,
|
|
||||||
comment: '',
|
|
||||||
visible: true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
updateTransactionCategoryListInvalidState(invalidState) {
|
|
||||||
this.transactionCategoryListStateInvalid = invalidState;
|
|
||||||
},
|
|
||||||
resetTransactionCategories() {
|
|
||||||
this.allTransactionCategories = {};
|
|
||||||
this.allTransactionCategoriesMap = {};
|
|
||||||
this.transactionCategoryListStateInvalid = true;
|
|
||||||
},
|
|
||||||
loadAllCategories({ force }) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
if (!force && !self.transactionCategoryListStateInvalid) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
resolve(self.allTransactionCategories);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
services.getAllTransactionCategories().then(response => {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
|
||||||
reject({ message: 'Unable to retrieve category list' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.result[CategoryType.Income]) {
|
|
||||||
data.result[CategoryType.Income] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.result[CategoryType.Expense]) {
|
|
||||||
data.result[CategoryType.Expense] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.result[CategoryType.Transfer]) {
|
|
||||||
data.result[CategoryType.Transfer] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let categoryType in data.result) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(data.result, categoryType)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const categories = data.result[categoryType];
|
|
||||||
|
|
||||||
for (let i = 0; i < categories.length; i++) {
|
|
||||||
const category = categories[i];
|
|
||||||
|
|
||||||
if (!category.subCategories) {
|
|
||||||
category.subCategories = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.transactionCategoryListStateInvalid) {
|
|
||||||
self.updateTransactionCategoryListInvalidState(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force && data.result && isEquals(self.allTransactionCategories, data.result)) {
|
|
||||||
reject({ message: 'Category list is up to date' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadTransactionCategoryList(self, data.result);
|
|
||||||
|
|
||||||
resolve(data.result);
|
|
||||||
}).catch(error => {
|
|
||||||
if (force) {
|
|
||||||
logger.error('failed to force load category list', error);
|
|
||||||
} else {
|
|
||||||
logger.error('failed to load category list', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
||||||
reject({ error: error.response.data });
|
|
||||||
} else if (!error.processed) {
|
|
||||||
reject({ message: 'Unable to retrieve category list' });
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getCategory({ categoryId }) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
services.getTransactionCategory({
|
|
||||||
id: categoryId
|
|
||||||
}).then(response => {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
|
||||||
reject({ message: 'Unable to retrieve category' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(data.result);
|
|
||||||
}).catch(error => {
|
|
||||||
logger.error('failed to load category info', error);
|
|
||||||
|
|
||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
||||||
reject({ error: error.response.data });
|
|
||||||
} else if (!error.processed) {
|
|
||||||
reject({ message: 'Unable to retrieve category' });
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
saveCategory({ category, isEdit, clientSessionId }) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
const submitCategory = {
|
|
||||||
type: category.type,
|
|
||||||
name: category.name,
|
|
||||||
parentId: category.parentId,
|
|
||||||
icon: category.icon,
|
|
||||||
color: category.color,
|
|
||||||
comment: category.comment
|
|
||||||
};
|
|
||||||
|
|
||||||
if (clientSessionId) {
|
|
||||||
submitCategory.clientSessionId = clientSessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEdit) {
|
|
||||||
submitCategory.id = category.id;
|
|
||||||
submitCategory.hidden = !category.visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let promise = null;
|
|
||||||
|
|
||||||
if (!submitCategory.id) {
|
|
||||||
promise = services.addTransactionCategory(submitCategory);
|
|
||||||
} else {
|
|
||||||
promise = services.modifyTransactionCategory(submitCategory);
|
|
||||||
}
|
|
||||||
|
|
||||||
promise.then(response => {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
|
||||||
if (!submitCategory.id) {
|
|
||||||
reject({ message: 'Unable to add category' });
|
|
||||||
} else {
|
|
||||||
reject({ message: 'Unable to save category' });
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.result.subCategories) {
|
|
||||||
data.result.subCategories = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!submitCategory.id) {
|
|
||||||
addCategoryToTransactionCategoryList(self, data.result);
|
|
||||||
} else {
|
|
||||||
const result = updateCategoryInTransactionCategoryList(self, data.result, self.allTransactionCategoriesMap[submitCategory.id]);
|
|
||||||
|
|
||||||
if (!result && !self.transactionCategoryListStateInvalid) {
|
|
||||||
self.updateTransactionCategoryListInvalidState(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(data.result);
|
|
||||||
}).catch(error => {
|
|
||||||
logger.error('failed to save category', error);
|
|
||||||
|
|
||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
||||||
reject({ error: error.response.data });
|
|
||||||
} else if (!error.processed) {
|
|
||||||
if (!submitCategory.id) {
|
|
||||||
reject({ message: 'Unable to add category' });
|
|
||||||
} else {
|
|
||||||
reject({ message: 'Unable to save category' });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addCategories({ categories }) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
services.addTransactionCategoryBatch({
|
|
||||||
categories: categories
|
|
||||||
}).then(response => {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
|
||||||
reject({ message: 'Unable to add preset categories' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!self.transactionCategoryListStateInvalid) {
|
|
||||||
self.updateTransactionCategoryListInvalidState(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(data.result);
|
|
||||||
}).catch(error => {
|
|
||||||
logger.error('failed to add preset categories', error);
|
|
||||||
|
|
||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
||||||
reject({ error: error.response.data });
|
|
||||||
} else if (!error.processed) {
|
|
||||||
reject({ message: 'Unable to add preset categories' });
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
changeCategoryDisplayOrder({ categoryId, from, to }) {
|
|
||||||
const self = this;
|
|
||||||
const category = self.allTransactionCategoriesMap[categoryId];
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!category) {
|
|
||||||
reject({ message: 'Unable to move category' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!category.parentId || category.parentId === '0') {
|
|
||||||
if (!self.allTransactionCategories[category.type] ||
|
|
||||||
!self.allTransactionCategories[category.type][to]) {
|
|
||||||
reject({ message: 'Unable to move category' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!self.allTransactionCategoriesMap[category.parentId].subCategories ||
|
|
||||||
!self.allTransactionCategoriesMap[category.parentId].subCategories[to]) {
|
|
||||||
reject({ message: 'Unable to move category' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!self.transactionCategoryListStateInvalid) {
|
|
||||||
self.updateTransactionCategoryListInvalidState(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCategoryDisplayOrderInCategoryList(self, {
|
|
||||||
category: category,
|
|
||||||
from: from,
|
|
||||||
to: to
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
updateCategoryDisplayOrders({ type, parentId }) {
|
|
||||||
const self = this;
|
|
||||||
const newDisplayOrders = [];
|
|
||||||
|
|
||||||
let categoryList = null;
|
|
||||||
|
|
||||||
if (!parentId || parentId === '0') {
|
|
||||||
categoryList = self.allTransactionCategories[type];
|
|
||||||
} else if (self.allTransactionCategoriesMap[parentId]) {
|
|
||||||
categoryList = self.allTransactionCategoriesMap[parentId].subCategories;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (categoryList) {
|
|
||||||
for (let i = 0; i < categoryList.length; i++) {
|
|
||||||
newDisplayOrders.push({
|
|
||||||
id: categoryList[i].id,
|
|
||||||
displayOrder: i + 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
services.moveTransactionCategory({
|
|
||||||
newDisplayOrders: newDisplayOrders
|
|
||||||
}).then(response => {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
|
||||||
reject({ message: 'Unable to move category' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.transactionCategoryListStateInvalid) {
|
|
||||||
self.updateTransactionCategoryListInvalidState(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(data.result);
|
|
||||||
}).catch(error => {
|
|
||||||
logger.error('failed to save categories display order', error);
|
|
||||||
|
|
||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
||||||
reject({ error: error.response.data });
|
|
||||||
} else if (!error.processed) {
|
|
||||||
reject({ message: 'Unable to move category' });
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
hideCategory({ category, hidden }) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
services.hideTransactionCategory({
|
|
||||||
id: category.id,
|
|
||||||
hidden: hidden
|
|
||||||
}).then(response => {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
|
||||||
if (hidden) {
|
|
||||||
reject({ message: 'Unable to hide this category' });
|
|
||||||
} else {
|
|
||||||
reject({ message: 'Unable to unhide this category' });
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCategoryVisibilityInTransactionCategoryList(self, {
|
|
||||||
category: category,
|
|
||||||
hidden: hidden
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve(data.result);
|
|
||||||
}).catch(error => {
|
|
||||||
logger.error('failed to change category visibility', error);
|
|
||||||
|
|
||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
||||||
reject({ error: error.response.data });
|
|
||||||
} else if (!error.processed) {
|
|
||||||
if (hidden) {
|
|
||||||
reject({ message: 'Unable to hide this category' });
|
|
||||||
} else {
|
|
||||||
reject({ message: 'Unable to unhide this category' });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteCategory({ category, beforeResolve }) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
services.deleteTransactionCategory({
|
|
||||||
id: category.id
|
|
||||||
}).then(response => {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
|
||||||
reject({ message: 'Unable to delete this category' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beforeResolve) {
|
|
||||||
beforeResolve(() => {
|
|
||||||
removeCategoryFromTransactionCategoryList(self, category);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
removeCategoryFromTransactionCategoryList(self, category);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(data.result);
|
|
||||||
}).catch(error => {
|
|
||||||
logger.error('failed to delete category', error);
|
|
||||||
|
|
||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
||||||
reject({ error: error.response.data });
|
|
||||||
} else if (!error.processed) {
|
|
||||||
reject({ message: 'Unable to delete this category' });
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,518 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
import type { BeforeResolveFunction } from '@/core/base.ts';
|
||||||
|
|
||||||
|
import { CategoryType } from '@/core/category.ts';
|
||||||
|
|
||||||
|
import {
|
||||||
|
type TransactionCategoryInfoResponse,
|
||||||
|
type TransactionCategoryCreateBatchRequest,
|
||||||
|
type TransactionCategoryNewDisplayOrderRequest,
|
||||||
|
TransactionCategory,
|
||||||
|
} from '@/models/transaction_category.ts';
|
||||||
|
|
||||||
|
import { isEquals } from '@/lib/common.ts';
|
||||||
|
import services, { type ApiResponsePromise } from '@/lib/services.ts';
|
||||||
|
import logger from '@/lib/logger.ts';
|
||||||
|
|
||||||
|
export const useTransactionCategoriesStore = defineStore('transactionCategories', () =>{
|
||||||
|
const allTransactionCategories = ref<Record<number, TransactionCategory[]>>({});
|
||||||
|
const allTransactionCategoriesMap = ref<Record<string, TransactionCategory>>({});
|
||||||
|
const transactionCategoryListStateInvalid = ref<boolean>(true);
|
||||||
|
|
||||||
|
function loadTransactionCategoryList(allCategories: Record<number, TransactionCategory[]>): void {
|
||||||
|
allTransactionCategories.value = allCategories;
|
||||||
|
allTransactionCategoriesMap.value = {};
|
||||||
|
|
||||||
|
for (const categoryType in allCategories) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(allCategories, categoryType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const categories = allCategories[categoryType];
|
||||||
|
|
||||||
|
for (let i = 0; i < categories.length; i++) {
|
||||||
|
const category = categories[i];
|
||||||
|
allTransactionCategoriesMap.value[category.id] = category;
|
||||||
|
|
||||||
|
if (!category.secondaryCategories) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < category.secondaryCategories.length; j++) {
|
||||||
|
const subCategory = category.secondaryCategories[j];
|
||||||
|
allTransactionCategoriesMap.value[subCategory.id] = subCategory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCategoryToTransactionCategoryList(category: TransactionCategory): void {
|
||||||
|
let categoryList: TransactionCategory[] | undefined = undefined;
|
||||||
|
|
||||||
|
if (!category.parentId || category.parentId === '0') {
|
||||||
|
categoryList = allTransactionCategories.value[category.type];
|
||||||
|
} else if (allTransactionCategoriesMap.value[category.parentId]) {
|
||||||
|
categoryList = allTransactionCategoriesMap.value[category.parentId].secondaryCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categoryList) {
|
||||||
|
categoryList.push(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactionCategoriesMap.value[category.id] = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCategoryInTransactionCategoryList(category: TransactionCategory, oldCategory: TransactionCategory): boolean {
|
||||||
|
if (oldCategory && category.parentId !== oldCategory.parentId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let categoryList: TransactionCategory[] | undefined = undefined;
|
||||||
|
|
||||||
|
if (!category.parentId || category.parentId === '0') {
|
||||||
|
categoryList = allTransactionCategories.value[category.type];
|
||||||
|
} else if (allTransactionCategoriesMap.value[category.parentId]) {
|
||||||
|
categoryList = allTransactionCategoriesMap.value[category.parentId].secondaryCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categoryList) {
|
||||||
|
for (let i = 0; i < categoryList.length; i++) {
|
||||||
|
if (categoryList[i].id === category.id) {
|
||||||
|
if (!category.parentId || category.parentId === '0') {
|
||||||
|
category.secondaryCategories = categoryList[i].secondaryCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
categoryList.splice(i, 1, category);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactionCategoriesMap.value[category.id] = category;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCategoryDisplayOrderInCategoryList(params: { category: TransactionCategory, from: number, to: number }): void {
|
||||||
|
let categoryList: TransactionCategory[] | undefined = undefined;
|
||||||
|
|
||||||
|
if (!params.category.parentId || params.category.parentId === '0') {
|
||||||
|
categoryList = allTransactionCategories.value[params.category.type];
|
||||||
|
} else if (allTransactionCategoriesMap.value[params.category.parentId]) {
|
||||||
|
categoryList = allTransactionCategoriesMap.value[params.category.parentId].secondaryCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categoryList) {
|
||||||
|
categoryList.splice(params.to, 0, categoryList.splice(params.from, 1)[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCategoryVisibilityInTransactionCategoryList(params: { category: TransactionCategory, hidden: boolean }): void {
|
||||||
|
if (allTransactionCategoriesMap.value[params.category.id]) {
|
||||||
|
allTransactionCategoriesMap.value[params.category.id].visible = !params.hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCategoryFromTransactionCategoryList(category: TransactionCategory): void {
|
||||||
|
let categoryList: TransactionCategory[] | undefined = undefined;
|
||||||
|
|
||||||
|
if (!category.parentId || category.parentId === '0') {
|
||||||
|
categoryList = allTransactionCategories.value[category.type];
|
||||||
|
} else if (allTransactionCategoriesMap.value[category.parentId]) {
|
||||||
|
categoryList = allTransactionCategoriesMap.value[category.parentId].secondaryCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categoryList) {
|
||||||
|
for (let i = 0; i < categoryList.length; i++) {
|
||||||
|
if (categoryList[i].id === category.id) {
|
||||||
|
categoryList.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allTransactionCategoriesMap.value[category.id] && allTransactionCategoriesMap.value[category.id].secondaryCategories) {
|
||||||
|
const subCategoryList = allTransactionCategoriesMap.value[category.id].secondaryCategories;
|
||||||
|
|
||||||
|
if (subCategoryList) {
|
||||||
|
for (let i = 0; i < subCategoryList.length; i++) {
|
||||||
|
const subCategory = subCategoryList[i];
|
||||||
|
if (allTransactionCategoriesMap.value[subCategory.id]) {
|
||||||
|
delete allTransactionCategoriesMap.value[subCategory.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allTransactionCategoriesMap.value[category.id]) {
|
||||||
|
delete allTransactionCategoriesMap.value[category.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTransactionCategoryListInvalidState(invalidState: boolean): void {
|
||||||
|
transactionCategoryListStateInvalid.value = invalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetTransactionCategories(): void {
|
||||||
|
allTransactionCategories.value = {};
|
||||||
|
allTransactionCategoriesMap.value = {};
|
||||||
|
transactionCategoryListStateInvalid.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadAllCategories(params: { force?: boolean }): Promise<Record<number, TransactionCategory[]>> {
|
||||||
|
if (!params.force && !transactionCategoryListStateInvalid.value) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
resolve(allTransactionCategories.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
services.getAllTransactionCategories().then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
reject({ message: 'Unable to retrieve category list' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.result[CategoryType.Income]) {
|
||||||
|
data.result[CategoryType.Income] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.result[CategoryType.Expense]) {
|
||||||
|
data.result[CategoryType.Expense] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.result[CategoryType.Transfer]) {
|
||||||
|
data.result[CategoryType.Transfer] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionCategoryListStateInvalid.value) {
|
||||||
|
updateTransactionCategoryListInvalidState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transactionCategories = TransactionCategory.ofMap(data.result);
|
||||||
|
|
||||||
|
if (params.force && data.result && isEquals(allTransactionCategories.value, transactionCategories)) {
|
||||||
|
reject({ message: 'Category list is up to date' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadTransactionCategoryList(transactionCategories);
|
||||||
|
|
||||||
|
resolve(transactionCategories);
|
||||||
|
}).catch(error => {
|
||||||
|
if (params.force) {
|
||||||
|
logger.error('failed to force load category list', error);
|
||||||
|
} else {
|
||||||
|
logger.error('failed to load category list', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
reject({ message: 'Unable to retrieve category list' });
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCategory(params: { categoryId: string }): Promise<TransactionCategory> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
services.getTransactionCategory({
|
||||||
|
id: params.categoryId
|
||||||
|
}).then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
reject({ message: 'Unable to retrieve category' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transactionCategory = TransactionCategory.of(data.result);
|
||||||
|
|
||||||
|
resolve(transactionCategory);
|
||||||
|
}).catch(error => {
|
||||||
|
logger.error('failed to load category info', error);
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
reject({ message: 'Unable to retrieve category' });
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveCategory(params: { category: TransactionCategory, isEdit: boolean, clientSessionId: string }): Promise<TransactionCategory> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let promise: ApiResponsePromise<TransactionCategoryInfoResponse>;
|
||||||
|
|
||||||
|
if (!params.isEdit) {
|
||||||
|
promise = services.addTransactionCategory(params.category.toCreateRequest(params.clientSessionId));
|
||||||
|
} else {
|
||||||
|
promise = services.modifyTransactionCategory(params.category.toModifyRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
promise.then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
if (!params.isEdit) {
|
||||||
|
reject({ message: 'Unable to add category' });
|
||||||
|
} else {
|
||||||
|
reject({ message: 'Unable to save category' });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transactionCategory = TransactionCategory.of(data.result);
|
||||||
|
|
||||||
|
if (!params.isEdit) {
|
||||||
|
addCategoryToTransactionCategoryList(transactionCategory);
|
||||||
|
} else {
|
||||||
|
const result = updateCategoryInTransactionCategoryList(transactionCategory, allTransactionCategoriesMap.value[params.category.id]);
|
||||||
|
|
||||||
|
if (!result && !transactionCategoryListStateInvalid.value) {
|
||||||
|
updateTransactionCategoryListInvalidState(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(transactionCategory);
|
||||||
|
}).catch(error => {
|
||||||
|
logger.error('failed to save category', error);
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
if (!params.isEdit) {
|
||||||
|
reject({ message: 'Unable to add category' });
|
||||||
|
} else {
|
||||||
|
reject({ message: 'Unable to save category' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCategories(req: TransactionCategoryCreateBatchRequest): Promise<Record<number, TransactionCategory[]>> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
services.addTransactionCategoryBatch(req).then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
reject({ message: 'Unable to add preset categories' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transactionCategoryListStateInvalid.value) {
|
||||||
|
updateTransactionCategoryListInvalidState(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transactionCategories = TransactionCategory.ofMap(data.result);
|
||||||
|
|
||||||
|
resolve(transactionCategories);
|
||||||
|
}).catch(error => {
|
||||||
|
logger.error('failed to add preset categories', error);
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
reject({ message: 'Unable to add preset categories' });
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeCategoryDisplayOrder(params: { categoryId: string, from: number, to: number }): Promise<void> {
|
||||||
|
const category = allTransactionCategoriesMap.value[params.categoryId];
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!category) {
|
||||||
|
reject({ message: 'Unable to move category' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!category.parentId || category.parentId === '0') {
|
||||||
|
if (!allTransactionCategories.value[category.type] ||
|
||||||
|
!allTransactionCategories.value[category.type][params.to]) {
|
||||||
|
reject({ message: 'Unable to move category' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const subCategoryList = allTransactionCategoriesMap.value[category.parentId].secondaryCategories;
|
||||||
|
|
||||||
|
if (!subCategoryList || !subCategoryList[params.to]) {
|
||||||
|
reject({ message: 'Unable to move category' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transactionCategoryListStateInvalid.value) {
|
||||||
|
updateTransactionCategoryListInvalidState(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCategoryDisplayOrderInCategoryList({
|
||||||
|
category: category,
|
||||||
|
from: params.from,
|
||||||
|
to: params.to
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCategoryDisplayOrders(params: { type: CategoryType, parentId: string }): Promise<boolean> {
|
||||||
|
const newDisplayOrders: TransactionCategoryNewDisplayOrderRequest[] = [];
|
||||||
|
|
||||||
|
let categoryList: TransactionCategory[] | undefined = undefined;
|
||||||
|
|
||||||
|
if (!params.parentId || params.parentId === '0') {
|
||||||
|
categoryList = allTransactionCategories.value[params.type];
|
||||||
|
} else if (allTransactionCategoriesMap.value[params.parentId]) {
|
||||||
|
categoryList = allTransactionCategoriesMap.value[params.parentId].secondaryCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categoryList) {
|
||||||
|
for (let i = 0; i < categoryList.length; i++) {
|
||||||
|
newDisplayOrders.push({
|
||||||
|
id: categoryList[i].id,
|
||||||
|
displayOrder: i + 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
services.moveTransactionCategory({
|
||||||
|
newDisplayOrders: newDisplayOrders
|
||||||
|
}).then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
reject({ message: 'Unable to move category' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionCategoryListStateInvalid.value) {
|
||||||
|
updateTransactionCategoryListInvalidState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(data.result);
|
||||||
|
}).catch(error => {
|
||||||
|
logger.error('failed to save categories display order', error);
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
reject({ message: 'Unable to move category' });
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideCategory(params: { category: TransactionCategory, hidden: boolean }): Promise<boolean> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
services.hideTransactionCategory({
|
||||||
|
id: params.category.id,
|
||||||
|
hidden: params.hidden
|
||||||
|
}).then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
if (params.hidden) {
|
||||||
|
reject({ message: 'Unable to hide this category' });
|
||||||
|
} else {
|
||||||
|
reject({ message: 'Unable to unhide this category' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCategoryVisibilityInTransactionCategoryList({
|
||||||
|
category: params.category,
|
||||||
|
hidden: params.hidden
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(data.result);
|
||||||
|
}).catch(error => {
|
||||||
|
logger.error('failed to change category visibility', error);
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
if (params.hidden) {
|
||||||
|
reject({ message: 'Unable to hide this category' });
|
||||||
|
} else {
|
||||||
|
reject({ message: 'Unable to unhide this category' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteCategory(params: { category: TransactionCategory, beforeResolve: BeforeResolveFunction }): Promise<boolean> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
services.deleteTransactionCategory({
|
||||||
|
id: params.category.id
|
||||||
|
}).then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
reject({ message: 'Unable to delete this category' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.beforeResolve) {
|
||||||
|
params.beforeResolve(() => {
|
||||||
|
removeCategoryFromTransactionCategoryList(params.category);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
removeCategoryFromTransactionCategoryList(params.category);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(data.result);
|
||||||
|
}).catch(error => {
|
||||||
|
logger.error('failed to delete category', error);
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
reject({ message: 'Unable to delete this category' });
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
// states
|
||||||
|
allTransactionCategories,
|
||||||
|
allTransactionCategoriesMap,
|
||||||
|
transactionCategoryListStateInvalid,
|
||||||
|
// functions
|
||||||
|
updateTransactionCategoryListInvalidState,
|
||||||
|
resetTransactionCategories,
|
||||||
|
loadAllCategories,
|
||||||
|
getCategory,
|
||||||
|
saveCategory,
|
||||||
|
addCategories,
|
||||||
|
changeCategoryDisplayOrder,
|
||||||
|
updateCategoryDisplayOrders,
|
||||||
|
hideCategory,
|
||||||
|
deleteCategory
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -241,7 +241,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useRootStore } from '@/stores/index.js';
|
import { useRootStore } from '@/stores/index.js';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||||
|
|||||||
@@ -198,13 +198,13 @@ import PresetDialog from './list/dialogs/PresetDialog.vue';
|
|||||||
import { useDisplay } from 'vuetify';
|
import { useDisplay } from 'vuetify';
|
||||||
|
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import {
|
import {
|
||||||
isNoAvailableCategory,
|
isNoAvailableCategory,
|
||||||
getAvailableCategoryCount
|
getAvailableCategoryCount
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
import { getNavSideBarOuterHeight } from '@/lib/ui/desktop.ts';
|
import { getNavSideBarOuterHeight } from '@/lib/ui/desktop.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -95,16 +95,18 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import { ALL_CATEGORY_ICONS } from '@/consts/icon.ts';
|
import { ALL_CATEGORY_ICONS } from '@/consts/icon.ts';
|
||||||
import { ALL_CATEGORY_COLORS } from '@/consts/color.ts';
|
import { ALL_CATEGORY_COLORS } from '@/consts/color.ts';
|
||||||
|
import { TransactionCategory } from '@/models/transaction_category.ts';
|
||||||
|
|
||||||
import { generateRandomUUID } from '@/lib/misc.ts';
|
import { generateRandomUUID } from '@/lib/misc.ts';
|
||||||
import {
|
import {
|
||||||
setCategoryModelByAnotherCategory,
|
setCategoryModelByAnotherCategory,
|
||||||
allVisiblePrimaryTransactionCategoriesByType
|
allVisiblePrimaryTransactionCategoriesByType
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
@@ -115,15 +117,12 @@ export default {
|
|||||||
'open'
|
'open'
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
const transactionCategoriesStore = useTransactionCategoriesStore();
|
|
||||||
const newTransactionCategory = transactionCategoriesStore.generateNewTransactionCategoryModel();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
showState: false,
|
showState: false,
|
||||||
editCategoryId: null,
|
editCategoryId: null,
|
||||||
clientSessionId: '',
|
clientSessionId: '',
|
||||||
loading: false,
|
loading: false,
|
||||||
category: newTransactionCategory,
|
category: TransactionCategory.createNewCategory(),
|
||||||
submitting: false,
|
submitting: false,
|
||||||
resolve: null,
|
resolve: null,
|
||||||
reject: null
|
reject: null
|
||||||
@@ -176,7 +175,7 @@ export default {
|
|||||||
self.loading = true;
|
self.loading = true;
|
||||||
self.submitting = false;
|
self.submitting = false;
|
||||||
|
|
||||||
const newTransactionCategory = self.transactionCategoriesStore.generateNewTransactionCategoryModel();
|
const newTransactionCategory = TransactionCategory.createNewCategory();
|
||||||
setCategoryModelByAnotherCategory(self.category, newTransactionCategory);
|
setCategoryModelByAnotherCategory(self.category, newTransactionCategory);
|
||||||
|
|
||||||
if (options.id) {
|
if (options.id) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import { categorizedArrayToPlainArray } from '@/lib/common.ts';
|
import { categorizedArrayToPlainArray } from '@/lib/common.ts';
|
||||||
|
|||||||
@@ -145,7 +145,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.js';
|
import { useStatisticsStore } from '@/stores/statistics.js';
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ import {
|
|||||||
isCategoryOrSubCategoriesAllChecked,
|
isCategoryOrSubCategoriesAllChecked,
|
||||||
isSubCategoriesAllChecked,
|
isSubCategoriesAllChecked,
|
||||||
isSubCategoriesHasButNotAllChecked
|
isSubCategoriesHasButNotAllChecked
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiSelectAll,
|
mdiSelectAll,
|
||||||
@@ -187,9 +187,9 @@ export default {
|
|||||||
return {
|
return {
|
||||||
loading: true,
|
loading: true,
|
||||||
expandCategoryTypes: [
|
expandCategoryTypes: [
|
||||||
CategoryType.Income.toString(),
|
CategoryType.Income,
|
||||||
CategoryType.Expense.toString(),
|
CategoryType.Expense,
|
||||||
CategoryType.Transfer.toString()
|
CategoryType.Transfer
|
||||||
],
|
],
|
||||||
filterCategoryIds: {},
|
filterCategoryIds: {},
|
||||||
showHidden: false,
|
showHidden: false,
|
||||||
@@ -388,11 +388,11 @@ export default {
|
|||||||
},
|
},
|
||||||
getCategoryTypeName(categoryType) {
|
getCategoryTypeName(categoryType) {
|
||||||
switch (categoryType) {
|
switch (categoryType) {
|
||||||
case CategoryType.Income.toString():
|
case CategoryType.Income:
|
||||||
return this.$t('Income Categories');
|
return this.$t('Income Categories');
|
||||||
case CategoryType.Expense.toString():
|
case CategoryType.Expense:
|
||||||
return this.$t('Expense Categories');
|
return this.$t('Expense Categories');
|
||||||
case CategoryType.Transfer.toString():
|
case CategoryType.Transfer:
|
||||||
return this.$t('Transfer Categories');
|
return this.$t('Transfer Categories');
|
||||||
default:
|
default:
|
||||||
return this.$t('Transaction Categories');
|
return this.$t('Transaction Categories');
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.js';
|
import { useStatisticsStore } from '@/stores/statistics.js';
|
||||||
|
|
||||||
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
||||||
@@ -627,7 +627,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
categoryTypeToTransactionType,
|
categoryTypeToTransactionType,
|
||||||
transactionTypeToCategoryType
|
transactionTypeToCategoryType
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.js';
|
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.js';
|
||||||
import { getTransactionDisplayAmount } from '@/lib/transaction.js';
|
import { getTransactionDisplayAmount } from '@/lib/transaction.js';
|
||||||
import { isDataImportingEnabled } from '@/lib/server_settings.ts';
|
import { isDataImportingEnabled } from '@/lib/server_settings.ts';
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ import {
|
|||||||
getTransactionPrimaryCategoryName,
|
getTransactionPrimaryCategoryName,
|
||||||
getTransactionSecondaryCategoryName,
|
getTransactionSecondaryCategoryName,
|
||||||
getFirstAvailableCategoryId
|
getFirstAvailableCategoryId
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiPound
|
mdiPound
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
||||||
@@ -421,7 +421,7 @@ import {
|
|||||||
getTransactionPrimaryCategoryName,
|
getTransactionPrimaryCategoryName,
|
||||||
getTransactionSecondaryCategoryName,
|
getTransactionSecondaryCategoryName,
|
||||||
getFirstAvailableCategoryId
|
getFirstAvailableCategoryId
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
import { setTransactionModelByTransaction } from '@/lib/transaction.js';
|
import { setTransactionModelByTransaction } from '@/lib/transaction.js';
|
||||||
import {
|
import {
|
||||||
isTransactionPicturesEnabled,
|
isTransactionPicturesEnabled,
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
import { useOverviewStore } from '@/stores/overview.ts';
|
import { useOverviewStore } from '@/stores/overview.ts';
|
||||||
@@ -628,7 +628,7 @@ import {
|
|||||||
getTransactionPrimaryCategoryName,
|
getTransactionPrimaryCategoryName,
|
||||||
getTransactionSecondaryCategoryName,
|
getTransactionSecondaryCategoryName,
|
||||||
getFirstAvailableCategoryId
|
getFirstAvailableCategoryId
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiFilterOutline,
|
mdiFilterOutline,
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useRootStore } from '@/stores/index.js';
|
import { useRootStore } from '@/stores/index.js';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
<template #default>
|
<template #default>
|
||||||
<div class="grid grid-cols-2">
|
<div class="grid grid-cols-2">
|
||||||
<div class="list-item-subitem no-chevron">
|
<div class="list-item-subitem no-chevron">
|
||||||
<a class="item-link" href="#" @click="category.showIconSelectionSheet = true">
|
<a class="item-link" href="#" @click="showIconSelectionSheet = true">
|
||||||
<div class="item-content">
|
<div class="item-content">
|
||||||
<div class="item-inner">
|
<div class="item-inner">
|
||||||
<div class="item-header">
|
<div class="item-header">
|
||||||
@@ -100,12 +100,12 @@
|
|||||||
|
|
||||||
<icon-selection-sheet :all-icon-infos="allCategoryIcons"
|
<icon-selection-sheet :all-icon-infos="allCategoryIcons"
|
||||||
:color="category.color"
|
:color="category.color"
|
||||||
v-model:show="category.showIconSelectionSheet"
|
v-model:show="showIconSelectionSheet"
|
||||||
v-model="category.icon"
|
v-model="category.icon"
|
||||||
></icon-selection-sheet>
|
></icon-selection-sheet>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-item-subitem no-chevron">
|
<div class="list-item-subitem no-chevron">
|
||||||
<a class="item-link" href="#" @click="category.showColorSelectionSheet = true">
|
<a class="item-link" href="#" @click="showColorSelectionSheet = true">
|
||||||
<div class="item-content">
|
<div class="item-content">
|
||||||
<div class="item-inner">
|
<div class="item-inner">
|
||||||
<div class="item-header">
|
<div class="item-header">
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<color-selection-sheet :all-color-infos="allCategoryColors"
|
<color-selection-sheet :all-color-infos="allCategoryColors"
|
||||||
v-model:show="category.showColorSelectionSheet"
|
v-model:show="showColorSelectionSheet"
|
||||||
v-model="category.color"
|
v-model="category.color"
|
||||||
></color-selection-sheet>
|
></color-selection-sheet>
|
||||||
</div>
|
</div>
|
||||||
@@ -147,17 +147,19 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import { ALL_CATEGORY_ICONS } from '@/consts/icon.ts';
|
import { ALL_CATEGORY_ICONS } from '@/consts/icon.ts';
|
||||||
import { ALL_CATEGORY_COLORS } from '@/consts/color.ts';
|
import { ALL_CATEGORY_COLORS } from '@/consts/color.ts';
|
||||||
|
import { TransactionCategory } from '@/models/transaction_category.ts';
|
||||||
|
|
||||||
import { getNameByKeyValue } from '@/lib/common.ts';
|
import { getNameByKeyValue } from '@/lib/common.ts';
|
||||||
import { generateRandomUUID } from '@/lib/misc.ts';
|
import { generateRandomUUID } from '@/lib/misc.ts';
|
||||||
import {
|
import {
|
||||||
setCategoryModelByAnotherCategory,
|
setCategoryModelByAnotherCategory,
|
||||||
allVisiblePrimaryTransactionCategoriesByType
|
allVisiblePrimaryTransactionCategoriesByType
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
@@ -165,19 +167,17 @@ export default {
|
|||||||
'f7router'
|
'f7router'
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
const transactionCategoriesStore = useTransactionCategoriesStore();
|
|
||||||
const query = this.f7route.query;
|
const query = this.f7route.query;
|
||||||
const newTransactionCategory = transactionCategoriesStore.generateNewTransactionCategoryModel(parseInt(query.type), query.parentId);
|
|
||||||
newTransactionCategory.showIconSelectionSheet = false;
|
|
||||||
newTransactionCategory.showColorSelectionSheet = false;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
editCategoryId: null,
|
editCategoryId: null,
|
||||||
clientSessionId: '',
|
clientSessionId: '',
|
||||||
loading: false,
|
loading: false,
|
||||||
loadingError: null,
|
loadingError: null,
|
||||||
category: newTransactionCategory,
|
category: TransactionCategory.createNewCategory(parseInt(query.type), query.parentId),
|
||||||
showPrimaryCategorySheet: false,
|
showPrimaryCategorySheet: false,
|
||||||
|
showIconSelectionSheet: false,
|
||||||
|
showColorSelectionSheet: false,
|
||||||
submitting: false
|
submitting: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -88,14 +88,14 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import {
|
import {
|
||||||
isNoAvailableCategory,
|
isNoAvailableCategory,
|
||||||
getFirstShowingId,
|
getFirstShowingId,
|
||||||
getLastShowingId
|
getLastShowingId
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
import { onSwipeoutDeleted } from '@/lib/ui/mobile.ts';
|
import { onSwipeoutDeleted } from '@/lib/ui/mobile.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import { getObjectOwnFieldCount, categorizedArrayToPlainArray } from '@/lib/common.ts';
|
import { getObjectOwnFieldCount, categorizedArrayToPlainArray } from '@/lib/common.ts';
|
||||||
|
|||||||
@@ -141,7 +141,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.js';
|
import { useStatisticsStore } from '@/stores/statistics.js';
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ import {
|
|||||||
isCategoryOrSubCategoriesAllChecked,
|
isCategoryOrSubCategoriesAllChecked,
|
||||||
isSubCategoriesAllChecked,
|
isSubCategoriesAllChecked,
|
||||||
isSubCategoriesHasButNotAllChecked
|
isSubCategoriesHasButNotAllChecked
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
@@ -357,11 +357,11 @@ export default {
|
|||||||
},
|
},
|
||||||
getCategoryTypeName(categoryType) {
|
getCategoryTypeName(categoryType) {
|
||||||
switch (categoryType) {
|
switch (categoryType) {
|
||||||
case CategoryType.Income.toString():
|
case CategoryType.Income:
|
||||||
return this.$t('Income Categories');
|
return this.$t('Income Categories');
|
||||||
case CategoryType.Expense.toString():
|
case CategoryType.Expense:
|
||||||
return this.$t('Expense Categories');
|
return this.$t('Expense Categories');
|
||||||
case CategoryType.Transfer.toString():
|
case CategoryType.Transfer:
|
||||||
return this.$t('Transfer Categories');
|
return this.$t('Transfer Categories');
|
||||||
default:
|
default:
|
||||||
return this.$t('Transaction Categories');
|
return this.$t('Transaction Categories');
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.js';
|
import { useStatisticsStore } from '@/stores/statistics.js';
|
||||||
|
|
||||||
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
||||||
|
|||||||
@@ -434,7 +434,7 @@ import { useSettingsStore } from '@/stores/setting.ts';
|
|||||||
import { useEnvironmentsStore } from '@/stores/environment.ts';
|
import { useEnvironmentsStore } from '@/stores/environment.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
||||||
@@ -463,7 +463,7 @@ import {
|
|||||||
getTransactionPrimaryCategoryName,
|
getTransactionPrimaryCategoryName,
|
||||||
getTransactionSecondaryCategoryName,
|
getTransactionSecondaryCategoryName,
|
||||||
getFirstAvailableCategoryId
|
getFirstAvailableCategoryId
|
||||||
} from '@/lib/category.js';
|
} from '@/lib/category.ts';
|
||||||
import { setTransactionModelByTransaction } from '@/lib/transaction.js';
|
import { setTransactionModelByTransaction } from '@/lib/transaction.js';
|
||||||
import {
|
import {
|
||||||
isTransactionPicturesEnabled,
|
isTransactionPicturesEnabled,
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ import { mapStores } from 'pinia';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.js';
|
import { useAccountsStore } from '@/stores/account.js';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.js';
|
||||||
|
|
||||||
@@ -548,7 +548,7 @@ import {
|
|||||||
getDateRangeByDateType,
|
getDateRangeByDateType,
|
||||||
getDateRangeByBillingCycleDateType
|
getDateRangeByBillingCycleDateType
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.js';
|
import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.ts';
|
||||||
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.js';
|
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.js';
|
||||||
import { getTransactionDisplayAmount } from '@/lib/transaction.js';
|
import { getTransactionDisplayAmount } from '@/lib/transaction.js';
|
||||||
import { onSwipeoutDeleted, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
|
import { onSwipeoutDeleted, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
|
||||||
|
|||||||
Reference in New Issue
Block a user