feat: make time reactive (#2627)

Reviewed-on: https://kolaente.dev/vikunja/vikunja/pulls/2627
Reviewed-by: konrad <k@knt.li>
Co-authored-by: Dominik Pschenitschni <mail@celement.de>
Co-committed-by: Dominik Pschenitschni <mail@celement.de>
This commit is contained in:
Dominik Pschenitschni 2025-01-20 13:28:49 +00:00 committed by konrad
parent a7be41ef04
commit cb8fd09824
4 changed files with 51 additions and 7 deletions

View File

@ -122,11 +122,14 @@
</template>
<script lang="ts" setup>
import {computed} from 'vue'
import {useGlobalNow} from '@/composables/useGlobalNow'
import {formatDateShort} from '@/helpers/time/formatDate'
import BaseButton from '@/components/base/BaseButton.vue'
const exampleDate = formatDateShort(new Date())
const {now} = useGlobalNow()
const exampleDate = computed(() => formatDateShort(now.value))
</script>
<style scoped lang="scss">

View File

@ -43,9 +43,11 @@
</template>
<script setup lang="ts">
import {computed, ref, watch, toRefs, onActivated} from 'vue'
import {computed, ref, watch, toRefs} from 'vue'
import {useRouter} from 'vue-router'
import { useGlobalNow } from '@/composables/useGlobalNow'
import {getHexColor} from '@/models/task'
import {colorIsDark} from '@/helpers/color/colorIsDark'
@ -122,7 +124,7 @@ const GANTT_COLOR_SCHEME: ColorScheme = {
hoverHighlight: 'var(--grey-700)',
text: 'var(--grey-800)',
background: 'var(--white)',
}
} as const
/**
* Update ganttBars when tasks change
@ -198,8 +200,7 @@ function openTask(e: {
const weekDayFromDate = useWeekDayFromDate()
const today = ref(new Date())
onActivated(() => today.value = new Date())
const {now: today} = useGlobalNow()
const dateIsToday = computed(() => (date: Date) => {
return (
date.getDate() === today.value.getDate() &&

View File

@ -46,7 +46,7 @@
<span
v-if="task.dueDate > 0"
v-tooltip="formatDateLong(task.dueDate)"
:class="{'overdue': task.dueDate <= new Date() && !task.done}"
:class="{'overdue': isOverdue}"
class="due-date"
>
<span class="icon">
@ -107,6 +107,8 @@
import {computed, ref, watch} from 'vue'
import {useRouter} from 'vue-router'
import {useGlobalNow} from '@/composables/useGlobalNow'
import PriorityLabel from '@/components/tasks/partials/PriorityLabel.vue'
import ProgressBar from '@/components/misc/ProgressBar.vue'
import Done from '@/components/misc/Done.vue'
@ -145,7 +147,7 @@ const projectStore = useProjectStore()
const projectTitle = computed(() => {
if (props.projectId === props.task.projectId) {
return false
return
}
const project = projectStore.projects[props.task.projectId]
@ -154,6 +156,14 @@ const projectTitle = computed(() => {
const showTaskPosition = computed(() => window.DEBUG_TASK_POSITION)
const {now} = useGlobalNow()
const isOverdue = computed(() => (
!props.task.done &&
props.task.dueDate !== null &&
props.task.dueDate.getTime() > 0 &&
props.task.dueDate.getTime() <= now.value.getTime()
))
async function toggleTaskDone(task: ITask) {
loadingInternal.value = true
try {

View File

@ -0,0 +1,30 @@
import { ref } from 'vue'
import { createGlobalState, useIntervalFn } from '@vueuse/core'
import { onBeforeRouteUpdate } from 'vue-router'
import { MILLISECONDS_A_SECOND } from '@/constants/date'
const GLOBAL_NOW_INTERVAL = 60 * MILLISECONDS_A_SECOND
/**
* A global shared state that provides the current time, updated at a regular interval.
*
* Sharing this state globally ensures that all components accessing this hook use the same time reference, avoiding redundant intervals and ensuring consistency across the application.
*/
export const useGlobalNow = createGlobalState(() => {
const now = ref(new Date())
const update = () => now.value = new Date()
useIntervalFn(update, GLOBAL_NOW_INTERVAL, { immediate: true })
// ensure the now value is refreshed when the route changes
onBeforeRouteUpdate(() => {
update()
})
return {
now,
update,
}
})