Skip to content

Commit

Permalink
fix: remove date-fns (#3039)
Browse files Browse the repository at this point in the history
This removes date-fns and replaces it with the already used dayjs library. It does not make sense to have two libraries for the same purpose, and dayjs seems to be smaller and its translations are already integrated. Since we have to use dayjs because it is used by the gantt chart, this was the obvious way to go (instead of replacing dayjs with date-fns).

Resolves #391

Reviewed-on: https://kolaente.dev/vikunja/vikunja/pulls/3039
Co-authored-by: kolaente <[email protected]>
Co-committed-by: kolaente <[email protected]>
  • Loading branch information
kolaente committed Feb 21, 2025
1 parent 5cea469 commit 021d71b
Show file tree
Hide file tree
Showing 13 changed files with 45 additions and 54 deletions.
10 changes: 5 additions & 5 deletions frontend/cypress/e2e/project/project-view-gantt.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {formatISO, format} from 'date-fns'
import dayjs from 'dayjs'

import {createFakeUserAndLogin} from '../../support/authenticateUser'

Expand Down Expand Up @@ -28,8 +28,8 @@ describe('Project View Gantt', () => {
cy.visit('/projects/1/2')

cy.get('.g-timeunits-container')
.should('contain', format(now, 'MMMM'))
.should('contain', format(nextMonth, 'MMMM'))
.should('contain', dayjs(now).format('MMMM'))
.should('contain', dayjs(nextMonth).format('MMMM'))
})

it('Shows tasks with dates', () => {
Expand Down Expand Up @@ -112,8 +112,8 @@ describe('Project View Gantt', () => {
it('Should open a task when double clicked on it', () => {
const now = new Date()
const tasks = TaskFactory.create(1, {
start_date: formatISO(now),
end_date: formatISO(now.setDate(now.getDate() + 4)),
start_date: dayjs(now).format(),
end_date: dayjs(now.setDate(now.getDate() + 4)).format(),
})
cy.visit('/projects/1/2')

Expand Down
6 changes: 3 additions & 3 deletions frontend/cypress/e2e/task/task.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {BucketFactory} from '../../factories/bucket'

import {TaskAttachmentFactory} from '../../factories/task_attachments'
import {TaskReminderFactory} from '../../factories/task_reminders'
import {createDefaultViews} from "../project/prepareProjects";
import {createDefaultViews} from '../project/prepareProjects'
import { TaskBucketFactory } from '../../factories/task_buckets'

function addLabelToTaskAndVerify(labelTitle: string) {
Expand Down Expand Up @@ -572,7 +572,7 @@ describe('Task', () => {
const day = today.toLocaleString('default', {day: 'numeric'})
const month = today.toLocaleString('default', {month: 'short'})
const year = today.toLocaleString('default', {year: 'numeric'})
const date = `${day} ${month} ${year}, 12:00:00`
const date = `${month} ${day}, ${year} 12:00 PM`
cy.get('.task-view .columns.details .column')
.contains('Due Date')
.get('.date-input .datepicker-popup')
Expand Down Expand Up @@ -615,7 +615,7 @@ describe('Task', () => {
const day = today.toLocaleString('default', {day: 'numeric'})
const month = today.toLocaleString('default', {month: 'short'})
const year = today.toLocaleString('default', {year: 'numeric'})
const date = `${day} ${month} ${year}, 12:00:00`
const date = `${month} ${day}, ${year} 12:00 PM`
cy.get('.task-view .columns.details .column')
.contains('Due Date')
.get('.date-input .datepicker-popup')
Expand Down
1 change: 0 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@
"blurhash": "2.0.5",
"bulma-css-variables": "0.9.33",
"change-case": "5.4.4",
"date-fns": "4.1.0",
"dayjs": "1.11.13",
"dompurify": "3.2.3",
"fast-deep-equal": "3.1.3",
Expand Down
8 changes: 0 additions & 8 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions frontend/src/components/input/DatepickerInline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ const flatPickrDate = computed({
}
if (date.value !== null) {
const oldDate = formatDate(date.value, 'yyy-LL-dd H:mm')
const oldDate = formatDate(date.value, 'YYYY-MM-DD h:m')
if (oldDate === newValue) {
return
}
Expand All @@ -140,7 +140,7 @@ const flatPickrDate = computed({
return ''
}
return formatDate(date.value, 'yyy-LL-dd H:mm')
return formatDate(date.value, 'YYYY-MM-DD h:m')
},
})
Expand Down Expand Up @@ -208,7 +208,7 @@ function getWeekdayFromStringInterval(dateString: string) {
const interval = calculateDayInterval(dateString)
const newDate = new Date()
newDate.setDate(newDate.getDate() + interval)
return formatDate(newDate, 'E')
return formatDate(newDate, 'ddd')
}
</script>

Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/tasks/GanttChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import {getHexColor} from '@/models/task'
import {colorIsDark} from '@/helpers/color/colorIsDark'
import {isoToKebabDate} from '@/helpers/time/isoToKebabDate'
import {parseKebabDate} from '@/helpers/time/parseKebabDate'
import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask'
import type {DateISO} from '@/types/DateISO'
Expand Down Expand Up @@ -181,8 +180,8 @@ async function updateGanttTask(e: {
}) {
emit('update:task', {
id: Number(e.bar.ganttBarConfig.id),
startDate: new Date(parseKebabDate(e.bar.startDate).setHours(0,0,0,0)),
endDate: new Date(parseKebabDate(e.bar.endDate).setHours(23,59,0,0)),
startDate: new Date((new Date(e.bar.startDate)).setHours(0,0,0,0)),
endDate: new Date((new Date(e.bar.endDate)).setHours(23,59,0,0)),
})
}
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/constants/date.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const DATEFNS_DATE_FORMAT_KEBAB = 'yyyy-LL-dd' as const

export const SECONDS_A_MINUTE = 60
export const SECONDS_A_HOUR = SECONDS_A_MINUTE * 60
export const SECONDS_A_DAY = SECONDS_A_HOUR * 24
Expand Down
26 changes: 11 additions & 15 deletions frontend/src/helpers/time/formatDate.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import {createDateFromString} from '@/helpers/time/createDateFromString'
import {format, formatDistanceToNow} from 'date-fns'

// FIXME: support all locales and load dynamically
import {enGB, de, fr, ru} from 'date-fns/locale'
import dayjs from 'dayjs'

import {i18n} from '@/i18n'
import {createSharedComposable} from '@vueuse/core'
import {computed, toValue, type MaybeRefOrGetter} from 'vue'

const locales = {en: enGB, de, ch: de, fr, ru}

export function dateIsValid(date: Date | null) {
if (date === null) {
return false
Expand All @@ -18,35 +13,36 @@ export function dateIsValid(date: Date | null) {
return date instanceof Date && !isNaN(date)
}

export const formatDate = (date, f, locale = i18n.global.t('date.locale')) => {
export const formatDate = (date: Date | string | null, f: string, locale = i18n.global.t('date.locale')) => {
if (!dateIsValid(date)) {
return ''
}

date = createDateFromString(date)

return date ? format(date, f, {locale: locales[locale]}) : ''
return date
? dayjs(date).locale(locale).format(f)
: ''
}

export function formatDateLong(date) {
return formatDate(date, 'PPPPpppp')
return formatDate(date, 'LLLL')
}

export function formatDateShort(date) {
return formatDate(date, 'PPpp')
return formatDate(date, 'lll')
}

export const formatDateSince = (date) => {
export const formatDateSince = (date: Date | string | null, locale = i18n.global.t('date.locale')) => {
if (!dateIsValid(date)) {
return ''
}

date = createDateFromString(date)

return formatDistanceToNow(date, {
locale: locales[i18n.global.t('date.locale')],
addSuffix: true,
})
return date
? dayjs(date).locale(locale).fromNow()
: ''
}

export function formatISO(date) {
Expand Down
7 changes: 0 additions & 7 deletions frontend/src/helpers/time/parseKebabDate.ts

This file was deleted.

10 changes: 10 additions & 0 deletions frontend/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import {createI18n} from 'vue-i18n'
import type {PluralizationRule} from 'vue-i18n'
import langEN from './lang/en.json'

import localizedFormat from 'dayjs/plugin/localizedFormat'
import relativeTime from 'dayjs/plugin/relativeTime'
import dayjs from 'dayjs'
import {loadDayJsLocale} from '@/i18n/useDayjsLanguageSync.ts'

dayjs.extend(localizedFormat)
dayjs.extend(relativeTime)

export const SUPPORTED_LOCALES = {
'en': 'English',
'de-DE': 'Deutsch',
Expand Down Expand Up @@ -85,6 +93,8 @@ export async function setLanguage(lang: SupportedLocale): Promise<SupportedLocal
return setLanguage(getBrowserLanguage())
}
}

await loadDayJsLocale(lang)

i18n.global.locale.value = lang
document.documentElement.lang = lang
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/i18n/useDayjsLanguageSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ export const DAYJS_LANGUAGE_IMPORTS = {
'ko-kr': () => import('dayjs/locale/ko'),
} as Record<SupportedLocale, () => Promise<ILocale>>

export async function loadDayJsLocale(language: SupportedLocale) {
if (language === 'en') {
return
}

await DAYJS_LANGUAGE_IMPORTS[language.toLowerCase()]()
}

export function useDayjsLanguageSync(dayjsGlobal: typeof dayjs) {

const dayjsLanguageLoaded = ref(false)
Expand All @@ -70,7 +78,7 @@ export function useDayjsLanguageSync(dayjsGlobal: typeof dayjs) {
if (dayjsLanguageLoaded.value) {
return
}
await DAYJS_LANGUAGE_IMPORTS[currentLanguage.toLowerCase()]()
await loadDayJsLocale(currentLanguage)
dayjsGlobal.locale(dayjsLanguageCode)
dayjsLanguageLoaded.value = true
},
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/types/DateKebab.ts

This file was deleted.

4 changes: 2 additions & 2 deletions frontend/src/views/tasks/ShowTasks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ const pageTitle = computed(() => {
return showAll.value
? t('task.show.titleCurrent')
: t('task.show.fromuntil', {
from: formatDate(props.dateFrom, 'PPP'),
until: formatDate(props.dateTo, 'PPP'),
from: formatDate(props.dateFrom, 'LL'),
until: formatDate(props.dateTo, 'LL'),
})
})
const hasTasks = computed(() => tasks.value && tasks.value.length > 0)
Expand Down

0 comments on commit 021d71b

Please sign in to comment.