diff --git a/apps/ui/src/components/layout/sidebar.tsx b/apps/ui/src/components/layout/sidebar.tsx index 2efd6972..9a7950e3 100644 --- a/apps/ui/src/components/layout/sidebar.tsx +++ b/apps/ui/src/components/layout/sidebar.tsx @@ -2,7 +2,6 @@ import { useState, useMemo, useEffect, useCallback, useRef } from "react"; import { useNavigate, useLocation } from "@tanstack/react-router"; import { cn } from "@/lib/utils"; import { useAppStore, formatShortcut, type ThemeMode } from "@/store/app-store"; -import { CoursePromoBadge } from "@/components/ui/course-promo-badge"; import { FolderOpen, Plus, @@ -1942,8 +1941,6 @@ export function Sidebar() { "bg-gradient-to-t from-background/10 via-sidebar/50 to-transparent" )} > - {/* Course Promo Badge */} - {/* Wiki Link */} {!hideWiki && (
diff --git a/apps/ui/src/components/ui/course-promo-badge.tsx b/apps/ui/src/components/ui/course-promo-badge.tsx deleted file mode 100644 index 74353ae6..00000000 --- a/apps/ui/src/components/ui/course-promo-badge.tsx +++ /dev/null @@ -1,90 +0,0 @@ - -import * as React from "react"; -import { Sparkles, X } from "lucide-react"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { useAppStore } from "@/store/app-store"; - -interface CoursePromoBadgeProps { - sidebarOpen?: boolean; -} - -export function CoursePromoBadge({ sidebarOpen = true }: CoursePromoBadgeProps) { - const [dismissed, setDismissed] = React.useState(false); - const hideMarketingContent = useAppStore((state) => state.hideMarketingContent); - - // If marketing content is hidden globally or dismissed locally, don't render - if (hideMarketingContent || dismissed) { - return null; - } - - // Collapsed state - show only icon with tooltip - if (!sidebarOpen) { - return ( -
- - - - - - - - - Become a 10x Dev - { - e.preventDefault(); - e.stopPropagation(); - setDismissed(true); - }} - className="p-0.5 rounded-full hover:bg-primary/30 transition-colors cursor-pointer" - aria-label="Dismiss" - > - - - - - -
- ); - } - - // Expanded state - show full badge - return ( -
- -
- - Become a 10x Dev -
- { - e.preventDefault(); - e.stopPropagation(); - setDismissed(true); - }} - className="hidden lg:block p-1 rounded-full hover:bg-primary/30 transition-colors cursor-pointer" - aria-label="Dismiss" - > - - -
-
- ); -} diff --git a/apps/ui/src/components/views/settings-view.tsx b/apps/ui/src/components/views/settings-view.tsx index ea8ce41d..8729699b 100644 --- a/apps/ui/src/components/views/settings-view.tsx +++ b/apps/ui/src/components/views/settings-view.tsx @@ -37,8 +37,6 @@ export function SettingsView() { setShowProfilesOnly, muteDoneSound, setMuteDoneSound, - hideMarketingContent, - setHideMarketingContent, currentProject, moveProjectToTrash, defaultPlanningMode, @@ -104,9 +102,7 @@ export function SettingsView() { ); case "keyboard": diff --git a/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx b/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx index 40a21650..c3bdc218 100644 --- a/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx +++ b/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx @@ -1,6 +1,5 @@ import { Label } from "@/components/ui/label"; -import { Checkbox } from "@/components/ui/checkbox"; -import { Palette, Megaphone } from "lucide-react"; +import { Palette } from "lucide-react"; import { themeOptions } from "@/config/theme-options"; import { cn } from "@/lib/utils"; import type { Theme, Project } from "../shared/types"; @@ -8,17 +7,13 @@ import type { Theme, Project } from "../shared/types"; interface AppearanceSectionProps { effectiveTheme: Theme; currentProject: Project | null; - hideMarketingContent: boolean; onThemeChange: (theme: Theme) => void; - onHideMarketingContentChange: (hide: boolean) => void; } export function AppearanceSection({ effectiveTheme, currentProject, - hideMarketingContent, onThemeChange, - onHideMarketingContentChange, }: AppearanceSectionProps) { return (
- - {/* Separator */} -
- - {/* Hide Marketing Content Setting */} -
- - onHideMarketingContentChange(checked === true) - } - className="mt-1" - data-testid="hide-marketing-content-checkbox" - /> -
- -

- When enabled, hides promotional content like the "Become a 10x Dev" badge - in the sidebar. This setting persists across sessions. -

-
-
); diff --git a/apps/ui/src/store/app-store.ts b/apps/ui/src/store/app-store.ts index 728485bc..bec00c75 100644 --- a/apps/ui/src/store/app-store.ts +++ b/apps/ui/src/store/app-store.ts @@ -459,9 +459,6 @@ export interface AppState { // Audio Settings muteDoneSound: boolean; // When true, mute the notification sound when agents complete (default: false) - // Marketing Settings - hideMarketingContent: boolean; // When true, hide marketing content like the "Become a 10x Dev" badge (default: false) - // Enhancement Model Settings enhancementModel: AgentModel; // Model used for feature enhancement (default: sonnet) @@ -673,9 +670,6 @@ export interface AppActions { // Audio Settings actions setMuteDoneSound: (muted: boolean) => void; - // Marketing Settings actions - setHideMarketingContent: (hide: boolean) => void; - // Enhancement Model actions setEnhancementModel: (model: AgentModel) => void; @@ -830,7 +824,6 @@ const initialState: AppState = { showProfilesOnly: false, // Default to showing all options (not profiles only) keyboardShortcuts: DEFAULT_KEYBOARD_SHORTCUTS, // Default keyboard shortcuts muteDoneSound: false, // Default to sound enabled (not muted) - hideMarketingContent: false, // Default to showing marketing content enhancementModel: "sonnet", // Default to sonnet for feature enhancement aiProfiles: DEFAULT_AI_PROFILES, projectAnalysis: null, @@ -1494,9 +1487,6 @@ export const useAppStore = create()( // Audio Settings actions setMuteDoneSound: (muted) => set({ muteDoneSound: muted }), - // Marketing Settings actions - setHideMarketingContent: (hide) => set({ hideMarketingContent: hide }), - // Enhancement Model actions setEnhancementModel: (model) => set({ enhancementModel: model }), @@ -2341,7 +2331,6 @@ export const useAppStore = create()( showProfilesOnly: state.showProfilesOnly, keyboardShortcuts: state.keyboardShortcuts, muteDoneSound: state.muteDoneSound, - hideMarketingContent: state.hideMarketingContent, enhancementModel: state.enhancementModel, // Profiles and sessions aiProfiles: state.aiProfiles, diff --git a/apps/ui/tests/settings-marketing.spec.ts b/apps/ui/tests/settings-marketing.spec.ts deleted file mode 100644 index 4964ea90..00000000 --- a/apps/ui/tests/settings-marketing.spec.ts +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Settings Marketing Content Toggle Tests - * - * Tests for the "Hide marketing content" setting in the Appearance section. - */ - -import { test, expect } from "@playwright/test"; -import * as fs from "fs"; - -import { - waitForNetworkIdle, - createTestGitRepo, - cleanupTempDir, - createTempDirPath, - setupProjectWithPathNoWorktrees, - navigateToSettings, -} from "./utils"; - -// Create unique temp dir for this test run -const TEST_TEMP_DIR = createTempDirPath("settings-marketing-tests"); - -interface TestRepo { - path: string; - cleanup: () => Promise; -} - -// Configure all tests to run serially -test.describe.configure({ mode: "serial" }); - -test.describe("Settings Marketing Content Tests", () => { - let testRepo: TestRepo; - - test.beforeAll(async () => { - // Create test temp directory - if (!fs.existsSync(TEST_TEMP_DIR)) { - fs.mkdirSync(TEST_TEMP_DIR, { recursive: true }); - } - }); - - test.beforeEach(async () => { - // Create a fresh test repo for each test - testRepo = await createTestGitRepo(TEST_TEMP_DIR); - }); - - test.afterEach(async () => { - // Cleanup test repo after each test - if (testRepo) { - await testRepo.cleanup(); - } - }); - - test.afterAll(async () => { - // Cleanup temp directory - cleanupTempDir(TEST_TEMP_DIR); - }); - - test("should show course promo badge by default", async ({ page }) => { - // Setup project without worktrees for simpler testing - await setupProjectWithPathNoWorktrees(page, testRepo.path); - await page.goto("/"); - await waitForNetworkIdle(page); - - // Wait for sidebar to load - await expect(page.locator('[data-testid="sidebar"]')).toBeVisible({ - timeout: 10000, - }); - - // Course promo badge should be visible by default - const promoBadge = page.locator('[data-testid="course-promo-badge"]'); - await expect(promoBadge).toBeVisible({ timeout: 5000 }); - }); - - test("should hide course promo badge when setting is enabled", async ({ - page, - }) => { - // Setup project - await setupProjectWithPathNoWorktrees(page, testRepo.path); - await page.goto("/"); - await waitForNetworkIdle(page); - - // Navigate to settings - await navigateToSettings(page); - - // Click on Appearance tab in settings navigation - const appearanceTab = page.getByRole("button", { name: /appearance/i }); - await appearanceTab.click(); - - // Find and click the hide marketing content checkbox - const hideMarketingCheckbox = page.locator( - '[data-testid="hide-marketing-content-checkbox"]' - ); - await expect(hideMarketingCheckbox).toBeVisible({ timeout: 5000 }); - await hideMarketingCheckbox.click(); - - // Navigate back to board to see the sidebar - await page.goto("/board"); - await waitForNetworkIdle(page); - - // Wait for Zustand store to rehydrate from localStorage - await page.waitForFunction(() => { - const storage = localStorage.getItem('automaker-storage'); - if (!storage) return false; - const parsed = JSON.parse(storage); - return parsed.state?.hideMarketingContent === true; - }); - - // Course promo badge should now be hidden - const promoBadge = page.locator('[data-testid="course-promo-badge"]'); - await expect(promoBadge).not.toBeVisible({ timeout: 5000 }); - }); - - test("should persist hide marketing setting across page reloads", async ({ - page, - }) => { - // Setup project - await setupProjectWithPathNoWorktrees(page, testRepo.path); - await page.goto("/"); - await waitForNetworkIdle(page); - - // Navigate to settings and enable hide marketing - await navigateToSettings(page); - - const appearanceTab = page.getByRole("button", { name: /appearance/i }); - await appearanceTab.click(); - - const hideMarketingCheckbox = page.locator( - '[data-testid="hide-marketing-content-checkbox"]' - ); - await hideMarketingCheckbox.click(); - - // Reload the page - await page.reload(); - await waitForNetworkIdle(page); - - // Course promo badge should still be hidden after reload - const promoBadge = page.locator('[data-testid="course-promo-badge"]'); - await expect(promoBadge).not.toBeVisible({ timeout: 5000 }); - }); - - test("should show course promo badge again when setting is disabled", async ({ - page, - }) => { - // Setup project with hide marketing already enabled via localStorage - await page.addInitScript(() => { - const state = { - state: { - hideMarketingContent: true, - projects: [], - currentProject: null, - theme: "dark", - sidebarOpen: true, - }, - version: 2, - }; - localStorage.setItem("automaker-storage", JSON.stringify(state)); - }); - - await setupProjectWithPathNoWorktrees(page, testRepo.path); - await page.goto("/"); - await waitForNetworkIdle(page); - - // Verify promo is hidden initially - const promoBadge = page.locator('[data-testid="course-promo-badge"]'); - await expect(promoBadge).not.toBeVisible({ timeout: 5000 }); - - // Navigate to settings and disable hide marketing - await navigateToSettings(page); - - const appearanceTab = page.getByRole("button", { name: /appearance/i }); - await appearanceTab.click(); - - const hideMarketingCheckbox = page.locator( - '[data-testid="hide-marketing-content-checkbox"]' - ); - await hideMarketingCheckbox.click(); // Uncheck - - // Navigate back to board - await page.goto("/board"); - await waitForNetworkIdle(page); - - // Course promo badge should now be visible again - await expect(promoBadge).toBeVisible({ timeout: 5000 }); - }); -});