Files
leim-tools/stores/CalendarStore.ts
2024-05-13 14:41:28 +02:00

418 lines
9.7 KiB
TypeScript

import {
monthsPerYear,
daysPerWeek,
daysPerMonth,
daysPerYear,
type LeimDate,
type LeimPeriod,
type LeimPeriodShort
} from '@/models/Date'
import { useSessionStorage, useUrlSearchParams } from '@vueuse/core'
import { defineStore } 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<number>
currentMonth: ComputedRef<number>
currentMonthName: ComputedRef<string>
currentYear: ComputedRef<number>
currentPeriod: Ref<LeimPeriod>
currentPeriodAbbr: Ref<LeimPeriodShort>
currentDateTitle: ComputedRef<string>
}
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<CalendarCurrentConfig> = ref({
viewType: 'month'
})
const viewTypeOptions: Set<CalendarViewType> = new Set<CalendarViewType>([
'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<LeimDate> = 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<number>(() => {
return Number(params.day)
})
const currentMonth = computed<number>(() => {
return Number(params.month)
})
// Gets the label from currentMonth index
const currentMonthName = computed<string>(() => getMonthName(currentMonth.value))
const currentYear = computed<number>(() => {
return Number(params.year)
})
// Get period from currentYear
const currentPeriod = computed<LeimPeriod>(() => getPeriodOfYear(currentYear.value).long)
const currentPeriodAbbr = computed<LeimPeriodShort>(
() => getPeriodOfYear(currentYear.value).short
)
const currentDateTitle = computed<string>(() => {
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<LeimDate>(() => {
return {
day: currentDate.currentDay.value,
month: currentDate.currentMonth.value,
year: currentDate.currentYear.value,
period: currentDate.currentPeriod.value
}
})
const selectedDate = useSessionStorage<LeimDate>('selected-date', currentLeimDate.value, { deep: true })
/**
* Check whether the current viewType is active
*/
const isCurrentScreenActive = computed<boolean>(() => {
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<boolean> = ref<boolean>(false)
function revealAdvancedSearch() {
isAdvancedSearchOpen.value = true
}
return {
staticConfig,
viewTypeOptions,
currentConfig,
currentDate,
currentLeimDate,
defaultDate,
selectedDate,
selectDate,
params,
getPeriodOfYear,
incrementMonth,
decrementMonth,
setMonth,
getPreviousMonth,
getNextMonth,
incrementYear,
decrementYear,
jumpToDate,
jumpToDefaultDate,
getFormattedDateTitle,
getMonthName,
setViewType,
getViewTypeTitle,
isCurrentScreenActive,
isAdvancedSearchOpen,
revealAdvancedSearch
}
})