Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ceca99b
feat: add multi-step download app dropdown with platform-specific opt…
devin-ai-integration[bot] Jan 24, 2026
3bdd700
fix: use valid icon names (globe, monitor) instead of invalid ones
devin-ai-integration[bot] Jan 24, 2026
b4232c5
test: add mocks for new dropdown submenu components and useUserAgentD…
devin-ai-integration[bot] Jan 24, 2026
45a2b74
refactor: migrate download app submenu to coss.com/ui Menu components
devin-ai-integration[bot] Jan 26, 2026
fe18191
Merge branch 'main' into devin/1769278561-download-app-multi-step-dro…
PeerRich Jan 26, 2026
36bfadb
fix: revert to Radix-based dropdown submenu components to fix 500 error
devin-ai-integration[bot] Jan 26, 2026
fc4ad12
Merge branch 'devin/1769278561-download-app-multi-step-dropdown' of h…
devin-ai-integration[bot] Jan 26, 2026
de7aaf7
feat: use custom SVG icons for download app dropdown options
devin-ai-integration[bot] Jan 26, 2026
1d4b027
refactor: migrate UserDropdown to coss-ui Menu components
devin-ai-integration[bot] Jan 26, 2026
f24d0a5
refactor: improve menu component
pasqualevitiello Jan 26, 2026
956abb7
fix: convert Apple icon to inline SVG for dark/light mode support
devin-ai-integration[bot] Jan 26, 2026
08836d1
Merge branch 'devin/1769278561-download-app-multi-step-dropdown' of h…
pasqualevitiello Jan 26, 2026
34aeee4
chore: remove unnneeded class
pasqualevitiello Jan 26, 2026
c2a8824
refactor: convert all download icons to inline SVG components
devin-ai-integration[bot] Jan 26, 2026
64b8de6
Merge remote-tracking branch 'origin/devin/1769278561-download-app-mu…
devin-ai-integration[bot] Jan 26, 2026
b82b00e
refactor: remove classes from MenuItem and use size-4 for SVG icons
devin-ai-integration[bot] Jan 26, 2026
9114611
mc
pasqualevitiello Jan 26, 2026
cdf1a2f
refactor: hide iOS/Android download links on desktop devices
devin-ai-integration[bot] Jan 26, 2026
5144c63
Merge branch 'devin/1769278561-download-app-multi-step-dropdown' of h…
devin-ai-integration[bot] Jan 26, 2026
4050eff
refactor: show platform-specific download links only (iOS for iOS, An…
devin-ai-integration[bot] Jan 26, 2026
ba973b2
chore: keep the download menu item visible on smaller screens
pasqualevitiello Jan 26, 2026
77168f1
refactor: show iOS/Android on desktop, platform-specific on mobile
devin-ai-integration[bot] Jan 26, 2026
5f0c3f5
Merge branch 'devin/1769278561-download-app-multi-step-dropdown' of h…
devin-ai-integration[bot] Jan 26, 2026
ab4428a
refactor: simplify download menu - direct link on mobile, submenu on …
devin-ai-integration[bot] Jan 26, 2026
76f68ac
mc
pasqualevitiello Jan 26, 2026
143491a
Merge branch 'main' into devin/1769278561-download-app-multi-step-dro…
PeerRich Jan 26, 2026
eab940e
chore: remove unused SVG files (now inline in DownloadIcons.tsx)
devin-ai-integration[bot] Jan 26, 2026
344807a
Merge branch 'devin/1769278561-download-app-multi-step-dropdown' of h…
devin-ai-integration[bot] Jan 26, 2026
609ecc1
test: add comprehensive tests for useUserAgentData hook
devin-ai-integration[bot] Jan 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
625 changes: 625 additions & 0 deletions apps/web/modules/shell/user-dropdown/DownloadIcons.tsx

Large diffs are not rendered by default.

34 changes: 24 additions & 10 deletions apps/web/modules/shell/user-dropdown/UserDropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ vi.mock("@calcom/lib/hooks/useLocale", () => ({
}),
}));

vi.mock("@calcom/lib/hooks/useUserAgentData", () => ({
useUserAgentData: () => ({
os: "linux",
browser: "chrome",
isMobile: false,
}),
}));

const mockUseMeQuery = vi.fn();
vi.mock("@calcom/trpc/react/hooks/useMeQuery", () => ({
default: () => mockUseMeQuery(),
Expand All @@ -39,14 +47,20 @@ vi.mock("@calcom/ui/components/icon", () => ({
Icon: ({ name }: { name: string }) => <span data-testid={`icon-${name}`}>{name}</span>,
}));

vi.mock("@calcom/ui/components/dropdown", () => ({
Dropdown: ({ children }: { children: React.ReactNode }) => <div data-testid="dropdown">{children}</div>,
DropdownItem: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuContent: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuItem: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuPortal: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuSeparator: () => <hr />,
DropdownMenuTrigger: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
vi.mock("@coss/ui/components/menu", () => ({
Menu: ({ children }: { children: React.ReactNode }) => <div data-testid="menu">{children}</div>,
MenuTrigger: ({ children, render }: { children: React.ReactNode; render?: React.ReactElement }) => {
if (render) {
return React.cloneElement(render, {}, children);
}
return <div>{children}</div>;
},
MenuPopup: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
MenuItem: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
MenuSeparator: () => <hr />,
MenuSub: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
MenuSubTrigger: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
MenuSubPopup: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));

vi.mock("@calcom/ui/classNames", () => ({
Expand Down Expand Up @@ -232,7 +246,7 @@ describe("UserDropdown", () => {
const { UserDropdown } = await import("./UserDropdown");
const { getByTestId } = render(<UserDropdown />);

expect(getByTestId("dropdown")).toBeInTheDocument();
expect(getByTestId("menu")).toBeInTheDocument();
});

it("should render dropdown when isPending is true (loading state)", async () => {
Expand All @@ -244,7 +258,7 @@ describe("UserDropdown", () => {
const { UserDropdown } = await import("./UserDropdown");
const { getByTestId } = render(<UserDropdown />);

expect(getByTestId("dropdown")).toBeInTheDocument();
expect(getByTestId("menu")).toBeInTheDocument();
});
});
});
Loading
Loading