@asd20/ui 3.2.990 → 3.2.991

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package-lock.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui",
3
- "version": "3.2.989",
3
+ "version": "3.2.990",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
@@ -11665,6 +11665,11 @@
11665
11665
  "@babel/runtime": "^7.21.0"
11666
11666
  }
11667
11667
  },
11668
+ "date-fns-tz": {
11669
+ "version": "1.1.7",
11670
+ "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.1.7.tgz",
11671
+ "integrity": "sha512-xfL918kXO528DJ17Sao60H07rYv5L/X0Bp6zojDssuZAR/acYETDS9PaICKAnodcO9XVHL/0bpLRGKd7kNnvcQ=="
11672
+ },
11668
11673
  "dateformat": {
11669
11674
  "version": "3.0.3",
11670
11675
  "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "*.scss",
6
6
  "*.vue"
7
7
  ],
8
- "version": "3.2.990",
8
+ "version": "3.2.991",
9
9
  "private": false,
10
10
  "license": "MIT",
11
11
  "repository": {
@@ -31,6 +31,7 @@
31
31
  "basicscroll": "^3.0.2",
32
32
  "countup.js": "^2.0.0",
33
33
  "date-fns": "^2.30.0",
34
+ "date-fns-tz": "^1.1.7",
34
35
  "focus-trap": "^6.9.4",
35
36
  "focus-trap-vue": "^1.1.1",
36
37
  "js-cookie": "^2.2.1",
@@ -52,25 +52,19 @@ export default {
52
52
  }
53
53
  },
54
54
  startTime() {
55
- return format(
56
- parse(this.event.start, "yyyy-MM-dd'T'HH:mm:ssX", new Date()),
57
- 'h:mm aa'
58
- )
55
+ const d = this.toDateSafe(this.event.start)
56
+ if (!d) return ''
57
+ return format(d, 'h:mm aa')
59
58
  },
60
59
  start() {
61
- return format(
62
- parse(this.event.start, "yyyy-MM-dd'T'HH:mm:ssX", new Date()),
63
- 'h:mm aa, MMMM dd yyyy'
64
- )
60
+ const d = this.toDateSafe(this.event.start)
61
+ if (!d) return ''
62
+ return format(d, 'h:mm aa, MMMM dd yyyy')
65
63
  },
66
64
  end() {
67
- return (
68
- ' to ' +
69
- format(
70
- parse(this.event.end, "yyyy-MM-dd'T'HH:mm:ssX", new Date()),
71
- 'h:mm aa, MMMM dd yyyy'
72
- )
73
- )
65
+ const d = this.toDateSafe(this.event.end)
66
+ if (!d) return ''
67
+ return ' to ' + format(d, 'h:mm aa, MMMM dd yyyy')
74
68
  },
75
69
  sanitizedSummary() {
76
70
  return this.sanitizeSummary(this.event.summary)
@@ -104,8 +98,15 @@ export default {
104
98
  return summary.replace(pattern, 'vs. Multiple Schools')
105
99
  },
106
100
  formatDate(date, opts = { month: 'short', day: 'numeric' }) {
107
- if (!date) return ''
108
- return new Date(date).toLocaleDateString(undefined, opts)
101
+ const d = this.toDateSafe(date)
102
+ if (!d) return ''
103
+ return d.toLocaleDateString(undefined, opts)
104
+ },
105
+ toDateSafe(value) {
106
+ if (!value) return null;
107
+ if (value instanceof Date) return isNaN(value) ? null : value;
108
+ const d = new Date(value);
109
+ return isNaN(d) ? null : d;
109
110
  },
110
111
  },
111
112
  }
@@ -11,7 +11,11 @@
11
11
  :key="day.unix"
12
12
  :label="`${day.weekday}, ${day.month} ${day.shortDay}, ${day.year}`"
13
13
  />
14
- <asd20-list-item v-for="event in day.events" :key="event.uid" condensed>
14
+ <asd20-list-item
15
+ v-for="event in day.events"
16
+ :key="`${event.uid}-${new Date(event.start).getTime()}`"
17
+ condensed
18
+ >
15
19
  <asd20-calendar-event-button
16
20
  :event="event"
17
21
  large
@@ -1,39 +1,48 @@
1
1
  import { format, addDays, isSameDay } from 'date-fns'
2
+ import { utcToZonedTime } from 'date-fns-tz'
3
+
4
+ const MOUNTAIN_TZ = 'America/Denver'
5
+
6
+ // Convert to Mountain Time
7
+ function toMountain(dateLike) {
8
+ // Accepts string/Date; handles undefined/null gracefully
9
+ if (!dateLike) return null
10
+ return utcToZonedTime(new Date(dateLike), MOUNTAIN_TZ)
11
+ }
2
12
 
3
13
  export default function expandEvents(events, includePastEvents = false) {
14
+ // Today in Mountain Time, at midnight
15
+ const now = new Date()
16
+ const today = toMountain(now)
17
+ today.setHours(0, 0, 0, 0)
18
+
4
19
  return events
5
20
  .reduce((acc, event) => {
6
- // Use new Date() for ISO date strings
7
- const start = new Date(event.start)
8
- const end = event.end ? new Date(event.end) : start
9
-
10
- const today = new Date()
11
- today.setHours(0, 0, 0, 0)
21
+ // Always parse and convert to Mountain Time
22
+ const start = toMountain(event.start)
23
+ const end = event.end ? toMountain(event.end) : start
12
24
 
25
+ // Do all date math in Mountain Time
13
26
  const diffTime = end.getTime() - start.getTime()
14
27
  const diffHours = diffTime / (1000 * 60 * 60)
15
28
  let diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
16
-
17
29
  if (diffDays === 0) diffDays = 1
18
30
 
19
31
  const isAllDay = event.allDay || diffHours >= 23
20
32
 
21
- // Normalize for date-only comparisons
33
+ // Normalize for date-only comparisons (still in Mountain)
22
34
  const normalizedStart = new Date(start)
23
35
  normalizedStart.setHours(0, 0, 0, 0)
24
-
25
36
  const normalizedEnd = new Date(end)
26
37
  normalizedEnd.setHours(0, 0, 0, 0)
27
38
 
28
- const isMultiDay =
29
- diffDays > 1 || !isSameDay(normalizedStart, normalizedEnd)
39
+ const isMultiDay = diffDays > 1 || !isSameDay(normalizedStart, normalizedEnd)
30
40
 
31
41
  const expandedEvents = []
32
42
 
33
43
  if (isMultiDay) {
34
44
  for (let d = 0; d < diffDays; d++) {
35
45
  const currentDay = addDays(normalizedStart, d)
36
-
37
46
  if (includePastEvents || currentDay >= today) {
38
47
  expandedEvents.push({
39
48
  ...event,
@@ -54,7 +63,7 @@ export default function expandEvents(events, includePastEvents = false) {
54
63
  if (includePastEvents || normalizedStart >= today) {
55
64
  expandedEvents.push({
56
65
  ...event,
57
- start: start, // keep original start WITH time
66
+ start: start, // Mountain Time, with time for timed events
58
67
  end: end,
59
68
  originalStart: null,
60
69
  allDay: isAllDay,
@@ -1,7 +1,27 @@
1
- import { format, addDays, isSameDay, getDaysInMonth } from 'date-fns'
1
+ import { format, addDays, getDaysInMonth } from 'date-fns'
2
+ import { utcToZonedTime } from 'date-fns-tz'
3
+
4
+ const MOUNTAIN_TZ = 'America/Denver'
5
+
6
+ // Converts any date-like input to a Mountain Time Date object.
7
+ function toMountain(dateLike) {
8
+ if (!dateLike) return null
9
+ return utcToZonedTime(new Date(dateLike), MOUNTAIN_TZ)
10
+ }
11
+
12
+ // Checks if two dates are the same day in Mountain Time.
13
+ function isSameDayMT(dateLeft, dateRight) {
14
+ const d1 = toMountain(dateLeft)
15
+ const d2 = toMountain(dateRight)
16
+ return (
17
+ d1.getFullYear() === d2.getFullYear() &&
18
+ d1.getMonth() === d2.getMonth() &&
19
+ d1.getDate() === d2.getDate()
20
+ )
21
+ }
2
22
 
3
23
  /**
4
- * Given an array of events, returns an array of days with events grouped by date.
24
+ * Given an array of events, returns an array of days with events grouped by date (in Mountain Time).
5
25
  */
6
26
  export default function mapEventsToDays(
7
27
  events,
@@ -9,28 +29,30 @@ export default function mapEventsToDays(
9
29
  month = 0,
10
30
  showAll = false
11
31
  ) {
12
- const today = new Date()
32
+ const today = toMountain(new Date())
13
33
  today.setHours(0, 0, 0, 0)
14
34
 
15
35
  let days = []
16
36
 
17
37
  if (showAll) {
18
- // Collect unique event dates
38
+ // Collect unique event dates (in Mountain Time)
19
39
  const uniqueDatesMap = new Map()
20
40
 
21
41
  events.forEach(event => {
22
- const eventDate = new Date(event.start)
23
- const dateKey = format(eventDate, 'yyyy-MM-dd')
42
+ const eventDate = toMountain(event.start)
43
+ const dateKey = format(eventDate, 'yyyy-MM-dd', { timeZone: MOUNTAIN_TZ })
24
44
  if (!uniqueDatesMap.has(dateKey)) {
25
45
  uniqueDatesMap.set(dateKey, eventDate)
26
46
  }
27
47
  })
28
48
 
29
- days = Array.from(uniqueDatesMap.values()).map(date => createDayObject(date, events, false, today))
49
+ days = Array.from(uniqueDatesMap.values()).map(date =>
50
+ createDayObject(date, events, false, today)
51
+ )
30
52
  } else {
31
- // Month view: create a full calendar grid
32
- const firstDayOfMonth = new Date(year, month, 1)
33
- const lastDayOfMonth = new Date(year, month + 1, 0)
53
+ // Month view: create a full calendar grid in Mountain Time
54
+ const firstDayOfMonth = toMountain(new Date(year, month, 1))
55
+ const lastDayOfMonth = toMountain(new Date(year, month + 1, 0))
34
56
  const daysInMonth = getDaysInMonth(firstDayOfMonth)
35
57
 
36
58
  const prevMonthDays = firstDayOfMonth.getDay()
@@ -44,28 +66,30 @@ export default function mapEventsToDays(
44
66
  }
45
67
  }
46
68
 
47
- // Sort by unix timestamp (probably unnecessary unless something weird happens)
69
+ // Sort by unix timestamp
48
70
  return days.sort((a, b) => a.unix - b.unix)
49
71
  }
50
72
 
51
73
  /**
52
- * Builds a day object with events attached.
74
+ * Builds a day object (in Mountain Time) with events attached.
53
75
  */
54
76
  function createDayObject(date, events, outsideOfCurrentMonth = false, today) {
55
- const normalizedDate = new Date(date)
77
+ const normalizedDate = toMountain(date)
56
78
  normalizedDate.setHours(0, 0, 0, 0)
57
79
 
58
80
  return {
59
81
  outsideOfCurrentMonth,
60
82
  date: normalizedDate,
61
83
  unix: normalizedDate.getTime(),
62
- today: isSameDay(normalizedDate, today),
63
- events: events.filter(event => isSameDay(new Date(event.start), normalizedDate)),
64
- weekday: format(normalizedDate, 'EEEE'),
65
- day: format(normalizedDate, 'dd'),
66
- shortDay: format(normalizedDate, 'd'),
67
- number: format(normalizedDate, 'd'),
68
- month: format(normalizedDate, 'MMMM'),
69
- year: format(normalizedDate, 'yyyy'),
84
+ today: isSameDayMT(normalizedDate, today),
85
+ events: events.filter(event =>
86
+ isSameDayMT(event.start, normalizedDate)
87
+ ),
88
+ weekday: format(normalizedDate, 'EEEE', { timeZone: MOUNTAIN_TZ }),
89
+ day: format(normalizedDate, 'dd', { timeZone: MOUNTAIN_TZ }),
90
+ shortDay: format(normalizedDate, 'd', { timeZone: MOUNTAIN_TZ }),
91
+ number: format(normalizedDate, 'd', { timeZone: MOUNTAIN_TZ }),
92
+ month: format(normalizedDate, 'MMMM', { timeZone: MOUNTAIN_TZ }),
93
+ year: format(normalizedDate, 'yyyy', { timeZone: MOUNTAIN_TZ }),
70
94
  }
71
95
  }