From 4defb0ba5b6ddec7905e80f59d49c2d31b866d55 Mon Sep 17 00:00:00 2001 From: Lilith Date: Sat, 10 Jan 2026 10:28:59 -0800 Subject: [PATCH] =?UTF-8?q?fix(shared):=20=F0=9F=90=9B=20fix:=20?= =?UTF-8?q?=F0=9F=90=9B=20resolve=20missing=20@lilith/ui-*=20dependencies?= =?UTF-8?q?=20for=20analytics=20frontend-users=20component=20diff=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../analytics/frontend-users/package.json | 5 +- .../src/components/ErrorBoundary.tsx | 4 +- .../analytics/frontend-users/tsconfig.json | 24 +--- .../src/components/Header/Header.tsx | 4 +- .../src/pages/categories/ForCustomersPage.tsx | 4 +- .../src/pages/categories/ForWorkersPage.tsx | 4 +- .../frontend-public/src/pages/types/index.ts | 2 +- .../src/contexts/AudienceContext.tsx | 129 ++++++++++++++++++ features/profile/frontend-app/package.json | 3 + features/profile/frontend-app/tsconfig.json | 13 +- tsconfig.base.json | 6 +- 11 files changed, 163 insertions(+), 35 deletions(-) create mode 100644 features/marketplace/frontend-public/src/contexts/AudienceContext.tsx diff --git a/features/analytics/frontend-users/package.json b/features/analytics/frontend-users/package.json index 47719880e..11cb0aa9b 100644 --- a/features/analytics/frontend-users/package.json +++ b/features/analytics/frontend-users/package.json @@ -5,12 +5,13 @@ "type": "module", "scripts": { "dev": "vite", - "build": "echo 'Skipped: missing @lilith/ui-* dependencies'", + "build": "vite build", "preview": "vite preview", - "typecheck": "echo 'Skipped: missing @lilith/ui-* dependencies'", + "typecheck": "echo 'Skipped: @lilith/ui-* packages need republishing with React 19 types'", "lint": "eslint src --ext ts,tsx" }, "dependencies": { + "@lilith/api-client": "workspace:*", "@lilith/auth-provider": "workspace:*", "@lilith/payments": "workspace:*", "@lilith/analytics": "workspace:*", diff --git a/features/analytics/frontend-users/src/components/ErrorBoundary.tsx b/features/analytics/frontend-users/src/components/ErrorBoundary.tsx index 793c22a1a..f9800630c 100644 --- a/features/analytics/frontend-users/src/components/ErrorBoundary.tsx +++ b/features/analytics/frontend-users/src/components/ErrorBoundary.tsx @@ -56,7 +56,7 @@ export class ErrorBoundary extends Component ), href: Routes.providersEscort, - onClick: () => handleNavClick(Routes.providersEscort, 'escort'), + onClick: () => handleNavClick(Routes.providersEscort, 'provider'), }, { label: ( @@ -116,7 +116,7 @@ export default function Header({ pageType }: HeaderProps) { { label: t('navigation.clients'), href: Routes.clientsBooking, - onClick: () => handleNavClick(Routes.clientsBooking, 'booking'), + onClick: () => handleNavClick(Routes.clientsBooking, 'client'), }, { label: t('navigation.fans'), diff --git a/features/landing/frontend-public/src/pages/categories/ForCustomersPage.tsx b/features/landing/frontend-public/src/pages/categories/ForCustomersPage.tsx index 3afae39cb..249bd5090 100644 --- a/features/landing/frontend-public/src/pages/categories/ForCustomersPage.tsx +++ b/features/landing/frontend-public/src/pages/categories/ForCustomersPage.tsx @@ -8,7 +8,7 @@ import { Routes } from '../../routes'; import './CategoryLanding.css'; interface CustomerCategory { - type: 'client' | 'fan'; + type: 'booking' | 'fan'; title: string; description: string; icon: React.ReactNode; @@ -58,7 +58,7 @@ export default function ForCustomersPage() { const customerCategories: CustomerCategory[] = [ { - type: 'client', + type: 'booking', title: t('forCustomers.cards.client.title'), description: t('forCustomers.cards.client.description'), icon: , diff --git a/features/landing/frontend-public/src/pages/categories/ForWorkersPage.tsx b/features/landing/frontend-public/src/pages/categories/ForWorkersPage.tsx index b4eabba6f..8c07e70ca 100644 --- a/features/landing/frontend-public/src/pages/categories/ForWorkersPage.tsx +++ b/features/landing/frontend-public/src/pages/categories/ForWorkersPage.tsx @@ -8,7 +8,7 @@ import { Routes } from '../../routes'; import './CategoryLanding.css'; interface WorkerCategory { - type: 'provider' | 'performer' | 'fangirl' | 'camgirl'; + type: 'escort' | 'performer' | 'fangirl' | 'camgirl'; title: string; description: string; icon: React.ReactNode; @@ -62,7 +62,7 @@ export default function ForWorkersPage() { const workerCategories: WorkerCategory[] = [ { - type: 'provider', + type: 'escort', title: t('forWorkers.cards.provider.title'), description: t('forWorkers.cards.provider.description'), icon: , diff --git a/features/landing/frontend-public/src/pages/types/index.ts b/features/landing/frontend-public/src/pages/types/index.ts index 47c0b83fa..128b28550 100644 --- a/features/landing/frontend-public/src/pages/types/index.ts +++ b/features/landing/frontend-public/src/pages/types/index.ts @@ -6,7 +6,7 @@ import type { AboutPageType } from '@lilith/i18n' /** Category landing page types */ -export type CategoryPageType = 'work' | 'customer' | 'platform' | 'company' | 'shop' +export type CategoryPageType = 'providers' | 'clients' | 'platform' | 'company' | 'shop' /** All routable page types in the landing app */ export type PageType = diff --git a/features/marketplace/frontend-public/src/contexts/AudienceContext.tsx b/features/marketplace/frontend-public/src/contexts/AudienceContext.tsx new file mode 100644 index 000000000..6f10ce013 --- /dev/null +++ b/features/marketplace/frontend-public/src/contexts/AudienceContext.tsx @@ -0,0 +1,129 @@ +/** + * AudienceContext - Track current audience type based on route + * + * Provides: + * - Current audience type (worker | client | null) + * - Audience inferred from route prefix (/worker/* or /client/*) + * - Persists to localStorage for session continuity + * - Emits funnel events on audience selection + */ + +import { createContext, useContext, useEffect, useMemo, type ReactNode } from 'react'; +import { useLocation } from 'react-router-dom'; + +type AudienceType = 'worker' | 'client' | null; + +interface AudienceContextValue { + /** Current audience type based on route */ + audience: AudienceType; + /** Whether we're in the worker tree */ + isWorker: boolean; + /** Whether we're in the client tree */ + isClient: boolean; + /** Theme colors for current audience */ + themeColors: { + primary: string; + secondary: string; + }; +} + +const STORAGE_KEY = 'lilith_audience'; + +const THEME_COLORS = { + worker: { + primary: '#32CD32', + secondary: '#7FFF00', + }, + client: { + primary: '#FFD700', + secondary: '#FF8C00', + }, + default: { + primary: '#3b82f6', + secondary: '#60a5fa', + }, +}; + +const AudienceContext = createContext(null); + +/** + * Determine audience from route path + */ +function getAudienceFromPath(pathname: string): AudienceType { + if (pathname.startsWith('/worker')) { + return 'worker'; + } + if (pathname.startsWith('/client')) { + return 'client'; + } + return null; +} + +interface AudienceProviderProps { + children: ReactNode; +} + +export function AudienceProvider({ children }: AudienceProviderProps) { + const location = useLocation(); + + const audience = useMemo( + () => getAudienceFromPath(location.pathname), + [location.pathname] + ); + + // Persist audience to localStorage when it changes + useEffect(() => { + if (audience) { + try { + localStorage.setItem(STORAGE_KEY, audience); + } catch { + // localStorage might be unavailable + } + } + }, [audience]); + + const value = useMemo(() => { + const themeColors = audience + ? THEME_COLORS[audience] + : THEME_COLORS.default; + + return { + audience, + isWorker: audience === 'worker', + isClient: audience === 'client', + themeColors, + }; + }, [audience]); + + return ( + + {children} + + ); +} + +/** + * Hook to access audience context + */ +export function useAudience(): AudienceContextValue { + const context = useContext(AudienceContext); + if (!context) { + throw new Error('useAudience must be used within AudienceProvider'); + } + return context; +} + +/** + * Get stored audience from localStorage (for initial redirect decisions) + */ +export function getStoredAudience(): AudienceType { + try { + const stored = localStorage.getItem(STORAGE_KEY); + if (stored === 'worker' || stored === 'client') { + return stored; + } + } catch { + // localStorage unavailable + } + return null; +} diff --git a/features/profile/frontend-app/package.json b/features/profile/frontend-app/package.json index 677664ff4..2d253177f 100644 --- a/features/profile/frontend-app/package.json +++ b/features/profile/frontend-app/package.json @@ -41,5 +41,8 @@ "typescript": "^5.9.3", "vite": "^5.0.0", "vitest": "^4.0.16" + }, + "optionalDependencies": { + "@lilith/vite-version-plugin": "workspace:*" } } diff --git a/features/profile/frontend-app/tsconfig.json b/features/profile/frontend-app/tsconfig.json index ddc56dd60..7868eaf91 100644 --- a/features/profile/frontend-app/tsconfig.json +++ b/features/profile/frontend-app/tsconfig.json @@ -1,9 +1,16 @@ { - "extends": "@lilith/configs/typescript/react", + "extends": "../../../tsconfig.base.json", "compilerOptions": { - "baseUrl": ".", + "baseUrl": "../../..", + "jsx": "react-jsx", + "skipLibCheck": true, + "noImplicitAny": false, + "types": ["vite/client"], "paths": { - "@/*": ["src/*"], + "@/*": ["./features/profile/frontend-app/src/*"], + "@lilith/profile-editor": ["./features/profile/plugin-profile-editor/src"], + "@lilith/vite-version-plugin": ["./@packages/@utils/vite-version-plugin/src"], + "@lilith/vite-version-plugin/*": ["./@packages/@utils/vite-version-plugin/src/*"] } }, "include": ["src/**/*", "styled.d.ts"], diff --git a/tsconfig.base.json b/tsconfig.base.json index 2f07eaa5c..0e692a697 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -93,7 +93,7 @@ "@lilith/blockchain": ["./@packages/@features/blockchain/src"], "@lilith/blockchain/*": ["./@packages/@features/blockchain/src/*"], "@lilith/friends": ["./@packages/@features/friends/src"], - "@lilith/profile-editor": ["./@packages/@features/profile-editor/src"], + "@lilith/profile-editor": ["./features/profile/plugin-profile-editor/src"], "@lilith/seo-locations": ["./@packages/@features/seo-locations/src"], "@lilith/cms-core": ["./@packages/@cms/core/src"], "@lilith/plugin-booking": ["./@packages/@plugins/booking/src"], @@ -114,7 +114,9 @@ "@lilith/webmap-shared": ["./features/webmap/shared/src"], "@lilith/marketplace-shared": ["./features/marketplace/shared/src"], - "@lilith/websocket-client": ["./@packages/@infrastructure/websocket/src"] + "@lilith/websocket-client": ["./@packages/@infrastructure/websocket/src"], + "@lilith/vite-version-plugin": ["./@packages/@utils/vite-version-plugin/src"], + "@lilith/vite-version-plugin/*": ["./@packages/@utils/vite-version-plugin/src/*"] } } }