refactor: high-cohesion low-coupling cleanup across store and components

ical-io.js:
- Import pad2/parseISODate from date.js (remove local duplicates)
- Rename ICAL.Time helpers to icalTimeTo* for clarity

useCalendar.js:
- Delegate addEvent to createEvent() factory
- Delegate splitEvent to splitRecurringEvent() pure function
- Use cloneEvent() instead of JSON.parse(JSON.stringify())
- Add selectEvent() action (components no longer mutate state.selectedUid directly)

Components:
- EventList: use selectEvent action + toDate() from date.js
- HeaderBar: destructure loadFile at top level (was re-calling useCalendar in handler)
- EventDetail: import DOW from weekday.js (was inlining the array)
- OccurrenceGrid: use toDate() from date.js
This commit is contained in:
timeTable2 dev
2026-07-13 20:06:00 +08:00
parent 02cfdda900
commit b352c4e116
6 changed files with 32 additions and 74 deletions

View File

@@ -1,4 +1,5 @@
import ICAL from 'ical.js'
import { pad2, parseISODate } from './date.js'
// ------------------------------------------------------------------ //
// Timezone registration (ical.js does not bundle IANA zones)
@@ -13,17 +14,14 @@ function registerTimezones(vcalendar) {
}
// ------------------------------------------------------------------ //
// Helpers
// ICAL.Time <-> plain string helpers
// (ICAL.Time exposes .year/.month/.day/.hour/.minute directly)
// ------------------------------------------------------------------ //
function pad2(n) {
return String(n).padStart(2, '0')
}
function timeToISODate(t) {
function icalTimeToISODate(t) {
return `${t.year}-${pad2(t.month)}-${pad2(t.day)}`
}
function timeToHHMM(t) {
function icalTimeToHHMM(t) {
return `${pad2(t.hour)}:${pad2(t.minute)}`
}
@@ -67,7 +65,7 @@ function parseEvent(veventComp) {
const exdates = []
for (const prop of veventComp.getAllProperties('exdate')) {
for (const t of prop.getValues()) {
exdates.push(timeToISODate(t))
exdates.push(icalTimeToISODate(t))
}
}
@@ -83,9 +81,9 @@ function parseEvent(veventComp) {
summary: veventComp.getFirstPropertyValue('summary') || '',
location: veventComp.getFirstPropertyValue('location') || '',
description: veventComp.getFirstPropertyValue('description') || '',
dtstartDate: timeToISODate(start),
dtstartTime: timeToHHMM(start),
dtendTime: timeToHHMM(end),
dtstartDate: icalTimeToISODate(start),
dtstartTime: icalTimeToHHMM(start),
dtendTime: icalTimeToHHMM(end),
tzid,
rrule,
exdates,
@@ -125,11 +123,6 @@ export function parseICS(text) {
// ------------------------------------------------------------------ //
// Helpers for serialization
// ------------------------------------------------------------------ //
function parseISODate(s) {
const [y, m, d] = s.split('-').map(Number)
return { year: y, month: m, day: d }
}
function parseHHMM(s) {
const [h, m] = s.split(':').map(Number)
return { hour: h, minute: m }