support calendar display type (Gregorian and Buddhist)

This commit is contained in:
MaysWind
2025-08-28 00:31:59 +08:00
parent c099443783
commit 411130db4e
47 changed files with 769 additions and 788 deletions
+3
View File
@@ -9,6 +9,7 @@ type CalendarDisplayType byte
const ( const (
CALENDAR_DISPLAY_TYPE_DEFAULT CalendarDisplayType = 0 CALENDAR_DISPLAY_TYPE_DEFAULT CalendarDisplayType = 0
CALENDAR_DISPLAY_TYPE_GREGORAIN CalendarDisplayType = 1 CALENDAR_DISPLAY_TYPE_GREGORAIN CalendarDisplayType = 1
CALENDAR_DISPLAY_TYPE_BUDDHIST CalendarDisplayType = 2
CALENDAR_DISPLAY_TYPE_INVALID CalendarDisplayType = 255 CALENDAR_DISPLAY_TYPE_INVALID CalendarDisplayType = 255
) )
@@ -19,6 +20,8 @@ func (f CalendarDisplayType) String() string {
return "Default" return "Default"
case CALENDAR_DISPLAY_TYPE_GREGORAIN: case CALENDAR_DISPLAY_TYPE_GREGORAIN:
return "Gregorian" return "Gregorian"
case CALENDAR_DISPLAY_TYPE_BUDDHIST:
return "Buddhist"
case CALENDAR_DISPLAY_TYPE_INVALID: case CALENDAR_DISPLAY_TYPE_INVALID:
return "Invalid" return "Invalid"
default: default:
+1 -1
View File
@@ -199,7 +199,7 @@ type UserProfileUpdateRequest struct {
DefaultCurrency string `json:"defaultCurrency" binding:"omitempty,len=3,validCurrency"` DefaultCurrency string `json:"defaultCurrency" binding:"omitempty,len=3,validCurrency"`
FirstDayOfWeek *core.WeekDay `json:"firstDayOfWeek" binding:"omitempty,min=0,max=6"` FirstDayOfWeek *core.WeekDay `json:"firstDayOfWeek" binding:"omitempty,min=0,max=6"`
FiscalYearStart *core.FiscalYearStart `json:"fiscalYearStart" binding:"omitempty,validFiscalYearStart"` FiscalYearStart *core.FiscalYearStart `json:"fiscalYearStart" binding:"omitempty,validFiscalYearStart"`
CalendarDisplayType *core.CalendarDisplayType `json:"calendarDisplayType" binding:"omitempty,min=0,max=1"` CalendarDisplayType *core.CalendarDisplayType `json:"calendarDisplayType" binding:"omitempty,min=0,max=2"`
DateDisplayType *core.DateDisplayType `json:"dateDisplayType" binding:"omitempty,min=0,max=2"` DateDisplayType *core.DateDisplayType `json:"dateDisplayType" binding:"omitempty,min=0,max=2"`
LongDateFormat *core.LongDateFormat `json:"longDateFormat" binding:"omitempty,min=0,max=3"` LongDateFormat *core.LongDateFormat `json:"longDateFormat" binding:"omitempty,min=0,max=3"`
ShortDateFormat *core.ShortDateFormat `json:"shortDateFormat" binding:"omitempty,min=0,max=3"` ShortDateFormat *core.ShortDateFormat `json:"shortDateFormat" binding:"omitempty,min=0,max=3"`
+2 -2
View File
@@ -293,8 +293,8 @@ func (s *UserService) UpdateUser(c core.Context, user *models.User, modifyUserLa
updateCols = append(updateCols, "fiscal_year_start") updateCols = append(updateCols, "fiscal_year_start")
} }
if core.CALENDAR_DISPLAY_TYPE_DEFAULT <= user.CalendarDisplayType && user.CalendarDisplayType <= core.CALENDAR_DISPLAY_TYPE_GREGORAIN { if core.CALENDAR_DISPLAY_TYPE_DEFAULT <= user.CalendarDisplayType && user.CalendarDisplayType <= core.CALENDAR_DISPLAY_TYPE_BUDDHIST {
updateCols = append(updateCols, "calendar_type") updateCols = append(updateCols, "calendar_display_type")
} }
if core.DATE_DISPLAY_TYPE_DEFAULT <= user.DateDisplayType && user.DateDisplayType <= core.DATE_DISPLAY_TYPE_BUDDHIST { if core.DATE_DISPLAY_TYPE_DEFAULT <= user.DateDisplayType && user.DateDisplayType <= core.DATE_DISPLAY_TYPE_BUDDHIST {
+2 -12
View File
@@ -1,10 +1,9 @@
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { type TimeRangeAndDateType, type PresetDateRange, type UnixTimeRange, type WeekDayValue, DateRange } from '@/core/datetime.ts'; import { type TimeRangeAndDateType, type PresetDateRange, type UnixTimeRange, type WeekDayValue, DateRange } from '@/core/datetime.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { import {
getCurrentUnixTime, getCurrentUnixTime,
getAllowedYearRange,
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
getUnixTimeFromLocalDatetime, getUnixTimeFromLocalDatetime,
getTodayFirstUnixTime, getTodayFirstUnixTime,
@@ -46,21 +45,16 @@ function getDateRangeFromProps(props: CommonDateRangeSelectionProps): { minDate:
} }
export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) { export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) {
const { tt, getAllMinWeekdayNames, formatUnixTimeToLongDateTime, isLongDateMonthAfterYear, isLongTime24HourFormat } = useI18n(); const { tt, formatUnixTimeToLongDateTime } = useI18n();
const userStore = useUserStore(); const userStore = useUserStore();
const { minDate, maxDate } = getDateRangeFromProps(props); const { minDate, maxDate } = getDateRangeFromProps(props);
const yearRange = ref<number[]>(getAllowedYearRange());
const dateRange = ref<Date[]>([ const dateRange = ref<Date[]>([
getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(minDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())), getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(minDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())),
getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(maxDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())) getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(maxDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))
]); ]);
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek); const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value));
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
const is24Hour = computed<boolean>(() => isLongTime24HourFormat());
const beginDateTime = computed<string>(() => { const beginDateTime = computed<string>(() => {
const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[0]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[0]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes());
return formatUnixTimeToLongDateTime(actualBeginUnixTime); return formatUnixTimeToLongDateTime(actualBeginUnixTime);
@@ -123,12 +117,8 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
return { return {
// states // states
yearRange,
dateRange, dateRange,
// computed states // computed states
dayNames,
isYearFirst,
is24Hour,
beginDateTime, beginDateTime,
endDateTime, endDateTime,
presetRanges, presetRanges,
@@ -2,12 +2,7 @@ import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useUserStore } from '@/stores/user.ts';
import { type NameValue } from '@/core/base.ts'; import { type NameValue } from '@/core/base.ts';
import { type WeekDayValue } from '@/core/datetime.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { getAllowedYearRange } from '@/lib/datetime.ts';
export interface TimePickerValue { export interface TimePickerValue {
value: string; value: string;
@@ -16,9 +11,7 @@ export interface TimePickerValue {
export function useDateTimeSelectionBase() { export function useDateTimeSelectionBase() {
const { const {
getAllMinWeekdayNames,
getAllMeridiemIndicators, getAllMeridiemIndicators,
isLongDateMonthAfterYear,
isLongTime24HourFormat, isLongTime24HourFormat,
isLongTimeMeridiemIndicatorFirst, isLongTimeMeridiemIndicatorFirst,
isLongTimeHourTwoDigits, isLongTimeHourTwoDigits,
@@ -26,22 +19,14 @@ export function useDateTimeSelectionBase() {
isLongTimeSecondTwoDigits isLongTimeSecondTwoDigits
} = useI18n(); } = useI18n();
const userStore = useUserStore();
const is24Hour = ref<boolean>(isLongTime24HourFormat()); const is24Hour = ref<boolean>(isLongTime24HourFormat());
const isHourTwoDigits = ref<boolean>(isLongTimeHourTwoDigits()); const isHourTwoDigits = ref<boolean>(isLongTimeHourTwoDigits());
const isMinuteTwoDigits = ref<boolean>(isLongTimeMinuteTwoDigits()); const isMinuteTwoDigits = ref<boolean>(isLongTimeMinuteTwoDigits());
const isSecondTwoDigits = ref<boolean>(isLongTimeSecondTwoDigits()); const isSecondTwoDigits = ref<boolean>(isLongTimeSecondTwoDigits());
const isMeridiemIndicatorFirst = ref<boolean>(isLongTimeMeridiemIndicatorFirst() || false); const isMeridiemIndicatorFirst = ref<boolean>(isLongTimeMeridiemIndicatorFirst() || false);
const yearRange = ref<number[]>(getAllowedYearRange());
const meridiemItems = computed<NameValue[]>(() => getAllMeridiemIndicators()); const meridiemItems = computed<NameValue[]>(() => getAllMeridiemIndicators());
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value));
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
function getDisplayTimeValue(value: number, forceTwoDigits: boolean): string { function getDisplayTimeValue(value: number, forceTwoDigits: boolean): string {
if (forceTwoDigits && value < 10) { if (forceTwoDigits && value < 10) {
return `0${value}`; return `0${value}`;
@@ -96,12 +81,8 @@ export function useDateTimeSelectionBase() {
isMinuteTwoDigits, isMinuteTwoDigits,
isSecondTwoDigits, isSecondTwoDigits,
isMeridiemIndicatorFirst, isMeridiemIndicatorFirst,
yearRange,
// computed // computed
meridiemItems, meridiemItems,
firstDayOfWeek,
dayNames,
isYearFirst,
// functions // functions
getDisplayTimeValue, getDisplayTimeValue,
generateAllHours, generateAllHours,
@@ -2,11 +2,9 @@ import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useUserStore } from '@/stores/user.ts'; import type { MonthDay } from '@/core/datetime.ts';
import { type WeekDayValue } from '@/core/datetime.ts';
import { FiscalYearStart } from '@/core/fiscalyear.ts'; import { FiscalYearStart } from '@/core/fiscalyear.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { import {
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
getThisYearFirstUnixTime, getThisYearFirstUnixTime,
@@ -39,12 +37,7 @@ function getFiscalYearStartFromProps(props: CommonFiscalYearStartSelectionProps)
} }
export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSelectionProps) { export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSelectionProps) {
const { const { formatGregorianCalendarMonthDashDayToLongMonthDay } = useI18n();
getAllMinWeekdayNames,
formatGregorianCalendarMonthDashDayToLongMonthDay
} = useI18n();
const userStore = useUserStore();
const disabledDates = (date: Date) => { const disabledDates = (date: Date) => {
// Disable February 29 (leap day) // Disable February 29 (leap day)
@@ -53,18 +46,15 @@ export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSele
const selectedFiscalYearStart = ref<number>(getFiscalYearStartFromProps(props)); const selectedFiscalYearStart = ref<number>(getFiscalYearStartFromProps(props));
const selectedFiscalYearStartValue = computed<string>({ const selectedFiscalYearStartValue = computed<Date>({
get: () => { get: () => {
const fiscalYearStart = FiscalYearStart.valueOf(selectedFiscalYearStart.value); const fiscalYearStart = FiscalYearStart.valueOf(selectedFiscalYearStart.value);
const monthDay: MonthDay = fiscalYearStart?.toMonthDay() ?? FiscalYearStart.Default.toMonthDay();
if (fiscalYearStart) { return new Date(new Date().getFullYear(), monthDay.month - 1, monthDay.day);
return fiscalYearStart.toMonthDashDayString();
} else {
return FiscalYearStart.Default.toMonthDashDayString();
}
}, },
set: (value: string) => { set: (value: Date) => {
const fiscalYearStart = FiscalYearStart.parse(value); const fiscalYearStart = FiscalYearStart.of(value.getMonth() + 1, value.getDate());
if (fiscalYearStart) { if (fiscalYearStart) {
selectedFiscalYearStart.value = fiscalYearStart.value; selectedFiscalYearStart.value = fiscalYearStart.value;
@@ -87,9 +77,6 @@ export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSele
const allowedMinDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getThisYearFirstUnixTime())); const allowedMinDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getThisYearFirstUnixTime()));
const allowedMaxDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getThisYearLastUnixTime())); const allowedMaxDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getThisYearLastUnixTime()));
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value));
return { return {
// constants // constants
disabledDates, disabledDates,
@@ -99,8 +86,6 @@ export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSele
selectedFiscalYearStartValue, selectedFiscalYearStartValue,
displayFiscalYearStartDate, displayFiscalYearStartDate,
allowedMinDate, allowedMinDate,
allowedMaxDate, allowedMaxDate
firstDayOfWeek,
dayNames
}; };
} }
+10 -52
View File
@@ -7,7 +7,6 @@ import {
getYear0BasedMonthObjectFromString, getYear0BasedMonthObjectFromString,
getYearMonthStringFromYear0BasedMonthObject, getYearMonthStringFromYear0BasedMonthObject,
getCurrentUnixTime, getCurrentUnixTime,
getAllowedYearRange,
getThisYearFirstUnixTime, getThisYearFirstUnixTime,
getYearMonthFirstUnixTime, getYearMonthFirstUnixTime,
getYearMonthLastUnixTime getYearMonthLastUnixTime
@@ -15,11 +14,6 @@ import {
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
export interface MonthSelectionValue {
year: number;
month: number; // 0-based month (0 = January, 11 = December)
}
export interface CommonMonthRangeSelectionProps { export interface CommonMonthRangeSelectionProps {
minTime?: TextualYearMonth; minTime?: TextualYearMonth;
maxTime?: TextualYearMonth; maxTime?: TextualYearMonth;
@@ -28,7 +22,7 @@ export interface CommonMonthRangeSelectionProps {
show: boolean; show: boolean;
} }
function getMonthRangeFromProps(props: CommonMonthRangeSelectionProps): { minDate: MonthSelectionValue; maxDate: MonthSelectionValue } { function getMonthRangeFromProps(props: CommonMonthRangeSelectionProps): { minDate: Year0BasedMonth; maxDate: Year0BasedMonth } {
let minDate: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getThisYearFirstUnixTime()); let minDate: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getThisYearFirstUnixTime());
let maxDate: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getCurrentUnixTime()); let maxDate: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getCurrentUnixTime());
@@ -49,67 +43,34 @@ function getMonthRangeFromProps(props: CommonMonthRangeSelectionProps): { minDat
} }
return { return {
minDate: { minDate: minDate,
year: minDate.year, maxDate: maxDate
month: minDate.month0base
},
maxDate: {
year: maxDate.year,
month: maxDate.month0base
}
}; };
} }
export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps) { export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps) {
const { formatUnixTimeToLongYearMonth, isLongDateMonthAfterYear } = useI18n(); const { formatUnixTimeToLongYearMonth } = useI18n();
const { minDate, maxDate } = getMonthRangeFromProps(props); const { minDate, maxDate } = getMonthRangeFromProps(props);
const yearRange = ref<number[]>(getAllowedYearRange()); const dateRange = ref<Year0BasedMonth[]>([
const dateRange = ref<MonthSelectionValue[]>([
minDate, minDate,
maxDate maxDate
]); ]);
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear()); const beginDateTime = computed<string>(() => formatUnixTimeToLongYearMonth(getYearMonthFirstUnixTime(dateRange.value[0])));
const beginDateTime = computed<string>(() => formatUnixTimeToLongYearMonth(getYearMonthFirstUnixTime({ const endDateTime = computed<string>(() => formatUnixTimeToLongYearMonth(getYearMonthLastUnixTime(dateRange.value[1])));
year: dateRange.value[0].year,
month0base: dateRange.value[0].month
})));
const endDateTime = computed<string>(() => formatUnixTimeToLongYearMonth(getYearMonthLastUnixTime({
year: dateRange.value[1].year,
month0base: dateRange.value[1].month
})));
function getMonthSelectionValue(yearMonth: TextualYearMonth): MonthSelectionValue | null {
const yearMonthObj = getYear0BasedMonthObjectFromString(yearMonth);
if (!yearMonthObj) {
return null;
}
return {
year: yearMonthObj.year,
month: yearMonthObj.month0base
};
}
function getFinalMonthRange(): { minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | '' } | null { function getFinalMonthRange(): { minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | '' } | null {
if (!dateRange.value[0] || !dateRange.value[1]) { if (!dateRange.value[0] || !dateRange.value[1]) {
return null; return null;
} }
if (dateRange.value[0].year <= 0 || dateRange.value[0].month < 0 || dateRange.value[1].year <= 0 || dateRange.value[1].month < 0) { if (dateRange.value[0].year <= 0 || dateRange.value[0].month0base < 0 || dateRange.value[1].year <= 0 || dateRange.value[1].month0base < 0) {
throw new Error('Date is too early'); throw new Error('Date is too early');
} }
const minYearMonth = getYearMonthStringFromYear0BasedMonthObject({ const minYearMonth = getYearMonthStringFromYear0BasedMonthObject(dateRange.value[0]);
year: dateRange.value[0].year, const maxYearMonth = getYearMonthStringFromYear0BasedMonthObject(dateRange.value[1]);
month0base: dateRange.value[0].month
});
const maxYearMonth = getYearMonthStringFromYear0BasedMonthObject({
year: dateRange.value[1].year,
month0base: dateRange.value[1].month
});
return { return {
minYearMonth, minYearMonth,
@@ -119,14 +80,11 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps
return { return {
// states // states
yearRange,
dateRange, dateRange,
// computed states // computed states
isYearFirst,
beginDateTime, beginDateTime,
endDateTime, endDateTime,
// functions // functions
getMonthSelectionValue,
getFinalMonthRange getFinalMonthRange
}; };
} }
-82
View File
@@ -1,82 +0,0 @@
import { ref, computed } from 'vue';
import type { Year0BasedMonth } from '@/core/datetime.ts';
import {
getYear0BasedMonthObjectFromUnixTime,
getAllowedYearRange,
getThisMonthFirstUnixTime
} from '@/lib/datetime.ts';
import { useI18n } from '@/locales/helpers.ts';
export interface MonthSelectionValue {
year: number;
month: number; // 0-based month (0 = January, 11 = December)
}
export interface CommonMonthSelectionProps {
modelValue?: Year0BasedMonth;
title?: string;
hint?: string;
show: boolean;
}
function getYearMonthValueFromProps(props: CommonMonthSelectionProps): MonthSelectionValue {
let value: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getThisMonthFirstUnixTime());
if (props.modelValue) {
value = props.modelValue;
}
return {
year: value.year,
month: value.month0base
};
}
export function useMonthSelectionBase(props: CommonMonthSelectionProps) {
const { isLongDateMonthAfterYear } = useI18n();
const yearRange = ref<number[]>(getAllowedYearRange());
const monthValue = ref<MonthSelectionValue>(getYearMonthValueFromProps(props));
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
function getMonthSelectionValue(yearMonth: Year0BasedMonth): MonthSelectionValue | null {
if (!yearMonth) {
return null;
}
return {
year: yearMonth.year,
month: yearMonth.month0base
};
}
function getYear0BasedMonth(): Year0BasedMonth | null {
if (!monthValue.value) {
return null;
}
if (monthValue.value.year <= 0 || monthValue.value.month < 0) {
throw new Error('Date is too early');
}
return {
year: monthValue.value.year,
month0base: monthValue.value.month
};
}
return {
// states
yearRange,
monthValue,
// computed states
isYearFirst,
// functions
getMonthSelectionValue,
getYear0BasedMonth
};
}
+133
View File
@@ -0,0 +1,133 @@
<template>
<vue-date-picker ref="datetimepicker"
inline auto-apply
enable-seconds
six-weeks="center"
:class="datetimePickerClass"
:config="noSwipeAndScroll ? { noSwipe: true } : undefined"
:dark="isDarkMode"
:vertical="vertical"
:enable-time-picker="enableTimePicker"
:disable-year-select="disableYearSelect"
:clearable="!!clearable"
:year-range="yearRange"
:day-names="dayNames"
:week-start="firstDayOfWeek"
:year-first="isYearFirst"
:is24="is24Hour"
:min-date="minDate"
:max-date="maxDate"
:disabled-dates="disabledDates"
:month-change-on-scroll="!noSwipeAndScroll"
:range="isDateRange ? { partialRange: false } : undefined"
:preset-dates="presetRanges"
v-model="dateTime">
<template #year="{ value }">
{{ getDisplayYear(value) }}
</template>
<template #year-overlay-value="{ value }">
{{ getDisplayYear(value) }}
</template>
<template #month="{ value }">
{{ getDisplayMonth(value) }}
</template>
<template #month-overlay-value="{ value }">
{{ getDisplayMonth(value) }}
</template>
<template #day="{ date }">
{{ getDisplayDay(date) }}
</template>
<template #am-pm-button="{ toggle, value }">
<button class="dp__pm_am_button" tabindex="0" @click="toggle">{{ tt(`datetime.${value}.content`) }}</button>
</template>
</vue-date-picker>
</template>
<script setup lang="ts">
import { computed, useTemplateRef } from 'vue';
import VueDatePicker, { type MenuView } from '@vuepic/vue-datepicker';
import { useI18n } from '@/locales/helpers.ts';
import { useUserStore } from '@/stores/user.ts';
import { type PresetDateRange, type WeekDayValue } from '@/core/datetime.ts';
import { isArray, arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { getAllowedYearRange, getYearMonthDayDateTime } from '@/lib/datetime.ts';
type VueDatePickerType = InstanceType<typeof VueDatePicker>;
type SupportedModelValue = Date | Date[] | null;
const props = defineProps<{
modelValue: SupportedModelValue;
datetimePickerClass?: string;
isDarkMode: boolean;
enableTimePicker: boolean;
disableYearSelect?: boolean;
vertical?: boolean;
noSwipeAndScroll?: boolean;
clearable?: boolean;
minDate?: Date;
maxDate?: Date;
disabledDates?: (date: Date) => boolean;
presetRanges?: PresetDateRange[];
}>();
const emit = defineEmits<{
(e: 'update:modelValue', value: SupportedModelValue): void;
}>();
const {
tt,
getAllMinWeekdayNames,
isLongDateMonthAfterYear,
isLongTime24HourFormat,
getCalendarShortYearFromUnixTime,
getCalendarShortMonthFromUnixTime,
getCalendarDayOfMonthFromUnixTime
} = useI18n();
const userStore = useUserStore();
const datetimepicker = useTemplateRef<VueDatePickerType>('datetimepicker');
const yearRange = getAllowedYearRange();
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value));
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
const is24Hour = computed<boolean>(() => isLongTime24HourFormat());
const dateTime = computed<SupportedModelValue>({
get: () => props.modelValue,
set: (value: SupportedModelValue) => emit('update:modelValue', value)
});
const isDateRange = computed<boolean>(() => isArray(props.modelValue));
function switchView(viewType: MenuView): void {
datetimepicker.value?.switchView(viewType);
}
function getDisplayYear(year: number): string {
return getCalendarShortYearFromUnixTime(getYearMonthDayDateTime(year, 1, 1).getUnixTime());
}
function getDisplayMonth(month: number): string {
if (isArray(dateTime.value)) {
return getCalendarShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0].getFullYear(), month + 1, 1).getUnixTime());
} else if (dateTime.value) {
return getCalendarShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value.getFullYear(), month + 1, 1).getUnixTime());
} else {
return getCalendarShortMonthFromUnixTime(getYearMonthDayDateTime(new Date().getFullYear(), month + 1, 1).getUnixTime());
}
}
function getDisplayDay(date: Date): string {
return getCalendarDayOfMonthFromUnixTime(getYearMonthDayDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate()).getUnixTime());
}
defineExpose({
switchView
});
</script>
+110
View File
@@ -0,0 +1,110 @@
<template>
<vue-date-picker inline auto-apply
month-picker
:class="monthPickerClass"
:dark="isDarkMode"
:clearable="!!clearable"
:year-range="yearRange"
:year-first="isYearFirst"
:range="isDateRange ? { partialRange: false } : undefined"
v-model="dateTime">
<!-- @vue-expect-error It seems to be a bug in vue-date-picker (https://github.com/Vuepic/vue-datepicker/issues/1154), when using the month picker, it does not provide the value and text props in the slot, but provides the year. -->
<template #year="{ year }">
{{ getDisplayYear(year) }}
</template>
<template #year-overlay-value="{ value }">
{{ getDisplayYear(value) }}
</template>
<template #month="{ value }">
{{ getDisplayMonth(value) }}
</template>
<template #month-overlay-value="{ value }">
{{ getDisplayMonth(value) }}
</template>
</vue-date-picker>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import VueDatePicker from '@vuepic/vue-datepicker';
import { useI18n } from '@/locales/helpers.ts';
import type { Year0BasedMonth } from '@/core/datetime.ts';
import { isArray } from '@/lib/common.ts';
import { getAllowedYearRange, getYearMonthDayDateTime } from '@/lib/datetime.ts';
export interface MonthSelectionValue {
year: number;
month: number; // 0-based month (0 = January, 11 = December)
}
type SupportedModelValue = Year0BasedMonth | Year0BasedMonth[];
const props = defineProps<{
modelValue: SupportedModelValue;
monthPickerClass?: string;
isDarkMode: boolean;
clearable?: boolean;
}>();
const emit = defineEmits<{
(e: 'update:modelValue', value: SupportedModelValue): void;
}>();
const {
isLongDateMonthAfterYear,
getCalendarShortYearFromUnixTime,
getCalendarShortMonthFromUnixTime
} = useI18n();
const yearRange = getAllowedYearRange();
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
const dateTime = computed<MonthSelectionValue | MonthSelectionValue[]>({
get: () => {
if (isArray(props.modelValue)) {
return props.modelValue.map(item => getMonthSelectionValueFromYear0BasedMonth(item));
} else {
return getMonthSelectionValueFromYear0BasedMonth(props.modelValue);
}
},
set: (value: MonthSelectionValue | MonthSelectionValue[]) => {
if (isArray(value)) {
emit('update:modelValue', value.map(item => getYear0BasedMonthFromMonthSelectionValue(item)));
} else {
emit('update:modelValue', getYear0BasedMonthFromMonthSelectionValue(value));
}
}
});
const isDateRange = computed<boolean>(() => isArray(props.modelValue));
function getMonthSelectionValueFromYear0BasedMonth(value: Year0BasedMonth): MonthSelectionValue {
return {
year: value.year,
month: value.month0base
};
}
function getYear0BasedMonthFromMonthSelectionValue(value: MonthSelectionValue): Year0BasedMonth {
return {
year: value.year,
month0base: value.month
};
}
function getDisplayYear(year: number): string {
return getCalendarShortYearFromUnixTime(getYearMonthDayDateTime(year, 1, 1).getUnixTime());
}
function getDisplayMonth(month: number): string {
if (isArray(dateTime.value)) {
return getCalendarShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0].year, month + 1, 1).getUnixTime());
} else {
return getCalendarShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value.year, month + 1, 1).getUnixTime());
}
}
</script>
@@ -0,0 +1,115 @@
<template>
<vue-date-picker inline auto-apply
model-type="yyyy-MM-dd"
:class="`transaction-calendar ${calendarClass}`"
:config="{ noSwipe: true }"
:readonly="readonly"
:dark="isDarkMode"
:enable-time-picker="false"
:clearable="false"
:day-names="dayNames"
:week-start="firstDayOfWeek"
:min-date="minDate"
:max-date="maxDate"
:disabled-dates="noTransactionInMonthDay"
:prevent-min-max-navigation="true"
:hide-offset-dates="true"
:disable-month-year-select="true"
:month-change-on-scroll="false"
:month-change-on-arrows="false"
v-model="dateTime">
<template #day="{ day, date }">
<div class="transaction-calendar-daily-amounts">
<span :class="dayHasTransactionClass && dailyTotalAmounts && dailyTotalAmounts[day] ? dayHasTransactionClass : undefined">{{ getDisplayDay(date) }}</span>
<span class="transaction-calendar-daily-amount text-income" v-if="dailyTotalAmounts && dailyTotalAmounts[day] && dailyTotalAmounts[day].income">{{ getDisplayMonthTotalAmount(dailyTotalAmounts[day].income, defaultCurrency, '', dailyTotalAmounts[day].incompleteIncome) }}</span>
<span class="transaction-calendar-daily-amount text-expense" v-if="dailyTotalAmounts && dailyTotalAmounts[day] && dailyTotalAmounts[day].expense">{{ getDisplayMonthTotalAmount(dailyTotalAmounts[day].expense, defaultCurrency, '', dailyTotalAmounts[day].incompleteExpense) }}</span>
</div>
</template>
</vue-date-picker>
</template>
<script setup lang="ts">
import { computed, } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { useUserStore } from '@/stores/user.ts';
import type { TransactionTotalAmount } from '@/stores/transaction.ts';
import { type TextualYearMonthDay, type WeekDayValue } from '@/core/datetime.ts';
import { INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import {
getTimezoneOffsetMinutes,
getBrowserTimezoneOffsetMinutes,
getUnixTimeFromLocalDatetime,
getActualUnixTimeForStore,
getYearMonthDayDateTime,
parseDateTimeFromUnixTime
} from '@/lib/datetime.ts';
const props = defineProps<{
modelValue: TextualYearMonthDay | '';
isDarkMode: boolean;
defaultCurrency: string | false;
minDate: Date;
maxDate: Date;
weekDayNameType?: 'long' | 'short';
dailyTotalAmounts?: Record<string, TransactionTotalAmount>;
readonly?: boolean;
calendarClass?: string;
dayHasTransactionClass?: string;
}>();
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void;
}>();
const {
getAllLongWeekdayNames,
getAllShortWeekdayNames,
getCalendarDayOfMonthFromUnixTime,
formatAmountToLocalizedNumeralsWithCurrency
} = useI18n();
const userStore = useUserStore();
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(props.weekDayNameType === 'short' ? getAllShortWeekdayNames() : getAllLongWeekdayNames(), firstDayOfWeek.value));
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const dateTime = computed<TextualYearMonthDay | ''>({
get: () => props.modelValue,
set: (value: TextualYearMonthDay | '') => emit('update:modelValue', value)
});
function noTransactionInMonthDay(date: Date): boolean {
const dateTime = parseDateTimeFromUnixTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
return !props.dailyTotalAmounts || !props.dailyTotalAmounts[dateTime.getGregorianCalendarDay()];
}
function getDisplayMonthTotalAmount(amount: number, currency: string | false, symbol: string, incomplete: boolean): string {
const displayAmount = formatAmountToLocalizedNumeralsWithCurrency(amount, currency);
return symbol + displayAmount + (incomplete ? INCOMPLETE_AMOUNT_SUFFIX : '');
}
function getDisplayDay(date: Date): string {
return getCalendarDayOfMonthFromUnixTime(getYearMonthDayDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate()).getUnixTime());
}
</script>
<style>
.transaction-calendar-daily-amounts {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.transaction-calendar .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > span {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
@@ -18,29 +18,12 @@
</div> </div>
</template> </template>
<v-card-text class="mb-md-4 w-100 d-flex justify-center"> <v-card-text class="mb-md-4 w-100 d-flex justify-center">
<vue-date-picker inline enable-seconds auto-apply <date-time-picker :is-dark-mode="isDarkMode"
month-name-format="long" :enable-time-picker="true"
six-weeks="center" :vertical="true"
:clearable="false" :preset-dates="presetRanges"
:dark="isDarkMode" v-model="dateRange">
:week-start="firstDayOfWeek" </date-time-picker>
:year-range="yearRange"
:day-names="dayNames"
:year-first="isYearFirst"
:is24="is24Hour"
:range="{ partialRange: false }"
:preset-dates="presetRanges"
v-model="dateRange">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #am-pm-button="{ toggle, value }">
<button class="dp__pm_am_button" tabindex="0" @click="toggle">{{ tt(`datetime.${value}.content`) }}</button>
</template>
</vue-date-picker>
</v-card-text> </v-card-text>
<v-card-text class="overflow-y-visible"> <v-card-text class="overflow-y-visible">
<div class="w-100 d-flex justify-center gap-4"> <div class="w-100 d-flex justify-center gap-4">
@@ -59,9 +42,6 @@ import { useTheme } from 'vuetify';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { type CommonDateRangeSelectionProps, useDateRangeSelectionBase } from '@/components/base/DateRangeSelectionBase.ts'; import { type CommonDateRangeSelectionProps, useDateRangeSelectionBase } from '@/components/base/DateRangeSelectionBase.ts';
import { useUserStore } from '@/stores/user.ts';
import { type WeekDayValue } from '@/core/datetime.ts';
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import { import {
@@ -84,13 +64,10 @@ const emit = defineEmits<{
const theme = useTheme(); const theme = useTheme();
const { tt, getMonthShortName } = useI18n(); const { tt } = useI18n();
const { yearRange, dateRange, dayNames, isYearFirst, is24Hour, beginDateTime, endDateTime, presetRanges, getFinalDateRange } = useDateRangeSelectionBase(props); const { dateRange, beginDateTime, endDateTime, presetRanges, getFinalDateRange } = useDateRangeSelectionBase(props);
const userStore = useUserStore();
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const showState = computed<boolean>({ const showState = computed<boolean>({
get: () => props.show || false, get: () => props.show || false,
set: (value) => emit('update:show', value) set: (value) => emit('update:show', value)
+32 -45
View File
@@ -6,48 +6,35 @@
:clearable="modelValue ? clearable : false" :clearable="modelValue ? clearable : false"
:label="label" :label="label"
:menu-props="{ contentClass: 'date-select-menu' }" :menu-props="{ contentClass: 'date-select-menu' }"
v-model="dateTime" v-model="displayTime"
> >
<template #selection> <template #selection>
<span class="text-truncate cursor-pointer">{{ displayTime }}</span> <span class="text-truncate cursor-pointer">{{ displayTime }}</span>
</template> </template>
<template #no-data> <template #no-data>
<vue-date-picker inline vertical auto-apply <date-time-picker :is-dark-mode="isDarkMode"
ref="datepicker" :enable-time-picker="false"
month-name-format="long" :clearable="true"
model-type="yyyy-MM-dd" v-model="dateTime">
:clearable="true" </date-time-picker>
:enable-time-picker="false"
:dark="isDarkMode"
:week-start="firstDayOfWeek"
:year-range="yearRange"
:day-names="dayNames"
:year-first="isYearFirst"
v-model="dateTime">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</template> </template>
</v-select> </v-select>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue'; import { computed } from 'vue';
import { useTheme } from 'vuetify'; import { useTheme } from 'vuetify';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useUserStore } from '@/stores/user.ts'; import { type TextualYearMonthDay } from '@/core/datetime.ts';
import { type TextualYearMonthDay, type WeekDayValue } from '@/core/datetime.ts';
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { getAllowedYearRange } from '@/lib/datetime.ts'; import {
getLocalDateFromYearDashMonthDashDay,
getGregorianCalendarYearAndMonthFromLocalDate
} from '@/lib/datetime.ts';
const props = defineProps<{ const props = defineProps<{
modelValue?: TextualYearMonthDay; modelValue?: TextualYearMonthDay;
@@ -59,32 +46,32 @@ const props = defineProps<{
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: TextualYearMonthDay): void; (e: 'update:modelValue', value: TextualYearMonthDay | ''): void;
}>(); }>();
const theme = useTheme(); const theme = useTheme();
const { tt, getAllMinWeekdayNames, getMonthShortName, formatGregorianCalendarYearDashMonthDashDayToLongDate, isLongDateMonthAfterYear } = useI18n(); const { tt, formatGregorianCalendarYearDashMonthDashDayToLongDate } = useI18n();
const userStore = useUserStore(); const dateTime = computed<Date | null>({
get: () => props.modelValue ? getLocalDateFromYearDashMonthDashDay(props.modelValue) : null,
const yearRange = ref<number[]>(getAllowedYearRange()); set: (value: Date | null) => emit('update:modelValue', value ? getGregorianCalendarYearAndMonthFromLocalDate(value) : '')
const dateTime = computed<string>({
get: () => props.modelValue ?? '',
set: (value: string) => emit('update:modelValue', value as TextualYearMonthDay)
}); });
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek); const displayTime = computed<string>({
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value)); get: () => {
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear()); if (props.modelValue) {
const displayTime = computed<string>(() => { return formatGregorianCalendarYearDashMonthDashDayToLongDate(props.modelValue);
if (props.modelValue) { } else if (props.noDataText) {
return formatGregorianCalendarYearDashMonthDashDayToLongDate(props.modelValue); return props.noDataText;
} else if (props.noDataText) { } else {
return props.noDataText; return tt('Unspecified');
} else { }
return tt('Unspecified'); },
set: (value: string) => {
if (!value) {
dateTime.value = null;
}
} }
}); });
</script> </script>
+9 -31
View File
@@ -12,28 +12,11 @@
</template> </template>
<template #no-data> <template #no-data>
<vue-date-picker inline vertical enable-seconds auto-apply <date-time-picker :is-dark-mode="isDarkMode"
ref="datepicker" :enable-time-picker="false"
month-name-format="long" :vertical="true"
:clearable="false" v-model="dateTime">
:enable-time-picker="false" </date-time-picker>
:dark="isDarkMode"
:week-start="firstDayOfWeek"
:year-range="yearRange"
:day-names="dayNames"
:year-first="isYearFirst"
:is24="is24Hour"
v-model="dateTime">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #am-pm-button="{ toggle, value }">
<button class="dp__pm_am_button" tabindex="0" @click="toggle">{{ tt(`datetime.${value}.content`) }}</button>
</template>
</vue-date-picker>
<div class="date-time-select-time-picker-container"> <div class="date-time-select-time-picker-container">
<v-btn class="px-3" color="primary" variant="flat" <v-btn class="px-3" color="primary" variant="flat"
v-if="!is24Hour && isMeridiemIndicatorFirst" v-if="!is24Hour && isMeridiemIndicatorFirst"
@@ -50,6 +33,7 @@
:hide-no-data="true" :hide-no-data="true"
v-model="currentHour" v-model="currentHour"
@update:focused="onFocused(hourInput, $event)" @update:focused="onFocused(hourInput, $event)"
@click="onFocused(hourInput, true)"
@keydown="onKeyDown('hour', $event)" @keydown="onKeyDown('hour', $event)"
/> />
<span>:</span> <span>:</span>
@@ -63,6 +47,7 @@
:hide-no-data="true" :hide-no-data="true"
v-model="currentMinute" v-model="currentMinute"
@update:focused="onFocused(minuteInput, $event)" @update:focused="onFocused(minuteInput, $event)"
@click="onFocused(minuteInput, true)"
@keydown="onKeyDown('minute', $event)" @keydown="onKeyDown('minute', $event)"
/> />
<span>:</span> <span>:</span>
@@ -76,6 +61,7 @@
:hide-no-data="true" :hide-no-data="true"
v-model="currentSecond" v-model="currentSecond"
@update:focused="onFocused(secondInput, $event)" @update:focused="onFocused(secondInput, $event)"
@click="onFocused(secondInput, true)"
@keydown="onKeyDown('second', $event)" @keydown="onKeyDown('second', $event)"
/> />
<v-btn class="px-3" color="primary" variant="flat" <v-btn class="px-3" color="primary" variant="flat"
@@ -124,11 +110,7 @@ const emit = defineEmits<{
}>(); }>();
const theme = useTheme(); const theme = useTheme();
const { const { tt, formatUnixTimeToLongDateTime } = useI18n();
tt,
getMonthShortName,
formatUnixTimeToLongDateTime
} = useI18n();
const { const {
is24Hour, is24Hour,
@@ -136,10 +118,6 @@ const {
isMinuteTwoDigits, isMinuteTwoDigits,
isSecondTwoDigits, isSecondTwoDigits,
isMeridiemIndicatorFirst, isMeridiemIndicatorFirst,
yearRange,
firstDayOfWeek,
dayNames,
isYearFirst,
getDisplayTimeValue, getDisplayTimeValue,
generateAllHours, generateAllHours,
generateAllMinutesOrSeconds generateAllMinutesOrSeconds
@@ -12,29 +12,16 @@
</template> </template>
<template #no-data> <template #no-data>
<vue-date-picker inline auto-apply disable-year-select <date-time-picker :is-dark-mode="isDarkMode"
month-name-format="long" :vertical="true"
model-type="MM-dd" :enable-time-picker="false"
six-weeks="center" :disable-year-select="true"
:config="{ noSwipe: true }" :no-swipe-and-scroll="true"
:month-change-on-scroll="false" :min-date="allowedMinDate"
:enable-time-picker="false" :max-date="allowedMaxDate"
:min-date="allowedMinDate" :disabled-dates="disabledDates"
:max-date="allowedMaxDate" v-model="selectedFiscalYearStartValue">
:disabled-dates="disabledDates" </date-time-picker>
:clearable="false"
:dark="isDarkMode"
:week-start="firstDayOfWeek"
:day-names="dayNames"
v-model="selectedFiscalYearStartValue"
>
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</template> </template>
</v-select> </v-select>
</template> </template>
@@ -43,8 +30,6 @@
import { computed, watch } from 'vue'; import { computed, watch } from 'vue';
import { useTheme } from 'vuetify'; import { useTheme } from 'vuetify';
import { useI18n } from '@/locales/helpers.ts';
import { import {
type CommonFiscalYearStartSelectionProps, type CommonFiscalYearStartSelectionProps,
type CommonFiscalYearStartSelectionEmits, type CommonFiscalYearStartSelectionEmits,
@@ -56,8 +41,6 @@ import { ThemeType } from '@/core/theme.ts';
const props = defineProps<CommonFiscalYearStartSelectionProps>(); const props = defineProps<CommonFiscalYearStartSelectionProps>();
const emit = defineEmits<CommonFiscalYearStartSelectionEmits>(); const emit = defineEmits<CommonFiscalYearStartSelectionEmits>();
const { getMonthShortName } = useI18n();
const theme = useTheme(); const theme = useTheme();
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
@@ -69,8 +52,6 @@ const {
displayFiscalYearStartDate, displayFiscalYearStartDate,
allowedMinDate, allowedMinDate,
allowedMaxDate, allowedMaxDate,
firstDayOfWeek,
dayNames
} = useFiscalYearStartSelectionBase(props); } = useFiscalYearStartSelectionBase(props);
watch(() => props.modelValue, (newValue) => { watch(() => props.modelValue, (newValue) => {
@@ -20,36 +20,10 @@
<v-card-text class="mb-md-4 w-100 d-flex justify-center"> <v-card-text class="mb-md-4 w-100 d-flex justify-center">
<v-row class="match-height"> <v-row class="match-height">
<v-col cols="12" md="6"> <v-col cols="12" md="6">
<vue-date-picker inline month-picker auto-apply <month-picker :is-dark-mode="isDarkMode" v-model="dateRange[0]"></month-picker>
month-name-format="long"
:clearable="false"
:dark="isDarkMode"
:year-range="yearRange"
:year-first="isYearFirst"
v-model="dateRange[0]">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</v-col> </v-col>
<v-col cols="12" md="6"> <v-col cols="12" md="6">
<vue-date-picker inline month-picker auto-apply <month-picker :is-dark-mode="isDarkMode" v-model="dateRange[1]"></month-picker>
month-name-format="long"
:clearable="false"
:dark="isDarkMode"
:year-range="yearRange"
:year-first="isYearFirst"
v-model="dateRange[1]">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</v-col> </v-col>
</v-row> </v-row>
</v-card-text> </v-card-text>
@@ -73,6 +47,8 @@ import { type CommonMonthRangeSelectionProps, useMonthRangeSelectionBase } from
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import { type TextualYearMonth } from '@/core/datetime.ts'; import { type TextualYearMonth } from '@/core/datetime.ts';
import { getYear0BasedMonthObjectFromString } from '@/lib/datetime.ts';
interface DesktopMonthRangeSelectionProps extends CommonMonthRangeSelectionProps { interface DesktopMonthRangeSelectionProps extends CommonMonthRangeSelectionProps {
persistent?: boolean; persistent?: boolean;
} }
@@ -86,8 +62,8 @@ const emit = defineEmits<{
const theme = useTheme(); const theme = useTheme();
const { tt, getMonthShortName } = useI18n(); const { tt } = useI18n();
const { yearRange, dateRange, isYearFirst, beginDateTime, endDateTime, getMonthSelectionValue, getFinalMonthRange } = useMonthRangeSelectionBase(props); const { dateRange, beginDateTime, endDateTime, getFinalMonthRange } = useMonthRangeSelectionBase(props);
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const showState = computed<boolean>({ const showState = computed<boolean>({
@@ -117,7 +93,7 @@ function cancel(): void {
watch(() => props.minTime, (newValue) => { watch(() => props.minTime, (newValue) => {
if (newValue) { if (newValue) {
const yearMonth = getMonthSelectionValue(newValue); const yearMonth = getYear0BasedMonthObjectFromString(newValue);
if (yearMonth) { if (yearMonth) {
dateRange.value[0] = yearMonth; dateRange.value[0] = yearMonth;
@@ -127,7 +103,7 @@ watch(() => props.minTime, (newValue) => {
watch(() => props.maxTime, (newValue) => { watch(() => props.maxTime, (newValue) => {
if (newValue) { if (newValue) {
const yearMonth = getMonthSelectionValue(newValue); const yearMonth = getYear0BasedMonthObjectFromString(newValue);
if (yearMonth) { if (yearMonth) {
dateRange.value[1] = yearMonth; dateRange.value[1] = yearMonth;
+21 -44
View File
@@ -15,20 +15,7 @@
<v-card-text class="mb-md-4 w-100 d-flex justify-center"> <v-card-text class="mb-md-4 w-100 d-flex justify-center">
<v-row class="match-height"> <v-row class="match-height">
<v-col> <v-col>
<vue-date-picker inline month-picker auto-apply <month-picker :is-dark-mode="isDarkMode" v-model="monthValue"></month-picker>
month-name-format="long"
:clearable="false"
:dark="isDarkMode"
:year-range="yearRange"
:year-first="isYearFirst"
v-model="monthValue">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</v-col> </v-col>
</v-row> </v-row>
</v-card-text> </v-card-text>
@@ -43,20 +30,24 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import { useTheme } from 'vuetify'; import { useTheme } from 'vuetify';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts';
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import type { Year0BasedMonth } from '@/core/datetime.ts'; import type { Year0BasedMonth } from '@/core/datetime.ts';
interface DesktopMonthSelectionProps extends CommonMonthSelectionProps { import { getYear0BasedMonthObjectFromUnixTime, getThisMonthFirstUnixTime } from '@/lib/datetime.ts';
persistent?: boolean;
} const props = defineProps<{
modelValue?: Year0BasedMonth;
title?: string;
hint?: string;
show: boolean;
persistent?: boolean;
}>();
const props = defineProps<DesktopMonthSelectionProps>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: Year0BasedMonth): void; (e: 'update:modelValue', value: Year0BasedMonth): void;
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
@@ -65,8 +56,9 @@ const emit = defineEmits<{
const theme = useTheme(); const theme = useTheme();
const { tt, getMonthShortName } = useI18n(); const { tt } = useI18n();
const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getYear0BasedMonth } = useMonthSelectionBase(props);
const monthValue = ref<Year0BasedMonth>(getYear0BasedMonthObjectFromUnixTime(getThisMonthFirstUnixTime()));
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const showState = computed<boolean>({ const showState = computed<boolean>({
@@ -75,19 +67,12 @@ const showState = computed<boolean>({
}); });
function confirm(): void { function confirm(): void {
try { if (monthValue.value.year <= 0 || monthValue.value.month0base < 0) {
const finalMonthRange = getYear0BasedMonth(); emit('error', 'Date is too early');
return;
if (!finalMonthRange) {
return;
}
emit('update:modelValue', finalMonthRange);
} catch (ex: unknown) {
if (ex instanceof Error) {
emit('error', ex.message);
}
} }
emit('update:modelValue', monthValue.value);
} }
function cancel(): void { function cancel(): void {
@@ -96,21 +81,13 @@ function cancel(): void {
watch(() => props.modelValue, (newValue) => { watch(() => props.modelValue, (newValue) => {
if (newValue) { if (newValue) {
const yearMonth = getMonthSelectionValue(newValue); monthValue.value = newValue;
if (yearMonth) {
monthValue.value = yearMonth;
}
} }
}); });
watch(() => props.show, (newValue) => { watch(() => props.show, (newValue) => {
if (newValue && props.modelValue) { if (newValue && props.modelValue) {
const yearMonth = getMonthSelectionValue(props.modelValue); monthValue.value = props.modelValue;
if (yearMonth) {
monthValue.value = yearMonth;
}
} }
}); });
</script> </script>
@@ -14,31 +14,13 @@
<span>{{ endDateTime }}</span> <span>{{ endDateTime }}</span>
</p> </p>
<slot></slot> <slot></slot>
<vue-date-picker inline enable-seconds auto-apply <date-time-picker ref="datetimepicker"
ref="datetimepicker" datetime-picker-class="justify-content-center margin-bottom"
month-name-format="long" :is-dark-mode="isDarkMode"
six-weeks="center" :enable-time-picker="true"
class="justify-content-center margin-bottom" :preset-dates="presetRanges"
:clearable="false" v-model="dateRange">
:dark="isDarkMode" </date-time-picker>
:week-start="firstDayOfWeek"
:year-range="yearRange"
:day-names="dayNames"
:year-first="isYearFirst"
:is24="is24Hour"
:range="{ partialRange: false }"
:preset-dates="presetRanges"
v-model="dateRange">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #am-pm-button="{ toggle, value }">
<button class="dp__pm_am_button" tabindex="0" @click="toggle">{{ tt(`datetime.${value}.content`) }}</button>
</template>
</vue-date-picker>
<f7-button large fill <f7-button large fill
:class="{ 'disabled': !dateRange[0] || !dateRange[1] }" :class="{ 'disabled': !dateRange[0] || !dateRange[1] }"
:text="tt('Continue')" :text="tt('Continue')"
@@ -53,17 +35,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import DateTimePicker from '@/components/common/DateTimePicker.vue';
import { computed, useTemplateRef } from 'vue'; import { computed, useTemplateRef } from 'vue';
import VueDatePicker from '@vuepic/vue-datepicker';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
import { type CommonDateRangeSelectionProps, useDateRangeSelectionBase } from '@/components/base/DateRangeSelectionBase.ts'; import { type CommonDateRangeSelectionProps, useDateRangeSelectionBase } from '@/components/base/DateRangeSelectionBase.ts';
import { useEnvironmentsStore } from '@/stores/environment.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts';
import { useUserStore } from '@/stores/user.ts';
import { type WeekDayValue } from '@/core/datetime.ts';
import { import {
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
@@ -72,7 +51,7 @@ import {
getBrowserTimezoneOffsetMinutes getBrowserTimezoneOffsetMinutes
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
type VueDatePickerType = InstanceType<typeof VueDatePicker>; type DateTimePickerType = InstanceType<typeof DateTimePicker>;
const props = defineProps<CommonDateRangeSelectionProps>(); const props = defineProps<CommonDateRangeSelectionProps>();
const emit = defineEmits<{ const emit = defineEmits<{
@@ -80,16 +59,14 @@ const emit = defineEmits<{
(e: 'dateRange:change', minUnixTime: number, maxUnixTime: number): void; (e: 'dateRange:change', minUnixTime: number, maxUnixTime: number): void;
}>(); }>();
const { tt, getMonthShortName } = useI18n(); const { tt } = useI18n();
const { showToast } = useI18nUIComponents(); const { showToast } = useI18nUIComponents();
const { yearRange, dateRange, dayNames, isYearFirst, is24Hour, beginDateTime, endDateTime, presetRanges, getFinalDateRange } = useDateRangeSelectionBase(props); const { dateRange, beginDateTime, endDateTime, presetRanges, getFinalDateRange } = useDateRangeSelectionBase(props);
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
const userStore = useUserStore();
const datetimepicker = useTemplateRef<VueDatePickerType>('datetimepicker'); const datetimepicker = useTemplateRef<DateTimePickerType>('datetimepicker');
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false); const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
function confirm(): void { function confirm(): void {
try { try {
@@ -121,10 +98,7 @@ function onSheetOpen(): void {
} }
window.dispatchEvent(new Event('resize')); // fix vue-datepicker preset max-width window.dispatchEvent(new Event('resize')); // fix vue-datepicker preset max-width
datetimepicker.value?.switchView('calendar');
if (datetimepicker.value) {
datetimepicker.value.switchView('calendar');
}
} }
function onSheetClosed(): void { function onSheetClosed(): void {
+18 -35
View File
@@ -12,26 +12,12 @@
</f7-toolbar> </f7-toolbar>
<f7-page-content> <f7-page-content>
<div class="block block-outline no-margin no-padding"> <div class="block block-outline no-margin no-padding">
<vue-date-picker inline auto-apply <date-time-picker datetime-picker-class="justify-content-center"
month-name-format="long" :is-dark-mode="isDarkMode"
model-type="yyyy-MM-dd" :enable-time-picker="false"
six-weeks="center" :clearable="true"
class="justify-content-center" v-model="dateTime">
:enable-time-picker="false" </date-time-picker>
:clearable="true"
:dark="isDarkMode"
:week-start="firstDayOfWeek"
:year-range="yearRange"
:day-names="dayNames"
:year-first="isYearFirst"
v-model="dateTime">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</div> </div>
</f7-page-content> </f7-page-content>
</f7-sheet> </f7-sheet>
@@ -43,11 +29,13 @@ import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useEnvironmentsStore } from '@/stores/environment.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts';
import { useUserStore } from '@/stores/user.ts';
import { type TextualYearMonthDay, type WeekDayValue } from '@/core/datetime.ts'; import { type TextualYearMonthDay } from '@/core/datetime.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { getAllowedYearRange } from '@/lib/datetime.ts'; import {
getLocalDateFromYearDashMonthDashDay,
getGregorianCalendarYearAndMonthFromLocalDate
} from '@/lib/datetime.ts';
const props = defineProps<{ const props = defineProps<{
modelValue?: TextualYearMonthDay; modelValue?: TextualYearMonthDay;
@@ -55,35 +43,30 @@ const props = defineProps<{
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: TextualYearMonthDay): void; (e: 'update:modelValue', value: TextualYearMonthDay | ''): void;
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
}>(); }>();
const { tt, getAllMinWeekdayNames, getMonthShortName, isLongDateMonthAfterYear } = useI18n(); const { tt } = useI18n();
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
const userStore = useUserStore();
const yearRange = ref<number[]>(getAllowedYearRange()); const dateTime = ref<Date | null>(null);
const dateTime = ref<string>('');
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false); const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value));
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
function clear(): void { function clear(): void {
dateTime.value = ''; dateTime.value = null;
confirm(); confirm();
} }
function confirm(): void { function confirm(): void {
emit('update:modelValue', dateTime.value as TextualYearMonthDay); emit('update:modelValue', dateTime.value ? getGregorianCalendarYearAndMonthFromLocalDate(dateTime.value) : '');
emit('update:show', false); emit('update:show', false);
} }
function onSheetOpen(): void { function onSheetOpen(): void {
dateTime.value = props.modelValue ?? ''; dateTime.value = props.modelValue ? getLocalDateFromYearDashMonthDashDay(props.modelValue) : null;
} }
function onSheetClosed(): void { function onSheetClosed(): void {
@@ -12,27 +12,13 @@
</f7-toolbar> </f7-toolbar>
<f7-page-content class="padding-bottom"> <f7-page-content class="padding-bottom">
<div class="block block-outline no-margin no-padding"> <div class="block block-outline no-margin no-padding">
<vue-date-picker inline enable-seconds auto-apply <date-time-picker ref="datetimepicker"
ref="datetimepicker" datetime-picker-class="justify-content-center"
month-name-format="long" :is-dark-mode="isDarkMode"
six-weeks="center" :enable-time-picker="false"
class="justify-content-center" v-model="dateTime"
:enable-time-picker="false" v-show="mode === 'date'">
:clearable="false" </date-time-picker>
:dark="isDarkMode"
:week-start="firstDayOfWeek"
:year-range="yearRange"
:day-names="dayNames"
:year-first="isYearFirst"
v-model="dateTime"
v-show="mode === 'date'">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</div> </div>
<div class="block block-outline no-margin no-padding padding-vertical-half" v-show="mode === 'time'"> <div class="block block-outline no-margin no-padding padding-vertical-half" v-show="mode === 'time'">
<div id="time-picker-container" class="time-picker-container"> <div id="time-picker-container" class="time-picker-container">
@@ -115,8 +101,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import DateTimePicker from '@/components/common/DateTimePicker.vue';
import { ref, computed, nextTick, useTemplateRef, watch } from 'vue'; import { ref, computed, nextTick, useTemplateRef, watch } from 'vue';
import VueDatePicker from '@vuepic/vue-datepicker';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
@@ -137,7 +123,7 @@ import {
getCombinedDateAndTimeValues getCombinedDateAndTimeValues
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
type VueDatePickerType = InstanceType<typeof VueDatePicker>; type DateTimePickerType = InstanceType<typeof DateTimePicker>;
const props = defineProps<{ const props = defineProps<{
modelValue: number; modelValue: number;
@@ -150,11 +136,7 @@ const emit = defineEmits<{
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
}>(); }>();
const { const { tt, formatUnixTimeToLongDateTime } = useI18n();
tt,
getMonthShortName,
formatUnixTimeToLongDateTime
} = useI18n();
const { showToast } = useI18nUIComponents(); const { showToast } = useI18nUIComponents();
const { const {
@@ -163,11 +145,7 @@ const {
isMinuteTwoDigits, isMinuteTwoDigits,
isSecondTwoDigits, isSecondTwoDigits,
isMeridiemIndicatorFirst, isMeridiemIndicatorFirst,
yearRange,
meridiemItems, meridiemItems,
firstDayOfWeek,
dayNames,
isYearFirst,
getDisplayTimeValue, getDisplayTimeValue,
generateAllHours, generateAllHours,
generateAllMinutesOrSeconds generateAllMinutesOrSeconds
@@ -175,7 +153,7 @@ const {
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
const datetimepicker = useTemplateRef<VueDatePickerType>('datetimepicker'); const datetimepicker = useTemplateRef<DateTimePickerType>('datetimepicker');
let resetTimePickerItemPositionItemsClass: string | undefined = undefined; let resetTimePickerItemPositionItemsClass: string | undefined = undefined;
let resetTimePickerItemPositionItemClass: string | undefined = undefined; let resetTimePickerItemPositionItemClass: string | undefined = undefined;
@@ -455,9 +433,7 @@ function onSheetOpen(): void {
}); });
} }
if (datetimepicker.value) { datetimepicker.value?.switchView('calendar');
datetimepicker.value.switchView('calendar');
}
} }
function onSheetClosed(): void { function onSheetClosed(): void {
@@ -465,8 +441,8 @@ function onSheetClosed(): void {
} }
watch(mode, (newValue) => { watch(mode, (newValue) => {
if (newValue === 'date' && datetimepicker.value) { if (newValue === 'date') {
datetimepicker.value.switchView('calendar'); datetimepicker.value?.switchView('calendar');
} else if (newValue === 'time') { } else if (newValue === 'time') {
nextTick(() => { nextTick(() => {
initTimePickerStyle(); initTimePickerStyle();
@@ -12,29 +12,16 @@
</f7-toolbar> </f7-toolbar>
<f7-page-content> <f7-page-content>
<div class="block block-outline no-margin no-padding"> <div class="block block-outline no-margin no-padding">
<vue-date-picker inline auto-apply disable-year-select <date-time-picker datetime-picker-class="justify-content-center"
month-name-format="long" :is-dark-mode="isDarkMode"
model-type="MM-dd" :enable-time-picker="false"
six-weeks="center" :disable-year-select="true"
class="justify-content-center" :no-swipe-and-scroll="true"
:config="{ noSwipe: true }" :min-date="allowedMinDate"
:month-change-on-scroll="false" :max-date="allowedMaxDate"
:enable-time-picker="false" :disabled-dates="disabledDates"
:min-date="allowedMinDate" v-model="selectedFiscalYearStartValue">
:max-date="allowedMaxDate" </date-time-picker>
:disabled-dates="disabledDates"
:clearable="false"
:dark="isDarkMode"
:week-start="firstDayOfWeek"
:day-names="dayNames"
v-model="selectedFiscalYearStartValue">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
</div> </div>
</f7-page-content> </f7-page-content>
</f7-sheet> </f7-sheet>
@@ -67,7 +54,7 @@ interface MobileFiscalYearStartSelectionSheetEmits extends CommonFiscalYearStart
const props = defineProps<MobileFiscalYearStartSelectionSheetProps>(); const props = defineProps<MobileFiscalYearStartSelectionSheetProps>();
const emit = defineEmits<MobileFiscalYearStartSelectionSheetEmits>(); const emit = defineEmits<MobileFiscalYearStartSelectionSheetEmits>();
const { tt, getMonthShortName } = useI18n(); const { tt } = useI18n();
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
const userStore = useUserStore(); const userStore = useUserStore();
@@ -78,8 +65,6 @@ const {
selectedFiscalYearStartValue, selectedFiscalYearStartValue,
allowedMinDate, allowedMinDate,
allowedMaxDate, allowedMaxDate,
firstDayOfWeek,
dayNames
} = useFiscalYearStartSelectionBase(props); } = useFiscalYearStartSelectionBase(props);
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false); const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
@@ -14,22 +14,8 @@
<span>{{ endDateTime }}</span> <span>{{ endDateTime }}</span>
</p> </p>
<slot></slot> <slot></slot>
<vue-date-picker inline month-picker auto-apply <month-picker month-picker-class="justify-content-center margin-bottom"
month-name-format="long" :is-dark-mode="isDarkMode" v-model="dateRange"></month-picker>
class="justify-content-center margin-bottom"
:clearable="false"
:dark="isDarkMode"
:year-range="yearRange"
:year-first="isYearFirst"
:range="{ partialRange: false }"
v-model="dateRange">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
<f7-button large fill <f7-button large fill
:class="{ 'disabled': !dateRange[0] || !dateRange[1] }" :class="{ 'disabled': !dateRange[0] || !dateRange[1] }"
:text="tt('Continue')" :text="tt('Continue')"
@@ -54,15 +40,17 @@ import { useEnvironmentsStore } from '@/stores/environment.ts';
import { type TextualYearMonth } from '@/core/datetime.ts'; import { type TextualYearMonth } from '@/core/datetime.ts';
import { getYear0BasedMonthObjectFromString } from '@/lib/datetime.ts';
const props = defineProps<CommonMonthRangeSelectionProps>(); const props = defineProps<CommonMonthRangeSelectionProps>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
(e: 'dateRange:change', minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | ''): void; (e: 'dateRange:change', minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | ''): void;
}>(); }>();
const { tt, getMonthShortName } = useI18n(); const { tt } = useI18n();
const { showToast } = useI18nUIComponents(); const { showToast } = useI18nUIComponents();
const { yearRange, dateRange, isYearFirst, beginDateTime, endDateTime, getMonthSelectionValue, getFinalMonthRange } = useMonthRangeSelectionBase(props); const { dateRange, beginDateTime, endDateTime, getFinalMonthRange } = useMonthRangeSelectionBase(props);
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
@@ -90,7 +78,7 @@ function cancel(): void {
function onSheetOpen(): void { function onSheetOpen(): void {
if (props.minTime) { if (props.minTime) {
const yearMonth = getMonthSelectionValue(props.minTime); const yearMonth = getYear0BasedMonthObjectFromString(props.minTime);
if (yearMonth) { if (yearMonth) {
dateRange.value[0] = yearMonth; dateRange.value[0] = yearMonth;
@@ -98,7 +86,7 @@ function onSheetOpen(): void {
} }
if (props.maxTime) { if (props.maxTime) {
const yearMonth = getMonthSelectionValue(props.maxTime); const yearMonth = getYear0BasedMonthObjectFromString(props.maxTime);
if (yearMonth) { if (yearMonth) {
dateRange.value[1] = yearMonth; dateRange.value[1] = yearMonth;
+20 -37
View File
@@ -9,21 +9,8 @@
<div class="padding-horizontal padding-bottom"> <div class="padding-horizontal padding-bottom">
<p class="no-margin-top" v-if="hint">{{ hint }}</p> <p class="no-margin-top" v-if="hint">{{ hint }}</p>
<slot></slot> <slot></slot>
<vue-date-picker inline month-picker auto-apply <month-picker month-picker-class="justify-content-center margin-bottom"
month-name-format="long" :is-dark-mode="isDarkMode" v-model="monthValue"></month-picker>
class="justify-content-center margin-bottom"
:clearable="false"
:dark="isDarkMode"
:year-range="yearRange"
:year-first="isYearFirst"
v-model="monthValue">
<template #month="{ text }">
{{ getMonthShortName(text) }}
</template>
<template #month-overlay-value="{ text }">
{{ getMonthShortName(text) }}
</template>
</vue-date-picker>
<f7-button large fill <f7-button large fill
:class="{ 'disabled': !monthValue }" :class="{ 'disabled': !monthValue }"
:text="tt('Continue')" :text="tt('Continue')"
@@ -38,43 +25,43 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts';
import type { Year0BasedMonth } from '@/core/datetime.ts'; import type { Year0BasedMonth } from '@/core/datetime.ts';
import { useEnvironmentsStore } from '@/stores/environment.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts';
const props = defineProps<CommonMonthSelectionProps>(); import { getYear0BasedMonthObjectFromUnixTime, getThisMonthFirstUnixTime } from '@/lib/datetime.ts';
const props = defineProps<{
modelValue?: Year0BasedMonth;
title?: string;
hint?: string;
show: boolean;
}>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: Year0BasedMonth): void; (e: 'update:modelValue', value: Year0BasedMonth): void;
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
}>(); }>();
const { tt, getMonthShortName } = useI18n(); const { tt } = useI18n();
const { showToast } = useI18nUIComponents(); const { showToast } = useI18nUIComponents();
const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getYear0BasedMonth } = useMonthSelectionBase(props);
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
const monthValue = ref<Year0BasedMonth>(getYear0BasedMonthObjectFromUnixTime(getThisMonthFirstUnixTime()));
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false); const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
function confirm(): void { function confirm(): void {
try { if (monthValue.value.year <= 0 || monthValue.value.month0base < 0) {
const finalMonthRange = getYear0BasedMonth(); showToast('Date is too early');
return;
if (!finalMonthRange) {
return;
}
emit('update:modelValue', finalMonthRange);
} catch (ex: unknown) {
if (ex instanceof Error) {
showToast(ex.message);
}
} }
emit('update:modelValue', monthValue.value);
} }
function cancel(): void { function cancel(): void {
@@ -83,11 +70,7 @@ function cancel(): void {
function onSheetOpen(): void { function onSheetOpen(): void {
if (props.modelValue) { if (props.modelValue) {
const yearMonth = getMonthSelectionValue(props.modelValue); monthValue.value = props.modelValue;
if (yearMonth) {
monthValue.value = yearMonth;
}
} }
} }
+2 -2
View File
@@ -2,8 +2,7 @@ import type { TypeAndName } from '@/core/base.ts';
export enum CalendarType { export enum CalendarType {
Gregorian = 0, Gregorian = 0,
Buddhist = 1, Buddhist = 1
Chinese = 2
} }
export class CalendarDisplayType implements TypeAndName { export class CalendarDisplayType implements TypeAndName {
@@ -13,6 +12,7 @@ export class CalendarDisplayType implements TypeAndName {
public static readonly LanguageDefaultType: number = 0; public static readonly LanguageDefaultType: number = 0;
public static readonly Gregorian = new CalendarDisplayType(1, 'Gregorian', 'Gregorian', CalendarType.Gregorian); public static readonly Gregorian = new CalendarDisplayType(1, 'Gregorian', 'Gregorian', CalendarType.Gregorian);
public static readonly Buddhist = new CalendarDisplayType(2, 'Buddhist', 'Buddhist', CalendarType.Buddhist);
public static readonly Default = CalendarDisplayType.Gregorian; public static readonly Default = CalendarDisplayType.Gregorian;
+11 -5
View File
@@ -4,18 +4,19 @@ import type { NumeralSystem } from '@/core/numeral.ts';
export interface DateTime { export interface DateTime {
getUnixTime(): number; getUnixTime(): number;
getLocalizedCalendarYear(options: DateTimeFormatOptions): number; getLocalizedCalendarYear(options: DateTimeFormatOptions): string;
getGregorianCalendarYear(): number; getGregorianCalendarYear(): number;
getGregorianCalendarQuarter(): number; getGregorianCalendarQuarter(): number;
getLocalizedCalendarQuarter(options: DateTimeFormatOptions): number; getLocalizedCalendarQuarter(options: DateTimeFormatOptions): number;
getGregorianCalendarMonth(): number; getGregorianCalendarMonth(): number;
getGregorianCalendarMonthDisplayName(options: DateTimeFormatOptions): string; getGregorianCalendarMonthDisplayName(options: DateTimeFormatOptions): string;
getGregorianCalendarMonthDisplayShortName(options: DateTimeFormatOptions): string; getGregorianCalendarMonthDisplayShortName(options: DateTimeFormatOptions): string;
getLocalizedCalendarMonth(options: DateTimeFormatOptions): number; getLocalizedCalendarMonth(options: DateTimeFormatOptions): string;
getLocalizedCalendarMonthIndex(options: DateTimeFormatOptions): number;
getLocalizedCalendarMonthDisplayName(options: DateTimeFormatOptions): string; getLocalizedCalendarMonthDisplayName(options: DateTimeFormatOptions): string;
getLocalizedCalendarMonthDisplayShortName(options: DateTimeFormatOptions): string; getLocalizedCalendarMonthDisplayShortName(options: DateTimeFormatOptions): string;
getGregorianCalendarDay(): number; getGregorianCalendarDay(): number;
getLocalizedCalendarDay(options: DateTimeFormatOptions): number; getLocalizedCalendarDay(options: DateTimeFormatOptions): string;
getGregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay; getGregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay;
getGregorianCalendarYearDashMonth(): TextualYearMonth; getGregorianCalendarYearDashMonth(): TextualYearMonth;
getWeekDay(): WeekDay; getWeekDay(): WeekDay;
@@ -33,8 +34,8 @@ export interface DateTime {
} }
export interface DateTimeFormatOptions { export interface DateTimeFormatOptions {
calendarType: CalendarType;
numeralSystem: NumeralSystem; numeralSystem: NumeralSystem;
calendarType: CalendarType;
localeData: DateTimeLocaleData; localeData: DateTimeLocaleData;
} }
@@ -70,12 +71,17 @@ export interface YearMonthRange {
readonly endYearMonth: Year0BasedMonth; readonly endYearMonth: Year0BasedMonth;
} }
export interface YearMonthDay { export interface YearMonthDay extends MonthDay {
readonly year: number; readonly year: number;
readonly month: number; // 1-based (1 = January, 12 = December) readonly month: number; // 1-based (1 = January, 12 = December)
readonly day: number; readonly day: number;
} }
export interface MonthDay {
readonly month: number; // 1-based (1 = January, 12 = December
readonly day: number;
}
export interface TimeRange { export interface TimeRange {
readonly minTime: number; readonly minTime: number;
readonly maxTime: number; readonly maxTime: number;
+8 -1
View File
@@ -1,4 +1,4 @@
import type { TextualYearMonth, UnixTimeRange } from './datetime.ts'; import type { TextualYearMonth, MonthDay, UnixTimeRange } from './datetime.ts';
export class FiscalYearStart { export class FiscalYearStart {
public static readonly JanuaryFirstDay = new FiscalYearStart(1, 1); public static readonly JanuaryFirstDay = new FiscalYearStart(1, 1);
@@ -79,6 +79,13 @@ export class FiscalYearStart {
return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}` as TextualYearMonth; return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}` as TextualYearMonth;
} }
public toMonthDay(): MonthDay {
return {
month: this.month,
day: this.day
};
}
private static isValidFiscalYearMonthDay(month: number, day: number): boolean { private static isValidFiscalYearMonthDay(month: number, day: number): boolean {
return 1 <= month && month <= 12 && 1 <= day && day <= FiscalYearStart.MONTH_MAX_DAYS[month - 1]; return 1 <= month && month <= 12 && 1 <= day && day <= FiscalYearStart.MONTH_MAX_DAYS[month - 1];
} }
+6
View File
@@ -76,6 +76,9 @@ import { getI18nOptions, getRtlLocales } from '@/locales/helpers.ts';
import PinCodeInput from '@/components/common/PinCodeInput.vue'; import PinCodeInput from '@/components/common/PinCodeInput.vue';
import MapView from '@/components/common/MapView.vue'; import MapView from '@/components/common/MapView.vue';
import DateTimePicker from '@/components/common/DateTimePicker.vue';
import MonthPicker from '@/components/common/MonthPicker.vue';
import TransactionCalendar from '@/components/common/TransactionCalendar.vue';
import ItemIcon from '@/components/desktop/ItemIcon.vue'; import ItemIcon from '@/components/desktop/ItemIcon.vue';
import BtnVerticalGroup from '@/components/desktop/BtnVerticalGroup.vue'; import BtnVerticalGroup from '@/components/desktop/BtnVerticalGroup.vue';
@@ -506,6 +509,9 @@ app.component('DraggableList', draggable);
app.component('PinCodeInput', PinCodeInput); app.component('PinCodeInput', PinCodeInput);
app.component('MapView', MapView); app.component('MapView', MapView);
app.component('DateTimePicker', DateTimePicker);
app.component('MonthPicker', MonthPicker);
app.component('TransactionCalendar', TransactionCalendar);
app.component('ItemIcon', ItemIcon); app.component('ItemIcon', ItemIcon);
app.component('BtnVerticalGroup', BtnVerticalGroup); app.component('BtnVerticalGroup', BtnVerticalGroup);
+90 -27
View File
@@ -36,6 +36,10 @@ import {
type FiscalYearUnixTime, type FiscalYearUnixTime,
FiscalYearStart FiscalYearStart
} from '@/core/fiscalyear.ts'; } from '@/core/fiscalyear.ts';
import {
NumeralSystem
} from '@/core/numeral.ts';
import { import {
isFunction, isFunction,
isDefined, isDefined,
@@ -47,7 +51,8 @@ import {
interface DateTimeFormatResult { interface DateTimeFormatResult {
value: number | string; value: number | string;
numeralLength?: number; minNumeralLength?: number;
maxLength?: number;
hasNumeral?: boolean; hasNumeral?: boolean;
} }
@@ -55,25 +60,25 @@ type DateTimeTokenFormatFunction = (d: MomentDateTime, options: DateTimeFormatOp
class MomentDateTime implements DateTime { class MomentDateTime implements DateTime {
private static readonly tokenFormatFuncs: Record<string, DateTimeTokenFormatFunction> = { private static readonly tokenFormatFuncs: Record<string, DateTimeTokenFormatFunction> = {
'YY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options) % 100, numeralLength: 2 }), 'YY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options), minNumeralLength: 2, maxLength: 2 }),
'YYYY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options), numeralLength: 4 }), 'YYYY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options), minNumeralLength: 4 }),
'M': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options) }), 'M': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options) }),
'MM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options), numeralLength: 2 }), 'MM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options), minNumeralLength: 2 }),
'MMM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonthDisplayShortName(options) }), 'MMM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonthDisplayShortName(options) }),
'MMMM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonthDisplayName(options) }), 'MMMM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonthDisplayName(options) }),
'D': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options) }), 'D': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options) }),
'DD': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options), numeralLength: 2 }), 'DD': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options), minNumeralLength: 2 }),
'dd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayMinName(options) }), 'dd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayMinName(options) }),
'ddd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayShortName(options) }), 'ddd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayShortName(options) }),
'dddd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayName(options) }), 'dddd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayName(options) }),
'H': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getHour() }), 'H': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getHour() }),
'HH': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getHour(), numeralLength: 2 }), 'HH': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getHour(), minNumeralLength: 2 }),
'h': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: getHourIn12HourFormat(d.getHour()) }), 'h': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: getHourIn12HourFormat(d.getHour()) }),
'hh': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: getHourIn12HourFormat(d.getHour()), numeralLength: 2 }), 'hh': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: getHourIn12HourFormat(d.getHour()), minNumeralLength: 2 }),
'm': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getMinute() }), 'm': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getMinute() }),
'mm': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getMinute(), numeralLength: 2 }), 'mm': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getMinute(), minNumeralLength: 2 }),
's': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getSecond() }), 's': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getSecond() }),
'ss': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getSecond(), numeralLength: 2 }), 'ss': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: d.getSecond(), minNumeralLength: 2 }),
'A': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getDisplayAMPM(options) }), 'A': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getDisplayAMPM(options) }),
'Z': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: getUtcOffsetByUtcOffsetMinutes(d.getTimezoneUtcOffsetMinutes()), hasNumeral: true }), 'Z': (d: MomentDateTime) => ofObject<DateTimeFormatResult>({ value: getUtcOffsetByUtcOffsetMinutes(d.getTimezoneUtcOffsetMinutes()), hasNumeral: true }),
}; };
@@ -88,12 +93,12 @@ class MomentDateTime implements DateTime {
return this.instance.unix(); return this.instance.unix();
} }
public getLocalizedCalendarYear(options: DateTimeFormatOptions): number { public getLocalizedCalendarYear(options: DateTimeFormatOptions): string {
if (options && options.calendarType === CalendarType.Buddhist) { if (options && options.calendarType === CalendarType.Buddhist) {
return this.instance.year() + 543; return (this.instance.year() + 543).toString();
} }
return this.instance.year(); return this.instance.year().toString();
} }
public getGregorianCalendarYear(): number { public getGregorianCalendarYear(): number {
@@ -132,8 +137,13 @@ class MomentDateTime implements DateTime {
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public getLocalizedCalendarMonth(options: DateTimeFormatOptions): number { public getLocalizedCalendarMonth(options: DateTimeFormatOptions): string {
return this.instance.month() + 1; return (this.instance.month() + 1).toString();
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public getLocalizedCalendarMonthIndex(options: DateTimeFormatOptions): number {
return this.instance.month();
} }
public getLocalizedCalendarMonthDisplayName(options: DateTimeFormatOptions): string { public getLocalizedCalendarMonthDisplayName(options: DateTimeFormatOptions): string {
@@ -142,7 +152,7 @@ class MomentDateTime implements DateTime {
} }
const names = options.localeData.months(); const names = options.localeData.months();
return names[this.getLocalizedCalendarMonth(options) - 1] || ''; return names[this.getLocalizedCalendarMonthIndex(options)] || '';
} }
public getLocalizedCalendarMonthDisplayShortName(options: DateTimeFormatOptions): string { public getLocalizedCalendarMonthDisplayShortName(options: DateTimeFormatOptions): string {
@@ -151,7 +161,7 @@ class MomentDateTime implements DateTime {
} }
const names = options.localeData.monthsShort(); const names = options.localeData.monthsShort();
return names[this.getLocalizedCalendarMonth(options) - 1] || ''; return names[this.getLocalizedCalendarMonthIndex(options)] || '';
} }
public getGregorianCalendarDay(): number { public getGregorianCalendarDay(): number {
@@ -159,16 +169,16 @@ class MomentDateTime implements DateTime {
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public getLocalizedCalendarDay(options: DateTimeFormatOptions): number { public getLocalizedCalendarDay(options: DateTimeFormatOptions): string {
return this.instance.date(); return this.instance.date().toString();
} }
public getGregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay { public getGregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay {
return (this.instance.year() + '-' + (this.instance.month() + 1).toString().padStart(2, '0') + '-' + this.instance.date().toString().padStart(2, '0')) as TextualYearMonthDay; return (this.instance.year() + '-' + (this.instance.month() + 1).toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero) + '-' + this.instance.date().toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero)) as TextualYearMonthDay;
} }
public getGregorianCalendarYearDashMonth(): TextualYearMonth { public getGregorianCalendarYearDashMonth(): TextualYearMonth {
return (this.instance.year() + '-' + (this.instance.month() + 1).toString().padStart(2, '0')) as TextualYearMonth; return (this.instance.year() + '-' + (this.instance.month() + 1).toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero)) as TextualYearMonth;
} }
public getWeekDay(): WeekDay { public getWeekDay(): WeekDay {
@@ -255,11 +265,15 @@ class MomentDateTime implements DateTime {
const formattedResult: DateTimeFormatResult = formatFunc(this, options); const formattedResult: DateTimeFormatResult = formatFunc(this, options);
let formattedValue: string = formattedResult.value.toString(); let formattedValue: string = formattedResult.value.toString();
if (isNumber(formattedResult.value)) { if (isDefined(formattedResult.minNumeralLength)) {
if (isDefined(formattedResult.numeralLength)) { formattedValue = formattedValue.padStart(formattedResult.minNumeralLength, NumeralSystem.WesternArabicNumerals.digitZero);
formattedValue = formattedValue.padStart(formattedResult.numeralLength, '0'); }
}
if (isDefined(formattedResult.maxLength) && formattedValue.length > formattedResult.maxLength) {
formattedValue = formattedValue.substring(formattedValue.length - formattedResult.maxLength);
}
if (isNumber(formattedResult.value)) {
if (options && options.numeralSystem) { if (options && options.numeralSystem) {
formattedValue = options.numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(formattedValue); formattedValue = options.numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(formattedValue);
} }
@@ -407,8 +421,8 @@ export function getUtcOffsetByUtcOffsetMinutes(utcOffsetMinutes: number): string
const offsetHours = Math.trunc(Math.abs(utcOffsetMinutes) / 60); const offsetHours = Math.trunc(Math.abs(utcOffsetMinutes) / 60);
const offsetMinutes = Math.abs(utcOffsetMinutes) - offsetHours * 60; const offsetMinutes = Math.abs(utcOffsetMinutes) - offsetHours * 60;
const finalOffsetHours = offsetHours.toString().padStart(2, '0'); const finalOffsetHours = offsetHours.toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero);
const finalOffsetMinutes = offsetMinutes.toString().padStart(2, '0'); const finalOffsetMinutes = offsetMinutes.toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero);
if (utcOffsetMinutes >= 0) { if (utcOffsetMinutes >= 0) {
return `+${finalOffsetHours}:${finalOffsetMinutes}`; return `+${finalOffsetHours}:${finalOffsetMinutes}`;
@@ -442,7 +456,7 @@ export function getLocalDatetimeFromUnixTime(unixTime: number): Date {
} }
export function getUnixTimeFromLocalDatetime(datetime: Date): number { export function getUnixTimeFromLocalDatetime(datetime: Date): number {
return datetime.getTime() / 1000; return Math.floor(datetime.getTime() / 1000);
} }
export function getActualUnixTimeForStore(unixTime: number, utcOffset: number, currentUtcOffset: number): number { export function getActualUnixTimeForStore(unixTime: number, utcOffset: number, currentUtcOffset: number): number {
@@ -461,6 +475,11 @@ export function getCurrentUnixTime(): number {
return moment().unix(); return moment().unix();
} }
export function getYearMonthDayDateTime(year: number, month: number, day: number): DateTime {
const date = moment().set({ year: year, month: month - 1, date: day, hour: 0, minute: 0, second: 0, millisecond: 0 });
return MomentDateTime.of(date);
}
export function parseDateTimeFromUnixTime(unixTime: number, utcOffset?: number, currentUtcOffset?: number): DateTime { export function parseDateTimeFromUnixTime(unixTime: number, utcOffset?: number, currentUtcOffset?: number): DateTime {
if (isNumber(utcOffset)) { if (isNumber(utcOffset)) {
if (!isNumber(currentUtcOffset)) { if (!isNumber(currentUtcOffset)) {
@@ -489,6 +508,50 @@ export function formatGregorianCalendarMonthDashDay(monthDay: TextualYearMonth,
return MomentDateTime.of(moment(monthDay, 'MM-DD')).format(format, options); return MomentDateTime.of(moment(monthDay, 'MM-DD')).format(format, options);
} }
export function getLocalDateFromYearDashMonthDashDay(date: TextualYearMonthDay): Date | null {
if (!isString(date)) {
return null;
}
const items = date.split('-');
if (items.length !== 3) {
return null;
}
const year = parseInt(items[0]);
const month = parseInt(items[1]);
const day = parseInt(items[2]);
if (!isNumber(year) || !isNumber(month) || !isNumber(day)) {
return null;
}
if (year < 1000 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31) {
return null;
}
const dateObj = new Date(year, month - 1, day);
if (dateObj.getFullYear() !== year || dateObj.getMonth() !== (month - 1) || dateObj.getDate() !== day) {
return null;
}
return dateObj;
}
export function getGregorianCalendarYearAndMonthFromLocalDate(date: Date): TextualYearMonthDay | '' {
if (!date) {
return '';
}
const year = date.getFullYear().toString().padStart(4, NumeralSystem.WesternArabicNumerals.digitZero);
const month = (date.getMonth() + 1).toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero);
const day = (date.getDate()).toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero);
return (`${year}-${month}-${day}`) as TextualYearMonthDay;
}
export function getGregorianCalendarYearAndMonthFromUnixTime(unixTime: number): TextualYearMonth | '' { export function getGregorianCalendarYearAndMonthFromUnixTime(unixTime: number): TextualYearMonth | '' {
if (!unixTime) { if (!unixTime) {
return ''; return '';
+5 -5
View File
@@ -76,9 +76,9 @@
"dd_mm_yyyy": "DD.MM" "dd_mm_yyyy": "DD.MM"
}, },
"shortDay": { "shortDay": {
"yyyy_mm_dd": "DD", "yyyy_mm_dd": "D",
"mm_dd_yyyy": "DD", "mm_dd_yyyy": "D",
"dd_mm_yyyy": "DD" "dd_mm_yyyy": "D"
}, },
"longTime": { "longTime": {
"hh_mm_ss": "HH:mm:ss", "hh_mm_ss": "HH:mm:ss",
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Transaktionsliste kann nicht abgerufen werden", "Unable to retrieve transaction list": "Transaktionsliste kann nicht abgerufen werden",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Benutzerdefinierter Datumsbereich", "Custom Date Range": "Benutzerdefinierter Datumsbereich",
"Select Month": "Select Month",
"Transaction Detail": "Transaktionsdetails", "Transaction Detail": "Transaktionsdetails",
"No transaction data": "Keine Transaktionsdaten", "No transaction data": "Keine Transaktionsdaten",
"Are you sure you want to delete this transaction?": "Sind Sie sicher, dass Sie diese Transaktion löschen möchten?", "Are you sure you want to delete this transaction?": "Sind Sie sicher, dass Sie diese Transaktion löschen möchten?",
+2 -2
View File
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Unable to retrieve transaction list", "Unable to retrieve transaction list": "Unable to retrieve transaction list",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Custom Date Range", "Custom Date Range": "Custom Date Range",
"Select Month": "Select Month",
"Transaction Detail": "Transaction Detail", "Transaction Detail": "Transaction Detail",
"No transaction data": "No transaction data", "No transaction data": "No transaction data",
"Are you sure you want to delete this transaction?": "Are you sure you want to delete this transaction?", "Are you sure you want to delete this transaction?": "Are you sure you want to delete this transaction?",
+5 -5
View File
@@ -76,9 +76,9 @@
"dd_mm_yyyy": "DD/MM" "dd_mm_yyyy": "DD/MM"
}, },
"shortDay": { "shortDay": {
"yyyy_mm_dd": "DD", "yyyy_mm_dd": "D",
"mm_dd_yyyy": "DD", "mm_dd_yyyy": "D",
"dd_mm_yyyy": "DD" "dd_mm_yyyy": "D"
}, },
"longTime": { "longTime": {
"hh_mm_ss": "H:mm:ss", "hh_mm_ss": "H:mm:ss",
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "No se puede recuperar la lista de transacciones", "Unable to retrieve transaction list": "No se puede recuperar la lista de transacciones",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Rango de fechas personalizado", "Custom Date Range": "Rango de fechas personalizado",
"Select Month": "Select Month",
"Transaction Detail": "Detalle de la transacción", "Transaction Detail": "Detalle de la transacción",
"No transaction data": "Sin datos de transacción", "No transaction data": "Sin datos de transacción",
"Are you sure you want to delete this transaction?": "¿Está seguro de que desea eliminar esta transacción?", "Are you sure you want to delete this transaction?": "¿Está seguro de que desea eliminar esta transacción?",
+22 -19
View File
@@ -669,20 +669,20 @@ export function useI18n() {
} }
function getDateTimeFormatOptions(options?: { calendarType?: CalendarType, numeralSystem?: NumeralSystem }): DateTimeFormatOptions { function getDateTimeFormatOptions(options?: { calendarType?: CalendarType, numeralSystem?: NumeralSystem }): DateTimeFormatOptions {
let calendarType: CalendarType | undefined = options?.calendarType;
let numeralSystem: NumeralSystem | undefined = options?.numeralSystem; let numeralSystem: NumeralSystem | undefined = options?.numeralSystem;
let calendarType: CalendarType | undefined = options?.calendarType;
if (!isDefined(calendarType)) {
calendarType = getCurrentDateDisplayType().calendarType;
}
if (!isDefined(numeralSystem)) { if (!isDefined(numeralSystem)) {
numeralSystem = getCurrentNumeralSystemType(); numeralSystem = getCurrentNumeralSystemType();
} }
if (!isDefined(calendarType)) {
calendarType = getCurrentDateDisplayType().calendarType;
}
return { return {
calendarType: calendarType,
numeralSystem: numeralSystem, numeralSystem: numeralSystem,
calendarType: calendarType,
localeData: getDateTimeLocaleData() localeData: getDateTimeLocaleData()
}; };
} }
@@ -966,10 +966,10 @@ export function useI18n() {
return ret; return ret;
} }
function getLocalizedDateTimeFormats<T extends DateFormat | TimeFormat>(type: string, allFormatMap: Record<string, T>, allFormatArray: T[], languageDefaultTypeNameKey: string, systemDefaultFormatType: T, calendarType?: CalendarType): LocalizedDateTimeFormat[] { function getLocalizedDateTimeFormats<T extends DateFormat | TimeFormat>(type: string, allFormatMap: Record<string, T>, allFormatArray: T[], languageDefaultTypeNameKey: string, systemDefaultFormatType: T, numeralSystem: NumeralSystem, calendarType?: CalendarType): LocalizedDateTimeFormat[] {
const defaultFormat = getLocalizedDateTimeFormat<T>(type, allFormatMap, allFormatArray, LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE, languageDefaultTypeNameKey, systemDefaultFormatType); const defaultFormat = getLocalizedDateTimeFormat<T>(type, allFormatMap, allFormatArray, LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE, languageDefaultTypeNameKey, systemDefaultFormatType);
const ret: LocalizedDateTimeFormat[] = []; const ret: LocalizedDateTimeFormat[] = [];
const dateTimeFormatOptions = getDateTimeFormatOptions({ calendarType: calendarType }); const dateTimeFormatOptions = getDateTimeFormatOptions({ numeralSystem, calendarType });
ret.push({ ret.push({
type: LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE, type: LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE,
@@ -1127,7 +1127,7 @@ export function useI18n() {
]; ];
} }
function getAllFiscalYearFormats(): TypeAndDisplayName[] { function getAllFiscalYearFormats(numeralSystem: NumeralSystem, calendarType: CalendarType): TypeAndDisplayName[] {
const now = getCurrentUnixTime(); const now = getCurrentUnixTime();
let fiscalYearStart = userStore.currentUserFiscalYearStart; let fiscalYearStart = userStore.currentUserFiscalYearStart;
@@ -1146,7 +1146,7 @@ export function useI18n() {
ret.push({ ret.push({
type: LANGUAGE_DEFAULT_FISCAL_YEAR_FORMAT_VALUE, type: LANGUAGE_DEFAULT_FISCAL_YEAR_FORMAT_VALUE,
displayName: `${t('Language Default')} (${formatTimeRangeToFiscalYearFormat(defaultFiscalYearFormat, currentFiscalYearRange)})` displayName: `${t('Language Default')} (${formatTimeRangeToFiscalYearFormat(defaultFiscalYearFormat, currentFiscalYearRange, numeralSystem, calendarType)})`
}); });
const allFiscalYearFormats = FiscalYearFormat.values(); const allFiscalYearFormats = FiscalYearFormat.values();
@@ -1156,7 +1156,7 @@ export function useI18n() {
ret.push({ ret.push({
type: fiscalYearFormat.type, type: fiscalYearFormat.type,
displayName: formatTimeRangeToFiscalYearFormat(fiscalYearFormat, currentFiscalYearRange), displayName: formatTimeRangeToFiscalYearFormat(fiscalYearFormat, currentFiscalYearRange, numeralSystem, calendarType),
}); });
} }
@@ -1728,7 +1728,7 @@ export function useI18n() {
return formatYearQuarter(year, quarter); return formatYearQuarter(year, quarter);
} }
function formatYearQuarter(year: number, quarter: number): string { function formatYearQuarter(year: number | string, quarter: number): string {
if (1 <= quarter && quarter <= 4) { if (1 <= quarter && quarter <= 4) {
return t('format.yearQuarter.q' + quarter, { return t('format.yearQuarter.q' + quarter, {
year: year, year: year,
@@ -1788,12 +1788,12 @@ export function useI18n() {
return `${displayStartTime} ~ ${displayEndTime}`; return `${displayStartTime} ~ ${displayEndTime}`;
} }
function formatTimeRangeToFiscalYearFormat(format: FiscalYearFormat, timeRange: FiscalYearUnixTime | UnixTimeRange): string { function formatTimeRangeToFiscalYearFormat(format: FiscalYearFormat, timeRange: FiscalYearUnixTime | UnixTimeRange, numeralSystem?: NumeralSystem, calendarType?: CalendarType): string {
if (!format) { if (!format) {
format = FiscalYearFormat.Default; format = FiscalYearFormat.Default;
} }
const dateTimeFormatOptions = getDateTimeFormatOptions(); const dateTimeFormatOptions = getDateTimeFormatOptions({ numeralSystem, calendarType });
return t('format.fiscalYear.' + format.typeName, { return t('format.fiscalYear.' + format.typeName, {
StartYYYY: formatUnixTime(timeRange.minUnixTime, 'YYYY', dateTimeFormatOptions), StartYYYY: formatUnixTime(timeRange.minUnixTime, 'YYYY', dateTimeFormatOptions),
@@ -2193,10 +2193,10 @@ export function useI18n() {
getAllWeekDays, getAllWeekDays,
getAllCalendarDisplayTypes: () => getAllLocalizedCalendarTypes(CalendarDisplayType.values(), CalendarDisplayType.parse(t('default.calendarDisplayType')), CalendarDisplayType.Default, CalendarDisplayType.LanguageDefaultType), getAllCalendarDisplayTypes: () => getAllLocalizedCalendarTypes(CalendarDisplayType.values(), CalendarDisplayType.parse(t('default.calendarDisplayType')), CalendarDisplayType.Default, CalendarDisplayType.LanguageDefaultType),
getAllDateDisplayTypes: () => getAllLocalizedCalendarTypes(DateDisplayType.values(), DateDisplayType.parse(t('default.dateDisplayType')), DateDisplayType.Default, DateDisplayType.LanguageDefaultType), getAllDateDisplayTypes: () => getAllLocalizedCalendarTypes(DateDisplayType.values(), DateDisplayType.parse(t('default.dateDisplayType')), DateDisplayType.Default, DateDisplayType.LanguageDefaultType),
getAllLongDateFormats: (calendarType?: CalendarType) => getLocalizedDateTimeFormats<LongDateFormat>('longDate', LongDateFormat.all(), LongDateFormat.values(), 'longDateFormat', LongDateFormat.Default, calendarType), getAllLongDateFormats: (numeralSystem: NumeralSystem, calendarType: CalendarType) => getLocalizedDateTimeFormats<LongDateFormat>('longDate', LongDateFormat.all(), LongDateFormat.values(), 'longDateFormat', LongDateFormat.Default, numeralSystem, calendarType),
getAllShortDateFormats: (calendarType?: CalendarType) => getLocalizedDateTimeFormats<ShortDateFormat>('shortDate', ShortDateFormat.all(), ShortDateFormat.values(), 'shortDateFormat', ShortDateFormat.Default, calendarType), getAllShortDateFormats: (numeralSystem: NumeralSystem, calendarType: CalendarType) => getLocalizedDateTimeFormats<ShortDateFormat>('shortDate', ShortDateFormat.all(), ShortDateFormat.values(), 'shortDateFormat', ShortDateFormat.Default, numeralSystem, calendarType),
getAllLongTimeFormats: (calendarType?: CalendarType) => getLocalizedDateTimeFormats<LongTimeFormat>('longTime', LongTimeFormat.all(), LongTimeFormat.values(), 'longTimeFormat', LongTimeFormat.Default, calendarType), getAllLongTimeFormats: (numeralSystem: NumeralSystem) => getLocalizedDateTimeFormats<LongTimeFormat>('longTime', LongTimeFormat.all(), LongTimeFormat.values(), 'longTimeFormat', LongTimeFormat.Default, numeralSystem),
getAllShortTimeFormats: (calendarType?: CalendarType) => getLocalizedDateTimeFormats<ShortTimeFormat>('shortTime', ShortTimeFormat.all(), ShortTimeFormat.values(), 'shortTimeFormat', ShortTimeFormat.Default, calendarType), getAllShortTimeFormats: (numeralSystem: NumeralSystem) => getLocalizedDateTimeFormats<ShortTimeFormat>('shortTime', ShortTimeFormat.all(), ShortTimeFormat.values(), 'shortTimeFormat', ShortTimeFormat.Default, numeralSystem),
getAllFiscalYearFormats, getAllFiscalYearFormats,
getAllDateRanges, getAllDateRanges,
getAllRecentMonthDateRanges, getAllRecentMonthDateRanges,
@@ -2256,7 +2256,10 @@ export function useI18n() {
isLongTimeMinuteTwoDigits, isLongTimeMinuteTwoDigits,
isLongTimeSecondTwoDigits, isLongTimeSecondTwoDigits,
// format functions // format functions
formatUnixTimeToDefaultDateTimeWithoutLocaleOptions: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, KnownDateTimeFormat.DefaultDateTime.format, getDateTimeFormatOptions({ calendarType: CalendarType.Gregorian, numeralSystem: NumeralSystem.WesternArabicNumerals }), utcOffset, currentUtcOffset), getCalendarShortYearFromUnixTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortYearFormat(), getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType }), utcOffset, currentUtcOffset),
getCalendarShortMonthFromUnixTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, 'MMM', getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType }), utcOffset, currentUtcOffset),
getCalendarDayOfMonthFromUnixTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDayFormat(), getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType }), utcOffset, currentUtcOffset),
formatUnixTimeToDefaultDateTimeWithoutLocaleOptions: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, KnownDateTimeFormat.DefaultDateTime.format, getDateTimeFormatOptions({ numeralSystem: NumeralSystem.WesternArabicNumerals, calendarType: CalendarType.Gregorian }), utcOffset, currentUtcOffset),
formatUnixTimeToLongDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat() + ' ' + getLocalizedLongTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset), formatUnixTimeToLongDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat() + ' ' + getLocalizedLongTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
formatUnixTimeToShortDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDateFormat() + ' ' + getLocalizedShortTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset), formatUnixTimeToShortDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDateFormat() + ' ' + getLocalizedShortTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
formatUnixTimeToLongDate: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset), formatUnixTimeToLongDate: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
+5 -5
View File
@@ -76,9 +76,9 @@
"dd_mm_yyyy": "DD/MM" "dd_mm_yyyy": "DD/MM"
}, },
"shortDay": { "shortDay": {
"yyyy_mm_dd": "DD", "yyyy_mm_dd": "D",
"mm_dd_yyyy": "DD", "mm_dd_yyyy": "D",
"dd_mm_yyyy": "DD" "dd_mm_yyyy": "D"
}, },
"longTime": { "longTime": {
"hh_mm_ss": "HH:mm:ss", "hh_mm_ss": "HH:mm:ss",
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Impossibile recuperare l'elenco delle transazioni", "Unable to retrieve transaction list": "Impossibile recuperare l'elenco delle transazioni",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Intervallo date personalizzato", "Custom Date Range": "Intervallo date personalizzato",
"Select Month": "Select Month",
"Transaction Detail": "Dettaglio transazione", "Transaction Detail": "Dettaglio transazione",
"No transaction data": "Nessun dato di transazione", "No transaction data": "Nessun dato di transazione",
"Are you sure you want to delete this transaction?": "Sei sicuro di voler eliminare questa transazione?", "Are you sure you want to delete this transaction?": "Sei sicuro di voler eliminare questa transazione?",
+2 -2
View File
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "取引リストを取得できません", "Unable to retrieve transaction list": "取引リストを取得できません",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "カスタム日付範囲", "Custom Date Range": "カスタム日付範囲",
"Select Month": "Select Month",
"Transaction Detail": "取引の詳細", "Transaction Detail": "取引の詳細",
"No transaction data": "取引データがありません", "No transaction data": "取引データがありません",
"Are you sure you want to delete this transaction?": "この取引を削除しますか?", "Are you sure you want to delete this transaction?": "この取引を削除しますか?",
+2 -2
View File
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Kan transactielijst niet ophalen", "Unable to retrieve transaction list": "Kan transactielijst niet ophalen",
"Unable to retrieve reconciliation statements": "Kan afstemmingsrapporten niet ophalen", "Unable to retrieve reconciliation statements": "Kan afstemmingsrapporten niet ophalen",
"Custom Date Range": "Aangepast datumbereik", "Custom Date Range": "Aangepast datumbereik",
"Select Month": "Select Month",
"Transaction Detail": "Transactiedetail", "Transaction Detail": "Transactiedetail",
"No transaction data": "Geen transactiegegevens", "No transaction data": "Geen transactiegegevens",
"Are you sure you want to delete this transaction?": "Weet je zeker dat je deze transactie wilt verwijderen?", "Are you sure you want to delete this transaction?": "Weet je zeker dat je deze transactie wilt verwijderen?",
+5 -5
View File
@@ -76,9 +76,9 @@
"dd_mm_yyyy": "DD/MM" "dd_mm_yyyy": "DD/MM"
}, },
"shortDay": { "shortDay": {
"yyyy_mm_dd": "DD", "yyyy_mm_dd": "D",
"mm_dd_yyyy": "DD", "mm_dd_yyyy": "D",
"dd_mm_yyyy": "DD" "dd_mm_yyyy": "D"
}, },
"longTime": { "longTime": {
"hh_mm_ss": "HH:mm:ss", "hh_mm_ss": "HH:mm:ss",
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Incapaz de recuperar a lista de transações", "Unable to retrieve transaction list": "Incapaz de recuperar a lista de transações",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Intervalo de Datas Personalizado", "Custom Date Range": "Intervalo de Datas Personalizado",
"Select Month": "Select Month",
"Transaction Detail": "Detalhes da Transação", "Transaction Detail": "Detalhes da Transação",
"No transaction data": "Sem dados de transação", "No transaction data": "Sem dados de transação",
"Are you sure you want to delete this transaction?": "Tem certeza de que deseja excluir esta transação?", "Are you sure you want to delete this transaction?": "Tem certeza de que deseja excluir esta transação?",
+5 -5
View File
@@ -76,9 +76,9 @@
"dd_mm_yyyy": "DD.MM" "dd_mm_yyyy": "DD.MM"
}, },
"shortDay": { "shortDay": {
"yyyy_mm_dd": "DD", "yyyy_mm_dd": "D",
"mm_dd_yyyy": "DD", "mm_dd_yyyy": "D",
"dd_mm_yyyy": "DD" "dd_mm_yyyy": "D"
}, },
"longTime": { "longTime": {
"hh_mm_ss": "H:mm:ss", "hh_mm_ss": "H:mm:ss",
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Не удалось получить список транзакций", "Unable to retrieve transaction list": "Не удалось получить список транзакций",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Пользовательский диапазон дат", "Custom Date Range": "Пользовательский диапазон дат",
"Select Month": "Select Month",
"Transaction Detail": "Детали транзакции", "Transaction Detail": "Детали транзакции",
"No transaction data": "Нет данных о транзакциях", "No transaction data": "Нет данных о транзакциях",
"Are you sure you want to delete this transaction?": "Вы уверены, что хотите удалить эту транзакцию?", "Are you sure you want to delete this transaction?": "Вы уверены, что хотите удалить эту транзакцию?",
+5 -5
View File
@@ -76,9 +76,9 @@
"dd_mm_yyyy": "DD.MM" "dd_mm_yyyy": "DD.MM"
}, },
"shortDay": { "shortDay": {
"yyyy_mm_dd": "DD", "yyyy_mm_dd": "D",
"mm_dd_yyyy": "DD", "mm_dd_yyyy": "D",
"dd_mm_yyyy": "DD" "dd_mm_yyyy": "D"
}, },
"longTime": { "longTime": {
"hh_mm_ss": "HH:mm:ss", "hh_mm_ss": "HH:mm:ss",
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Не вдалося отримати список транзакцій", "Unable to retrieve transaction list": "Не вдалося отримати список транзакцій",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Користувацький діапазон дат", "Custom Date Range": "Користувацький діапазон дат",
"Select Month": "Select Month",
"Transaction Detail": "Деталі транзакції", "Transaction Detail": "Деталі транзакції",
"No transaction data": "Немає даних про транзакції", "No transaction data": "Немає даних про транзакції",
"Are you sure you want to delete this transaction?": "Ви впевнені, що хочете видалити цю транзакцію?", "Are you sure you want to delete this transaction?": "Ви впевнені, що хочете видалити цю транзакцію?",
+2 -2
View File
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "Gregorian", "Gregorian": "Gregorian",
"Buddhist": "Buddhist", "Buddhist": "Buddhist"
"Gregorian (with Chinese Calendar)": "Gregorian (with Chinese Calendar)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "Không thể lấy danh sách giao dịch", "Unable to retrieve transaction list": "Không thể lấy danh sách giao dịch",
"Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements", "Unable to retrieve reconciliation statements": "Unable to retrieve reconciliation statements",
"Custom Date Range": "Phạm vi ngày tùy chỉnh", "Custom Date Range": "Phạm vi ngày tùy chỉnh",
"Select Month": "Select Month",
"Transaction Detail": "Chi tiết giao dịch", "Transaction Detail": "Chi tiết giao dịch",
"No transaction data": "Không có dữ liệu giao dịch", "No transaction data": "Không có dữ liệu giao dịch",
"Are you sure you want to delete this transaction?": "Bạn có chắc chắn muốn xóa giao dịch này không?", "Are you sure you want to delete this transaction?": "Bạn có chắc chắn muốn xóa giao dịch này không?",
+2 -2
View File
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "公历", "Gregorian": "公历",
"Buddhist": "佛教日历", "Buddhist": "佛教日历"
"Gregorian (with Chinese Calendar)": "公历(含农历)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "无法获取交易列表", "Unable to retrieve transaction list": "无法获取交易列表",
"Unable to retrieve reconciliation statements": "无法获取对账单", "Unable to retrieve reconciliation statements": "无法获取对账单",
"Custom Date Range": "自定义日期范围", "Custom Date Range": "自定义日期范围",
"Select Month": "选择月份",
"Transaction Detail": "交易详情", "Transaction Detail": "交易详情",
"No transaction data": "没有交易数据", "No transaction data": "没有交易数据",
"Are you sure you want to delete this transaction?": "您确定要删除该交易?", "Are you sure you want to delete this transaction?": "您确定要删除该交易?",
+2 -2
View File
@@ -138,8 +138,7 @@
}, },
"calendar": { "calendar": {
"Gregorian": "公曆", "Gregorian": "公曆",
"Buddhist": "佛曆", "Buddhist": "佛曆"
"Gregorian (with Chinese Calendar)": "公曆(含農曆)"
}, },
"datetime": { "datetime": {
"AM": { "AM": {
@@ -1857,6 +1856,7 @@
"Unable to retrieve transaction list": "無法取得交易清單", "Unable to retrieve transaction list": "無法取得交易清單",
"Unable to retrieve reconciliation statements": "無法取得對帳單", "Unable to retrieve reconciliation statements": "無法取得對帳單",
"Custom Date Range": "自訂日期範圍", "Custom Date Range": "自訂日期範圍",
"Select Month": "選擇月份",
"Transaction Detail": "交易明細", "Transaction Detail": "交易明細",
"No transaction data": "沒有交易資料", "No transaction data": "沒有交易資料",
"Are you sure you want to delete this transaction?": "您確定要刪除這筆交易?", "Are you sure you want to delete this transaction?": "您確定要刪除這筆交易?",
+6
View File
@@ -49,6 +49,9 @@ import { getI18nOptions } from '@/locales/helpers.ts';
import PinCodeInput from '@/components/common/PinCodeInput.vue'; import PinCodeInput from '@/components/common/PinCodeInput.vue';
import MapView from '@/components/common/MapView.vue'; import MapView from '@/components/common/MapView.vue';
import DateTimePicker from '@/components/common/DateTimePicker.vue';
import MonthPicker from '@/components/common/MonthPicker.vue';
import TransactionCalendar from '@/components/common/TransactionCalendar.vue';
import ItemIcon from '@/components/mobile/ItemIcon.vue'; import ItemIcon from '@/components/mobile/ItemIcon.vue';
import LanguageSelectButton from '@/components/mobile/LanguageSelectButton.vue'; import LanguageSelectButton from '@/components/mobile/LanguageSelectButton.vue';
@@ -139,6 +142,9 @@ app.component('VueDatePicker', VueDatePicker);
app.component('PinCodeInput', PinCodeInput); app.component('PinCodeInput', PinCodeInput);
app.component('MapView', MapView); app.component('MapView', MapView);
app.component('DateTimePicker', DateTimePicker);
app.component('MonthPicker', MonthPicker);
app.component('TransactionCalendar', TransactionCalendar);
app.component('ItemIcon', ItemIcon); app.component('ItemIcon', ItemIcon);
app.component('LanguageSelectButton', LanguageSelectButton); app.component('LanguageSelectButton', LanguageSelectButton);
@@ -26,12 +26,10 @@ import {
getTimezoneOffsetMinutes, getTimezoneOffsetMinutes,
getBrowserTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes,
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
getActualUnixTimeForStore,
getDummyUnixTimeForLocalUsage, getDummyUnixTimeForLocalUsage,
getCurrentDateTime, getCurrentDateTime,
parseDateTimeFromUnixTime, parseDateTimeFromUnixTime,
getYearMonthFirstUnixTime, getYearMonthFirstUnixTime,
getUnixTimeFromLocalDatetime,
isDateRangeMatchOneMonth isDateRangeMatchOneMonth
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
@@ -257,11 +255,6 @@ export function useTransactionListPageBase() {
return null; return null;
}); });
function noTransactionInMonthDay(date: Date): boolean {
const dateTime = parseDateTimeFromUnixTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[dateTime.getGregorianCalendarDay()];
}
const canAddTransaction = computed<boolean>(() => { const canAddTransaction = computed<boolean>(() => {
if (query.value.accountIds && queryAllFilterAccountIdsCount.value === 1) { if (query.value.accountIds && queryAllFilterAccountIdsCount.value === 1) {
const account = allAccountsMap.value[query.value.accountIds]; const account = allAccountsMap.value[query.value.accountIds];
@@ -395,7 +388,6 @@ export function useTransactionListPageBase() {
transactionCalendarMinDate, transactionCalendarMinDate,
transactionCalendarMaxDate, transactionCalendarMaxDate,
currentMonthTransactionData, currentMonthTransactionData,
noTransactionInMonthDay,
canAddTransaction, canAddTransaction,
// functions // functions
getDisplayTime, getDisplayTime,
+5 -5
View File
@@ -63,11 +63,11 @@ export function useUserProfilePageBase() {
const allWeekDays = computed<TypeAndDisplayName[]>(() => getAllWeekDays()); const allWeekDays = computed<TypeAndDisplayName[]>(() => getAllWeekDays());
const allCalendarDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCalendarDisplayTypes()); const allCalendarDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCalendarDisplayTypes());
const allDateDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllDateDisplayTypes()); const allDateDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllDateDisplayTypes());
const allLongDateFormats = computed<TypeAndDisplayName[]>(() => getAllLongDateFormats(DateDisplayType.valueOf(newProfile.value.dateDisplayType)?.calendarType)); const allLongDateFormats = computed<TypeAndDisplayName[]>(() => getAllLongDateFormats(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default, DateDisplayType.valueOf(newProfile.value.dateDisplayType)?.calendarType || DateDisplayType.Default.calendarType));
const allShortDateFormats = computed<TypeAndDisplayName[]>(() => getAllShortDateFormats(DateDisplayType.valueOf(newProfile.value.dateDisplayType)?.calendarType)); const allShortDateFormats = computed<TypeAndDisplayName[]>(() => getAllShortDateFormats(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default, DateDisplayType.valueOf(newProfile.value.dateDisplayType)?.calendarType || DateDisplayType.Default.calendarType));
const allLongTimeFormats = computed<TypeAndDisplayName[]>(() => getAllLongTimeFormats()); const allLongTimeFormats = computed<TypeAndDisplayName[]>(() => getAllLongTimeFormats(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default));
const allShortTimeFormats = computed<TypeAndDisplayName[]>(() => getAllShortTimeFormats()); const allShortTimeFormats = computed<TypeAndDisplayName[]>(() => getAllShortTimeFormats(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default));
const allFiscalYearFormats = computed<TypeAndDisplayName[]>(() => getAllFiscalYearFormats()); const allFiscalYearFormats = computed<TypeAndDisplayName[]>(() => getAllFiscalYearFormats(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default, DateDisplayType.valueOf(newProfile.value.dateDisplayType)?.calendarType || DateDisplayType.Default.calendarType));
const allCurrencyDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCurrencyDisplayTypes(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default, DecimalSeparator.valueOf(newProfile.value.decimalSeparator)?.symbol || DecimalSeparator.Default.symbol)); const allCurrencyDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCurrencyDisplayTypes(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default, DecimalSeparator.valueOf(newProfile.value.decimalSeparator)?.symbol || DecimalSeparator.Default.symbol));
const allNumeralSystemTypes = computed<TypeAndDisplayName[]>(() => getAllNumeralSystemTypes()); const allNumeralSystemTypes = computed<TypeAndDisplayName[]>(() => getAllNumeralSystemTypes());
const allDecimalSeparators = computed<TypeAndDisplayName[]>(() => getAllDecimalSeparators()); const allDecimalSeparators = computed<TypeAndDisplayName[]>(() => getAllDecimalSeparators());
+9 -40
View File
@@ -165,32 +165,13 @@
</v-card-text> </v-card-text>
<v-card-text class="transaction-calendar-container pt-0" v-if="pageType === TransactionListPageType.Calendar.type"> <v-card-text class="transaction-calendar-container pt-0" v-if="pageType === TransactionListPageType.Calendar.type">
<vue-date-picker inline auto-apply model-type="yyyy-MM-dd" <transaction-calendar day-has-transaction-class="font-weight-bold"
month-name-format="long" :readonly="loading" :is-dark-mode="isDarkMode"
:config="{ noSwipe: true }" :default-currency="defaultCurrency"
:readonly="loading" :min-date="transactionCalendarMinDate"
:disable-month-year-select="true" :max-date="transactionCalendarMaxDate"
:month-change-on-scroll="false" :dailyTotalAmounts="currentMonthTransactionData?.dailyTotalAmounts"
:month-change-on-arrows="false" v-model="currentCalendarDate"></transaction-calendar>
: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 d-flex flex-column align-center justify-center w-100">
<span :class="{ 'font-weight-bold': currentMonthTransactionData && currentMonthTransactionData.dailyTotalAmounts[day] }">{{ day }}</span>
<span class="text-income" v-if="currentMonthTransactionData && currentMonthTransactionData.dailyTotalAmounts[day] && currentMonthTransactionData.dailyTotalAmounts[day].income">{{ getDisplayMonthTotalAmount(currentMonthTransactionData.dailyTotalAmounts[day].income, defaultCurrency, '', currentMonthTransactionData.dailyTotalAmounts[day].incompleteIncome) }}</span>
<span class="text-expense" v-if="currentMonthTransactionData && currentMonthTransactionData.dailyTotalAmounts[day] && currentMonthTransactionData.dailyTotalAmounts[day].expense">{{ getDisplayMonthTotalAmount(currentMonthTransactionData.dailyTotalAmounts[day].expense, defaultCurrency, '', currentMonthTransactionData.dailyTotalAmounts[day].incompleteExpense) }}</span>
</div>
</template>
</vue-date-picker>
</v-card-text> </v-card-text>
<v-table class="transaction-table" :hover="!loading"> <v-table class="transaction-table" :hover="!loading">
@@ -629,7 +610,7 @@
@dateRange:change="changeCustomDateFilter" @dateRange:change="changeCustomDateFilter"
@error="onShowDateRangeError" /> @error="onShowDateRangeError" />
<month-selection-dialog :title="tt('Custom Date Range')" <month-selection-dialog :title="tt('Select Month')"
:model-value="queryMonth" :model-value="queryMonth"
v-model:show="showCustomMonthDialog" v-model:show="showCustomMonthDialog"
@update:modelValue="changeCustomMonthDateFilter" @update:modelValue="changeCustomMonthDateFilter"
@@ -704,8 +685,7 @@ import type { TransactionTemplate } from '@/models/transaction_template.ts';
import { import {
isObject, isObject,
isString, isString,
isNumber, isNumber
arrangeArrayWithNewStartIndex
} from '@/lib/common.ts'; } from '@/lib/common.ts';
import { import {
getCurrentUnixTime, getCurrentUnixTime,
@@ -792,7 +772,6 @@ const theme = useTheme();
const { const {
tt, tt,
getAllLongWeekdayNames,
getAllRecentMonthDateRanges, getAllRecentMonthDateRanges,
getAllTransactionTagFilterTypes, getAllTransactionTagFilterTypes,
getWeekdayLongName getWeekdayLongName
@@ -837,7 +816,6 @@ const {
transactionCalendarMinDate, transactionCalendarMinDate,
transactionCalendarMaxDate, transactionCalendarMaxDate,
currentMonthTransactionData, currentMonthTransactionData,
noTransactionInMonthDay,
canAddTransaction, canAddTransaction,
getDisplayTime, getDisplayTime,
getDisplayLongDate, getDisplayLongDate,
@@ -896,7 +874,6 @@ const showFilterCategoryDialog = ref<boolean>(false);
const showFilterTagDialog = ref<boolean>(false); const showFilterTagDialog = ref<boolean>(false);
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllLongWeekdayNames(), firstDayOfWeek.value));
const recentMonthDateRanges = computed<LocalizedRecentMonthDateRange[]>(() => getAllRecentMonthDateRanges(pageType.value === TransactionListPageType.List.type, true)); const recentMonthDateRanges = computed<LocalizedRecentMonthDateRange[]>(() => getAllRecentMonthDateRanges(pageType.value === TransactionListPageType.List.type, true));
@@ -1889,12 +1866,4 @@ init(props);
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item { .transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item {
overflow: hidden; overflow: hidden;
} }
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > span {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style> </style>
+10 -39
View File
@@ -67,33 +67,13 @@
</f7-toolbar> </f7-toolbar>
<f7-block class="transaction-calendar-container margin-vertical" v-if="pageType === TransactionListPageType.Calendar.type"> <f7-block class="transaction-calendar-container margin-vertical" v-if="pageType === TransactionListPageType.Calendar.type">
<vue-date-picker inline auto-apply model-type="yyyy-MM-dd" <transaction-calendar calendar-class="justify-content-center" week-day-name-type="short"
month-name-format="long" :readonly="loading" :is-dark-mode="isDarkMode"
class="justify-content-center" :default-currency="false"
:config="{ noSwipe: true }" :min-date="transactionCalendarMinDate"
:readonly="loading" :max-date="transactionCalendarMaxDate"
:disable-month-year-select="true" :dailyTotalAmounts="currentMonthTransactionData?.dailyTotalAmounts"
:month-change-on-scroll="false" v-model="currentCalendarDate"></transaction-calendar>
: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> </f7-block>
<div class="skeleton-text" v-if="loading"> <div class="skeleton-text" v-if="loading">
@@ -351,7 +331,7 @@
@dateRange:change="changeCustomDateFilter"> @dateRange:change="changeCustomDateFilter">
</date-range-selection-sheet> </date-range-selection-sheet>
<month-selection-sheet :title="tt('Custom Date Range')" <month-selection-sheet :title="tt('Select Month')"
:model-value="queryMonth" :model-value="queryMonth"
v-model:show="showCustomMonthSheet" v-model:show="showCustomMonthSheet"
@update:modelValue="changeCustomMonthDateFilter"> @update:modelValue="changeCustomMonthDateFilter">
@@ -632,8 +612,7 @@ import type { TransactionCategory } from '@/models/transaction_category.ts';
import type { Transaction } from '@/models/transaction.ts'; import type { Transaction } from '@/models/transaction.ts';
import { import {
isNumber, isNumber
arrangeArrayWithNewStartIndex
} from '@/lib/common.ts'; } from '@/lib/common.ts';
import { import {
getCurrentUnixTime, getCurrentUnixTime,
@@ -665,7 +644,6 @@ const props = defineProps<{
const { const {
tt, tt,
getCurrentLanguageTextDirection, getCurrentLanguageTextDirection,
getAllShortWeekdayNames,
getAllTransactionTagFilterTypes, getAllTransactionTagFilterTypes,
getWeekdayShortName, getWeekdayShortName,
formatUnixTimeToDayOfMonth formatUnixTimeToDayOfMonth
@@ -713,7 +691,6 @@ const {
transactionCalendarMinDate, transactionCalendarMinDate,
transactionCalendarMaxDate, transactionCalendarMaxDate,
currentMonthTransactionData, currentMonthTransactionData,
noTransactionInMonthDay,
canAddTransaction, canAddTransaction,
getDisplayTime, getDisplayTime,
getDisplayLongYearMonth, getDisplayLongYearMonth,
@@ -745,7 +722,6 @@ const showDeleteActionSheet = ref<boolean>(false);
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection()); const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false); const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllShortWeekdayNames(), firstDayOfWeek.value));
const allTransactionTagFilterTypes = computed<TypeAndDisplayName[]>(() => getAllTransactionTagFilterTypes()); const allTransactionTagFilterTypes = computed<TypeAndDisplayName[]>(() => getAllTransactionTagFilterTypes());
@@ -1697,12 +1673,7 @@ html[dir="rtl"] .list.transaction-info-list li.transaction-info .transaction-foo
white-space: nowrap; white-space: nowrap;
} }
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > small { .transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > span.transaction-calendar-daily-amount {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: var(--ebk-transaction-calendar-amount-font-size); font-size: var(--ebk-transaction-calendar-amount-font-size);
} }
</style> </style>
+1 -1
View File
@@ -226,7 +226,7 @@
<f7-list-item <f7-list-item
link="#" link="#"
class="list-item-with-header-and-title list-item-no-item-after" class="list-item-with-header-and-title list-item-no-item-after"
:header="tt('Calendar')" :header="tt('Calendar Display Type')"
:title="findDisplayNameByType(allCalendarDisplayTypes, newProfile.calendarDisplayType)" :title="findDisplayNameByType(allCalendarDisplayTypes, newProfile.calendarDisplayType)"
@click="showCalendarDisplayTypePopup = true" @click="showCalendarDisplayTypePopup = true"
> >