add transaction calendar for mobile version
This commit is contained in:
@@ -48,6 +48,7 @@ input[type=number] {
|
||||
/** Custom class **/
|
||||
:root {
|
||||
--default-icon-color: #000;
|
||||
--ebk-primary-color: 198, 126, 72;
|
||||
--v-expand-panel-title-bg: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
|
||||
--v-card-title-bg: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
--ebk-transaction-date-width: 25px;
|
||||
--ebk-transaction-day-font-size: 16px;
|
||||
--ebk-transaction-day-of-week-font-size: 12px;
|
||||
--ebk-transaction-calendar-amount-font-size: 12px;
|
||||
--ebk-transaction-calendar-daily-amounts-height: 65px;
|
||||
--ebk-transaction-account-arrow-font-size: 12px;
|
||||
--ebk-transaction-account-arrow-margin-top: -1px;
|
||||
--ebk-transaction-tag-icon-font-size: 22px;
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
--ebk-transaction-date-width: 28px;
|
||||
--ebk-transaction-day-font-size: 17px;
|
||||
--ebk-transaction-day-of-week-font-size: 13px;
|
||||
--ebk-transaction-calendar-amount-font-size: 13px;
|
||||
--ebk-transaction-calendar-daily-amounts-height: 65px;
|
||||
--ebk-transaction-account-arrow-font-size: 13px;
|
||||
--ebk-transaction-account-arrow-margin-top: -2px;
|
||||
--ebk-transaction-tag-icon-font-size: 24px;
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
--ebk-transaction-date-width: 25px;
|
||||
--ebk-transaction-day-font-size: 16px;
|
||||
--ebk-transaction-day-of-week-font-size: 12px;
|
||||
--ebk-transaction-calendar-amount-font-size: 12px;
|
||||
--ebk-transaction-calendar-daily-amounts-height: 65px;
|
||||
--ebk-transaction-account-arrow-font-size: 12px;
|
||||
--ebk-transaction-account-arrow-margin-top: -1px;
|
||||
--ebk-transaction-tag-icon-font-size: 20px;
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
--ebk-transaction-date-width: 30px;
|
||||
--ebk-transaction-day-font-size: 18px;
|
||||
--ebk-transaction-day-of-week-font-size: 14px;
|
||||
--ebk-transaction-calendar-amount-font-size: 14px;
|
||||
--ebk-transaction-calendar-daily-amounts-height: 70px;
|
||||
--ebk-transaction-account-arrow-font-size: 14px;
|
||||
--ebk-transaction-account-arrow-margin-top: -2px;
|
||||
--ebk-transaction-tag-icon-font-size: 26px;
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
--ebk-transaction-date-width: 32px;
|
||||
--ebk-transaction-day-font-size: 20px;
|
||||
--ebk-transaction-day-of-week-font-size: 15px;
|
||||
--ebk-transaction-calendar-amount-font-size: 15px;
|
||||
--ebk-transaction-calendar-daily-amounts-height: 75px;
|
||||
--ebk-transaction-account-arrow-font-size: 15px;
|
||||
--ebk-transaction-account-arrow-margin-top: -3px;
|
||||
--ebk-transaction-tag-icon-font-size: 28px;
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
--ebk-transaction-date-width: 36px;
|
||||
--ebk-transaction-day-font-size: 22px;
|
||||
--ebk-transaction-day-of-week-font-size: 17px;
|
||||
--ebk-transaction-calendar-amount-font-size: 17px;
|
||||
--ebk-transaction-calendar-daily-amounts-height: 80px;
|
||||
--ebk-transaction-account-arrow-font-size: 17px;
|
||||
--ebk-transaction-account-arrow-margin-top: -4px;
|
||||
--ebk-transaction-tag-icon-font-size: 30px;
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
--ebk-transaction-date-width: 40px;
|
||||
--ebk-transaction-day-font-size: 24px;
|
||||
--ebk-transaction-day-of-week-font-size: 19px;
|
||||
--ebk-transaction-calendar-amount-font-size: 19px;
|
||||
--ebk-transaction-calendar-daily-amounts-height: 85px;
|
||||
--ebk-transaction-account-arrow-font-size: 19px;
|
||||
--ebk-transaction-account-arrow-margin-top: -4px;
|
||||
--ebk-transaction-tag-icon-font-size: 32px;
|
||||
|
||||
@@ -108,6 +108,7 @@ i.icon.la, i.icon.las, i.icon.lab {
|
||||
/** custom class **/
|
||||
:root {
|
||||
--default-icon-color: #000;
|
||||
--ebk-primary-color: 198, 126, 72;
|
||||
--ebk-transaction-tag-chip-bg-color: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
@@ -535,6 +536,10 @@ i.icon.la, i.icon.las, i.icon.lab {
|
||||
border-radius: 0 0 var(--f7-list-inset-border-radius) var(--f7-list-inset-border-radius);
|
||||
}
|
||||
|
||||
.combination-list-wrapper.no-accordion-toggle .list.combination-list-content.inset > ul {
|
||||
border-radius: var(--f7-list-inset-border-radius);
|
||||
}
|
||||
|
||||
/** Nested List item for framework7 **/
|
||||
.nested-list-item .item-title {
|
||||
width: 100%;
|
||||
|
||||
@@ -23,9 +23,17 @@ import {
|
||||
getUtcOffsetByUtcOffsetMinutes,
|
||||
getTimezoneOffset,
|
||||
getTimezoneOffsetMinutes,
|
||||
getBrowserTimezoneOffsetMinutes,
|
||||
getLocalDatetimeFromUnixTime,
|
||||
getActualUnixTimeForStore,
|
||||
getDummyUnixTimeForLocalUsage,
|
||||
parseDateFromUnixTime,
|
||||
getUnixTime,
|
||||
getYearMonthFirstUnixTime
|
||||
getYear,
|
||||
getMonth,
|
||||
getDay,
|
||||
getYearMonthFirstUnixTime,
|
||||
isDateRangeMatchOneMonth
|
||||
} from '@/lib/datetime.ts';
|
||||
|
||||
import {
|
||||
@@ -162,6 +170,7 @@ export function useTransactionListPageBase() {
|
||||
});
|
||||
const queryMinTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.minTime));
|
||||
const queryMaxTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.maxTime));
|
||||
const queryMonthlyData = computed<boolean>(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime));
|
||||
const queryAllFilterCategoryIds = computed<Record<string, boolean>>(() => transactionsStore.allFilterCategoryIds);
|
||||
const queryAllFilterAccountIds = computed<Record<string, boolean>>(() => transactionsStore.allFilterAccountIds);
|
||||
const queryAllFilterTagIds = computed<Record<string, boolean>>(() => transactionsStore.allFilterTagIds);
|
||||
@@ -217,6 +226,34 @@ export function useTransactionListPageBase() {
|
||||
return displayAmount.join(' ~ ');
|
||||
});
|
||||
|
||||
const transactionCalendarMinDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(query.value.minTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())));
|
||||
const transactionCalendarMaxDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(query.value.maxTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())));
|
||||
|
||||
const currentMonthTransactionData = computed<TransactionMonthList | null>(() => {
|
||||
const allTransactions = transactionsStore.transactions;
|
||||
|
||||
if (!allTransactions || !allTransactions.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime);
|
||||
const currentYear = getYear(currentMonthMinDate);
|
||||
const currentMonth = getMonth(currentMonthMinDate);
|
||||
|
||||
for (let i = 0; i < allTransactions.length; i++) {
|
||||
if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) {
|
||||
return allTransactions[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
function noTransactionInMonthDay(date: Date): boolean {
|
||||
const dateTime = parseDateFromUnixTime(getActualUnixTimeForStore(getUnixTime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
||||
return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[getDay(dateTime)];
|
||||
}
|
||||
|
||||
const canAddTransaction = computed<boolean>(() => {
|
||||
if (query.value.accountIds && queryAllFilterAccountIdsCount.value === 1) {
|
||||
const account = allAccountsMap.value[query.value.accountIds];
|
||||
@@ -335,6 +372,7 @@ export function useTransactionListPageBase() {
|
||||
queryDateRangeName,
|
||||
queryMinTime,
|
||||
queryMaxTime,
|
||||
queryMonthlyData,
|
||||
queryAllFilterCategoryIds,
|
||||
queryAllFilterAccountIds,
|
||||
queryAllFilterTagIds,
|
||||
@@ -345,6 +383,10 @@ export function useTransactionListPageBase() {
|
||||
queryCategoryName,
|
||||
queryTagName,
|
||||
queryAmount,
|
||||
transactionCalendarMinDate,
|
||||
transactionCalendarMaxDate,
|
||||
currentMonthTransactionData,
|
||||
noTransactionInMonthDay,
|
||||
canAddTransaction,
|
||||
// functions
|
||||
getDisplayTime,
|
||||
|
||||
@@ -146,8 +146,8 @@
|
||||
:month-change-on-arrows="false"
|
||||
:enable-time-picker="false"
|
||||
:hide-offset-dates="true"
|
||||
:min-date="getShortDate(parseDateFromUnixTime(query.minTime))"
|
||||
:max-date="getShortDate(parseDateFromUnixTime(query.maxTime))"
|
||||
:min-date="transactionCalendarMinDate"
|
||||
:max-date="transactionCalendarMaxDate"
|
||||
:disabled-dates="noTransactionInMonthDay"
|
||||
:prevent-min-max-navigation="true"
|
||||
:clearable="false"
|
||||
@@ -648,7 +648,7 @@ import { useSettingsStore } from '@/stores/setting.ts';
|
||||
import { useAccountsStore } from '@/stores/account.ts';
|
||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||
import { type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts';
|
||||
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.ts';
|
||||
import { useDesktopPageStore } from '@/stores/desktopPage.ts';
|
||||
|
||||
@@ -676,10 +676,8 @@ import {
|
||||
import {
|
||||
getCurrentUnixTime,
|
||||
parseDateFromUnixTime,
|
||||
getShortDate,
|
||||
getYear,
|
||||
getMonth,
|
||||
getDay,
|
||||
getSpecifiedDayFirstUnixTime,
|
||||
getBrowserTimezoneOffsetMinutes,
|
||||
getActualUnixTimeForStore,
|
||||
@@ -691,8 +689,7 @@ import {
|
||||
getDateRangeByBillingCycleDateType,
|
||||
getRecentDateRangeIndex,
|
||||
getFullMonthDateRange,
|
||||
getMonthFirstDayOrCurrentDayShortDate,
|
||||
isDateRangeMatchOneMonth
|
||||
getMonthFirstDayOrCurrentDayShortDate
|
||||
} from '@/lib/datetime.ts';
|
||||
import {
|
||||
categoryTypeToTransactionType,
|
||||
@@ -763,7 +760,6 @@ const {
|
||||
getAllLongWeekdayNames,
|
||||
getAllRecentMonthDateRanges,
|
||||
getAllTransactionTagFilterTypes,
|
||||
getMonthShortName,
|
||||
getWeekdayLongName
|
||||
} = useI18n();
|
||||
|
||||
@@ -790,6 +786,7 @@ const {
|
||||
query,
|
||||
queryMinTime,
|
||||
queryMaxTime,
|
||||
queryMonthlyData,
|
||||
queryAllFilterCategoryIds,
|
||||
queryAllFilterAccountIds,
|
||||
queryAllFilterTagIds,
|
||||
@@ -800,6 +797,10 @@ const {
|
||||
queryCategoryName,
|
||||
queryTagName,
|
||||
queryAmount,
|
||||
transactionCalendarMinDate,
|
||||
transactionCalendarMaxDate,
|
||||
currentMonthTransactionData,
|
||||
noTransactionInMonthDay,
|
||||
canAddTransaction,
|
||||
getDisplayTime,
|
||||
getDisplayLongDate,
|
||||
@@ -930,26 +931,6 @@ const transactions = computed<Transaction[]>(() => {
|
||||
}
|
||||
});
|
||||
|
||||
const currentMonthTransactionData = computed<TransactionMonthList | null>(() => {
|
||||
const allTransactions = transactionsStore.transactions;
|
||||
|
||||
if (!allTransactions || !allTransactions.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime);
|
||||
const currentYear = getYear(currentMonthMinDate);
|
||||
const currentMonth = getMonth(currentMonthMinDate);
|
||||
|
||||
for (let i = 0; i < allTransactions.length; i++) {
|
||||
if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) {
|
||||
return allTransactions[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
const recentDateRangeIndex = computed<number>({
|
||||
get: () => getRecentDateRangeIndex(recentMonthDateRanges.value, query.value.dateType, query.value.minTime, query.value.maxTime, firstDayOfWeek.value),
|
||||
set: (value) => {
|
||||
@@ -1001,8 +982,6 @@ const queryAllSelectedFilterTagIds = computed<string>(() => {
|
||||
}
|
||||
});
|
||||
|
||||
const queryMonthlyData = computed<boolean>(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime));
|
||||
|
||||
const countPerPage = computed<number>({
|
||||
get: () => {
|
||||
if (temporaryCountPerPage.value) {
|
||||
@@ -1066,10 +1045,6 @@ const currentMonthTotalAmount = computed<TransactionListDisplayTotalAmount | nul
|
||||
}
|
||||
});
|
||||
|
||||
function noTransactionInMonthDay(date: Date): boolean {
|
||||
return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[getDay(date)];
|
||||
}
|
||||
|
||||
function getCategoryListItemCheckedClass(category: TransactionCategory, queryCategoryIds: Record<string, boolean>): Record<string, boolean> {
|
||||
if (queryCategoryIds && queryCategoryIds[category.id]) {
|
||||
return {
|
||||
@@ -1150,6 +1125,7 @@ function init(initProps: TransactionListProps): void {
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(query.value.minTime);
|
||||
updateUrlWhenChanged(changed);
|
||||
return;
|
||||
}
|
||||
@@ -1243,6 +1219,7 @@ function changePageType(type: number): void {
|
||||
maxTime: dateRange.maxTime,
|
||||
minTime: dateRange.minTime
|
||||
});
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(query.value.minTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1281,6 +1258,7 @@ function changeDateFilter(dateRange: TimeRangeAndDateType | number | null): void
|
||||
|
||||
if (fullMonthDateRange) {
|
||||
dateRange = fullMonthDateRange;
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(dateRange.minTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1316,6 +1294,7 @@ function changeCustomDateFilter(minTime: number, maxTime: number): void {
|
||||
minTime = dateRange.minTime;
|
||||
maxTime = dateRange.maxTime;
|
||||
dateType = dateRange.dateType;
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(minTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1355,6 +1334,7 @@ function shiftDateRange(startTime: number, endTime: number, scale: number): void
|
||||
|
||||
if (fullMonthDateRange) {
|
||||
newDateRange = fullMonthDateRange;
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(newDateRange.minTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
@infinite="loadMore(true)">
|
||||
<f7-navbar>
|
||||
<f7-nav-left :back-link="tt('Back')"></f7-nav-left>
|
||||
<f7-nav-title :title="tt('Transaction List')"></f7-nav-title>
|
||||
<f7-nav-title>
|
||||
<f7-link popover-open=".chart-data-type-popover-menu">
|
||||
<span style="color: var(--f7-text-color)">{{ displayPageTypeName }}</span>
|
||||
<f7-icon size="16px" color="gray" style="opacity: 0.5" f7="chevron_down_circle_fill"></f7-icon>
|
||||
</f7-link>
|
||||
</f7-nav-title>
|
||||
<f7-nav-right class="navbar-compact-icons">
|
||||
<f7-link icon-f7="plus" :class="{ 'disabled': !canAddTransaction }" :href="`/transaction/add?type=${query.type}&categoryId=${queryAllFilterCategoryIdsCount === 1 ? query.categoryIds : ''}&accountId=${queryAllFilterAccountIdsCount === 1 ? query.accountIds : ''}&tagIds=${query.tagIds || ''}`"></f7-link>
|
||||
</f7-nav-right>
|
||||
@@ -25,6 +30,21 @@
|
||||
</f7-subnavbar>
|
||||
</f7-navbar>
|
||||
|
||||
<f7-popover class="chart-data-type-popover-menu"
|
||||
v-model:opened="showTransactionListPageTypePopover">
|
||||
<f7-list dividers>
|
||||
<f7-list-item :title="tt(type.name)"
|
||||
:class="{ 'list-item-selected': pageType === type.type }"
|
||||
:key="type.type"
|
||||
v-for="type in TransactionListPageType.values()"
|
||||
@click="changePageType(type.type); showTransactionListPageTypePopover = false">
|
||||
<template #after>
|
||||
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="pageType === type.type"></f7-icon>
|
||||
</template>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-popover>
|
||||
|
||||
<f7-toolbar tabbar bottom class="toolbar-item-auto-size transaction-list-toolbar">
|
||||
<f7-link :class="{ 'disabled': loading || query.dateType === DateRange.All.type }" @click="shiftDateRange(query.minTime, query.maxTime, -1)">
|
||||
<f7-icon f7="arrow_left_square"></f7-icon>
|
||||
@@ -46,10 +66,41 @@
|
||||
</f7-link>
|
||||
</f7-toolbar>
|
||||
|
||||
<f7-block class="transaction-calendar-container margin-vertical" v-if="pageType === TransactionListPageType.Calendar.type">
|
||||
<vue-date-picker inline auto-apply model-type="yyyy-M-d"
|
||||
month-name-format="long"
|
||||
class="justify-content-center"
|
||||
:config="{ noSwipe: true }"
|
||||
:readonly="loading"
|
||||
:disable-month-year-select="true"
|
||||
:month-change-on-scroll="false"
|
||||
:month-change-on-arrows="false"
|
||||
:enable-time-picker="false"
|
||||
:hide-offset-dates="true"
|
||||
:min-date="transactionCalendarMinDate"
|
||||
:max-date="transactionCalendarMaxDate"
|
||||
:disabled-dates="noTransactionInMonthDay"
|
||||
:prevent-min-max-navigation="true"
|
||||
:clearable="false"
|
||||
:dark="isDarkMode"
|
||||
:week-start="firstDayOfWeek"
|
||||
:day-names="dayNames"
|
||||
v-model="currentCalendarDate">
|
||||
<template #day="{ day }">
|
||||
<div class="transaction-calendar-daily-amounts display-flex flex-direction-column align-items-center justify-content-center">
|
||||
<span>{{ day }}</span>
|
||||
<small class="text-income" v-if="currentMonthTransactionData && currentMonthTransactionData.dailyTotalAmounts[day] && currentMonthTransactionData.dailyTotalAmounts[day].income">{{ getDisplayMonthTotalAmount(currentMonthTransactionData.dailyTotalAmounts[day].income, false, '', currentMonthTransactionData.dailyTotalAmounts[day].incompleteIncome) }}</small>
|
||||
<small class="text-expense" v-if="currentMonthTransactionData && currentMonthTransactionData.dailyTotalAmounts[day] && currentMonthTransactionData.dailyTotalAmounts[day].expense">{{ getDisplayMonthTotalAmount(currentMonthTransactionData.dailyTotalAmounts[day].expense, false, '', currentMonthTransactionData.dailyTotalAmounts[day].incompleteExpense) }}</small>
|
||||
</div>
|
||||
</template>
|
||||
</vue-date-picker>
|
||||
</f7-block>
|
||||
|
||||
<div class="skeleton-text" v-if="loading">
|
||||
<f7-block class="combination-list-wrapper margin-vertical" :key="blockIdx" v-for="blockIdx in [ 1, 2 ]">
|
||||
<f7-block class="combination-list-wrapper margin-vertical" :class="{ 'no-accordion-toggle': pageType !== TransactionListPageType.List.type }"
|
||||
:key="blockIdx" v-for="blockIdx in (pageType === TransactionListPageType.List.type ? [ 1, 2 ] : [ 1 ])">
|
||||
<f7-accordion-item>
|
||||
<f7-block-title>
|
||||
<f7-block-title v-if="pageType === TransactionListPageType.List.type">
|
||||
<f7-accordion-toggle>
|
||||
<f7-list strong inset dividers media-list
|
||||
class="transaction-amount-list combination-list-header combination-list-opened">
|
||||
@@ -122,12 +173,12 @@
|
||||
<f7-list-item :title="tt('No transaction data')"></f7-list-item>
|
||||
</f7-list>
|
||||
|
||||
<f7-block class="combination-list-wrapper margin-vertical"
|
||||
<f7-block class="combination-list-wrapper margin-vertical" :class="{ 'no-accordion-toggle': pageType !== TransactionListPageType.List.type }"
|
||||
:key="transactionMonthList.yearMonth" v-for="(transactionMonthList) in transactions">
|
||||
<f7-accordion-item :opened="transactionMonthList.opened"
|
||||
@accordion:open="collapseTransactionMonthList(transactionMonthList, false)"
|
||||
@accordion:close="collapseTransactionMonthList(transactionMonthList, true)">
|
||||
<f7-block-title>
|
||||
<f7-block-title v-if="pageType === TransactionListPageType.List.type">
|
||||
<f7-accordion-toggle>
|
||||
<f7-list strong inset dividers media-list
|
||||
class="transaction-amount-list combination-list-header"
|
||||
@@ -254,7 +305,8 @@
|
||||
</f7-accordion-item>
|
||||
</f7-block>
|
||||
|
||||
<f7-block class="text-align-center" :class="{ 'disabled': loadingMore }" v-show="!loading && hasMoreTransaction">
|
||||
<f7-block class="text-align-center" :class="{ 'disabled': loadingMore }" v-show="!loading && hasMoreTransaction"
|
||||
v-if="pageType === TransactionListPageType.List.type">
|
||||
<f7-link href="#" @click="loadMore(false)">{{ tt('Load More') }}</f7-link>
|
||||
</f7-block>
|
||||
|
||||
@@ -266,6 +318,7 @@
|
||||
:class="{ 'list-item-selected': query.dateType === dateRange.type }"
|
||||
:key="dateRange.type"
|
||||
v-for="dateRange in allDateRanges"
|
||||
v-show="pageType === TransactionListPageType.List.type || dateRange.type === DateRange.ThisMonth.type || dateRange.type === DateRange.LastMonth.type || dateRange.type === DateRange.Custom.type"
|
||||
@click="changeDateFilter(dateRange.type)">
|
||||
<template #after>
|
||||
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.dateType === dateRange.type"></f7-icon>
|
||||
@@ -525,8 +578,9 @@ import type { Router } from 'framework7/types';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
import { type Framework7Dom, useI18nUIComponents, showLoading, hideLoading, onSwipeoutDeleted, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
|
||||
import { useTransactionListPageBase } from '@/views/base/transactions/TransactionListPageBase.ts';
|
||||
import { TransactionListPageType, useTransactionListPageBase } from '@/views/base/transactions/TransactionListPageBase.ts';
|
||||
|
||||
import { useEnvironmentsStore } from '@/stores/environment.ts';
|
||||
import { useAccountsStore } from '@/stores/account.ts';
|
||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||
@@ -543,8 +597,12 @@ import { TransactionType } from '@/core/transaction.ts';
|
||||
import type { TransactionCategory } from '@/models/transaction_category.ts';
|
||||
import type { Transaction } from '@/models/transaction.ts';
|
||||
|
||||
import {
|
||||
arrangeArrayWithNewStartIndex
|
||||
} from '@/lib/common.ts';
|
||||
import {
|
||||
getCurrentUnixTime,
|
||||
parseDateFromUnixTime,
|
||||
getSpecifiedDayFirstUnixTime,
|
||||
getBrowserTimezoneOffsetMinutes,
|
||||
getActualUnixTimeForStore,
|
||||
@@ -553,7 +611,9 @@ import {
|
||||
getDateTypeByDateRange,
|
||||
getDateTypeByBillingCycleDateRange,
|
||||
getDateRangeByDateType,
|
||||
getDateRangeByBillingCycleDateType
|
||||
getDateRangeByBillingCycleDateType,
|
||||
getFullMonthDateRange,
|
||||
getMonthFirstDayOrCurrentDayShortDate, getYear, getMonth
|
||||
} from '@/lib/datetime.ts';
|
||||
import {
|
||||
categoryTypeToTransactionType,
|
||||
@@ -567,6 +627,7 @@ const props = defineProps<{
|
||||
|
||||
const {
|
||||
tt,
|
||||
getAllShortWeekdayNames,
|
||||
getAllTransactionTagFilterTypes,
|
||||
getWeekdayShortName
|
||||
} = useI18n();
|
||||
@@ -574,9 +635,11 @@ const {
|
||||
const { showAlert, showToast, routeBackOnError } = useI18nUIComponents();
|
||||
|
||||
const {
|
||||
pageType,
|
||||
loading,
|
||||
customMinDatetime,
|
||||
customMaxDatetime,
|
||||
currentCalendarDate,
|
||||
currentTimezoneOffsetMinutes,
|
||||
firstDayOfWeek,
|
||||
defaultCurrency,
|
||||
@@ -591,10 +654,12 @@ const {
|
||||
allAvailableCategoriesCount,
|
||||
allTransactionTags,
|
||||
allAvailableTagsCount,
|
||||
displayPageTypeName,
|
||||
query,
|
||||
queryDateRangeName,
|
||||
queryMinTime,
|
||||
queryMaxTime,
|
||||
queryMonthlyData,
|
||||
queryAllFilterCategoryIds,
|
||||
queryAllFilterAccountIds,
|
||||
queryAllFilterTagIds,
|
||||
@@ -604,6 +669,10 @@ const {
|
||||
queryAccountName,
|
||||
queryCategoryName,
|
||||
queryAmount,
|
||||
transactionCalendarMinDate,
|
||||
transactionCalendarMaxDate,
|
||||
currentMonthTransactionData,
|
||||
noTransactionInMonthDay,
|
||||
canAddTransaction,
|
||||
getDisplayTime,
|
||||
getDisplayLongYearMonth,
|
||||
@@ -613,14 +682,19 @@ const {
|
||||
getTransactionTypeName,
|
||||
} = useTransactionListPageBase();
|
||||
|
||||
const environmentsStore = useEnvironmentsStore();
|
||||
const accountsStore = useAccountsStore();
|
||||
const transactionCategoriesStore = useTransactionCategoriesStore();
|
||||
const transactionTagsStore = useTransactionTagsStore();
|
||||
const transactionsStore = useTransactionsStore();
|
||||
|
||||
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
|
||||
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllShortWeekdayNames(), firstDayOfWeek.value));
|
||||
|
||||
const loadingError = ref<unknown | null>(null);
|
||||
const loadingMore = ref<boolean>(false);
|
||||
const transactionToDelete = ref<Transaction | null>(null);
|
||||
const showTransactionListPageTypePopover = ref<boolean>(false);
|
||||
const showDatePopover = ref<boolean>(false);
|
||||
const showCategoryPopover = ref<boolean>(false);
|
||||
const showAccountPopover = ref<boolean>(false);
|
||||
@@ -635,10 +709,60 @@ const transactions = computed<TransactionMonthList[]>(() => {
|
||||
return [];
|
||||
}
|
||||
|
||||
return transactionsStore.transactions;
|
||||
if (pageType.value === TransactionListPageType.List.type) {
|
||||
return transactionsStore.transactions;
|
||||
} else if (pageType.value === TransactionListPageType.Calendar.type) {
|
||||
if (queryMonthlyData.value) {
|
||||
const transactionData = currentMonthTransactionData.value;
|
||||
|
||||
if (!transactionData || !transactionData.items) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const transactions :Transaction[] = [];
|
||||
|
||||
for (let i = 0; i < transactionData.items.length; i++) {
|
||||
const transaction = transactionData.items[i];
|
||||
|
||||
if (transaction.date === currentCalendarDate.value) {
|
||||
transactions.push(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
const dailyTransactionList: TransactionMonthList = {
|
||||
year: currentMonthTransactionData.value.year,
|
||||
month: currentMonthTransactionData.value.month,
|
||||
yearMonth: currentMonthTransactionData.value.yearMonth,
|
||||
opened: true,
|
||||
items: transactions,
|
||||
totalAmount: {
|
||||
income: 0,
|
||||
expense: 0,
|
||||
incompleteIncome: false,
|
||||
incompleteExpense: false
|
||||
},
|
||||
dailyTotalAmounts: {}
|
||||
};
|
||||
|
||||
return [dailyTransactionList];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
const noTransaction = computed<boolean>(() => {
|
||||
if (pageType.value === TransactionListPageType.List.type) {
|
||||
return transactionsStore.noTransaction;
|
||||
} else if (pageType.value === TransactionListPageType.Calendar.type) {
|
||||
return !transactions.value || !transactions.value.length || !transactions.value[0].items || !transactions.value[0].items.length;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const noTransaction = computed<boolean>(() => transactionsStore.noTransaction);
|
||||
const hasMoreTransaction = computed<boolean>(() => transactionsStore.hasMoreTransaction);
|
||||
|
||||
function getTransactionDomId(transaction: Transaction): string {
|
||||
@@ -716,11 +840,24 @@ function reload(done?: () => void): void {
|
||||
transactionCategoriesStore.loadAllCategories({ force: false }),
|
||||
transactionTagsStore.loadAllTags({ force: false })
|
||||
]).then(() => {
|
||||
return transactionsStore.loadTransactions({
|
||||
reload: true,
|
||||
autoExpand: true,
|
||||
defaultCurrency: defaultCurrency.value
|
||||
});
|
||||
if (queryMonthlyData.value) {
|
||||
const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime);
|
||||
const currentYear = getYear(currentMonthMinDate);
|
||||
const currentMonth = getMonth(currentMonthMinDate);
|
||||
|
||||
return transactionsStore.loadMonthlyAllTransactions({
|
||||
year: currentYear,
|
||||
month: currentMonth,
|
||||
autoExpand: true,
|
||||
defaultCurrency: defaultCurrency.value
|
||||
});
|
||||
} else {
|
||||
return transactionsStore.loadTransactions({
|
||||
reload: true,
|
||||
autoExpand: true,
|
||||
defaultCurrency: defaultCurrency.value
|
||||
});
|
||||
}
|
||||
}).then(() => {
|
||||
done?.();
|
||||
|
||||
@@ -772,6 +909,28 @@ function loadMore(autoExpand: boolean): void {
|
||||
});
|
||||
}
|
||||
|
||||
function changePageType(type: number): void {
|
||||
pageType.value = type;
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(query.value.minTime);
|
||||
|
||||
if (pageType.value === TransactionListPageType.Calendar.type) {
|
||||
const dateRange = getFullMonthDateRange(query.value.minTime, query.value.maxTime, firstDayOfWeek.value);
|
||||
|
||||
if (dateRange) {
|
||||
const changed = transactionsStore.updateTransactionListFilter({
|
||||
dateType: dateRange.dateType,
|
||||
maxTime: dateRange.maxTime,
|
||||
minTime: dateRange.minTime
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(query.value.minTime);
|
||||
reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function changeDateFilter(dateType: number): void {
|
||||
if (dateType === DateRange.Custom.type) { // Custom
|
||||
if (!query.value.minTime || !query.value.maxTime) {
|
||||
@@ -801,6 +960,16 @@ function changeDateFilter(dateType: number): void {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pageType.value === TransactionListPageType.Calendar.type) {
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(dateRange.minTime);
|
||||
const fullMonthDateRange = getFullMonthDateRange(dateRange.minTime, dateRange.maxTime, firstDayOfWeek.value);
|
||||
|
||||
if (fullMonthDateRange) {
|
||||
dateRange = fullMonthDateRange;
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(dateRange.minTime);
|
||||
}
|
||||
}
|
||||
|
||||
const changed = transactionsStore.updateTransactionListFilter({
|
||||
dateType: dateRange.dateType,
|
||||
maxTime: dateRange.maxTime,
|
||||
@@ -825,6 +994,18 @@ function changeCustomDateFilter(minTime: number, maxTime: number): void {
|
||||
dateType = getDateTypeByDateRange(minTime, maxTime, firstDayOfWeek.value, DateRangeScene.Normal);
|
||||
}
|
||||
|
||||
if (pageType.value === TransactionListPageType.Calendar.type) {
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(minTime);
|
||||
const dateRange = getFullMonthDateRange(minTime, maxTime, firstDayOfWeek.value);
|
||||
|
||||
if (dateRange) {
|
||||
minTime = dateRange.minTime;
|
||||
maxTime = dateRange.maxTime;
|
||||
dateType = dateRange.dateType;
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(minTime);
|
||||
}
|
||||
}
|
||||
|
||||
const changed = transactionsStore.updateTransactionListFilter({
|
||||
dateType: dateType,
|
||||
maxTime: maxTime,
|
||||
@@ -853,6 +1034,16 @@ function shiftDateRange(minTime: number, maxTime: number, scale: number): void {
|
||||
newDateRange = getShiftedDateRangeAndDateType(minTime, maxTime, scale, firstDayOfWeek.value, DateRangeScene.Normal);
|
||||
}
|
||||
|
||||
if (pageType.value === TransactionListPageType.Calendar.type) {
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(newDateRange.minTime);
|
||||
const fullMonthDateRange = getFullMonthDateRange(newDateRange.minTime, newDateRange.maxTime, firstDayOfWeek.value);
|
||||
|
||||
if (fullMonthDateRange) {
|
||||
newDateRange = fullMonthDateRange;
|
||||
currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(newDateRange.minTime);
|
||||
}
|
||||
}
|
||||
|
||||
const changed = transactionsStore.updateTransactionListFilter({
|
||||
dateType: newDateRange.dateType,
|
||||
maxTime: newDateRange.maxTime,
|
||||
@@ -1199,4 +1390,57 @@ init();
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__menu {
|
||||
--dp-border-radius: var(--f7-list-inset-border-radius);
|
||||
--dp-menu-border-color: transparent;
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__menu.dp__theme_dark {
|
||||
--dp-background-color: var(--f7-list-strong-bg-color);
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row {
|
||||
--dp-cell-size: var(--ebk-transaction-calendar-daily-amounts-height);
|
||||
--dp-cell-padding: 1px;
|
||||
--dp-primary-text-color: var(--f7-theme-color);
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--f7-list-group-title-bg-color);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item > .dp__active_date {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item > .dp__today {
|
||||
border: inherit;
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item > .dp__active_date .transaction-calendar-daily-amounts {
|
||||
background-color: rgba(var(--ebk-primary-color), 0.16);
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item > .dp__today .transaction-calendar-daily-amounts {
|
||||
border: 1px solid var(--dp-primary-color);
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > small {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: var(--ebk-transaction-calendar-amount-font-size);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user