import { monthsPerYear, daysPerWeek, daysPerMonth, daysPerYear, type LeimDate, type LeimPeriod, type LeimPeriodShort } from '@/models/Date' import { useLocalStorage, useUrlSearchParams } from '@vueuse/core' import { defineStore, skipHydrate } from 'pinia' import { computed, ref, type ComputedRef, type Ref } from 'vue' type CalendarViewType = 'month' | 'year' | 'decade' | 'century' type CalendarStaticConfig = { months: string[] monthsPerYear: number daysPerYear: number daysPerMonth: number daysPerWeek: number } type CalendarCurrentConfig = { viewType: CalendarViewType } type CalendarCurrentDate = { currentDay: ComputedRef currentMonth: ComputedRef currentMonthName: ComputedRef currentYear: ComputedRef currentPeriod: Ref currentPeriodAbbr: Ref currentDateTitle: ComputedRef } export const useCalendar = defineStore('calendar', () => { /** * Static calendar config * This shouldn't change */ /** * Month list */ const months: string[] = [ 'Jalen', 'Malsen', 'Verlys', 'Nalys', 'Verdore', 'Sidore', 'Lyllion', 'Rion', 'Farene', 'Dalvene' ] // Assign the static config const staticConfig: CalendarStaticConfig = { months, monthsPerYear, daysPerYear, daysPerMonth, daysPerWeek } const currentConfig: Ref = ref({ viewType: 'month' }) const viewTypeOptions: Set = new Set([ 'month', 'year', 'decade', 'century' ]) // Default date settings (current day in the world) const defaultDay: number = 23 const defaultMonth: number = 8 const defaultYear: number = 3209 const defaultDate: ComputedRef = computed(() => { return { day: defaultDay, month: defaultMonth, year: defaultYear } }) // Get date from URL params const params = useUrlSearchParams('history', { write: false, initialValue: { day: defaultDate.value.day.toString(), month: defaultDate.value.month.toString(), year: defaultDate.value.year.toString() } }) const currentDay = computed(() => { return Number(params.day) }) const currentMonth = computed(() => { return Number(params.month) }) // Gets the label from currentMonth index const currentMonthName = computed(() => getMonthName(currentMonth.value)) const currentYear = computed(() => { return Number(params.year) }) // Get period from currentYear const currentPeriod = computed(() => getPeriodOfYear(currentYear.value).long) const currentPeriodAbbr = computed( () => getPeriodOfYear(currentYear.value).short ) const currentDateTitle = computed(() => { switch (currentConfig.value.viewType) { case 'month': return getFormattedDateTitle({ day: currentDate.currentDay.value, month: currentDate.currentMonth.value, year: currentDate.currentYear.value, period: currentDate.currentPeriod.value }) case 'year': return `Année ${currentYear.value} ${currentPeriodAbbr.value}` case 'decade': return `Années ${currentYear.value} ${getPeriodOfYear(currentYear.value).short} - ${currentYear.value + 10} ${getPeriodOfYear(currentYear.value + 10).short}` case 'century': return `Années ${currentYear.value} ${getPeriodOfYear(currentYear.value).short} - ${currentYear.value + 100} ${getPeriodOfYear(currentYear.value + 100).short}` default: return 'Date inconnue' } }) // Create base config const currentDate: CalendarCurrentDate = { currentDay, currentMonth, currentMonthName, currentYear, currentPeriod, currentPeriodAbbr, currentDateTitle } const currentLeimDate = computed(() => { return { day: currentDate.currentDay.value, month: currentDate.currentMonth.value, year: currentDate.currentYear.value, period: currentDate.currentPeriod.value } }) const selectedDate = useLocalStorage('selected-date', currentLeimDate.value, { deep: true }) /** * Check whether the current viewType is active */ const isCurrentScreenActive = computed(() => { switch (currentConfig.value.viewType) { case 'month': return ( defaultDate.value.month === currentDate.currentMonth.value && defaultDate.value.year === currentDate.currentYear.value ) case 'year': case 'decade': case 'century': return defaultDate.value.year === currentDate.currentYear.value default: return false } }) /** * Moves the current date forward one month */ function incrementMonth(): void { let newValue = Number(params.month) + 1 // If the new value would exceed the max number of month per year if (newValue >= staticConfig.monthsPerYear) { newValue = 0 // Increment the year incrementYear() } params.month = newValue.toString() } /** * Moves the current date backward one month */ function decrementMonth(): void { let newValue = Number(params.month) - 1 // If the new value would go below 0 if (newValue < 0) { newValue = staticConfig.monthsPerYear - 1 // Decrement the year decrementYear() } params.month = newValue.toString() } /** * Get the previous month number * * @param monthNumber Initial month * @returns The previous month number in the year */ function getPreviousMonth(monthNumber: number): number { const target: number = monthNumber - 1 if (target < 0) { return monthsPerYear - 1 } return target } /** * Get the following month number * * @param monthNumber Initial month * @returns The next month number in the year */ function getNextMonth(monthNumber: number): number { const target: number = monthNumber + 1 if (target + 1 >= monthsPerYear) { return 0 } return target } /** * Moves the current date to a particular month */ function setMonth(target: number): void { // If the target is outside the month bounds if (target < 0 || target >= staticConfig.monthsPerYear) { return } params.month = target.toString() } /** * Moves the current date forward one year */ function incrementYear(inc: number = 1): void { const newValue = Number(params.year) + inc params.year = newValue.toString() } /** * Moves the current date backward one year */ function decrementYear(inc: number = 1): void { const newValue = Number(params.year) - inc params.year = newValue.toString() } /** * From a given year, returns a set of LeimPeriod identifier * * This is used in range use-cases * * @param year The year to display * @returns An object containing both short and long LeimPeriod */ function getPeriodOfYear(year: string | number): { long: LeimPeriod; short: LeimPeriodShort } { const numYear = year as number return { long: numYear >= 0 ? 'nante' : 'ante', short: numYear >= 0 ? 'N.R' : 'A.R' } } /** * Get the formatted month name given its index * * @param monthNumber Index of the month * @returns Formatted month name */ function getMonthName(monthNumber: number): string { const index = Number(monthNumber) return staticConfig.months[index] } /** * Switches the active viewType * * @param viewType Target viewType */ function setViewType(viewType: CalendarViewType): void { currentConfig.value.viewType = viewType } /** * Gets the formatted viewType title * * @param viewType Target viewType * @returns Formatted mode title */ function getViewTypeTitle(viewType: CalendarViewType): string { switch (viewType) { case 'year': return 'Année' case 'decade': return 'Décennie' case 'century': return 'Siècle' case 'month': default: return 'Mois' } } /** * From a LeimDate, returns the legible date title * * @param date Date target * @param showNumber Should the date show the day number * @returns Formatted date name */ function getFormattedDateTitle(date: LeimDate, showNumber?: boolean): string { if (showNumber) { return `${date.day} ${getMonthName(date.month)} ${date.year} ${getPeriodOfYear(date.year).short}` } return `${getMonthName(date.month)} ${date.year} ${getPeriodOfYear(date.year).short}` } /** * Jumps the calendar to the given date * * @param date Target date */ function jumpToDate(date: LeimDate): void { params.day = date.day.toString() params.month = date.month.toString() params.year = date.year.toString() selectDate(date) } /** * Jump the calendar to the default date */ function jumpToDefaultDate(): void { jumpToDate(defaultDate.value) } /** * Jump the calendar to the default date */ function selectDate(date: LeimDate): void { selectedDate.value = date } const isAdvancedSearchOpen: Ref = ref(false) function revealAdvancedSearch() { isAdvancedSearchOpen.value = true } return { staticConfig, viewTypeOptions, currentConfig, currentDate, currentLeimDate, defaultDate, selectedDate: skipHydrate(selectedDate), selectDate, params, getPeriodOfYear, incrementMonth, decrementMonth, setMonth, getPreviousMonth, getNextMonth, incrementYear, decrementYear, jumpToDate, jumpToDefaultDate, getFormattedDateTitle, getMonthName, setViewType, getViewTypeTitle, isCurrentScreenActive, isAdvancedSearchOpen, revealAdvancedSearch } })