Add giraugh tools and update dayjs instance on client when lang changes

This commit is contained in:
Ben Grant 2023-05-24 19:10:52 +10:00
parent 3034605126
commit 6220e599cf
10 changed files with 53 additions and 39 deletions

View file

@ -11,6 +11,7 @@
},
"dependencies": {
"@azure/msal-browser": "^2.37.0",
"@giraugh/tools": "^1.5.0",
"@microsoft/microsoft-graph-client": "^3.0.5",
"accept-language": "^3.0.18",
"dayjs": "^1.11.7",

View file

@ -1,8 +1,10 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import { rotateArray } from '@giraugh/tools'
import { Dayjs } from 'dayjs'
import { ChevronLeft, ChevronRight } from 'lucide-react'
import Button from '/src/components/Button/Button'
import dayjs from '/src/config/dayjs'
import { useDayjs } from '/src/config/dayjs'
import { useTranslation } from '/src/i18n/client'
import { useStore } from '/src/stores'
import useSettingsStore from '/src/stores/settingsStore'
@ -10,10 +12,6 @@ import { makeClass } from '/src/utils'
import styles from './Month.module.scss'
// TODO: use from giraugh tools
export const rotateArray = <T, >(arr: T[], amount = 1): T[] =>
arr.map((_, i) => arr[((( -amount + i ) % arr.length) + arr.length) % arr.length])
interface MonthProps {
/** Array of dates in `DDMMYYYY` format */
value: string[]
@ -22,6 +20,7 @@ interface MonthProps {
const Month = ({ value, onChange }: MonthProps) => {
const { t } = useTranslation('home')
const dayjs = useDayjs()
const weekStart = useStore(useSettingsStore, state => state.weekStart) ?? 0
@ -29,7 +28,7 @@ const Month = ({ value, onChange }: MonthProps) => {
month: dayjs().month(),
year: dayjs().year(),
})
const [dates, setDates] = useState(calculateMonth(page, weekStart))
const [dates, setDates] = useState(calculateMonth(dayjs().month(page.month).year(page.year), weekStart))
// Ref and state required to rerender but also access static version in callbacks
const selectingRef = useRef<string[]>([])
@ -45,7 +44,7 @@ const Month = ({ value, onChange }: MonthProps) => {
// Update month view
useEffect(() => {
dayjs.updateLocale(dayjs.locale(), { weekStart })
setDates(calculateMonth(page, weekStart))
setDates(calculateMonth(dayjs().month(page.month).year(page.year), weekStart))
}, [weekStart, page])
const handleFinishSelection = useCallback(() => {
@ -149,8 +148,7 @@ interface Date {
}
/** Calculate the dates to show for the month in a 2d array */
const calculateMonth = ({ month, year }: { month: number, year: number }, weekStart: 0 | 1) => {
const date = dayjs().month(month).year(year)
const calculateMonth = (date: Dayjs, weekStart: 0 | 1) => {
const daysInMonth = date.daysInMonth()
const daysBefore = date.date(1).day() - weekStart
const daysAfter = 6 - date.date(daysInMonth).day() + weekStart

View file

@ -1,6 +1,7 @@
import { useCallback, useMemo, useRef, useState } from 'react'
import { rotateArray } from '@giraugh/tools'
import dayjs from '/src/config/dayjs'
import { useDayjs } from '/src/config/dayjs'
import { useTranslation } from '/src/i18n/client'
import { useStore } from '/src/stores'
import useSettingsStore from '/src/stores/settingsStore'
@ -9,10 +10,6 @@ import { makeClass } from '/src/utils'
// Use styles from Month picker
import styles from '../Month/Month.module.scss'
// TODO: use from giraugh tools
export const rotateArray = <T, >(arr: T[], amount = 1): T[] =>
arr.map((_, i) => arr[((( -amount + i ) % arr.length) + arr.length) % arr.length])
interface WeekdaysProps {
/** Array of weekdays as numbers from 0-6 (as strings) */
value: string[]
@ -21,6 +18,7 @@ interface WeekdaysProps {
const Weekdays = ({ value, onChange }: WeekdaysProps) => {
const { t } = useTranslation('home')
const dayjs = useDayjs()
const weekStart = useStore(useSettingsStore, state => state.weekStart) ?? 0

View file

@ -11,7 +11,7 @@ import SelectField from '/src/components/SelectField/SelectField'
import TextField from '/src/components/TextField/TextField'
import TimeRangeField from '/src/components/TimeRangeField/TimeRangeField'
import { API_BASE } from '/src/config/api'
import dayjs from '/src/config/dayjs'
import { useDayjs } from '/src/config/dayjs'
import { useTranslation } from '/src/i18n/client'
import timezones from '/src/res/timezones.json'
@ -36,6 +36,7 @@ const defaultValues: Fields = {
const CreateForm = () => {
const { t } = useTranslation('home')
const dayjs = useDayjs()
const { push } = useRouter()
const {

View file

@ -4,7 +4,7 @@ import Link from 'next/link'
import Content from '/src/components/Content/Content'
import Section from '/src/components/Section/Section'
import dayjs from '/src/config/dayjs'
import { useDayjs } from '/src/config/dayjs'
import { useTranslation } from '/src/i18n/client'
import { useStore } from '/src/stores'
import useRecentsStore from '/src/stores/recentsStore'
@ -18,6 +18,7 @@ interface RecentsProps {
const Recents = ({ target }: RecentsProps) => {
const recents = useStore(useRecentsStore, state => state.recents)
const { t } = useTranslation(['home', 'common'])
const dayjs = useDayjs()
return recents?.length ? <Section id="recents">
<Content>

View file

@ -7,7 +7,6 @@ import { Settings as SettingsIcon } from 'lucide-react'
import SelectField from '/src/components/SelectField/SelectField'
import ToggleField from '/src/components/ToggleField/ToggleField'
import dayjs from '/src/config/dayjs'
import { useTranslation } from '/src/i18n/client'
import { languageDetails } from '/src/i18n/options'
import { useStore } from '/src/stores'
@ -16,12 +15,6 @@ import { makeClass, unhyphenate } from '/src/utils'
import styles from './Settings.module.scss'
// TODO: add to giraugh tools
const isKeyOfObject = <T extends object>(
key: string | number | symbol,
obj: T,
): key is keyof T => key in obj
const Settings = () => {
const { t, i18n } = useTranslation('common')
const router = useRouter()
@ -128,17 +121,7 @@ const Settings = () => {
}}
isSmall
value={i18n.language}
onChange={e => {
if (isKeyOfObject(e.target.value, languageDetails)) {
store?.setWeekStart(languageDetails[e.target.value].weekStart)
store?.setTimeFormat(languageDetails[e.target.value].timeFormat)
languageDetails[e.target.value]?.import().then(() => {
dayjs.locale(e.target.value)
})
}
i18n.changeLanguage(e.target.value).then(() => router.refresh())
}}
onChange={e => i18n.changeLanguage(e.target.value).then(() => router.refresh())}
/>
</div>
</dialog>

View file

@ -1,3 +1,5 @@
import { useCallback, useState } from 'react'
import { isKeyOfObject } from '@giraugh/tools'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import isToday from 'dayjs/plugin/isToday'
@ -7,6 +9,11 @@ import timezone from 'dayjs/plugin/timezone'
import updateLocale from 'dayjs/plugin/updateLocale'
import utc from 'dayjs/plugin/utc'
import { useTranslation } from '/src/i18n/client'
import { languageDetails } from '/src/i18n/options'
import { useStore } from '/src/stores'
import useSettingsStore from '/src/stores/settingsStore'
dayjs.extend(customParseFormat)
dayjs.extend(isToday)
dayjs.extend(localeData)
@ -15,4 +22,26 @@ dayjs.extend(timezone)
dayjs.extend(updateLocale)
dayjs.extend(utc)
export default dayjs
export const useDayjs = () => {
const { i18n } = useTranslation()
const store = useStore(useSettingsStore, state => state)
const [updateInstance, setUpdateInstance] = useState(0)
const instance = useCallback(dayjs, [updateInstance, dayjs])
const handleLanguageChange = useCallback((lng: string) => {
if (isKeyOfObject(lng, languageDetails)) {
store?.setWeekStart(languageDetails[lng].weekStart)
store?.setTimeFormat(languageDetails[lng].timeFormat)
languageDetails[lng]?.import().then(() => {
dayjs.locale(lng)
setUpdateInstance(updateInstance + 1)
})
}
}, [store])
i18n.on('languageChanged', handleLanguageChange)
return instance
}

View file

@ -2,12 +2,11 @@
import { initReactI18next, useTranslation as useTranslationHook } from 'react-i18next'
import { cookies } from 'next/dist/client/components/headers' // risky disky (undocumented???)
import dayjs from 'dayjs'
import i18next from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import resourcesToBackend from 'i18next-resources-to-backend'
import dayjs from '/src/config/dayjs'
import { cookieName, getOptions, languageDetails } from './options'
i18next

View file

@ -1,10 +1,9 @@
import { cookies, headers } from 'next/headers'
import acceptLanguage from 'accept-language'
import dayjs from 'dayjs'
import { createInstance } from 'i18next'
import resourcesToBackend from 'i18next-resources-to-backend'
import dayjs from '/src/config/dayjs'
import { cookieName, fallbackLng, getOptions, languageDetails, languages } from './options'
type Mutable<T> = { -readonly [K in keyof T]: Mutable<T[K]> }

View file

@ -65,6 +65,11 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.40.0.tgz#3ba73359e11f5a7bd3e407f70b3528abfae69cec"
integrity sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==
"@giraugh/tools@^1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@giraugh/tools/-/tools-1.5.0.tgz#5c5cc8b248d1e04aebc46dcbeb7620c99f47d2ec"
integrity sha512-DZTrxKU5Ul5+UnDUNja0Cp1HcMLPGF2fh7j4ICEzaNwvRMwcHRH241L/pfneuibZ22w1Ka4U7LVzOWL+SjLIjw==
"@humanwhocodes/config-array@^0.11.8":
version "0.11.8"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"