mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-18 05:02:14 +01:00
fix timezone issues and add support for timezone user setting
This commit is contained in:
@@ -1,26 +1,26 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import dayjs from 'dayjs';
|
import { getLocalizedDayJs } from '@/utils/time';
|
||||||
|
|
||||||
const model = defineModel<string | null>({
|
const model = defineModel<string | null>({
|
||||||
default: null,
|
default: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const hours = computed(() => {
|
const hours = computed(() => {
|
||||||
return model.value ? dayjs(model.value).utc().hour() : null;
|
return model.value ? getLocalizedDayJs(model.value).hour() : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const minutes = computed(() => {
|
const minutes = computed(() => {
|
||||||
return model.value ? dayjs(model.value).utc().minute() : null;
|
return model.value ? getLocalizedDayJs(model.value).minute() : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateMinutes(event: Event) {
|
function updateMinutes(event: Event) {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
const newValue = target.value;
|
const newValue = target.value;
|
||||||
if (!isNaN(parseInt(newValue))) {
|
if (!isNaN(parseInt(newValue))) {
|
||||||
model.value = dayjs(model.value)
|
model.value = getLocalizedDayJs(model.value)
|
||||||
.utc()
|
|
||||||
.set('minutes', parseInt(newValue))
|
.set('minutes', parseInt(newValue))
|
||||||
|
.utc()
|
||||||
.format();
|
.format();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,9 +29,9 @@ function updateHours(event: Event) {
|
|||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
const newValue = target.value;
|
const newValue = target.value;
|
||||||
if (!isNaN(parseInt(newValue))) {
|
if (!isNaN(parseInt(newValue))) {
|
||||||
model.value = dayjs(model.value)
|
model.value = getLocalizedDayJs(model.value)
|
||||||
.utc()
|
|
||||||
.set('hours', parseInt(newValue))
|
.set('hours', parseInt(newValue))
|
||||||
|
.utc()
|
||||||
.format();
|
.format();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
} from 'echarts/components';
|
} from 'echarts/components';
|
||||||
import { CanvasRenderer } from 'echarts/renderers';
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { formatDate, formatTime } from '@/utils/time';
|
import { formatDate, formatHumanReadableDuration } from '@/utils/time';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
dailyHoursTracked: { duration: number; date: string }[];
|
dailyHoursTracked: { duration: number; date: string }[];
|
||||||
@@ -76,11 +76,11 @@ const option = ref({
|
|||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
valueFormatter: (value: string, dataIndex: number) => {
|
valueFormatter: (value: number, dataIndex: number) => {
|
||||||
return (
|
return (
|
||||||
formatDate(props.dailyHoursTracked[dataIndex].date) +
|
formatDate(props.dailyHoursTracked[dataIndex].date) +
|
||||||
': ' +
|
': ' +
|
||||||
formatTime(value)
|
formatHumanReadableDuration(value)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import { computed, onMounted, ref, watch } from 'vue';
|
|||||||
import MainContainer from '@/Pages/MainContainer.vue';
|
import MainContainer from '@/Pages/MainContainer.vue';
|
||||||
import { useTimeEntriesStore } from '@/utils/useTimeEntries';
|
import { useTimeEntriesStore } from '@/utils/useTimeEntries';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import type { TimeEntry } from '@/utils/api';
|
import type { TimeEntry } from '@/utils/api';
|
||||||
import TimeEntryRowHeading from '@/Components/Common/TimeEntry/TimeEntryRowHeading.vue';
|
import TimeEntryRowHeading from '@/Components/Common/TimeEntry/TimeEntryRowHeading.vue';
|
||||||
import TimeEntryRow from '@/Components/Common/TimeEntry/TimeEntryRow.vue';
|
import TimeEntryRow from '@/Components/Common/TimeEntry/TimeEntryRow.vue';
|
||||||
import { useElementVisibility } from '@vueuse/core';
|
import { useElementVisibility } from '@vueuse/core';
|
||||||
import { ClockIcon } from '@heroicons/vue/20/solid';
|
import { ClockIcon } from '@heroicons/vue/20/solid';
|
||||||
|
import { getLocalizedDateFromTimestamp } from '@/utils/time';
|
||||||
|
|
||||||
const timeEntriesStore = useTimeEntriesStore();
|
const timeEntriesStore = useTimeEntriesStore();
|
||||||
const { timeEntries, allTimeEntriesLoaded } = storeToRefs(timeEntriesStore);
|
const { timeEntries, allTimeEntriesLoaded } = storeToRefs(timeEntriesStore);
|
||||||
@@ -38,10 +38,9 @@ const groupedTimeEntries = computed(() => {
|
|||||||
const groupedEntries: Record<string, TimeEntry[]> = {};
|
const groupedEntries: Record<string, TimeEntry[]> = {};
|
||||||
for (const entry of timeEntries.value) {
|
for (const entry of timeEntries.value) {
|
||||||
const oldEntries =
|
const oldEntries =
|
||||||
groupedEntries[dayjs(entry.start).utc().format('YYYY-MM-DD')];
|
groupedEntries[getLocalizedDateFromTimestamp(entry.start)];
|
||||||
const newEntries = [...(oldEntries ?? []), entry];
|
const newEntries = [...(oldEntries ?? []), entry];
|
||||||
groupedEntries[dayjs(entry.start).utc().format('YYYY-MM-DD')] =
|
groupedEntries[getLocalizedDateFromTimestamp(entry.start)] = newEntries;
|
||||||
newEntries;
|
|
||||||
}
|
}
|
||||||
return groupedEntries;
|
return groupedEntries;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,12 +4,19 @@ import relativeTime from 'dayjs/plugin/relativeTime';
|
|||||||
import isToday from 'dayjs/plugin/isToday';
|
import isToday from 'dayjs/plugin/isToday';
|
||||||
import isYesterday from 'dayjs/plugin/isYesterday';
|
import isYesterday from 'dayjs/plugin/isYesterday';
|
||||||
import utc from 'dayjs/plugin/utc';
|
import utc from 'dayjs/plugin/utc';
|
||||||
|
import timezone from 'dayjs/plugin/timezone';
|
||||||
|
import { getUserTimezone } from '@/utils/useUser';
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
dayjs.extend(isToday);
|
dayjs.extend(isToday);
|
||||||
dayjs.extend(isYesterday);
|
dayjs.extend(isYesterday);
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
|
dayjs.extend(timezone);
|
||||||
|
|
||||||
|
export function getDayJsInstance() {
|
||||||
|
return dayjs;
|
||||||
|
}
|
||||||
|
|
||||||
export function formatHumanReadableDuration(duration: number): string {
|
export function formatHumanReadableDuration(duration: number): string {
|
||||||
return dayjs.duration(duration, 's').format('HH[h] mm[min]');
|
return dayjs.duration(duration, 's').format('HH[h] mm[min]');
|
||||||
@@ -21,14 +28,35 @@ export function calculateDifference(start: string, end: string | null) {
|
|||||||
}
|
}
|
||||||
return dayjs(end).diff(dayjs(start), 'second');
|
return dayjs(end).diff(dayjs(start), 'second');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a formatted time.
|
||||||
|
* @param date - A UTC date time string.
|
||||||
|
*/
|
||||||
export function formatTime(date: string) {
|
export function formatTime(date: string) {
|
||||||
return dayjs(date).utc().format('HH:mm');
|
return dayjs.utc(date).tz(getUserTimezone()).format('HH:mm');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getLocalizedDayJs(timestamp: string | null) {
|
||||||
|
return dayjs.utc(timestamp).tz(getUserTimezone());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLocalizedDateFromTimestamp(timestamp: string) {
|
||||||
|
return getLocalizedDayJs(timestamp).format('YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a formatted date.
|
||||||
|
* @param date - date in the format of 'YYYY-MM-DD'
|
||||||
|
*/
|
||||||
export function formatDate(date: string): string {
|
export function formatDate(date: string): string {
|
||||||
return dayjs(date).utc().format('DD.MM.YYYY');
|
return dayjs(date).format('DD.MM.YYYY');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a human readable date format.
|
||||||
|
* @param date - date in the format of 'YYYY-MM-DD'
|
||||||
|
*/
|
||||||
export function formatHumanReadableDate(date: string) {
|
export function formatHumanReadableDate(date: string) {
|
||||||
if (dayjs(date).isToday()) {
|
if (dayjs(date).isToday()) {
|
||||||
return 'Today';
|
return 'Today';
|
||||||
|
|||||||
@@ -14,4 +14,8 @@ function getCurrentOrganizationId() {
|
|||||||
return page.props.auth.user.current_team_id;
|
return page.props.auth.user.current_team_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getCurrentOrganizationId, getCurrentUserId };
|
function getUserTimezone() {
|
||||||
|
return page.props.auth.user.timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getCurrentOrganizationId, getCurrentUserId, getUserTimezone };
|
||||||
|
|||||||
Reference in New Issue
Block a user