Skip to content

Commit 1884410

Browse files
authored
fix: standardize relative timestamping (#3612)
* fix(frontend): relative timestamps are incorrectly rounded. Closes: #1371 * fix(all): remove legacy fromNow for proper relative timestamp creation Closes: #1395
1 parent 6d57da2 commit 1884410

File tree

33 files changed

+203
-120
lines changed

33 files changed

+203
-120
lines changed

apps/app-frontend/src/App.vue

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ import {
1919
WorldIcon,
2020
XIcon,
2121
} from '@modrinth/assets'
22-
import { Avatar, Button, ButtonStyled, Notifications, OverflowMenu } from '@modrinth/ui'
22+
import {
23+
Avatar,
24+
Button,
25+
ButtonStyled,
26+
Notifications,
27+
OverflowMenu,
28+
useRelativeTime,
29+
} from '@modrinth/ui'
2330
import { useLoading, useTheming } from '@/store/state'
2431
import ModrinthAppLogo from '@/assets/modrinth_app.svg?component'
2532
import AccountsCard from '@/components/ui/AccountsCard.vue'
@@ -62,6 +69,8 @@ import FriendsList from '@/components/ui/friends/FriendsList.vue'
6269
import { openUrl } from '@tauri-apps/plugin-opener'
6370
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
6471
72+
const formatRelativeTime = useRelativeTime()
73+
6574
const themeStore = useTheming()
6675
6776
const news = ref([])
@@ -590,7 +599,7 @@ function handleAuxClick(e) {
590599
</h4>
591600
<p class="my-1 text-sm text-secondary leading-tight">{{ item.summary }}</p>
592601
<p class="text-right text-sm text-secondary opacity-60 leading-tight m-0">
593-
{{ dayjs(item.date).fromNow() }}
602+
{{ formatRelativeTime(dayjs(item.date).toISOString()) }}
594603
</p>
595604
</a>
596605
<hr

apps/app-frontend/src/components/ui/Instance.vue

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
StopCircleIcon,
1010
TimerIcon,
1111
} from '@modrinth/assets'
12-
import { Avatar, ButtonStyled } from '@modrinth/ui'
12+
import { Avatar, ButtonStyled, useRelativeTime } from '@modrinth/ui'
1313
import { convertFileSrc } from '@tauri-apps/api/core'
1414
import { finish_install, kill, run } from '@/helpers/profile'
1515
import { get_by_profile_path } from '@/helpers/process'
@@ -19,10 +19,9 @@ import { showProfileInFolder } from '@/helpers/utils.js'
1919
import { handleSevereError } from '@/store/error.js'
2020
import { trackEvent } from '@/helpers/analytics'
2121
import dayjs from 'dayjs'
22-
import relativeTime from 'dayjs/plugin/relativeTime'
2322
import { formatCategory } from '@modrinth/utils'
2423
25-
dayjs.extend(relativeTime)
24+
const formatRelativeTime = useRelativeTime()
2625
2726
const props = defineProps({
2827
instance: {
@@ -173,7 +172,9 @@ onUnmounted(() => unlisten())
173172
</div>
174173
<div class="flex items-center col-span-3 gap-1 text-secondary font-semibold">
175174
<TimerIcon />
176-
<span class="text-sm"> Played {{ dayjs(instance.last_played).fromNow() }} </span>
175+
<span class="text-sm">
176+
Played {{ formatRelativeTime(dayjs(instance.last_played).toISOString()) }}
177+
</span>
177178
</div>
178179
</div>
179180
</template>

apps/app-frontend/src/components/ui/friends/FriendsList.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { Avatar, ButtonStyled, OverflowMenu } from '@modrinth/ui'
2+
import { Avatar, ButtonStyled, OverflowMenu, useRelativeTime } from '@modrinth/ui'
33
import {
44
UserPlusIcon,
55
MoreVerticalIcon,
@@ -18,6 +18,8 @@ import type { Dayjs } from 'dayjs'
1818
import dayjs from 'dayjs'
1919
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
2020
21+
const formatRelativeTime = useRelativeTime()
22+
2123
const props = defineProps<{
2224
credentials: unknown | null
2325
signIn: () => void
@@ -205,7 +207,9 @@ onUnmounted(() => {
205207
You sent <span class="font-bold">{{ friend.username }}</span> a friend request
206208
</template>
207209
</p>
208-
<p class="m-0 text-sm text-secondary">{{ friend.created.fromNow() }}</p>
210+
<p class="m-0 text-sm text-secondary">
211+
{{ formatRelativeTime(friend.created.toISOString()) }}
212+
</p>
209213
</div>
210214
<div class="flex gap-2">
211215
<template v-if="friend.id === userCredentials.user_id">

apps/app-frontend/src/components/ui/world/InstanceItem.vue

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ import {
88
SpinnerIcon,
99
StopCircleIcon,
1010
} from '@modrinth/assets'
11-
import { Avatar, ButtonStyled, commonMessages, OverflowMenu, SmartClickable } from '@modrinth/ui'
11+
import {
12+
Avatar,
13+
ButtonStyled,
14+
commonMessages,
15+
OverflowMenu,
16+
SmartClickable,
17+
useRelativeTime,
18+
} from '@modrinth/ui'
1219
import { useVIntl } from '@vintl/vintl'
1320
import { computed, nextTick, ref, onMounted, onUnmounted } from 'vue'
1421
import { showProfileInFolder } from '@/helpers/utils'
@@ -25,6 +32,7 @@ import { handleError } from '@/store/notifications'
2532
import { process_listener } from '@/helpers/events'
2633
2734
const { formatMessage } = useVIntl()
35+
const formatRelativeTime = useRelativeTime()
2836
2937
const router = useRouter()
3038
@@ -144,7 +152,7 @@ onUnmounted(() => {
144152
<template v-if="instance.last_played">
145153
{{
146154
formatMessage(commonMessages.playedLabel, {
147-
time: dayjs(instance.last_played).fromNow(),
155+
time: formatRelativeTime(instance.last_played.toISOString()),
148156
})
149157
}}
150158
</template>

apps/app-frontend/src/components/ui/world/WorldItem.vue

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ import {
77
showWorldInFolder,
88
} from '@/helpers/worlds.ts'
99
import { formatNumber } from '@modrinth/utils'
10+
import {
11+
useRelativeTime,
12+
Avatar,
13+
ButtonStyled,
14+
commonMessages,
15+
OverflowMenu,
16+
SmartClickable,
17+
} from '@modrinth/ui'
1018
import {
1119
IssuesIcon,
1220
EyeIcon,
@@ -25,7 +33,6 @@ import {
2533
UserIcon,
2634
XIcon,
2735
} from '@modrinth/assets'
28-
import { Avatar, ButtonStyled, commonMessages, OverflowMenu, SmartClickable } from '@modrinth/ui'
2936
import type { MessageDescriptor } from '@vintl/vintl'
3037
import { defineMessages, useVIntl } from '@vintl/vintl'
3138
import type { Component } from 'vue'
@@ -36,6 +43,7 @@ import { useRouter } from 'vue-router'
3643
import { Tooltip } from 'floating-vue'
3744
3845
const { formatMessage } = useVIntl()
46+
const formatRelativeTime = useRelativeTime()
3947
4048
const router = useRouter()
4149
@@ -255,7 +263,7 @@ const messages = defineMessages({
255263
<template v-if="world.last_played">
256264
{{
257265
formatMessage(commonMessages.playedLabel, {
258-
time: dayjs(world.last_played).fromNow(),
266+
time: formatRelativeTime(dayjs(world.last_played).toISOString()),
259267
})
260268
}}
261269
</template>

apps/frontend/src/components/ui/NotificationItem.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@
184184
"
185185
class="date"
186186
>
187-
{{ fromNow(notif.extra_data.version.date_published) }}
187+
{{ formatRelativeTime(notif.extra_data.version.date_published) }}
188188
</span>
189189
</span>
190190
</div>
@@ -201,7 +201,7 @@
201201
v-tooltip="$dayjs(notification.created).format('MMMM D, YYYY [at] h:mm A')"
202202
class="inline-flex"
203203
>
204-
<CalendarIcon class="mr-1" /> Received {{ fromNow(notification.created) }}
204+
<CalendarIcon class="mr-1" /> Received {{ formatRelativeTime(notification.created) }}
205205
</span>
206206
</span>
207207
<div v-if="compact" class="notification__actions">
@@ -331,6 +331,7 @@ import {
331331
XIcon,
332332
ExternalIcon,
333333
} from "@modrinth/assets";
334+
import { useRelativeTime } from "@modrinth/ui";
334335
import ThreadSummary from "~/components/ui/thread/ThreadSummary.vue";
335336
import { getProjectLink, getVersionLink } from "~/helpers/projects.js";
336337
import { getUserLink } from "~/helpers/users.js";
@@ -345,6 +346,8 @@ import Categories from "~/components/ui/search/Categories.vue";
345346
const app = useNuxtApp();
346347
const emit = defineEmits(["update:notifications"]);
347348
349+
const formatRelativeTime = useRelativeTime();
350+
348351
const props = defineProps({
349352
notification: {
350353
type: Object,

apps/frontend/src/components/ui/ProjectCard.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@
7575
class="stat date"
7676
>
7777
<UpdatedIcon aria-hidden="true" />
78-
<span class="date-label">Updated </span>{{ fromNow(updatedAt) }}
78+
<span class="date-label">Updated </span>{{ formatRelativeTime(updatedAt) }}
7979
</div>
8080
<div
8181
v-else-if="showCreatedDate"
8282
v-tooltip="$dayjs(createdAt).format('MMMM D, YYYY [at] h:mm A')"
8383
class="stat date"
8484
>
8585
<CalendarIcon aria-hidden="true" />
86-
<span class="date-label">Published </span>{{ fromNow(createdAt) }}
86+
<span class="date-label">Published </span>{{ formatRelativeTime(createdAt) }}
8787
</div>
8888
</div>
8989
</article>
@@ -95,6 +95,7 @@ import Categories from "~/components/ui/search/Categories.vue";
9595
import Badge from "~/components/ui/Badge.vue";
9696
import EnvironmentIndicator from "~/components/ui/EnvironmentIndicator.vue";
9797
import Avatar from "~/components/ui/Avatar.vue";
98+
import { useRelativeTime } from "@modrinth/ui";
9899
99100
export default {
100101
components: {
@@ -213,8 +214,9 @@ export default {
213214
},
214215
setup() {
215216
const tags = useTags();
217+
const formatRelativeTime = useRelativeTime();
216218
217-
return { tags };
219+
return { tags, formatRelativeTime };
218220
},
219221
computed: {
220222
projectTypeDisplay() {

apps/frontend/src/components/ui/report/ReportInfo.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
</nuxt-link>
9696
<span>&nbsp;</span>
9797
<span v-tooltip="$dayjs(report.created).format('MMMM D, YYYY [at] h:mm A')">{{
98-
fromNow(report.created)
98+
formatRelativeTime(report.created)
9999
}}</span>
100100
<CopyCode v-if="flags.developerMode" :text="report.id" class="report-id" />
101101
</div>
@@ -105,11 +105,14 @@
105105
<script setup>
106106
import { ReportIcon, UnknownIcon, VersionIcon } from "@modrinth/assets";
107107
import { renderHighlightedString } from "~/helpers/highlight.js";
108+
import { useRelativeTime } from "@modrinth/ui";
108109
import Avatar from "~/components/ui/Avatar.vue";
109110
import Badge from "~/components/ui/Badge.vue";
110111
import ThreadSummary from "~/components/ui/thread/ThreadSummary.vue";
111112
import CopyCode from "~/components/ui/CopyCode.vue";
112113
114+
const formatRelativeTime = useRelativeTime();
115+
113116
defineProps({
114117
report: {
115118
type: Object,

apps/frontend/src/components/ui/servers/notice/NoticeDashboardItem.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import dayjs from "dayjs";
33
import { ButtonStyled, commonMessages, CopyCode, ServerNotice, TagItem } from "@modrinth/ui";
44
import { EditIcon, SettingsIcon, TrashIcon } from "@modrinth/assets";
55
import { ServerNotice as ServerNoticeType } from "@modrinth/utils";
6+
import { useRelativeTime } from "@modrinth/ui";
67
import {
78
DISMISSABLE,
89
getDismissableMetadata,
@@ -11,6 +12,7 @@ import {
1112
import { useVIntl } from "@vintl/vintl";
1213
1314
const { formatMessage } = useVIntl();
15+
const formatRelativeTime = useRelativeTime();
1416
1517
const props = defineProps<{
1618
notice: ServerNoticeType;
@@ -25,7 +27,7 @@ const props = defineProps<{
2527
<div class="text-sm">
2628
<span v-if="notice.announce_at">
2729
{{ dayjs(notice.announce_at).format("MMM D, YYYY [at] h:mm A") }} ({{
28-
dayjs(notice.announce_at).fromNow()
30+
formatRelativeTime(notice.announce_at)
2931
}})
3032
</span>
3133
<template v-else> Never begins </template>
@@ -35,7 +37,7 @@ const props = defineProps<{
3537
v-if="notice.expires"
3638
v-tooltip="dayjs(notice.expires).format('MMMM D, YYYY [at] h:mm A')"
3739
>
38-
{{ dayjs(notice.expires).fromNow() }}
40+
{{ formatRelativeTime(notice.expires) }}
3941
</span>
4042
<template v-else> Never expires </template>
4143
</div>

apps/frontend/src/components/ui/thread/ThreadMessage.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ import {
103103
ModrinthIcon,
104104
ScaleIcon,
105105
} from "@modrinth/assets";
106-
import { AutoLink, OverflowMenu } from "@modrinth/ui";
106+
import { AutoLink, OverflowMenu, useRelativeTime } from "@modrinth/ui";
107107
import { renderString } from "@modrinth/utils";
108108
import Avatar from "~/components/ui/Avatar.vue";
109109
import Badge from "~/components/ui/Badge.vue";

apps/frontend/src/composables/date.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

apps/frontend/src/composables/how-ago.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

apps/frontend/src/pages/[type]/[id].vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,7 @@ import {
871871
ProjectSidebarDetails,
872872
ProjectSidebarLinks,
873873
ScrollablePanel,
874+
useRelativeTime,
874875
} from "@modrinth/ui";
875876
import VersionSummary from "@modrinth/ui/src/components/version/VersionSummary.vue";
876877
import { formatCategory, isRejected, isStaff, isUnderReview, renderString } from "@modrinth/utils";

apps/frontend/src/pages/admin/billing/[id].vue

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
<div class="mb-4 mt-2 flex w-full items-center gap-1 text-sm text-secondary">
9393
{{ formatCategory(subscription.interval) }} ⋅ {{ subscription.status }} ⋅
9494
{{ dayjs(subscription.created).format("MMMM D, YYYY [at] h:mma") }} ({{
95-
dayjs(subscription.created).fromNow()
95+
formatRelativeTime(subscription.created)
9696
}})
9797
</div>
9898
</div>
@@ -151,7 +151,7 @@
151151
</span>
152152
<span class="text-sm text-secondary">
153153
{{ dayjs(charge.due).format("MMMM D, YYYY [at] h:mma") }}
154-
<span class="text-secondary">({{ dayjs(charge.due).fromNow() }}) </span>
154+
<span class="text-secondary">({{ formatRelativeTime(charge.due) }}) </span>
155155
</span>
156156
<div
157157
v-if="flags.developerMode"
@@ -196,7 +196,15 @@
196196
</div>
197197
</template>
198198
<script setup>
199-
import { Avatar, ButtonStyled, CopyCode, DropdownSelect, NewModal, Toggle } from "@modrinth/ui";
199+
import {
200+
Avatar,
201+
ButtonStyled,
202+
CopyCode,
203+
DropdownSelect,
204+
NewModal,
205+
Toggle,
206+
useRelativeTime,
207+
} from "@modrinth/ui";
200208
import { formatCategory, formatPrice } from "@modrinth/utils";
201209
import {
202210
CheckIcon,
@@ -215,7 +223,9 @@ const flags = useFeatureFlags();
215223
const route = useRoute();
216224
const data = useNuxtApp();
217225
const vintl = useVIntl();
226+
218227
const { formatMessage } = vintl;
228+
const formatRelativeTime = useRelativeTime();
219229
220230
const messages = defineMessages({
221231
userNotFoundError: {

0 commit comments

Comments
 (0)