refactor: split handlers.go into 5 files, redesign export month picker, pad calendar rows, improve comments

- Split 1571-line handlers.go into: handlers.go (core), clock.go, settings.go, calendar.go, report.go
- Redesigned export month picker: year navigation + 12-month grid instead of prev/next month
- Fixed calendar last row: pad remaining cells with empty buttons to ensure 7 columns
- Added Go doc comments across all files (dateutil.go, totals.go, store.go, main.go, webhook.go)
This commit is contained in:
2026-06-24 11:33:17 +03:30
parent d8599657f4
commit a8b849f8fd
11 changed files with 1366 additions and 1176 deletions

View File

@@ -1,3 +1,5 @@
// Package bot implements the Telegram bot logic: message routing, calendar rendering,
// time tracking (multi-calendar), Excel export, and inline editing of events.
package bot
import (
@@ -63,8 +65,10 @@ func monthLenHijri(year, month int) int {
}
// JDN for March 21, 622 CE (Jalali epoch: 1 Farvardin 1)
// jalaliEpochJDN is the Julian Day Number for 1 Farvardin 1 (March 21, 622 CE).
const jalaliEpochJDN = 1948320
// gregorianToJDN converts a Gregorian date to a Julian Day Number.
func gregorianToJDN(gy, gm, gd int) int {
a := (14 - gm) / 12
y := gy + 4800 - a
@@ -72,6 +76,7 @@ func gregorianToJDN(gy, gm, gd int) int {
return gd + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045
}
// jdnToGregorian converts a Julian Day Number to a Gregorian date (year, month, day).
func jdnToGregorian(jdn int) (int, int, int) {
f := jdn + 1401 + ((4*jdn+274277)/146097)*3/4 - 38
e := 4*f + 3
@@ -83,6 +88,7 @@ func jdnToGregorian(jdn int) (int, int, int) {
return year, month, day
}
// gregorianToJalali converts a Gregorian date to Jalali (Persian/Solar Hijri).
func gregorianToJalali(gy, gm, gd int) (int, int, int) {
jdn := gregorianToJDN(gy, gm, gd)
days := jdn - jalaliEpochJDN
@@ -116,6 +122,7 @@ func gregorianToJalali(gy, gm, gd int) (int, int, int) {
return jy, jm, jd
}
// jalaliToGregorian converts a Jalali (Persian/Solar Hijri) date to Gregorian.
func jalaliToGregorian(jy, jm, jd int) (int, int, int) {
days := 0
for y := 1; y < jy; y++ {
@@ -133,6 +140,7 @@ func jalaliToGregorian(jy, jm, jd int) (int, int, int) {
return jdnToGregorian(jdn)
}
// hijriToGregorian converts a Hijri (Islamic) date to Gregorian.
func hijriToGregorian(hy, hm, hd int) (int, int, int) {
days := (hy-1)*354 + (hy-1)*11/30
for m := 1; m < hm; m++ {
@@ -152,6 +160,7 @@ func hijriToGregorian(hy, hm, hd int) (int, int, int) {
return year, month, day
}
// gregorianToHijri converts a Gregorian date to Hijri (Islamic).
func gregorianToHijri(gy, gm, gd int) (int, int, int) {
jdn := gregorianToJDN(gy, gm, gd)
days := jdn - 1948440
@@ -191,17 +200,20 @@ func dayOfWeekGregorian(gy, gm, gd int) int {
return (gd + (13*(gm+1))/5 + gy + gy/4 - gy/100 + gy/400) % 7
}
// calDay represents a single day cell in a calendar month view.
type calDay struct {
dayNum int
date string // YYYY-MM-DD gregorian key
}
// calMonth represents a rendered calendar month with title, weekday headers, and day cells.
type calMonth struct {
title string
weekDays []string
days []calDay
}
// buildCalendarMonth builds a calMonth struct for the given calendar type, year and month.
func buildCalendarMonth(cal string, year, month int) calMonth {
var title string
var weekDays []string
@@ -273,12 +285,14 @@ func buildCalendarMonth(cal string, year, month int) calMonth {
return calMonth{title: title, weekDays: weekDays, days: days}
}
// parseGregorianDateKey parses a "YYYY-MM-DD" string into year, month, day integers.
func parseGregorianDateKey(key string) (int, int, int) {
var y, m, d int
fmt.Sscanf(key, "%04d-%02d-%02d", &y, &m, &d)
return y, m, d
}
// formatDateForCalendar converts a Gregorian YYYY-MM-DD date string into the target calendar representation.
func formatDateForCalendar(date, calType string) string {
y, m, d := parseGregorianDateKey(date)
switch calType {