From fb3d326c28ca10eb36cf60862179b919659a009f Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Mon, 29 Apr 2024 16:47:46 +0200 Subject: [PATCH] respect start of week setting for charts --- e2e/timetracker.spec.ts | 1 + .../js/Components/CurrentSidebarTimer.vue | 4 +-- .../Dashboard/ActivityGraphCard.vue | 15 +++++++-- .../Components/Dashboard/ThisWeekOverview.vue | 32 +++++++++++++++++-- resources/js/utils/time.ts | 21 +++++++++++- resources/js/utils/useUser.ts | 11 ++++++- 6 files changed, 75 insertions(+), 9 deletions(-) diff --git a/e2e/timetracker.spec.ts b/e2e/timetracker.spec.ts index fbb11494..8a8cb707 100644 --- a/e2e/timetracker.spec.ts +++ b/e2e/timetracker.spec.ts @@ -35,6 +35,7 @@ test('test that starting and stopping a timer with a description works', async ( page, }) => { await goToDashboard(page); + // TODO: Fix flakyness by disabling description input field until timer is loaded await page .getByTestId('time_entry_description') .fill('New Time Entry Description'); diff --git a/resources/js/Components/CurrentSidebarTimer.vue b/resources/js/Components/CurrentSidebarTimer.vue index db2a3e3c..296a4342 100644 --- a/resources/js/Components/CurrentSidebarTimer.vue +++ b/resources/js/Components/CurrentSidebarTimer.vue @@ -5,9 +5,7 @@ import { computed } from 'vue'; import dayjs from 'dayjs'; import { formatHumanReadableDuration } from '@/utils/time'; import TimeTrackerStartStop from '@/Components/Common/TimeTrackerStartStop.vue'; -import { getCurrentOrganizationId } from "@/utils/useUser"; -import { switchOrganization } from "@/utils/useOrganization"; -import SecondaryButton from "@/Components/SecondaryButton.vue"; +import { getCurrentOrganizationId } from '@/utils/useUser'; const store = useCurrentTimeEntryStore(); const { currentTimeEntry, now, isActive } = storeToRefs(store); const { onToggleButtonPress } = store; diff --git a/resources/js/Components/Dashboard/ActivityGraphCard.vue b/resources/js/Components/Dashboard/ActivityGraphCard.vue index a0c1256a..95810f3d 100644 --- a/resources/js/Components/Dashboard/ActivityGraphCard.vue +++ b/resources/js/Components/Dashboard/ActivityGraphCard.vue @@ -13,7 +13,12 @@ import { } from 'echarts/components'; import { CanvasRenderer } from 'echarts/renderers'; import dayjs from 'dayjs'; -import { formatDate, formatHumanReadableDuration } from '@/utils/time'; +import { + firstDayIndex, + formatDate, + formatHumanReadableDuration, + getDayJsInstance, +} from '@/utils/time'; const props = defineProps<{ dailyHoursTracked: { duration: number; date: string }[]; @@ -55,12 +60,18 @@ const option = ref({ left: 40, right: 10, cellSize: [40, 40], + dayLabel: { + firstDay: firstDayIndex.value, + }, splitLine: { show: false, }, range: [ dayjs().format('YYYY-MM-DD'), - dayjs().subtract(50, 'day').startOf('week').format('YYYY-MM-DD'), + getDayJsInstance()() + .subtract(50, 'day') + .startOf('week') + .format('YYYY-MM-DD'), ], itemStyle: { borderWidth: 8, diff --git a/resources/js/Components/Dashboard/ThisWeekOverview.vue b/resources/js/Components/Dashboard/ThisWeekOverview.vue index 7ba65148..9cfadcc9 100644 --- a/resources/js/Components/Dashboard/ThisWeekOverview.vue +++ b/resources/js/Components/Dashboard/ThisWeekOverview.vue @@ -9,7 +9,7 @@ import { TooltipComponent, } from 'echarts/components'; import VChart, { THEME_KEY } from 'vue-echarts'; -import { provide, ref } from 'vue'; +import { computed, provide, ref } from 'vue'; import StatCard from '@/Components/Common/StatCard.vue'; import { ClockIcon } from '@heroicons/vue/20/solid'; import CardTitle from '@/Components/Common/CardTitle.vue'; @@ -17,6 +17,7 @@ import LinearGradient from 'zrender/lib/graphic/LinearGradient'; import ProjectsChartCard from '@/Components/Dashboard/ProjectsChartCard.vue'; import { formatHumanReadableDuration } from '@/utils/time'; import { formatCents } from '@/utils/money'; +import { getWeekStart } from '@/utils/useUser'; use([ CanvasRenderer, @@ -78,6 +79,33 @@ const seriesData = props.weeklyHistory.map((el) => { }, }; }); + +const weekdays = computed(() => { + const daysOrder = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; + const dayMapping: Record = { + monday: 'Mon', + tuesday: 'Tue', + wednesday: 'Wed', + thursday: 'Thu', + friday: 'Fri', + saturday: 'Sat', + sunday: 'Sun', + }; + + if (dayMapping[getWeekStart()]) { + const customOrder = []; + const startIndex = daysOrder.indexOf(dayMapping[getWeekStart()]); + + for (let i = startIndex; i < 7 + startIndex; i++) { + customOrder.push(daysOrder[i % daysOrder.length]); + } + + return customOrder; + } else { + return daysOrder; + } +}); + const option = ref({ grid: { top: 0, @@ -88,7 +116,7 @@ const option = ref({ backgroundColor: 'transparent', xAxis: { type: 'category', - data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + data: weekdays.value, markLine: { lineStyle: { color: 'rgba(125,156,188,0.1)', diff --git a/resources/js/utils/time.ts b/resources/js/utils/time.ts index c20e99fc..39ebef86 100644 --- a/resources/js/utils/time.ts +++ b/resources/js/utils/time.ts @@ -5,7 +5,9 @@ import isToday from 'dayjs/plugin/isToday'; import isYesterday from 'dayjs/plugin/isYesterday'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; -import { getUserTimezone } from '@/utils/useUser'; +import { getUserTimezone, getWeekStart } from '@/utils/useUser'; +import updateLocale from 'dayjs/plugin/updateLocale'; +import { computed } from 'vue'; dayjs.extend(relativeTime); dayjs.extend(isToday); @@ -13,11 +15,28 @@ dayjs.extend(isYesterday); dayjs.extend(duration); dayjs.extend(utc); dayjs.extend(timezone); +dayjs.extend(updateLocale); export function getDayJsInstance() { + dayjs.updateLocale('en', { + weekStart: firstDayIndex.value, + }); return dayjs; } +export const firstDayIndex = computed(() => { + const apiDayOrder = [ + 'sunday', + 'monday', + 'tuesday', + 'wednesday', + 'thursday', + 'friday', + 'saturday', + ]; + return apiDayOrder.indexOf(getWeekStart()); +}); + export function formatHumanReadableDuration(duration: number): string { const dayJsDuration = dayjs.duration(duration, 's'); const hours = dayJsDuration.hours() + dayJsDuration.days() * 24; diff --git a/resources/js/utils/useUser.ts b/resources/js/utils/useUser.ts index cecdac84..166afdea 100644 --- a/resources/js/utils/useUser.ts +++ b/resources/js/utils/useUser.ts @@ -10,6 +10,10 @@ function getCurrentUserId() { return page.props.auth.user.id; } +function getWeekStart() { + return page.props.auth.user.week_start; +} + function getCurrentOrganizationId() { return page.props.auth.user.current_team_id; } @@ -18,4 +22,9 @@ function getUserTimezone() { return page.props.auth.user.timezone; } -export { getCurrentOrganizationId, getCurrentUserId, getUserTimezone }; +export { + getCurrentOrganizationId, + getCurrentUserId, + getUserTimezone, + getWeekStart, +};