From 2d1280560b2af86399e906aad8191750a2bbf874 Mon Sep 17 00:00:00 2001 From: FinnRG Date: Fri, 19 May 2023 00:12:37 +0200 Subject: [PATCH 1/2] refactor: Move from moment to dayjs --- VocaDbWeb/Scripts/App.tsx | 8 +++--- .../KnockoutExtensions/MomentJsTimeAgo.tsx | 6 +++-- .../Components/Shared/ArtistPopupContent.tsx | 4 +-- .../Components/Shared/EventPopupContent.tsx | 6 ++--- .../Scripts/Components/Shared/PVs/PVEdit.tsx | 4 +-- .../Shared/Partials/ArchivedEntry/PVInfo.tsx | 4 +-- .../Partials/Shared/ConcurrentEditWarning.tsx | 4 +-- .../Shared/Partials/Shared/EventThumbs.tsx | 6 ++--- .../Partials/Shared/UniversalTimeLabel.tsx | 4 +-- .../Shared/Partials/Song/SongGrid.tsx | 9 ++++--- .../Partials/Song/SongListsKnockout.tsx | 6 ++--- .../Components/Shared/SongPopupContent.tsx | 4 +-- .../Components/Shared/UserPopupContent.tsx | 4 +-- .../DataContracts/Album/AlbumDetailsForApi.ts | 24 +++++++++-------- VocaDbWeb/Scripts/Helpers/DateTimeHelper.ts | 14 +++++++--- .../Helpers/EntryMergeValidationHelper.ts | 6 ++--- .../Pages/Admin/AdminManageIPRules.tsx | 4 +-- .../Scripts/Pages/Admin/AdminViewAuditLog.tsx | 4 +-- .../Scripts/Pages/Artist/ArtistBasicInfo.tsx | 4 +-- .../Pages/Discussion/Partials/ViewFolder.tsx | 6 ++--- .../Pages/Discussion/Partials/ViewFolders.tsx | 6 ++--- .../Scripts/Pages/Event/EventDetails.tsx | 6 ++--- .../Scripts/Pages/Event/EventEventsByDate.tsx | 6 ++--- VocaDbWeb/Scripts/Pages/Event/EventIndex.tsx | 4 +-- .../Pages/Event/EventSeriesDetails.tsx | 4 +-- .../Scripts/Pages/Song/SongBasicInfo.tsx | 6 ++--- VocaDbWeb/Scripts/Pages/Song/SongRankings.tsx | 4 +-- .../Pages/SongList/SongListDetails.tsx | 11 ++++---- .../Scripts/Pages/User/Partials/ListUsers.tsx | 4 +-- VocaDbWeb/Scripts/Pages/User/UserEvents.tsx | 4 +-- VocaDbWeb/Scripts/Pages/User/UserOverview.tsx | 6 ++--- .../Scripts/Pages/Venue/VenueDetails.tsx | 4 +-- .../Stores/Admin/ManageIPRulesStore.ts | 4 +-- .../Scripts/Stores/Album/AlbumEditStore.ts | 15 ++++++----- .../Scripts/Stores/Artist/ArtistEditStore.ts | 4 +-- .../ReleaseEvent/ReleaseEventEditStore.ts | 6 ++--- .../Stores/Search/SearchCategoryBaseStore.ts | 7 +++-- .../Scripts/Stores/Search/SongSearchStore.ts | 27 ++++++++++--------- .../Scripts/Stores/Song/SongEditStore.ts | 18 ++++++------- .../Stores/SongList/SongListEditStore.ts | 4 +-- .../Stores/SongList/SongListsBaseStore.ts | 6 ++--- VocaDbWeb/Scripts/Stores/StatsStore.ts | 8 +++--- .../Stores/User/RatedSongsSearchStore.ts | 4 +-- VocaDbWeb/Scripts/VdbContext.tsx | 22 +++++++++++++-- VocaDbWeb/Scripts/dayjs.ts | 6 +++++ VocaDbWeb/package-lock.json | 11 ++++++++ VocaDbWeb/package.json | 2 +- 47 files changed, 197 insertions(+), 143 deletions(-) create mode 100644 VocaDbWeb/Scripts/dayjs.ts diff --git a/VocaDbWeb/Scripts/App.tsx b/VocaDbWeb/Scripts/App.tsx index 96af095d3e..3220aa4028 100644 --- a/VocaDbWeb/Scripts/App.tsx +++ b/VocaDbWeb/Scripts/App.tsx @@ -11,19 +11,17 @@ import { LoginManagerProvider } from '@/LoginManagerContext'; import { MutedUsersProvider } from '@/MutedUsersContext'; import { VdbProvider, useVdb } from '@/VdbContext'; import '@/i18n'; +import '@/styles/css.less'; import { NostalgicDivaProvider } from '@vocadb/nostalgic-diva'; import { ScrollToTop } from '@vocadb/route-sphere'; import React from 'react'; import { Toaster } from 'react-hot-toast'; import { BrowserRouter } from 'react-router-dom'; -import "@/styles/css.less" - -const TetoDB = React.lazy(() => import("./styles/tetoDb")) -const DarkAngel = React.lazy(() => import("./styles/darkAngel")) +const TetoDB = React.lazy(() => import('./styles/tetoDb')); +const DarkAngel = React.lazy(() => import('./styles/darkAngel')); const AppContainer = (): React.ReactElement => { - const vdb = useVdb(); return ( diff --git a/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx b/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx index 0d589cd501..9d606c6454 100644 --- a/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx +++ b/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx @@ -1,4 +1,5 @@ -import moment from 'moment'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; import React from 'react'; interface MomentJsTimeAgoProps { @@ -12,7 +13,8 @@ export const MomentJsTimeAgo = ({ className, children, }: MomentJsTimeAgoProps): React.ReactElement => { - const parsed = moment(children); + dayjs.extend(relativeTime); + const parsed = dayjs(children); return ( diff --git a/VocaDbWeb/Scripts/Components/Shared/ArtistPopupContent.tsx b/VocaDbWeb/Scripts/Components/Shared/ArtistPopupContent.tsx index 0d1d1013af..6faad0b69a 100644 --- a/VocaDbWeb/Scripts/Components/Shared/ArtistPopupContent.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/ArtistPopupContent.tsx @@ -1,7 +1,7 @@ import { ArtistContract } from '@/DataContracts/Artist/ArtistContract'; import { UrlHelper } from '@/Helpers/UrlHelper'; import { ImageSize } from '@/Models/Images/ImageSize'; -import moment from 'moment'; +import dayjs from '@/dayjs'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -41,7 +41,7 @@ export const ArtistPopupContent = React.memo( {artist.releaseDate && (

{t('ViewRes.Artist:Details.ReleaseDate')}{' '} - {moment(artist.releaseDate).format('l')} + {dayjs(artist.releaseDate).format('l')}

)} diff --git a/VocaDbWeb/Scripts/Components/Shared/EventPopupContent.tsx b/VocaDbWeb/Scripts/Components/Shared/EventPopupContent.tsx index 5a357e4c10..6667f472f5 100644 --- a/VocaDbWeb/Scripts/Components/Shared/EventPopupContent.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/EventPopupContent.tsx @@ -1,8 +1,8 @@ import { Markdown } from '@/Components/KnockoutExtensions/Markdown'; import { ReleaseEventContract } from '@/DataContracts/ReleaseEvents/ReleaseEventContract'; import { EventCategory } from '@/Models/Events/EventCategory'; +import dayjs from '@/dayjs'; import { truncate } from 'lodash-es'; -import moment from 'moment'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -55,8 +55,8 @@ export const EventPopupContent = React.memo( {event.date && (

{t('ViewRes.Event:Details:OccurrenceDate')}{' '} - {moment(event.date).format('l')} - {event.endDate && ` - ${moment(event.endDate).format('l')}`} + {dayjs(event.date).format('l')} + {event.endDate && ` - ${dayjs(event.endDate).format('l')}`}

)} diff --git a/VocaDbWeb/Scripts/Components/Shared/PVs/PVEdit.tsx b/VocaDbWeb/Scripts/Components/Shared/PVs/PVEdit.tsx index c9c6d8afca..6cf17eedbf 100644 --- a/VocaDbWeb/Scripts/Components/Shared/PVs/PVEdit.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/PVs/PVEdit.tsx @@ -1,9 +1,9 @@ import SafeAnchor from '@/Bootstrap/SafeAnchor'; import { PVType } from '@/Models/PVs/PVType'; import { PVEditStore, PVListEditStore } from '@/Stores/PVs/PVListEditStore'; +import dayjs from '@/dayjs'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -48,7 +48,7 @@ export const PVEdit = observer( {pvListEditStore.showPublishDates && ( {pvListEditStore.showPublishDates && ( - <>{moment(contract.publishDate).format('l')} + <>{dayjs(contract.publishDate).format('l')} )} )} diff --git a/VocaDbWeb/Scripts/Components/Shared/Partials/ArchivedEntry/PVInfo.tsx b/VocaDbWeb/Scripts/Components/Shared/Partials/ArchivedEntry/PVInfo.tsx index 67e5345087..e8cb7490a1 100644 --- a/VocaDbWeb/Scripts/Components/Shared/Partials/ArchivedEntry/PVInfo.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/Partials/ArchivedEntry/PVInfo.tsx @@ -2,7 +2,7 @@ import { ArchivedPVContract } from '@/DataContracts/PVs/ArchivedPVContract'; import { PVContract } from '@/DataContracts/PVs/PVContract'; import { DateTimeHelper } from '@/Helpers/DateTimeHelper'; import { VideoServiceHelper } from '@/Helpers/VideoServiceHelper'; -import moment from 'moment'; +import dayjs from '@/dayjs'; import React from 'react'; interface PVInfoProps { @@ -21,7 +21,7 @@ export const PVInfo = React.memo( {pv.pvId} {' '} by {pv.author} ({DateTimeHelper.formatFromSeconds(pv.length)}) - {pv.publishDate && <> at {moment(pv.publishDate).format('l')}} + {pv.publishDate && <> at {dayjs(pv.publishDate).format('l')}} {pv.disabled && <> (unavailable)} ); diff --git a/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/ConcurrentEditWarning.tsx b/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/ConcurrentEditWarning.tsx index 32e28d7177..ccdc6f51c3 100644 --- a/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/ConcurrentEditWarning.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/ConcurrentEditWarning.tsx @@ -1,6 +1,6 @@ import { NotificationPanel } from '@/Components/Shared/Partials/Shared/NotificationPanel'; import { EntryEditDataContract } from '@/DataContracts/User/EntryEditDataContract'; -import moment from 'moment'; +import dayjs from 'dayjs'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -12,7 +12,7 @@ export const ConcurrentEditWarning = React.memo( ({ conflictingEditor }: ConcurrentEditWarningProps): React.ReactElement => { const { t } = useTranslation(['ViewRes']); - const ago = moment().diff(conflictingEditor.time, 'minutes'); + const ago = dayjs().diff(conflictingEditor.time, 'minutes'); return (
- {moment(event.date).format('l')} - {event.endDate && <> - {moment(event.endDate).format('l')}} + {dayjs(event.date).format('l')} + {event.endDate && <> - {dayjs(event.endDate).format('l')}} )} diff --git a/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/UniversalTimeLabel.tsx b/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/UniversalTimeLabel.tsx index db730e903c..21b7313ab5 100644 --- a/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/UniversalTimeLabel.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/Partials/Shared/UniversalTimeLabel.tsx @@ -1,4 +1,4 @@ -import moment from 'moment'; +import dayjs from '@/dayjs'; import React from 'react'; interface UniversalTimeLabelProps { @@ -8,7 +8,7 @@ interface UniversalTimeLabelProps { export const UniversalTimeLabel = React.memo( ({ dateTime }: UniversalTimeLabelProps): React.ReactElement => { return ( - {moment(dateTime).utc().format('lll')} + {dayjs(dateTime).utc().format('lll')} ); }, ); diff --git a/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongGrid.tsx b/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongGrid.tsx index d197f5b023..d93c68a19d 100644 --- a/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongGrid.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongGrid.tsx @@ -2,7 +2,8 @@ import { SongTypeLabel } from '@/Components/Shared/Partials/Song/SongTypeLabel'; import { SongApiContract } from '@/DataContracts/Song/SongApiContract'; import { UrlHelper } from '@/Helpers/UrlHelper'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; -import moment from 'moment'; +import dayjs from '@/dayjs'; +import UTC from 'dayjs/plugin/utc'; import React from 'react'; import { Link } from 'react-router-dom'; @@ -40,6 +41,8 @@ interface SongGridProps { displayPublishDate?: boolean; } +dayjs.extend(UTC); + export const SongGrid = ({ songs, columns, @@ -70,9 +73,7 @@ export const SongGrid = ({ diff --git a/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongListsKnockout.tsx b/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongListsKnockout.tsx index e359f3b3de..d89b9b5a2b 100644 --- a/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongListsKnockout.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/Partials/Song/SongListsKnockout.tsx @@ -2,8 +2,8 @@ import SafeAnchor from '@/Bootstrap/SafeAnchor'; import { EntryType } from '@/Models/EntryType'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; import { SongListsBaseStore } from '@/Stores/SongList/SongListsBaseStore'; +import dayjs from '@/dayjs'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import React from 'react'; import { Link } from 'react-router-dom'; @@ -26,7 +26,7 @@ export const SongListsKnockout = observer(

- {moment(item.eventDate).format('YYYY')} + {dayjs(item.eventDate).format('YYYY')}

@@ -54,7 +54,7 @@ export const SongListsKnockout = observer( {item.eventDate && (
- {moment(item.eventDate).format('l')} + {dayjs(item.eventDate).format('l')}
)} diff --git a/VocaDbWeb/Scripts/Components/Shared/SongPopupContent.tsx b/VocaDbWeb/Scripts/Components/Shared/SongPopupContent.tsx index 1eb2827889..79416cbae4 100644 --- a/VocaDbWeb/Scripts/Components/Shared/SongPopupContent.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/SongPopupContent.tsx @@ -1,6 +1,6 @@ import { SongContract } from '@/DataContracts/Song/SongContract'; import { DateTimeHelper } from '@/Helpers/DateTimeHelper'; -import moment from 'moment'; +import dayjs from '@/dayjs'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -38,7 +38,7 @@ export const SongPopupContent = React.memo( {song.publishDate && (

{t('ViewRes:EntryDetails.PublishDate')}{' '} - {moment(song.publishDate).format('l')} + {dayjs(song.publishDate).format('l')}

)} diff --git a/VocaDbWeb/Scripts/Components/Shared/UserPopupContent.tsx b/VocaDbWeb/Scripts/Components/Shared/UserPopupContent.tsx index 8f9fbbf802..2d41706694 100644 --- a/VocaDbWeb/Scripts/Components/Shared/UserPopupContent.tsx +++ b/VocaDbWeb/Scripts/Components/Shared/UserPopupContent.tsx @@ -1,6 +1,6 @@ import { ProfileIcon } from '@/Components/Shared/Partials/User/ProfileIcon'; import { UserApiContract } from '@/DataContracts/User/UserApiContract'; -import moment from 'moment'; +import dayjs from '@/dayjs'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -29,7 +29,7 @@ export const UserPopupContent = React.memo( )}

- Joined{/* LOC */} {moment(user.memberSince).format('l')} + Joined{/* LOC */} {dayjs(user.memberSince).format('l')}

); diff --git a/VocaDbWeb/Scripts/DataContracts/Album/AlbumDetailsForApi.ts b/VocaDbWeb/Scripts/DataContracts/Album/AlbumDetailsForApi.ts index ff45d619e2..90781e640a 100644 --- a/VocaDbWeb/Scripts/DataContracts/Album/AlbumDetailsForApi.ts +++ b/VocaDbWeb/Scripts/DataContracts/Album/AlbumDetailsForApi.ts @@ -24,8 +24,11 @@ import { ArtistCategories } from '@/Models/Artists/ArtistCategories'; import { ArtistRoles } from '@/Models/Artists/ArtistRoles'; import { ContentFocus } from '@/Models/ContentFocus'; import { EntryStatus } from '@/Models/EntryStatus'; +import dayjs from 'dayjs'; +import UTC from 'dayjs/plugin/utc'; import { has } from 'lodash-es'; -import moment from 'moment'; + +dayjs.extend(UTC); export enum DiscMediaType { Audio = 'Audio', @@ -182,12 +185,11 @@ export class AlbumDetailsForApi { this.releaseDate.year && this.releaseDate.month && this.releaseDate.day - ? moment - .utc([ - this.releaseDate.year, - this.releaseDate.month - 1, - this.releaseDate.day, - ]) + ? dayjs + .utc() + .year(this.releaseDate.year) + .month(this.releaseDate.month - 1) + .date(this.releaseDate.day) .toDate() : undefined; } @@ -274,21 +276,21 @@ export class AlbumDetailsForApi { get releaseDateIsInTheFarFuture(): boolean { return ( !!this.fullReleaseDate && - this.fullReleaseDate > moment.utc().add(7, 'd').toDate() + this.fullReleaseDate > dayjs.utc().add(7, 'd').toDate() ); } get releaseDateIsInTheNearFuture(): boolean { return ( !!this.fullReleaseDate && - this.fullReleaseDate > moment.utc().toDate() && - this.fullReleaseDate <= moment.utc().add(7, 'd').toDate() + this.fullReleaseDate > dayjs.utc().toDate() && + this.fullReleaseDate <= dayjs.utc().add(7, 'd').toDate() ); } get releaseDateIsInThePast(): boolean { return ( - !!this.fullReleaseDate && this.fullReleaseDate <= moment.utc().toDate() + !!this.fullReleaseDate && this.fullReleaseDate <= dayjs.utc().toDate() ); } diff --git a/VocaDbWeb/Scripts/Helpers/DateTimeHelper.ts b/VocaDbWeb/Scripts/Helpers/DateTimeHelper.ts index 78d63039ab..b23ca86c64 100644 --- a/VocaDbWeb/Scripts/Helpers/DateTimeHelper.ts +++ b/VocaDbWeb/Scripts/Helpers/DateTimeHelper.ts @@ -1,4 +1,7 @@ -import moment from 'moment'; +import dayjs from 'dayjs'; +import UTC from 'dayjs/plugin/utc'; + +dayjs.extend(UTC); export class DateTimeHelper { private static addLeadingZero(val: any): any { @@ -7,15 +10,18 @@ export class DateTimeHelper { static convertToLocal(utcDate: Date): Date | null { if (utcDate == null) return null; - const momentDate = moment.utc(utcDate); + const momentDate = dayjs.utc(utcDate); return new Date(momentDate.year(), momentDate.month(), momentDate.date()); //return new Date(utcDate.getFullYear(), utcDate.getMonth(), utcDate.getDate()); } static convertToUtc(localDate: Date): Date | null { if (localDate == null) return null; - return moment - .utc([localDate.getFullYear(), localDate.getMonth(), localDate.getDate()]) + return dayjs + .utc() + .year(localDate.getFullYear()) + .month(localDate.getMonth()) + .date(localDate.getDate()) .toDate(); } diff --git a/VocaDbWeb/Scripts/Helpers/EntryMergeValidationHelper.ts b/VocaDbWeb/Scripts/Helpers/EntryMergeValidationHelper.ts index 540b65efa8..7aeb5c2e63 100644 --- a/VocaDbWeb/Scripts/Helpers/EntryMergeValidationHelper.ts +++ b/VocaDbWeb/Scripts/Helpers/EntryMergeValidationHelper.ts @@ -1,6 +1,6 @@ import { CommonEntryContract } from '@/DataContracts/CommonEntryContract'; import { EntryStatus } from '@/Models/EntryStatus'; -import moment from 'moment'; +import dayjs from 'dayjs'; export class EntryMergeValidationHelper { private static toEnum(statusStr: string | EntryStatus): EntryStatus { @@ -22,14 +22,14 @@ export class EntryMergeValidationHelper { return { validationError_targetIsLessComplete: - moment(targetCreated) <= moment(baseCreated) && + dayjs(targetCreated) <= dayjs(baseCreated) && targetStatusEnum === EntryStatus.Draft && baseStatusEnum > EntryStatus.Draft, validationError_targetIsNewer: !( targetStatusEnum > EntryStatus.Draft && baseStatusEnum === EntryStatus.Draft - ) && moment(targetCreated) > moment(baseCreated), + ) && dayjs(targetCreated) > dayjs(baseCreated), }; } diff --git a/VocaDbWeb/Scripts/Pages/Admin/AdminManageIPRules.tsx b/VocaDbWeb/Scripts/Pages/Admin/AdminManageIPRules.tsx index 55aa402f24..99552a1ab6 100644 --- a/VocaDbWeb/Scripts/Pages/Admin/AdminManageIPRules.tsx +++ b/VocaDbWeb/Scripts/Pages/Admin/AdminManageIPRules.tsx @@ -7,10 +7,10 @@ import { SaveBtn } from '@/Components/Shared/Partials/Shared/SaveBtn'; import { showErrorMessage, showSuccessMessage } from '@/Components/ui'; import { adminRepo } from '@/Repositories/AdminRepository'; import { ManageIPRulesStore } from '@/Stores/Admin/ManageIPRulesStore'; +import dayjs from '@/dayjs'; import { getReasonPhrase } from 'http-status-codes'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; @@ -124,7 +124,7 @@ const AdminManageIPRules = observer( } /> - {moment(rule.created).format('L LT')} + {dayjs(rule.created).format('L LT')} {viewAuditLogStore.items.map((logEntry, index) => ( - {moment(logEntry.time).format('L LT')} + {dayjs(logEntry.time).format('L LT')} {t('ViewRes.Artist:Details.ReleaseDate')} - {moment(artist.releaseDate).format('l') /* REVIEW */} + {dayjs(artist.releaseDate).format('l') /* REVIEW */} )} diff --git a/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolder.tsx b/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolder.tsx index a96cd04073..7b45520c97 100644 --- a/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolder.tsx +++ b/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolder.tsx @@ -7,10 +7,10 @@ import { ImageSize } from '@/Models/Images/ImageSize'; import { useMutedUsers } from '@/MutedUsersContext'; import EditTopic from '@/Pages/Discussion/Partials/EditTopic'; import { DiscussionIndexStore } from '@/Stores/Discussion/DiscussionIndexStore'; +import dayjs from '@/dayjs'; import classNames from 'classnames'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { Link, useNavigate } from 'react-router-dom'; @@ -66,12 +66,12 @@ const ViewFolderTableRow = observer( {topic.commentCount} - {moment(topic.created).format('lll')} + {dayjs(topic.created).format('lll')} {topic.lastComment && ( - {moment(topic.lastComment.created).format('lll')} by{' '} + {dayjs(topic.lastComment.created).format('lll')} by{' '} {topic.lastComment.authorName} )} diff --git a/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolders.tsx b/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolders.tsx index 8a90c19d8c..a61f73227f 100644 --- a/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolders.tsx +++ b/VocaDbWeb/Scripts/Pages/Discussion/Partials/ViewFolders.tsx @@ -1,6 +1,6 @@ import { DiscussionIndexStore } from '@/Stores/Discussion/DiscussionIndexStore'; +import dayjs from '@/dayjs'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; @@ -47,7 +47,7 @@ const ViewFolders = observer( {folder.lastTopicDate && ( - {moment(folder.lastTopicDate).format('lll')} by{' '} + {dayjs(folder.lastTopicDate).format('lll')} by{' '} {folder.lastTopicAuthor?.name} )} @@ -74,7 +74,7 @@ const ViewFolders = observer( {recentTopic.name}
- {moment(recentTopic.created).format('lll')} by{' '} + {dayjs(recentTopic.created).format('lll')} by{' '} {recentTopic.author.name} diff --git a/VocaDbWeb/Scripts/Pages/Event/EventDetails.tsx b/VocaDbWeb/Scripts/Pages/Event/EventDetails.tsx index df4bb5e008..9831deaf05 100644 --- a/VocaDbWeb/Scripts/Pages/Event/EventDetails.tsx +++ b/VocaDbWeb/Scripts/Pages/Event/EventDetails.tsx @@ -48,8 +48,8 @@ import { urlMapper } from '@/Shared/UrlMapper'; import { ReleaseEventDetailsStore } from '@/Stores/ReleaseEvent/ReleaseEventDetailsStore'; import { SearchType } from '@/Stores/Search/SearchStore'; import { useVdb } from '@/VdbContext'; +import dayjs from '@/dayjs'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import NProgress from 'nprogress'; import qs from 'qs'; import React from 'react'; @@ -285,9 +285,9 @@ const EventDetailsLayout = observer( {event.date && (

{t('ViewRes.Event:Details.OccurrenceDate')}:{' '} - {moment(event.date).format('l')} + {dayjs(event.date).format('l')} {event.endDate && event.endDate > event.date && ( - <> - {moment(event.endDate).format('l')} + <> - {dayjs(event.endDate).format('l')} )}

)} diff --git a/VocaDbWeb/Scripts/Pages/Event/EventEventsByDate.tsx b/VocaDbWeb/Scripts/Pages/Event/EventEventsByDate.tsx index 9cc3384133..8c8cb935b1 100644 --- a/VocaDbWeb/Scripts/Pages/Event/EventEventsByDate.tsx +++ b/VocaDbWeb/Scripts/Pages/Event/EventEventsByDate.tsx @@ -3,7 +3,7 @@ import { ReleaseEventContract } from '@/DataContracts/ReleaseEvents/ReleaseEvent import { EntryType } from '@/Models/EntryType'; import { eventRepo } from '@/Repositories/ReleaseEventRepository'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; -import moment from 'moment'; +import dayjs from '@/dayjs'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; @@ -23,7 +23,7 @@ const EventEventsByDateLayout = ({ () => model .filter((event) => !!event.date) - .groupBy((event) => moment(event.date!).format('YYYY')), + .groupBy((event) => dayjs(event.date!).format('YYYY')), [model], ); @@ -73,7 +73,7 @@ const EventEventsByDateLayout = ({ {events.map((event, index) => ( - {moment(event.date).format('l')} + {dayjs(event.date).format('l')} { ReleaseEventOptionalField.Series, ReleaseEventOptionalField.Venue, ], - afterDate: moment().subtract(2, 'days').toDate(), + afterDate: dayjs().subtract(2, 'days').toDate(), start: 0, maxResults: 15, sort: EventSortRule.Date, diff --git a/VocaDbWeb/Scripts/Pages/Event/EventSeriesDetails.tsx b/VocaDbWeb/Scripts/Pages/Event/EventSeriesDetails.tsx index 01c9898060..a74cc2eed4 100644 --- a/VocaDbWeb/Scripts/Pages/Event/EventSeriesDetails.tsx +++ b/VocaDbWeb/Scripts/Pages/Event/EventSeriesDetails.tsx @@ -19,7 +19,7 @@ import { userRepo } from '@/Repositories/UserRepository'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; import { EventSeriesDetailsStore } from '@/Stores/ReleaseEvent/EventSeriesDetailsStore'; import { SearchType } from '@/Stores/Search/SearchStore'; -import moment from 'moment'; +import dayjs from '@/dayjs'; import NProgress from 'nprogress'; import qs from 'qs'; import React from 'react'; @@ -211,7 +211,7 @@ const EventSeriesDetailsLayout = ({ {event.date && ( <> {' '} - ({moment(event.date).format('l')}) + ({dayjs(event.date).format('l')}) )} diff --git a/VocaDbWeb/Scripts/Pages/Song/SongBasicInfo.tsx b/VocaDbWeb/Scripts/Pages/Song/SongBasicInfo.tsx index f1ea5de8e1..131a21f336 100644 --- a/VocaDbWeb/Scripts/Pages/Song/SongBasicInfo.tsx +++ b/VocaDbWeb/Scripts/Pages/Song/SongBasicInfo.tsx @@ -39,10 +39,10 @@ import { SongDetailsTabs } from '@/Pages/Song/SongDetailsRoutes'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; import { functions } from '@/Shared/GlobalFunctions'; import { SongDetailsStore } from '@/Stores/Song/SongDetailsStore'; +import dayjs from '@/dayjs'; import classNames from 'classnames'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import qs from 'qs'; import React from 'react'; import { Trans, useTranslation } from 'react-i18next'; @@ -159,7 +159,7 @@ const PVButton = observer( title={ pv.publishDate && pv.author ? `${t('ViewRes.Song:Details.PVDescription', { - 0: moment(pv.publishDate).format('l') /* REVIEW */, + 0: dayjs(pv.publishDate).format('l') /* REVIEW */, 1: pv.author, })}${ pv.disabled ? ` ${t('ViewRes.Song:Details.PVUnavailable')}` : '' @@ -622,7 +622,7 @@ const SongBasicInfo = observer( {model.publishDate && ( {t('ViewRes:EntryDetails.PublishDate')} - {moment(model.publishDate).format('l') /* REVIEW */} + {dayjs(model.publishDate).format('l') /* REVIEW */} )} diff --git a/VocaDbWeb/Scripts/Pages/Song/SongRankings.tsx b/VocaDbWeb/Scripts/Pages/Song/SongRankings.tsx index 34b503c177..bad38eb7bc 100644 --- a/VocaDbWeb/Scripts/Pages/Song/SongRankings.tsx +++ b/VocaDbWeb/Scripts/Pages/Song/SongRankings.tsx @@ -15,11 +15,11 @@ import { SearchType } from '@/Stores/Search/SearchStore'; import { ISongSearchItem } from '@/Stores/Search/SongSearchStore'; import { RankingsStore } from '@/Stores/Song/RankingsStore'; import { useVdb } from '@/VdbContext'; +import dayjs from '@/dayjs'; import { useLocationStateStore } from '@vocadb/route-sphere'; import classNames from 'classnames'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import qs from 'qs'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -140,7 +140,7 @@ const SongRankingsTableRow = observer( /> )} - {moment(song.publishDate).format('l')} + {dayjs(song.publishDate).format('l')} {song.tags && song.tags.length > 0 && ( <> diff --git a/VocaDbWeb/Scripts/Pages/SongList/SongListDetails.tsx b/VocaDbWeb/Scripts/Pages/SongList/SongListDetails.tsx index 3d31ebd348..c6fa55e0d1 100644 --- a/VocaDbWeb/Scripts/Pages/SongList/SongListDetails.tsx +++ b/VocaDbWeb/Scripts/Pages/SongList/SongListDetails.tsx @@ -44,11 +44,12 @@ import { SongListStore } from '@/Stores/SongList/SongListStore'; import { PlayQueueRepositoryType } from '@/Stores/VdbPlayer/PlayQueueRepository'; import { AutoplayContext } from '@/Stores/VdbPlayer/PlayQueueStore'; import { useVdb } from '@/VdbContext'; +import dayjs from '@/dayjs'; +import '@/styles/Styles/songlist.less'; import { useLocationStateStore } from '@vocadb/route-sphere'; import classNames from 'classnames'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import NProgress from 'nprogress'; import qs from 'qs'; import React from 'react'; @@ -56,8 +57,6 @@ import { DebounceInput } from 'react-debounce-input'; import { useTranslation } from 'react-i18next'; import { Link, useParams } from 'react-router-dom'; -import '@/styles/Styles/songlist.less' - interface SongListDetailsTableRowProps { songListStore: SongListStore; item: SongInListContract & { @@ -356,7 +355,7 @@ const SongListDetailsLayout = observer( {songList.eventDate && (

{t('ViewRes.SongList:Details.Date', { - 0: moment(songList.eventDate).format('l'), + 0: dayjs(songList.eventDate).format('l'), })}

)} @@ -413,11 +412,11 @@ const SongListDetailsLayout = observer( {event.date ? ( event.venue || event.venueName ? ( <> - {moment(event.date).format('l')} + {dayjs(event.date).format('l')} , ) : ( - moment(event.date).format('l') + dayjs(event.date).format('l') ) ) : ( (event.venue || event.venueName) && ( diff --git a/VocaDbWeb/Scripts/Pages/User/Partials/ListUsers.tsx b/VocaDbWeb/Scripts/Pages/User/Partials/ListUsers.tsx index b857c7f5e3..0886cc6f6e 100644 --- a/VocaDbWeb/Scripts/Pages/User/Partials/ListUsers.tsx +++ b/VocaDbWeb/Scripts/Pages/User/Partials/ListUsers.tsx @@ -11,10 +11,10 @@ import { UserGroup } from '@/Models/Users/UserGroup'; import { useMutedUsers } from '@/MutedUsersContext'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; import { ListUsersStore, UserSortRule } from '@/Stores/User/ListUsersStore'; +import dayjs from '@/dayjs'; import classNames from 'classnames'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import React from 'react'; import { DebounceInput } from 'react-debounce-input'; import { useTranslation } from 'react-i18next'; @@ -232,7 +232,7 @@ const UserSearchListTableRow = observer( {user.name} - {moment(user.memberSince).format('L')} + {dayjs(user.memberSince).format('L')} {t(`Resources:UserGroupNames.${user.groupId}`)} ); diff --git a/VocaDbWeb/Scripts/Pages/User/UserEvents.tsx b/VocaDbWeb/Scripts/Pages/User/UserEvents.tsx index d5e3315c65..e8aa454402 100644 --- a/VocaDbWeb/Scripts/Pages/User/UserEvents.tsx +++ b/VocaDbWeb/Scripts/Pages/User/UserEvents.tsx @@ -5,10 +5,10 @@ import { UserEventRelationshipType } from '@/Models/Users/UserEventRelationshipT import { UserDetailsNav } from '@/Pages/User/UserDetailsRoutes'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; import { UserDetailsStore } from '@/Stores/User/UserDetailsStore'; +import dayjs from '@/dayjs'; import classNames from 'classnames'; import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; @@ -106,7 +106,7 @@ const Events = observer( {event.date && (
- {moment(event.date).format('l')} + {dayjs(event.date).format('l')}
)} diff --git a/VocaDbWeb/Scripts/Pages/User/UserOverview.tsx b/VocaDbWeb/Scripts/Pages/User/UserOverview.tsx index d5156bf21b..e632fee126 100644 --- a/VocaDbWeb/Scripts/Pages/User/UserOverview.tsx +++ b/VocaDbWeb/Scripts/Pages/User/UserOverview.tsx @@ -24,10 +24,10 @@ import { UserDetailsNav } from '@/Pages/User/UserDetailsRoutes'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; import { UserDetailsStore } from '@/Stores/User/UserDetailsStore'; import { useVdb } from '@/VdbContext'; +import dayjs from '@/dayjs'; import Highcharts from 'highcharts'; import HighchartsReact from 'highcharts-react-official'; import { observer } from 'mobx-react-lite'; -import moment from 'moment'; import qs from 'qs'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -254,7 +254,7 @@ const UserOverview = observer(

{t('ViewRes.User:Details.MemberSince')}

- {moment(user.createDate).format('l')} + {dayjs(user.createDate).format('l')} {loginManager.canViewOldUsernames && user.oldUsernames && @@ -268,7 +268,7 @@ const UserOverview = observer( {index > 0 && ', '} {oldName.oldName}{' '} {t('ViewRes.User:Details.OldNameUntil', { - 0: moment(oldName.date).format('l'), + 0: dayjs(oldName.date).format('l'), })} ))} diff --git a/VocaDbWeb/Scripts/Pages/Venue/VenueDetails.tsx b/VocaDbWeb/Scripts/Pages/Venue/VenueDetails.tsx index e467dcc9c1..74c3ac7519 100644 --- a/VocaDbWeb/Scripts/Pages/Venue/VenueDetails.tsx +++ b/VocaDbWeb/Scripts/Pages/Venue/VenueDetails.tsx @@ -19,7 +19,7 @@ import { import { venueRepo } from '@/Repositories/VenueRepository'; import { EntryUrlMapper } from '@/Shared/EntryUrlMapper'; import { VenueDetailsStore } from '@/Stores/Venue/VenueDetailsStore'; -import moment from 'moment'; +import dayjs from '@/dayjs'; import NProgress from 'nprogress'; import qs from 'qs'; import React from 'react'; @@ -157,7 +157,7 @@ const VenueDetailsLayout = ({ {event.date && ( <> {' '} - ({moment(event.date).format('l')}) + ({dayjs(event.date).format('l')}) )} diff --git a/VocaDbWeb/Scripts/Stores/Admin/ManageIPRulesStore.ts b/VocaDbWeb/Scripts/Stores/Admin/ManageIPRulesStore.ts index a3622eb53d..0de295c3e4 100644 --- a/VocaDbWeb/Scripts/Stores/Admin/ManageIPRulesStore.ts +++ b/VocaDbWeb/Scripts/Stores/Admin/ManageIPRulesStore.ts @@ -2,9 +2,9 @@ import { AdminRepository, IPRuleContract, } from '@/Repositories/AdminRepository'; +import dayjs from 'dayjs'; import { pull } from 'lodash-es'; import { action, makeObservable, observable, runInAction } from 'mobx'; -import moment from 'moment'; class IPRule { @observable address: string; @@ -59,7 +59,7 @@ export class ManageIPRulesStore { }; @action deleteOldRules = (): void => { - const cutOff = moment().subtract(1, 'years').toDate(); + const cutOff = dayjs().subtract(1, 'years').toDate(); const toBeRemoved = this.rules.filter((r) => new Date(r.created) < cutOff); pull(this.rules, ...toBeRemoved); diff --git a/VocaDbWeb/Scripts/Stores/Album/AlbumEditStore.ts b/VocaDbWeb/Scripts/Stores/Album/AlbumEditStore.ts index aa10228564..856bf87398 100644 --- a/VocaDbWeb/Scripts/Stores/Album/AlbumEditStore.ts +++ b/VocaDbWeb/Scripts/Stores/Album/AlbumEditStore.ts @@ -28,6 +28,7 @@ import { NamesEditStore } from '@/Stores/Globalization/NamesEditStore'; import { PVListEditStore } from '@/Stores/PVs/PVListEditStore'; import { SongInAlbumEditStore } from '@/Stores/SongInAlbumEditStore'; import { WebLinksEditStore } from '@/Stores/WebLinksEditStore'; +import dayjs, { Dayjs } from 'dayjs'; import { isEmpty, isNumber, pull, some } from 'lodash-es'; import { action, @@ -37,7 +38,6 @@ import { reaction, runInAction, } from 'mobx'; -import moment, { Moment } from 'moment'; // Single artist selection for the track properties dialog. export class TrackArtistSelectionStore { @@ -287,18 +287,21 @@ export class AlbumEditStore { ); } - @computed get eventDate(): Moment | undefined { + @computed get eventDate(): Dayjs | undefined { return this.releaseEvent.entry && this.releaseEvent.entry.date - ? moment(this.releaseEvent.entry.date) + ? dayjs(this.releaseEvent.entry.date) : undefined; } - @computed get releaseDate(): Moment | undefined { + @computed get releaseDate(): Dayjs | undefined { return this.releaseYear && this.releaseMonth && this.releaseDay - ? moment([this.releaseYear, this.releaseMonth, this.releaseDay]) + ? dayjs() + .year(this.releaseYear) + .month(this.releaseMonth) + .date(this.releaseDay) : undefined; } - set releaseDate(value: Moment | undefined) { + set releaseDate(value: Dayjs | undefined) { this.releaseYear = value?.year(); this.releaseMonth = value ? value.month() + 1 : undefined; this.releaseDay = value?.date(); diff --git a/VocaDbWeb/Scripts/Stores/Artist/ArtistEditStore.ts b/VocaDbWeb/Scripts/Stores/Artist/ArtistEditStore.ts index aa58d32b6e..8b7cfea0f9 100644 --- a/VocaDbWeb/Scripts/Stores/Artist/ArtistEditStore.ts +++ b/VocaDbWeb/Scripts/Stores/Artist/ArtistEditStore.ts @@ -15,6 +15,7 @@ import { EntryPictureFileListEditStore } from '@/Stores/EntryPictureFileListEdit import { EnglishTranslatedStringEditStore } from '@/Stores/Globalization/EnglishTranslatedStringEditStore'; import { NamesEditStore } from '@/Stores/Globalization/NamesEditStore'; import { WebLinksEditStore } from '@/Stores/WebLinksEditStore'; +import dayjs from 'dayjs'; import { pull } from 'lodash-es'; import { action, @@ -24,7 +25,6 @@ import { reaction, runInAction, } from 'mobx'; -import moment from 'moment'; export class ArtistForArtistEditStore { @observable linkType: string /* TODO: enum */; @@ -112,7 +112,7 @@ export class ArtistEditStore { this.names = NamesEditStore.fromContracts(contract.names); this.pictures = new EntryPictureFileListEditStore(contract.pictures); this.releaseDate = contract.releaseDate - ? moment(contract.releaseDate).toDate() + ? dayjs(contract.releaseDate).toDate() : undefined; this.status = contract.status; this.voiceProvider.id = contract.voiceProvider?.id; diff --git a/VocaDbWeb/Scripts/Stores/ReleaseEvent/ReleaseEventEditStore.ts b/VocaDbWeb/Scripts/Stores/ReleaseEvent/ReleaseEventEditStore.ts index f390c58c25..06f817d71a 100644 --- a/VocaDbWeb/Scripts/Stores/ReleaseEvent/ReleaseEventEditStore.ts +++ b/VocaDbWeb/Scripts/Stores/ReleaseEvent/ReleaseEventEditStore.ts @@ -25,6 +25,7 @@ import { NamesEditStore } from '@/Stores/Globalization/NamesEditStore'; import { PVListEditStore } from '@/Stores/PVs/PVListEditStore'; import { ArtistForEventEditStore } from '@/Stores/ReleaseEvent/ArtistForEventEditStore'; import { WebLinksEditStore } from '@/Stores/WebLinksEditStore'; +import dayjs from 'dayjs'; import { pull } from 'lodash-es'; import { action, @@ -34,7 +35,6 @@ import { reaction, runInAction, } from 'mobx'; -import moment from 'moment'; export class EventArtistRolesEditStore extends ArtistRolesEditStore { constructor(roleNames: { [key: string]: string | undefined }) { @@ -118,11 +118,11 @@ export class ReleaseEventEditStore { ); this.category = contract.category; this.customName = contract.customName; - this.date = contract.date ? moment(contract.date).toDate() : undefined; + this.date = contract.date ? dayjs(contract.date).toDate() : undefined; this.defaultNameLanguage = contract.defaultNameLanguage; this.description = contract.description; this.endDate = contract.endDate - ? moment(contract.endDate).toDate() + ? dayjs(contract.endDate).toDate() : undefined; this.names = NamesEditStore.fromContracts(contract.names); diff --git a/VocaDbWeb/Scripts/Stores/Search/SearchCategoryBaseStore.ts b/VocaDbWeb/Scripts/Stores/Search/SearchCategoryBaseStore.ts index 510b69c50d..ba727079e3 100644 --- a/VocaDbWeb/Scripts/Stores/Search/SearchCategoryBaseStore.ts +++ b/VocaDbWeb/Scripts/Stores/Search/SearchCategoryBaseStore.ts @@ -7,7 +7,9 @@ import { ICommonSearchStore } from '@/Stores/Search/CommonSearchStore'; import { SearchRouteParams } from '@/Stores/Search/SearchStore'; import { TagFilter } from '@/Stores/Search/TagFilter'; import { ServerSidePagingStore } from '@/Stores/ServerSidePagingStore'; +import dayjs from '@/dayjs'; import { StateChangeEvent, LocationStateStore } from '@vocadb/route-sphere'; +import UTC from 'dayjs/plugin/utc'; import { action, computed, @@ -16,7 +18,6 @@ import { reaction, runInAction, } from 'mobx'; -import moment from 'moment'; export interface ISearchCategoryBaseStore< TRouteParams extends SearchRouteParams @@ -26,6 +27,8 @@ export interface ISearchCategoryBaseStore< updateResultsWithTotalCount(): Promise; } +dayjs.extend(UTC); + // Base class for different types of searches. export abstract class SearchCategoryBaseStore< TRouteParams extends SearchRouteParams, @@ -108,7 +111,7 @@ export abstract class SearchCategoryBaseStore< } formatDate = (dateStr: string): string => { - return moment(dateStr).utc().format('l'); + return dayjs(dateStr).utc().format('l'); }; // Method for loading a page of results. diff --git a/VocaDbWeb/Scripts/Stores/Search/SongSearchStore.ts b/VocaDbWeb/Scripts/Stores/Search/SongSearchStore.ts index db09db83ec..1181f030fd 100644 --- a/VocaDbWeb/Scripts/Stores/Search/SongSearchStore.ts +++ b/VocaDbWeb/Scripts/Stores/Search/SongSearchStore.ts @@ -26,8 +26,11 @@ import { SongBpmFilter } from '@/Stores/Search/SongBpmFilter'; import { SongLengthFilter } from '@/Stores/Search/SongLengthFilter'; import { SongWithPreviewStore } from '@/Stores/Song/SongWithPreviewStore'; import { includesAny, StateChangeEvent } from '@vocadb/route-sphere'; +import dayjs, { Dayjs } from 'dayjs'; +import UTC from 'dayjs/plugin/utc'; import { computed, makeObservable, observable } from 'mobx'; -import moment from 'moment'; + +dayjs.extend(UTC); export interface ISongSearchItem extends SongApiContract { previewStore?: SongWithPreviewStore; @@ -172,17 +175,17 @@ export class SongSearchStore // Remember, JavaScript months start from 0 (who came up with that??) // The answer song: https://stackoverflow.com/questions/2552483/why-does-the-month-argument-range-from-0-to-11-in-javascripts-date-constructor/41992352#41992352 - private toDateOrUndefined = (mom: moment.Moment): Date | undefined => + private toDateOrUndefined = (mom: Dayjs): Date | undefined => mom.isValid() ? mom.toDate() : undefined; @computed get afterDate(): Date | undefined { return this.dateYear ? this.toDateOrUndefined( - moment.utc([ - this.dateYear, - (this.dateMonth || 1) - 1, - this.dateDay || 1, - ]), + dayjs + .utc() + .year(this.dateYear) + .month((this.dateMonth || 1) - 1) + .date(this.dateDay || 1), ) : undefined; } @@ -190,11 +193,11 @@ export class SongSearchStore @computed get beforeDate(): Date | undefined { if (!this.dateYear) return undefined; - const mom = moment.utc([ - this.dateYear, - (this.dateMonth || 12) - 1, - this.dateDay || 1, - ]); + const mom = dayjs + .utc() + .year(this.dateYear) + .month((this.dateMonth || 12) - 1) + .date(this.dateDay || 1); return this.toDateOrUndefined( this.dateMonth && this.dateDay ? mom.add(1, 'd') : mom.add(1, 'M'), diff --git a/VocaDbWeb/Scripts/Stores/Song/SongEditStore.ts b/VocaDbWeb/Scripts/Stores/Song/SongEditStore.ts index 9091570f1f..3d013bfe3f 100644 --- a/VocaDbWeb/Scripts/Stores/Song/SongEditStore.ts +++ b/VocaDbWeb/Scripts/Stores/Song/SongEditStore.ts @@ -27,6 +27,7 @@ import { SongBpmFilter } from '@/Stores/Search/SongBpmFilter'; import { SongLengthFilter } from '@/Stores/Search/SongLengthFilter'; import { LyricsForSongListEditStore } from '@/Stores/Song/LyricsForSongListEditStore'; import { WebLinksEditStore } from '@/Stores/WebLinksEditStore'; +import dayjs, { Dayjs } from 'dayjs'; import { isEmpty, pull, some, unionBy } from 'lodash-es'; import { action, @@ -35,16 +36,15 @@ import { observable, runInAction, } from 'mobx'; -import moment, { Moment } from 'moment'; interface PotentialDate { - date: Moment; + date: Dayjs; source: string; } export class SongEditStore { private readonly albumEventId?: number; - private readonly albumReleaseDate?: Moment; + private readonly albumReleaseDate?: Dayjs; // List of artist links for this song. @observable artistLinks: ArtistForAlbumEditStore[] = []; readonly artistRolesEditStore: AlbumArtistRolesEditStore; @@ -110,7 +110,7 @@ export class SongEditStore { this.albumEventId = contract.albumEventId; this.albumReleaseDate = contract.albumReleaseDate - ? moment(contract.albumReleaseDate) + ? dayjs(contract.albumReleaseDate) : undefined; this.artistLinks = contract.artists.map( (artist) => new ArtistForAlbumEditStore(artist), @@ -131,7 +131,7 @@ export class SongEditStore { this.notes = new EnglishTranslatedStringEditStore(contract.notes); this.originalVersion.id = contract.originalVersion?.id; this.publishDate = contract.publishDate - ? moment(contract.publishDate).toDate() + ? dayjs(contract.publishDate).toDate() : undefined; this.pvs = new PVListEditStore( pvRepo, @@ -268,18 +268,18 @@ export class SongEditStore { ); } - @computed get eventDate(): Moment | undefined { + @computed get eventDate(): Dayjs | undefined { return this.releaseEvent.entry && this.releaseEvent.entry.date - ? moment(this.releaseEvent.entry.date) + ? dayjs(this.releaseEvent.entry.date) : undefined; } - @computed get firstPvDate(): Moment | undefined { + @computed get firstPvDate(): Dayjs | undefined { return this.pvs.pvs .filter( (pv) => !!pv.contract.publishDate && pv.pvType === PVType.Original, ) - .map((pv) => moment(pv.contract.publishDate)) + .map((pv) => dayjs(pv.contract.publishDate)) .sortBy((p) => p) .head(); } diff --git a/VocaDbWeb/Scripts/Stores/SongList/SongListEditStore.ts b/VocaDbWeb/Scripts/Stores/SongList/SongListEditStore.ts index 0d75dc0420..453ad79d9c 100644 --- a/VocaDbWeb/Scripts/Stores/SongList/SongListEditStore.ts +++ b/VocaDbWeb/Scripts/Stores/SongList/SongListEditStore.ts @@ -8,6 +8,7 @@ import { SongListRepository } from '@/Repositories/SongListRepository'; import { SongRepository } from '@/Repositories/SongRepository'; import { GlobalValues } from '@/Shared/GlobalValues'; import { DeleteEntryStore } from '@/Stores/DeleteEntryStore'; +import dayjs from 'dayjs'; import { pull } from 'lodash-es'; import { action, @@ -17,7 +18,6 @@ import { reaction, runInAction, } from 'mobx'; -import moment from 'moment'; export class SongInListEditStore { private static nextId = 1; @@ -86,7 +86,7 @@ export class SongListEditStore { this.name = contract.name; this.description = contract.description; this.eventDateDate = contract.eventDate - ? moment(contract.eventDate).toDate() + ? dayjs(contract.eventDate).toDate() : undefined; // Assume server date is UTC this.featuredCategory = contract.featuredCategory; this.status = contract.status; diff --git a/VocaDbWeb/Scripts/Stores/SongList/SongListsBaseStore.ts b/VocaDbWeb/Scripts/Stores/SongList/SongListsBaseStore.ts index b66f832c85..d6f4d0e487 100644 --- a/VocaDbWeb/Scripts/Stores/SongList/SongListsBaseStore.ts +++ b/VocaDbWeb/Scripts/Stores/SongList/SongListsBaseStore.ts @@ -6,8 +6,8 @@ import { GlobalValues } from '@/Shared/GlobalValues'; import { PagedItemsStore } from '@/Stores/PagedItemsStore'; import { TagFilter } from '@/Stores/Search/TagFilter'; import { TagFilters } from '@/Stores/Search/TagFilters'; +import dayjs from 'dayjs'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; -import moment from 'moment'; // Corresponds to the SongListSortRule enum in C#. export enum SongListSortRule { @@ -81,8 +81,8 @@ export abstract class SongListsBaseStore extends PagedItemsStore { const cutoff = - this.showTimespanFilter && this.timespan - ? moment().subtract(this.timespan, 'hours').toISOString() + this.showTimespanFilter && Number.isSafeInteger(this.timespan) + ? dayjs() + .subtract(Number.parseInt(this.timespan ?? '0'), 'hours') + .toISOString() : undefined; this.httpClient diff --git a/VocaDbWeb/Scripts/Stores/User/RatedSongsSearchStore.ts b/VocaDbWeb/Scripts/Stores/User/RatedSongsSearchStore.ts index aee48550cf..0b8fc4b617 100644 --- a/VocaDbWeb/Scripts/Stores/User/RatedSongsSearchStore.ts +++ b/VocaDbWeb/Scripts/Stores/User/RatedSongsSearchStore.ts @@ -22,6 +22,7 @@ import { TagFilters } from '@/Stores/Search/TagFilters'; import { ServerSidePagingStore } from '@/Stores/ServerSidePagingStore'; import { SongWithPreviewStore } from '@/Stores/Song/SongWithPreviewStore'; import { SongListSortRule } from '@/Stores/SongList/SongListsBaseStore'; +import dayjs from '@/dayjs'; import { includesAny, StateChangeEvent, @@ -36,7 +37,6 @@ import { reaction, runInAction, } from 'mobx'; -import moment from 'moment'; import schema from './RatedSongsSearchRouteParams.schema.json'; @@ -172,7 +172,7 @@ export class RatedSongsSearchStore }; formatDate = (dateStr: string): string => { - return moment(dateStr).format('l'); + return dayjs(dateStr).format('l'); }; getPVServiceIcons = ( diff --git a/VocaDbWeb/Scripts/VdbContext.tsx b/VocaDbWeb/Scripts/VdbContext.tsx index 3b1081ffdf..09686bb685 100644 --- a/VocaDbWeb/Scripts/VdbContext.tsx +++ b/VocaDbWeb/Scripts/VdbContext.tsx @@ -2,7 +2,7 @@ import { GlobalResources } from '@/Shared/GlobalResources'; import { GlobalValues } from '@/Shared/GlobalValues'; import { httpClient } from '@/Shared/HttpClient'; import { urlMapper } from '@/Shared/UrlMapper'; -import moment from 'moment'; +import dayjs from 'dayjs'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -12,6 +12,21 @@ interface VdbContextProps { refresh(): Promise; } +const locales: LocaleLoader = { + 'de-DE': () => import('dayjs/locale/de'), + 'en-US': () => import('dayjs/locale/en'), + es: () => import('dayjs/locale/es'), + pt: () => import('dayjs/locale/pt'), + 'fi-FI': () => import('dayjs/locale/fi'), + 'ru-RU': () => import('dayjs/locale/ru'), + 'zh-Hans': () => import('dayjs/locale/zh'), + 'ja-JP': () => import('dayjs/locale/ja'), +}; + +interface LocaleLoader { + [key: string]: () => Promise; +} + const VdbContext = React.createContext(undefined!); interface VdbProviderProps { @@ -35,8 +50,11 @@ export const VdbProvider = ({ ), ]); + locales[values.culture]() + .then(() => dayjs.locale(values.culture)) + .then(() => console.log('Hey')); + i18n.changeLanguage(values.uiCulture); - moment.locale(values.culture); setVdb({ resources, values, refresh }); }, [i18n]); diff --git a/VocaDbWeb/Scripts/dayjs.ts b/VocaDbWeb/Scripts/dayjs.ts new file mode 100644 index 0000000000..0f686cc08c --- /dev/null +++ b/VocaDbWeb/Scripts/dayjs.ts @@ -0,0 +1,6 @@ +import dayjs from 'dayjs'; +import LocalizedFormat from 'dayjs/plugin/localizedFormat'; + +dayjs.extend(LocalizedFormat); + +export default dayjs; diff --git a/VocaDbWeb/package-lock.json b/VocaDbWeb/package-lock.json index 63365af0b0..b0aa69c06c 100644 --- a/VocaDbWeb/package-lock.json +++ b/VocaDbWeb/package-lock.json @@ -14,6 +14,7 @@ "ajv-formats": "^2.1.1", "axios": "^0.21.2", "classnames": "^2.3.1", + "dayjs": "^1.11.7", "decimal.js-light": "^2.5.1", "highcharts": "^10.0.0", "highcharts-react-official": "^3.1.0", @@ -6996,6 +6997,11 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -24574,6 +24580,11 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", diff --git a/VocaDbWeb/package.json b/VocaDbWeb/package.json index c8a47920d4..d63c35320d 100644 --- a/VocaDbWeb/package.json +++ b/VocaDbWeb/package.json @@ -65,6 +65,7 @@ "ajv-formats": "^2.1.1", "axios": "^0.21.2", "classnames": "^2.3.1", + "dayjs": "^1.11.7", "decimal.js-light": "^2.5.1", "highcharts": "^10.0.0", "highcharts-react-official": "^3.1.0", @@ -79,7 +80,6 @@ "lodash-es": "^4.17.21", "mobx": "^6.3.2", "mobx-react-lite": "^3.2.0", - "moment": "^2.29.4", "nprogress": "^0.2.0", "qs": "^6.11.0", "react": "^17.0.2", From 61560a324433b21acbb5be11a62eadb5bf9bd445 Mon Sep 17 00:00:00 2001 From: FinnRG Date: Fri, 19 May 2023 00:14:44 +0200 Subject: [PATCH 2/2] fix: Move dayjs.extend out of react component --- .../Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx b/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx index 9d606c6454..7113156ca6 100644 --- a/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx +++ b/VocaDbWeb/Scripts/Components/KnockoutExtensions/MomentJsTimeAgo.tsx @@ -8,12 +8,13 @@ interface MomentJsTimeAgoProps { children: string; } +dayjs.extend(relativeTime); + export const MomentJsTimeAgo = ({ as: Component, className, children, }: MomentJsTimeAgoProps): React.ReactElement => { - dayjs.extend(relativeTime); const parsed = dayjs(children); return (