mirror of
https://github.com/whekin/household-bot.git
synced 2026-04-01 04:14:03 +00:00
fix(miniapp): clarify cycle summary and balance sections
This commit is contained in:
@@ -32,6 +32,48 @@ function formatCalendarDate(
|
||||
}).format(new Date(Date.UTC(year, month - 1, day)))
|
||||
}
|
||||
|
||||
function parsePeriod(period: string): { year: number; month: number } | null {
|
||||
const [yearValue, monthValue] = period.split('-')
|
||||
const year = Number.parseInt(yearValue ?? '', 10)
|
||||
const month = Number.parseInt(monthValue ?? '', 10)
|
||||
|
||||
if (!Number.isInteger(year) || !Number.isInteger(month) || month < 1 || month > 12) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
year,
|
||||
month
|
||||
}
|
||||
}
|
||||
|
||||
function daysInMonth(year: number, month: number): number {
|
||||
return new Date(Date.UTC(year, month, 0)).getUTCDate()
|
||||
}
|
||||
|
||||
function formatTodayParts(timezone: string): { year: number; month: number; day: number } | null {
|
||||
try {
|
||||
const parts = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: timezone,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
}).formatToParts(new Date())
|
||||
|
||||
const year = Number.parseInt(parts.find((part) => part.type === 'year')?.value ?? '', 10)
|
||||
const month = Number.parseInt(parts.find((part) => part.type === 'month')?.value ?? '', 10)
|
||||
const day = Number.parseInt(parts.find((part) => part.type === 'day')?.value ?? '', 10)
|
||||
|
||||
if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return { year, month, day }
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function formatFriendlyDate(value: string, locale: Locale): string {
|
||||
const calendarDateMatch = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value)
|
||||
if (calendarDateMatch) {
|
||||
@@ -61,19 +103,56 @@ export function formatFriendlyDate(value: string, locale: Locale): string {
|
||||
}
|
||||
|
||||
export function formatCyclePeriod(period: string, locale: Locale): string {
|
||||
const [yearValue, monthValue] = period.split('-')
|
||||
const year = Number.parseInt(yearValue ?? '', 10)
|
||||
const month = Number.parseInt(monthValue ?? '', 10)
|
||||
|
||||
if (!Number.isInteger(year) || !Number.isInteger(month) || month < 1 || month > 12) {
|
||||
const parsed = parsePeriod(period)
|
||||
if (!parsed) {
|
||||
return period
|
||||
}
|
||||
|
||||
const date = new Date(Date.UTC(year, month - 1, 1))
|
||||
const includeYear = year !== new Date().getUTCFullYear()
|
||||
const date = new Date(Date.UTC(parsed.year, parsed.month - 1, 1))
|
||||
const includeYear = parsed.year !== new Date().getUTCFullYear()
|
||||
|
||||
return new Intl.DateTimeFormat(localeTag(locale), {
|
||||
month: 'long',
|
||||
...(includeYear ? { year: 'numeric' } : {})
|
||||
}).format(date)
|
||||
}
|
||||
|
||||
export function formatPeriodDay(period: string, day: number, locale: Locale): string {
|
||||
const parsed = parsePeriod(period)
|
||||
if (!parsed) {
|
||||
return period
|
||||
}
|
||||
|
||||
const safeDay = Math.max(1, Math.min(day, daysInMonth(parsed.year, parsed.month)))
|
||||
|
||||
return (
|
||||
formatCalendarDate(parsed.year, parsed.month, safeDay, locale) ??
|
||||
`${formatCyclePeriod(period, locale)} ${safeDay}`
|
||||
)
|
||||
}
|
||||
|
||||
export function compareTodayToPeriodDay(
|
||||
period: string,
|
||||
day: number,
|
||||
timezone: string
|
||||
): -1 | 0 | 1 | null {
|
||||
const parsed = parsePeriod(period)
|
||||
const today = formatTodayParts(timezone)
|
||||
if (!parsed || !today) {
|
||||
return null
|
||||
}
|
||||
|
||||
const safeDay = Math.max(1, Math.min(day, daysInMonth(parsed.year, parsed.month)))
|
||||
const dueValue = Date.UTC(parsed.year, parsed.month - 1, safeDay)
|
||||
const todayValue = Date.UTC(today.year, today.month - 1, today.day)
|
||||
|
||||
if (todayValue < dueValue) {
|
||||
return -1
|
||||
}
|
||||
|
||||
if (todayValue > dueValue) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ const CURATED_TIMEZONES = [
|
||||
'Asia/Tbilisi',
|
||||
'Europe/Berlin',
|
||||
'Europe/London',
|
||||
'Europe/Moscow',
|
||||
'Europe/Paris',
|
||||
'Europe/Warsaw',
|
||||
'America/New_York',
|
||||
|
||||
Reference in New Issue
Block a user