fix(frontend): calendar session navigation - enable today click always, show indicator only for dates with sessions, use UTC for consistent date matching
This commit is contained in:
@@ -19,15 +19,15 @@ export const sidebarCollapsedModules = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
function formatDateKey(date: Date) {
|
function formatDateKey(date: Date) {
|
||||||
const year = date.getFullYear()
|
const year = date.getUTCFullYear()
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
const month = String(date.getUTCMonth() + 1).padStart(2, '0')
|
||||||
const day = String(date.getDate()).padStart(2, '0')
|
const day = String(date.getUTCDate()).padStart(2, '0')
|
||||||
return `${year}-${month}-${day}`
|
return `${year}-${month}-${day}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMonthKey(date: Date) {
|
function formatMonthKey(date: Date) {
|
||||||
const year = date.getFullYear()
|
const year = date.getUTCFullYear()
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
const month = String(date.getUTCMonth() + 1).padStart(2, '0')
|
||||||
return `${year}-${month}`
|
return `${year}-${month}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +39,10 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn
|
|||||||
// Build a map of date -> has conversation
|
// Build a map of date -> has conversation
|
||||||
const conversationDateMap = computed(() => {
|
const conversationDateMap = computed(() => {
|
||||||
const map = new Map<string, boolean>()
|
const map = new Map<string, boolean>()
|
||||||
conversationsRef.forEach((conv) => {
|
const conversations = Array.isArray(conversationsRef) ? conversationsRef : (conversationsRef.value ?? [])
|
||||||
const dateKey = formatDateKey(new Date(conv.updated_at))
|
conversations.forEach((conv) => {
|
||||||
|
const date = new Date(conv.updated_at)
|
||||||
|
const dateKey = formatDateKey(date)
|
||||||
map.set(dateKey, true)
|
map.set(dateKey, true)
|
||||||
})
|
})
|
||||||
return map
|
return map
|
||||||
@@ -50,21 +52,22 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn
|
|||||||
const monthPlanSummaryMap = computed(() => new Map(monthPlanDays.value.map((item) => [item.date, item])))
|
const monthPlanSummaryMap = computed(() => new Map(monthPlanDays.value.map((item) => [item.date, item])))
|
||||||
|
|
||||||
const calendarCells = computed(() => {
|
const calendarCells = computed(() => {
|
||||||
const year = clientTimeRef.value.getFullYear()
|
const year = clientTimeRef.value.getUTCFullYear()
|
||||||
const month = clientTimeRef.value.getMonth()
|
const month = clientTimeRef.value.getUTCMonth()
|
||||||
const daysInMonth = new Date(year, month + 1, 0).getDate()
|
const daysInMonth = new Date(Date.UTC(year, month + 1, 0)).getUTCDate()
|
||||||
const firstDayOffset = (new Date(year, month, 1).getDay() + 6) % 7
|
const firstDayOffset = (new Date(Date.UTC(year, month, 1)).getUTCDay() + 6) % 7
|
||||||
|
const today = clientTimeRef.value.getUTCDate()
|
||||||
const cells: Array<{ key: string; value: number | null; active: boolean; busy: boolean; selected: boolean; hasConversation: boolean }> = []
|
const cells: Array<{ key: string; value: number | null; active: boolean; busy: boolean; selected: boolean; hasConversation: boolean }> = []
|
||||||
for (let index = 0; index < firstDayOffset; index += 1) {
|
for (let index = 0; index < firstDayOffset; index += 1) {
|
||||||
cells.push({ key: `blank-start-${index}`, value: null, active: false, busy: false, selected: false, hasConversation: false })
|
cells.push({ key: `blank-start-${index}`, value: null, active: false, busy: false, selected: false, hasConversation: false })
|
||||||
}
|
}
|
||||||
for (let day = 1; day <= daysInMonth; day += 1) {
|
for (let day = 1; day <= daysInMonth; day += 1) {
|
||||||
const monthDate = new Date(year, month, day)
|
const monthDate = new Date(Date.UTC(year, month, day))
|
||||||
const dateKey = formatDateKey(monthDate)
|
const dateKey = formatDateKey(monthDate)
|
||||||
const summary = monthPlanSummaryMap.value.get(dateKey)
|
const summary = monthPlanSummaryMap.value.get(dateKey)
|
||||||
const busy = Boolean(summary && (summary.todo_total + summary.task_due_total + summary.goal_total + summary.reminder_total) > 0)
|
const busy = Boolean(summary && (summary.todo_total + summary.task_due_total + summary.goal_total + summary.reminder_total) > 0)
|
||||||
const hasConv = conversationDateMap.value.get(dateKey) || false
|
const hasConv = conversationDateMap.value.get(dateKey) || false
|
||||||
cells.push({ key: dateKey, value: day, active: day === clientTimeRef.value.getDate(), busy, selected: dateKey === selectedDate.value, hasConversation: hasConv })
|
cells.push({ key: dateKey, value: day, active: day === today, busy, selected: dateKey === selectedDate.value, hasConversation: hasConv })
|
||||||
}
|
}
|
||||||
while (cells.length % 7 !== 0) {
|
while (cells.length % 7 !== 0) {
|
||||||
cells.push({ key: `blank-end-${cells.length}`, value: null, active: false, busy: false, selected: false, hasConversation: false })
|
cells.push({ key: `blank-end-${cells.length}`, value: null, active: false, busy: false, selected: false, hasConversation: false })
|
||||||
@@ -72,8 +75,8 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn
|
|||||||
return cells
|
return cells
|
||||||
})
|
})
|
||||||
|
|
||||||
const calendarYear = computed(() => clientTimeRef.value.getFullYear())
|
const calendarYear = computed(() => clientTimeRef.value.getUTCFullYear())
|
||||||
const calendarMonth = computed(() => clientTimeRef.value.getMonth() + 1)
|
const calendarMonth = computed(() => clientTimeRef.value.getUTCMonth() + 1)
|
||||||
|
|
||||||
const todayPlanCounters = computed(() => {
|
const todayPlanCounters = computed(() => {
|
||||||
const detail = todayPlanDetail.value
|
const detail = todayPlanDetail.value
|
||||||
|
|||||||
@@ -121,12 +121,14 @@ function handleCalendarDateSelect(dateKey: string) {
|
|||||||
// Reload conversations to get latest data
|
// Reload conversations to get latest data
|
||||||
loadConversations().then(() => {
|
loadConversations().then(() => {
|
||||||
// Find conversation that matches the selected date (by updated_at)
|
// Find conversation that matches the selected date (by updated_at)
|
||||||
const targetDate = new Date(dateKey)
|
// Use UTC to avoid timezone issues
|
||||||
const targetDateStart = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate())
|
const [year, month, day] = dateKey.split('-').map(Number)
|
||||||
const targetDateEnd = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate() + 1)
|
const targetDateStart = new Date(Date.UTC(year, month - 1, day))
|
||||||
|
const targetDateEnd = new Date(Date.UTC(year, month - 1, day + 1))
|
||||||
|
|
||||||
// Find conversation that falls on the selected date
|
// Find conversation that falls on the selected date
|
||||||
const conversation = store.conversations.find((conv) => {
|
const conversations = store.conversations.value ?? store.conversations
|
||||||
|
const conversation = conversations.find((conv) => {
|
||||||
const convDate = new Date(conv.updated_at)
|
const convDate = new Date(conv.updated_at)
|
||||||
return convDate >= targetDateStart && convDate < targetDateEnd
|
return convDate >= targetDateStart && convDate < targetDateEnd
|
||||||
})
|
})
|
||||||
@@ -300,8 +302,8 @@ function renderMarkdown(content: string) {
|
|||||||
v-for="cell in calendarCells"
|
v-for="cell in calendarCells"
|
||||||
:key="cell.key"
|
:key="cell.key"
|
||||||
class="calendar-day"
|
class="calendar-day"
|
||||||
:class="{ active: cell.active, busy: cell.busy, muted: cell.value === null, selected: cell.selected, clickable: cell.hasConversation || cell.active }"
|
:class="{ active: cell.active, busy: cell.busy, muted: cell.value === null, selected: cell.selected, clickable: cell.active || cell.hasConversation }"
|
||||||
@click="(cell.hasConversation || cell.active) && handleCalendarDateSelect(cell.key)"
|
@click="(cell.active || cell.hasConversation) && handleCalendarDateSelect(cell.key)"
|
||||||
>
|
>
|
||||||
{{ cell.value ?? '' }}
|
{{ cell.value ?? '' }}
|
||||||
<span v-if="cell.hasConversation" class="conv-indicator"></span>
|
<span v-if="cell.hasConversation" class="conv-indicator"></span>
|
||||||
|
|||||||
Reference in New Issue
Block a user