Files
Starlight_Lancher/apps/app-frontend/src/components/home/home-utils.ts

113 lines
3.2 KiB
TypeScript

export type HomeTimeBucket = 'late-night' | 'dawn' | 'morning' | 'afternoon' | 'evening' | 'night'
export type PlaytimeView = 'month' | 'year'
export type HeatmapDay = {
date: Date
dateKey: string
inPeriod: boolean
}
export type MinecraftAccountLike = {
account_type?: string
profile?: {
id?: string
name?: string
}
}
export function getTimeBucket(date: Date): HomeTimeBucket {
const hour = date.getHours()
if (hour < 5) return 'late-night'
if (hour < 8) return 'dawn'
if (hour < 12) return 'morning'
if (hour < 17) return 'afternoon'
if (hour < 21) return 'evening'
return 'night'
}
export function stableGreetingIndex(seed: string, count: number): number {
if (count <= 0) return 0
let hash = 0
for (const character of seed) {
hash = (hash * 31 + character.charCodeAt(0)) | 0
}
return Math.abs(hash) % count
}
export function toDateKey(date: Date): string {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
export function dateFromKey(dateKey: string): Date {
const [year, month, day] = dateKey.split('-').map(Number)
return new Date(year, month - 1, day, 12)
}
export function startOfPeriod(anchor: Date, view: PlaytimeView): Date {
return view === 'month'
? new Date(anchor.getFullYear(), anchor.getMonth(), 1, 12)
: new Date(anchor.getFullYear(), 0, 1, 12)
}
export function endOfPeriod(anchor: Date, view: PlaytimeView): Date {
return view === 'month'
? new Date(anchor.getFullYear(), anchor.getMonth() + 1, 0, 12)
: new Date(anchor.getFullYear(), 11, 31, 12)
}
export function shiftPeriod(anchor: Date, view: PlaytimeView, amount: number): Date {
return view === 'month'
? new Date(anchor.getFullYear(), anchor.getMonth() + amount, 1, 12)
: new Date(anchor.getFullYear() + amount, 0, 1, 12)
}
export function buildHeatmapDays(anchor: Date, view: PlaytimeView): HeatmapDay[] {
const periodStart = startOfPeriod(anchor, view)
const periodEnd = endOfPeriod(anchor, view)
const periodStartKey = toDateKey(periodStart)
const periodEndKey = toDateKey(periodEnd)
const gridStart = new Date(periodStart)
gridStart.setDate(periodStart.getDate() - ((periodStart.getDay() + 6) % 7))
const gridEnd = new Date(periodEnd)
gridEnd.setDate(periodEnd.getDate() + ((7 - gridEnd.getDay()) % 7))
const days: HeatmapDay[] = []
const cursor = new Date(gridStart)
while (cursor <= gridEnd) {
const date = new Date(cursor)
const dateKey = toDateKey(date)
days.push({
date,
dateKey,
inPeriod: dateKey >= periodStartKey && dateKey <= periodEndKey,
})
cursor.setDate(cursor.getDate() + 1)
}
return days
}
export function getPlaytimeLevel(seconds: number): number {
if (seconds <= 0) return 0
if (seconds <= 30 * 60) return 1
if (seconds <= 90 * 60) return 2
if (seconds <= 180 * 60) return 3
return 4
}
export function getActivePlayerName(
selectedUser: string | null | undefined,
accounts: readonly MinecraftAccountLike[],
): string | null {
if (!selectedUser) return null
const account = accounts.find(
(candidate) =>
candidate.profile?.id === selectedUser &&
(candidate.account_type === 'microsoft' || candidate.account_type === 'yggdrasil'),
)
return account?.profile?.name ?? null
}