diff --git a/package.json b/package.json index 4d5538520..86fa44b8d 100644 --- a/package.json +++ b/package.json @@ -72,8 +72,6 @@ "i18next": "^22.5.1", "immer": "^10.0.2", "js-file-download": "^0.4.12", - "moment": "^2.29.4", - "moment-timezone": "^0.5.43", "next": "13.4.10", "next-i18next": "^13.0.0", "nzbget-api": "^0.0.3", @@ -230,4 +228,4 @@ ] } } -} \ No newline at end of file +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index bcfcf4e42..c62bbbee4 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -8,7 +8,9 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'; import Consola from 'consola'; import { getCookie } from 'cookies-next'; -import moment from 'moment-timezone'; +import dayjs from 'dayjs'; +import locale from 'dayjs/plugin/localeData' +import utc from 'dayjs/plugin/utc' import { GetServerSidePropsContext } from 'next'; import { appWithTranslation } from 'next-i18next'; import { AppProps } from 'next/app'; @@ -39,6 +41,9 @@ import { } from '../tools/server/getPackageVersion'; import { theme } from '../tools/server/theme/theme'; +dayjs.extend(locale); +dayjs.extend(utc); + function App( this: any, props: AppProps<{ @@ -54,8 +59,8 @@ function App( const { Component, pageProps } = props; // TODO: make mapping from our locales to moment locales const language = getLanguageByCode(pageProps.locale); - require('moment/locale/' + language.momentLocale); - moment.locale(language.momentLocale); + require(`dayjs/locale/${language.locale}.js`); + dayjs.locale(language.locale); const [primaryColor, setPrimaryColor] = useState( props.pageProps.config?.settings.customization.colors.primary || 'red' diff --git a/src/tools/language.ts b/src/tools/language.ts index 10978d707..e885e1500 100644 --- a/src/tools/language.ts +++ b/src/tools/language.ts @@ -3,7 +3,7 @@ export type Language = { originalName: string; translatedName: string; emoji: string; - momentLocale: string; + locale: string; }; export const languages: Language[] = [ @@ -12,14 +12,14 @@ export const languages: Language[] = [ originalName: 'Deutsch', translatedName: 'German', emoji: '🇩🇪', - momentLocale: 'de', + locale: 'de', }, { shortName: 'en', originalName: 'English', translatedName: 'English', emoji: '🇬🇧', - momentLocale: 'en-gb', + locale: 'en-gb', }, // Danish { @@ -27,7 +27,7 @@ export const languages: Language[] = [ originalName: 'Dansk', translatedName: 'Danish', emoji: '🇩🇰', - momentLocale: 'da', + locale: 'da', }, // Hebrew { @@ -35,49 +35,49 @@ export const languages: Language[] = [ originalName: 'עברית', translatedName: 'Hebrew', emoji: '🇮🇱', - momentLocale: 'he', + locale: 'he', }, { shortName: 'es', originalName: 'Español', translatedName: 'Spanish', emoji: '🇪🇸', - momentLocale: 'es', + locale: 'es', }, { shortName: 'fr', originalName: 'Français', translatedName: 'French', emoji: '🇫🇷', - momentLocale: 'fr', + locale: 'fr', }, { shortName: 'it', originalName: 'Italiano', translatedName: 'Italian', emoji: '🇮🇹', - momentLocale: 'it', + locale: 'it', }, { shortName: 'ja', originalName: '日本語', translatedName: 'Japanese', emoji: '🇯🇵', - momentLocale: 'ja', + locale: 'ja', }, { shortName: 'ko', originalName: '한국어', translatedName: 'Korean', emoji: '🇰🇷', - momentLocale: 'ko', + locale: 'ko', }, { shortName: 'lol', originalName: 'LOLCAT', translatedName: 'LOLCAT', emoji: '🐱', - momentLocale: 'en-gb', + locale: 'en-gb', }, // Norwegian { @@ -85,7 +85,7 @@ export const languages: Language[] = [ originalName: 'Norsk', translatedName: 'Norwegian', emoji: '🇳🇴', - momentLocale: 'nb', + locale: 'nb', }, // Slovak { @@ -93,42 +93,42 @@ export const languages: Language[] = [ originalName: 'Slovenčina', translatedName: 'Slovak', emoji: '🇸🇰', - momentLocale: 'sk', + locale: 'sk', }, { shortName: 'nl', originalName: 'Nederlands', translatedName: 'Dutch', emoji: '🇳🇱', - momentLocale: 'nl', + locale: 'nl', }, { shortName: 'pl', originalName: 'Polski', translatedName: 'Polish', emoji: '🇵🇱', - momentLocale: 'pl', + locale: 'pl', }, { shortName: 'pt', originalName: 'Português', translatedName: 'Portuguese', emoji: '🇵🇹', - momentLocale: 'pt', + locale: 'pt', }, { shortName: 'ru', originalName: 'Русский', translatedName: 'Russian', emoji: '🇷🇺', - momentLocale: 'ru', + locale: 'ru', }, { shortName: 'sl', originalName: 'Slovenščina', translatedName: 'Slovenian', emoji: '🇸🇮', - momentLocale: 'sl', + locale: 'sl', }, { @@ -136,14 +136,14 @@ export const languages: Language[] = [ originalName: 'Svenska', translatedName: 'Swedish', emoji: '🇸🇪', - momentLocale: 'sv', + locale: 'sv', }, { shortName: 'uk', originalName: 'Українська', translatedName: 'Ukrainian', emoji: '🇺🇦', - momentLocale: 'uk', + locale: 'uk', }, // Vietnamese { @@ -151,42 +151,42 @@ export const languages: Language[] = [ originalName: 'Tiếng Việt', translatedName: 'Vietnamese', emoji: '🇻🇳', - momentLocale: 'vi', + locale: 'vi', }, { shortName: 'zh', originalName: '中文', translatedName: 'Chinese', emoji: '🇨🇳', - momentLocale: 'zh-cn', + locale: 'zh-cn', }, { shortName: 'el', originalName: 'Ελληνικά', translatedName: 'Greek', emoji: '🇬🇷', - momentLocale: 'el', + locale: 'el', }, { shortName: 'tr', originalName: 'Türkçe', translatedName: 'Turkish', emoji: '🇹🇷', - momentLocale: 'tr', + locale: 'tr', }, { shortName: 'lv', originalName: 'Latvian', translatedName: 'Latvian', emoji: '🇱🇻', - momentLocale: 'lv', + locale: 'lv', }, { shortName: 'hr', originalName: 'Hrvatski', translatedName: 'Croatian', emoji: '🇭🇷', - momentLocale: 'hr', + locale: 'hr', }, ]; diff --git a/src/widgets/calendar/CalendarTile.tsx b/src/widgets/calendar/CalendarTile.tsx index ec421e191..bf1016968 100644 --- a/src/widgets/calendar/CalendarTile.tsx +++ b/src/widgets/calendar/CalendarTile.tsx @@ -1,8 +1,9 @@ import { useMantineTheme } from '@mantine/core'; import { Calendar } from '@mantine/dates'; import { IconCalendarTime } from '@tabler/icons-react'; -import { i18n } from 'next-i18next'; import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { getLanguageByCode } from '~/tools/language'; import { api } from '~/utils/api'; import { useEditModeStore } from '../../components/Dashboard/Views/useEditModeStore'; @@ -66,11 +67,15 @@ interface CalendarTileProps { } function CalendarTile({ widget }: CalendarTileProps) { + const { locale } = useRouter(); const { colorScheme, radius } = useMantineTheme(); const { name: configName } = useConfigContext(); const [month, setMonth] = useState(new Date()); const isEditMode = useEditModeStore((x) => x.enabled); + const language = getLanguageByCode(locale ?? 'en'); + require(`dayjs/locale/${language.locale}.js`); + const { data: medias } = api.calendar.medias.useQuery( { configName: configName!, @@ -90,7 +95,7 @@ function CalendarTile({ widget }: CalendarTileProps) { onPreviousMonth={setMonth} onNextMonth={setMonth} size={widget.properties.fontSize} - locale={i18n?.resolvedLanguage ?? 'en'} + locale={language.locale} firstDayOfWeek={widget.properties.sundayStart ? 0 : 1} hideWeekdays={widget.properties.hideWeekDays} style={{ position: 'relative' }} diff --git a/src/widgets/date/DateTile.tsx b/src/widgets/date/DateTile.tsx index c9ea0d645..faa479ed9 100644 --- a/src/widgets/date/DateTile.tsx +++ b/src/widgets/date/DateTile.tsx @@ -1,16 +1,21 @@ import { Stack, Text, createStyles } from '@mantine/core'; import { useElementSize } from '@mantine/hooks'; import { IconClock } from '@tabler/icons-react'; -import moment from 'moment-timezone'; import { useRouter } from 'next/router'; import { useEffect, useRef, useState } from 'react'; import { getLanguageByCode } from '~/tools/language'; import { api } from '~/utils/api'; +import dayjs from 'dayjs'; +import timezones from 'dayjs/plugin/timezone' +import utc from 'dayjs/plugin/utc' import { useSetSafeInterval } from '../../hooks/useSetSafeInterval'; import { defineWidget } from '../helper'; import { IWidget } from '../widgets'; +dayjs.extend(utc); +dayjs.extend(timezones); + const definition = defineWidget({ id: 'date', icon: IconClock, @@ -24,14 +29,14 @@ const definition = defineWidget({ defaultValue: 'dddd, MMMM D', data: () => [ { value: 'hide' }, - { value: 'dddd, MMMM D', label: moment().format('dddd, MMMM D') }, - { value: 'dddd, D MMMM', label: moment().format('dddd, D MMMM') }, - { value: 'MMM D', label: moment().format('MMM D') }, - { value: 'D MMM', label: moment().format('D MMM') }, - { value: 'DD/MM/YYYY', label: moment().format('DD/MM/YYYY') }, - { value: 'MM/DD/YYYY', label: moment().format('MM/DD/YYYY') }, - { value: 'DD/MM', label: moment().format('DD/MM') }, - { value: 'MM/DD', label: moment().format('MM/DD') }, + { value: 'dddd, MMMM D', label: dayjs().format('dddd, MMMM D') }, + { value: 'dddd, D MMMM', label: dayjs().format('dddd, D MMMM') }, + { value: 'MMM D', label: dayjs().format('MMM D') }, + { value: 'D MMM', label: dayjs().format('D MMM') }, + { value: 'DD/MM/YYYY', label: dayjs().format('DD/MM/YYYY') }, + { value: 'MM/DD/YYYY', label: dayjs().format('MM/DD/YYYY') }, + { value: 'DD/MM', label: dayjs().format('DD/MM') }, + { value: 'MM/DD', label: dayjs().format('MM/DD') }, ], }, enableTimezone: { @@ -84,11 +89,11 @@ function DateTile({ widget }: DateTileProps) { className={cx(classes.extras, 'dashboard-tile-clock-city')} > {widget.properties.timezoneLocation.name} - {widget.properties.titleState === 'both' && moment(date).format(' (z)')} + {widget.properties.titleState === 'both' && dayjs(date).format(' (z)')} )} - {moment(date).format(formatString)} + {dayjs(date).format(formatString)} {!widget.properties.dateFormat.includes('hide') && ( - {moment(date).format(widget.properties.dateFormat)} + {dayjs(date).format(widget.properties.dateFormat)} )} @@ -139,7 +144,7 @@ const useDateState = (location?: { latitude: number; longitude: number }) => { const timeoutRef = useRef(); // reference for initial timeout until first minute change useEffect(() => { const language = getLanguageByCode(locale ?? 'en'); - moment.locale(language.momentLocale); + dayjs.locale(language.locale); setDate(getNewDate(timezone)); timeoutRef.current = setTimeout( () => { @@ -150,9 +155,8 @@ const useDateState = (location?: { latitude: number; longitude: number }) => { }, 1000 * 60); //1 minute - current seconds and milliseconds count }, - 1000 * 60 - (1000 * moment().seconds() + moment().milliseconds()) + 1000 * 60 - (1000 * dayjs().second() + dayjs().millisecond()) ); - return () => timeoutRef.current && clearTimeout(timeoutRef.current); }, [timezone, locale]); @@ -162,9 +166,9 @@ const useDateState = (location?: { latitude: number; longitude: number }) => { //Returns a local date if no inputs or returns date from input zone const getNewDate = (timezone?: string) => { if (timezone) { - return moment().tz(timezone); + return dayjs().tz(timezone); } - return moment(); + return dayjs(); }; export default definition; diff --git a/yarn.lock b/yarn.lock index ccf3a52cb..7902e41c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5935,8 +5935,6 @@ __metadata: i18next: ^22.5.1 immer: ^10.0.2 js-file-download: ^0.4.12 - moment: ^2.29.4 - moment-timezone: ^0.5.43 next: 13.4.10 next-i18next: ^13.0.0 node-mocks-http: ^1.12.2 @@ -7254,22 +7252,6 @@ __metadata: languageName: node linkType: hard -"moment-timezone@npm:^0.5.43": - version: 0.5.43 - resolution: "moment-timezone@npm:0.5.43" - dependencies: - moment: ^2.29.4 - checksum: 8075c897ed8a044f992ef26fe8cdbcad80caf974251db424cae157473cca03be2830de8c74d99341b76edae59f148c9d9d19c1c1d9363259085688ec1cf508d0 - languageName: node - linkType: hard - -"moment@npm:^2.29.4": - version: 2.29.4 - resolution: "moment@npm:2.29.4" - checksum: 0ec3f9c2bcba38dc2451b1daed5daded747f17610b92427bebe1d08d48d8b7bdd8d9197500b072d14e326dd0ccf3e326b9e3d07c5895d3d49e39b6803b76e80e - languageName: node - linkType: hard - "mpd-parser@npm:^1.0.1, mpd-parser@npm:^1.1.1": version: 1.1.1 resolution: "mpd-parser@npm:1.1.1"