Skip to content

Commit 6b14ad7

Browse files
fix(desktop): add now note timeline card
Show a Create new note card next to the top timeline now indicator and wire it to create a normal note.
1 parent 0b47daf commit 6b14ad7

2 files changed

Lines changed: 139 additions & 55 deletions

File tree

apps/desktop/src/main/top-meeting-timeline.test.tsx

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
99

1010
const mocks = vi.hoisted(() => ({
11-
createNewMeeting: vi.fn(),
11+
createNewNote: vi.fn(),
1212
liveSessionId: null as string | null,
1313
openNew: vi.fn(),
1414
startDragging: vi.fn().mockResolvedValue(undefined),
@@ -60,7 +60,7 @@ vi.mock("~/shared/hooks/useNativeContextMenu", () => ({
6060
}));
6161

6262
vi.mock("~/shared/useNewNote", () => ({
63-
useNewNoteAndListen: () => mocks.createNewMeeting,
63+
useNewNote: () => mocks.createNewNote,
6464
}));
6565

6666
vi.mock("~/store/tinybase/hooks", () => ({
@@ -150,7 +150,7 @@ import {
150150

151151
describe("TopMeetingTimeline", () => {
152152
beforeEach(() => {
153-
mocks.createNewMeeting.mockClear();
153+
mocks.createNewNote.mockClear();
154154
mocks.openNew.mockClear();
155155
mocks.startDragging.mockClear();
156156
mocks.stopListening.mockClear();
@@ -170,7 +170,7 @@ describe("TopMeetingTimeline", () => {
170170
render(<TopMeetingTimeline currentTab={null} />);
171171

172172
const createButton = screen.getByRole("button", {
173-
name: /Create new meeting/,
173+
name: /Create new note/,
174174
});
175175

176176
fireEvent.pointerDown(createButton, {
@@ -182,14 +182,14 @@ describe("TopMeetingTimeline", () => {
182182
fireEvent.click(createButton);
183183

184184
expect(mocks.startDragging).not.toHaveBeenCalled();
185-
expect(mocks.createNewMeeting).toHaveBeenCalledTimes(1);
185+
expect(mocks.createNewNote).toHaveBeenCalledTimes(1);
186186
});
187187

188188
it("starts window drag and ignores the release click after dragging", () => {
189189
render(<TopMeetingTimeline currentTab={null} />);
190190

191191
const createButton = screen.getByRole("button", {
192-
name: /Create new meeting/,
192+
name: /Create new note/,
193193
});
194194

195195
fireEvent.pointerDown(createButton, {
@@ -206,7 +206,7 @@ describe("TopMeetingTimeline", () => {
206206
fireEvent.click(createButton);
207207

208208
expect(mocks.startDragging).toHaveBeenCalledTimes(1);
209-
expect(mocks.createNewMeeting).not.toHaveBeenCalled();
209+
expect(mocks.createNewNote).not.toHaveBeenCalled();
210210
});
211211

212212
it("shows timeline item titles above start time metadata", () => {
@@ -224,10 +224,11 @@ describe("TopMeetingTimeline", () => {
224224
render(<TopMeetingTimeline currentTab={null} />);
225225

226226
const title = screen.getByText("Design Review");
227-
const startMetadata = screen.getByText(startLabel);
228-
const buttonText = title.closest("button")?.textContent ?? "";
227+
const cardButton = title.closest("button");
228+
const startMetadata = within(cardButton!).getByText(startLabel);
229+
const buttonText = cardButton?.textContent ?? "";
229230

230-
expect(title.closest("button")).toBe(startMetadata.closest("button"));
231+
expect(cardButton).toBe(startMetadata.closest("button"));
231232
expect(buttonText.indexOf("Design Review")).toBeLessThan(
232233
buttonText.indexOf(startLabel),
233234
);
@@ -369,7 +370,7 @@ describe("TopMeetingTimeline", () => {
369370
expect(indicatorX).toBe(cardWidth / 2);
370371
});
371372

372-
it("places the current time marker between open-ended notes and future meetings", () => {
373+
it("places the create note card next to the latest note instead of a future event", () => {
373374
const now = new Date("2026-05-29T15:41:00.000Z");
374375
vi.useFakeTimers();
375376
vi.setSystemTime(now);
@@ -393,12 +394,32 @@ describe("TopMeetingTimeline", () => {
393394

394395
render(<TopMeetingTimeline currentTab={null} />);
395396

396-
expect(screen.getByTestId("top-timeline-now-indicator").style.left).toBe(
397-
"162px",
397+
const createButton = screen.getByRole("button", {
398+
name: /Create new note/,
399+
});
400+
const createCard = createButton.closest(
401+
"[data-timeline-start-ms]",
402+
) as HTMLDivElement | null;
403+
const cardWidth = Number.parseFloat(createCard?.style.width ?? "");
404+
const carousel = createCard?.parentElement as HTMLDivElement | null;
405+
const timelineCards = Array.from(
406+
document.querySelectorAll<HTMLElement>("[data-timeline-start-ms]"),
398407
);
408+
const indicatorX = Number.parseFloat(
409+
screen.getByTestId("top-timeline-now-indicator").style.left,
410+
);
411+
412+
expect(timelineCards[0]?.textContent).toContain("Untitled");
413+
expect(timelineCards[1]?.textContent).toContain("Create new note");
414+
expect(timelineCards[2]?.textContent).toContain("Design sync");
415+
expect(createCard?.textContent).not.toContain("Today");
416+
expect(createCard?.textContent).not.toContain("3:41 PM");
417+
expect(cardWidth).toBe(160);
418+
expect(carousel?.style.width).toBe("512px");
419+
expect(indicatorX).toBe(164);
399420
});
400421

401-
it("hides the current time marker during active ad-hoc meetings", () => {
422+
it("keeps create note visible next to active ad-hoc meetings", () => {
402423
const now = new Date("2026-05-29T15:41:00.000Z");
403424
vi.useFakeTimers();
404425
vi.setSystemTime(now);
@@ -415,6 +436,15 @@ describe("TopMeetingTimeline", () => {
415436

416437
render(<TopMeetingTimeline currentTab={null} />);
417438

439+
const timelineCards = Array.from(
440+
document.querySelectorAll<HTMLElement>("[data-timeline-start-ms]"),
441+
);
442+
443+
expect(timelineCards[0]?.textContent).toContain("Live Ad-hoc");
444+
expect(timelineCards[1]?.textContent).toContain("Create new note");
445+
expect(
446+
screen.getByRole("button", { name: /Create new note/ }),
447+
).toBeTruthy();
418448
expect(screen.queryByTestId("top-timeline-now-indicator")).toBeNull();
419449
});
420450

@@ -460,11 +490,11 @@ describe("TopMeetingTimeline", () => {
460490
configurable: true,
461491
value: 100,
462492
});
463-
scrollContainer!.scrollLeft = 250;
493+
scrollContainer!.scrollLeft = 380;
464494
fireEvent.scroll(scrollContainer!);
465495

466496
fireEvent.click(screen.getByRole("button", { name: "Now" }));
467497

468-
expect(scrollContainer!.scrollLeft).toBe(112);
498+
expect(scrollContainer!.scrollLeft).toBe(114);
469499
});
470500
});

0 commit comments

Comments
 (0)