From edea7a003467d7227d4d5c1d572281755c6fe71f Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Sat, 21 Feb 2026 10:08:22 +0700 Subject: [PATCH] Fix live review navigation and in-UI highlight behavior --- frontend/app.vue | 120 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 28 deletions(-) diff --git a/frontend/app.vue b/frontend/app.vue index b67ca16..03039d6 100644 --- a/frontend/app.vue +++ b/frontend/app.vue @@ -1267,6 +1267,11 @@ const activeReviewDealId = computed(() => { if (!item || item.entity !== "deal" || !item.entityId) return ""; return item.entityId; }); +const activeReviewMessageId = computed(() => { + const item = activeChangeItem.value; + if (!item || item.entity !== "message" || !item.entityId) return ""; + return item.entityId; +}); const activeReviewContactDiff = computed(() => { const item = activeChangeItem.value; if (!item || item.entity !== "contact_note" || !item.entityId) return null; @@ -1310,6 +1315,7 @@ function normalizeChangeText(raw: string | null | undefined) { function describeChangeEntity(entity: string) { if (entity === "contact_note") return "Contact summary"; if (entity === "calendar_event") return "Calendar event"; + if (entity === "message") return "Message"; if (entity === "deal") return "Deal"; return entity || "Change"; } @@ -1680,6 +1686,10 @@ function isReviewHighlightedDeal(dealId: string) { return Boolean(reviewActive.value && activeReviewDealId.value && activeReviewDealId.value === dealId); } +function isReviewHighlightedMessage(messageId: string) { + return Boolean(reviewActive.value && activeReviewMessageId.value && activeReviewMessageId.value === messageId); +} + function applyReviewStepToUi(push = false) { const item = activeChangeItem.value; if (!item) { @@ -1729,6 +1739,18 @@ function applyReviewStepToUi(push = false) { return; } + if (item.entity === "message" && item.entityId) { + peopleLeftMode.value = "contacts"; + peopleListMode.value = "contacts"; + const message = commItems.value.find((entry) => entry.id === item.entityId); + if (message?.contact) { + openCommunicationThread(message.contact); + } + focusedCalendarEventId.value = ""; + syncPathFromUi(push); + return; + } + peopleLeftMode.value = "contacts"; focusedCalendarEventId.value = ""; syncPathFromUi(push); @@ -1825,6 +1847,11 @@ const calendarCursor = ref(new Date(new Date().getFullYear(), new Date().getMont const selectedDateKey = ref(dayKey(new Date())); const sortedEvents = computed(() => [...calendarEvents.value].sort((a, b) => a.start.localeCompare(b.start))); +const focusedCalendarEvent = computed(() => { + const id = focusedCalendarEventId.value.trim(); + if (!id) return null; + return sortedEvents.value.find((event) => event.id === id) ?? null; +}); const eventsByDate = computed(() => { const map = new Map(); @@ -1876,6 +1903,21 @@ const monthCells = computed(() => { }); }); +function monthCellHasFocusedEvent(events: CalendarEvent[]) { + const id = focusedCalendarEventId.value.trim(); + if (!id) return false; + return events.some((event) => event.id === id); +} + +function monthCellEvents(events: CalendarEvent[]) { + const id = focusedCalendarEventId.value.trim(); + if (!id) return events.slice(0, 2); + const focused = events.find((event) => event.id === id); + if (!focused) return events.slice(0, 2); + const rest = events.filter((event) => event.id !== id).slice(0, 1); + return [focused, ...rest]; +} + const weekDays = computed(() => { const base = new Date(`${selectedDateKey.value}T00:00:00`); const mondayOffset = (base.getDay() + 6) % 7; @@ -2623,6 +2665,8 @@ async function togglePinForEntry(entry: any) { } const selectedWorkspaceContact = computed(() => { + if (selectedContact.value) return selectedContact.value; + const threadContactId = (selectedCommThread.value?.id ?? "").trim(); if (threadContactId) { const byId = contacts.value.find((contact) => contact.id === threadContactId); @@ -2634,8 +2678,6 @@ const selectedWorkspaceContact = computed(() => { const byName = contacts.value.find((contact) => contact.name === threadContactName); if (byName) return byName; } - - if (selectedContact.value) return selectedContact.value; return contacts.value[0] ?? null; }); @@ -3500,8 +3542,8 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected") class="min-h-0 flex-1" :class="selectedTab === 'communications' && peopleLeftMode === 'contacts' ? 'px-0 pt-0 pb-0' : 'px-3 pt-3 pb-0 md:px-4 md:pt-4 md:pb-0'" > -
-
+
+
@@ -3522,11 +3564,23 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected") {{ option.label }} -
-
+
+ -
-
+
+

Review focus event

+

{{ focusedCalendarEvent.title }}

+

+ {{ formatDay(focusedCalendarEvent.start) }} · {{ formatTime(focusedCalendarEvent.start) }} - {{ formatTime(focusedCalendarEvent.end) }} +

+

{{ focusedCalendarEvent.note || "No note" }}

+
+ +
+
Sun Mon @@ -3542,18 +3596,19 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected") v-for="cell in monthCells" :key="cell.key" class="min-h-24 rounded-lg border p-1 text-left" - :class="[ - cell.inMonth ? 'border-base-300 bg-base-100' : 'border-base-200 bg-base-200/40 text-base-content/40', - selectedDateKey === cell.key ? 'border-primary bg-primary/5' : '', - ]" - @click="pickDate(cell.key)" - > -

{{ cell.day }}

-
-
+

{{ formatDay(entry.item.at) }} · {{ formatTime(entry.item.at) }} · {{ entry.item.duration }} @@ -4249,13 +4307,19 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")

-
-
-

{{ entry.item.text }}

+
+
+

{{ entry.item.text }}