feat(frontend): add calendar click to switch conversation by date

- Add selected date state and conversation mapping in useSidebarPlan
- Connect calendar cells to conversation switching logic
- Add conversation indicator dot on dates with sessions
- Only clickable dates show hand cursor (today + dates with conversations)
- Add .selected styling for non-today dates, today keeps blue
- Fix hover effect to only apply to non-today dates
- Add daily doc for session date mapping feature

BREAKING: Calendar click now switches sessions by date
This commit is contained in:
2026-04-07 10:28:31 +08:00
parent 3bff9b3b93
commit 721ddbeef9
5 changed files with 198 additions and 45 deletions

View File

@@ -1,6 +1,7 @@
import { computed, onMounted, ref, watch } from 'vue'
import { computed, onMounted, ref, watch, toRef } from 'vue'
import { CornerDownLeft, Database, Sparkles, Sun, ListTodo } from 'lucide-vue-next'
import { scheduleCenterApi, type ScheduleCenterDateResponse, type ScheduleCenterDaySummary } from '@/api/scheduleCenter'
import type { Conversation } from '@/api/conversation'
export interface SidebarFocusItem {
id: string; label: string; title: string; meta: string; tone: 'done' | 'doing' | 'pending'
@@ -30,9 +31,20 @@ function formatMonthKey(date: Date) {
return `${year}-${month}`
}
export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn: () => void) {
export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn: () => void, conversationsRef: Conversation[] = []) {
const todayPlanDetail = ref<ScheduleCenterDateResponse | null>(null)
const monthPlanDays = ref<ScheduleCenterDaySummary[]>([])
const selectedDate = ref<string | null>(null)
// Build a map of date -> has conversation
const conversationDateMap = computed(() => {
const map = new Map<string, boolean>()
conversationsRef.forEach((conv) => {
const dateKey = formatDateKey(new Date(conv.updated_at))
map.set(dateKey, true)
})
return map
})
const todayDateKey = computed(() => formatDateKey(clientTimeRef.value))
const monthPlanSummaryMap = computed(() => new Map(monthPlanDays.value.map((item) => [item.date, item])))
@@ -42,19 +54,20 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn
const month = clientTimeRef.value.getMonth()
const daysInMonth = new Date(year, month + 1, 0).getDate()
const firstDayOffset = (new Date(year, month, 1).getDay() + 6) % 7
const cells: Array<{ key: string; value: number | null; active: boolean; busy: 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) {
cells.push({ key: `blank-start-${index}`, value: null, active: false, busy: 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) {
const monthDate = new Date(year, month, day)
const dateKey = formatDateKey(monthDate)
const summary = monthPlanSummaryMap.value.get(dateKey)
const busy = Boolean(summary && (summary.todo_total + summary.task_due_total + summary.goal_total + summary.reminder_total) > 0)
cells.push({ key: dateKey, value: day, active: day === clientTimeRef.value.getDate(), busy })
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 })
}
while (cells.length % 7 !== 0) {
cells.push({ key: `blank-end-${cells.length}`, value: null, active: false, busy: false })
cells.push({ key: `blank-end-${cells.length}`, value: null, active: false, busy: false, selected: false, hasConversation: false })
}
return cells
})
@@ -201,6 +214,10 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn
void loadSidebarPlanSnapshot(clientTimeRef.value)
})
function selectCalendarDate(dateKey: string) {
selectedDate.value = dateKey
}
onMounted(() => {
void loadDailyDigestFn()
void loadSidebarPlanSnapshot(new Date())
@@ -211,6 +228,7 @@ export function useSidebarPlan(clientTimeRef: { value: Date }, loadDailyDigestFn
calendarCells, calendarYear, calendarMonth, todayPlanCounters, monthReviewStats,
sidebarWeekLabels, sidebarStatusHeadline, sidebarStatusBreakdown,
sidebarFocusItems, sidebarReviewAchievements, sidebarReviewReflections,
sidebarFeedItems, topbarFeedItems, loadSidebarPlanSnapshot, sidebarCollapsedModules
sidebarFeedItems, topbarFeedItems, loadSidebarPlanSnapshot, sidebarCollapsedModules,
selectedDate, selectCalendarDate, conversationDateMap
}
}