From bc543bf5ab0fb49e4253261ba1374a65c495d500 Mon Sep 17 00:00:00 2001 From: Natalie Bridgers Date: Wed, 10 Jun 2026 15:43:58 -0500 Subject: [PATCH] Migrate web app to React Query and add search route - Integrate `@tanstack/react-query` and migrate home feed polling - Implement persistent light/dark theme toggle - Add search route and actor lookup functionality - Add Sentry error tracking with sourcemap uploads - Add global error boundary and loading states - Add standalone chat popout route - Add `TooltipProvider` and `FullscreenProvider` contexts --- js/core/src/index.ts | 8 +- js/web/index.html | 13 +- js/web/package.json | 3 + js/web/plan.md | 488 ++++++++++++++++++ js/web/src/components/header.tsx | 253 ++++++++- js/web/src/components/player/player.tsx | 4 +- js/web/src/components/stream/chat-panel.tsx | 149 ++++-- js/web/src/components/stream/stream-info.tsx | 175 ++++++- .../stream/stream-notifications.tsx | 168 +++++- .../src/components/stream/video-section.tsx | 18 +- js/web/src/components/svg/streamplace-bw.tsx | 20 +- js/web/src/components/ui/button.tsx | 2 + js/web/src/components/ui/dropdown-menu.tsx | 10 +- js/web/src/hooks/use-chat-send.ts | 40 +- js/web/src/hooks/use-color-scheme.ts | 49 +- js/web/src/hooks/use-live-user.ts | 19 - js/web/src/hooks/use-live-users.ts | 33 ++ js/web/src/hooks/use-platform.ts | 75 --- js/web/src/hooks/use-sidebar-control.ts | 39 -- js/web/src/hooks/use-streamplace-node.ts | 20 - js/web/src/hooks/use-video-list.ts | 119 ++--- .../lib/providers/streamplace-provider.tsx | 30 +- js/web/src/lib/store/hooks.ts | 44 -- js/web/src/lib/store/slices/blueskySlice.ts | 195 ++++--- .../lib/store/slices/contentMetadataSlice.ts | 34 +- .../src/lib/store/slices/streamplaceSlice.ts | 91 +--- js/web/src/lib/streamplace-url.ts | 3 +- js/web/src/main.tsx | 42 +- js/web/src/routeTree.gen.ts | 42 ++ js/web/src/routes/$user/index.tsx | 15 +- js/web/src/routes/$user/video/$tid.tsx | 84 ++- js/web/src/routes/__root.tsx | 135 ++++- js/web/src/routes/chat-popout.$user.tsx | 183 +++++++ js/web/src/routes/index.tsx | 85 +-- js/web/src/routes/search.tsx | 163 ++++++ js/web/src/styles.css | 32 +- js/web/vite.config.ts | 80 +-- pnpm-lock.yaml | 224 ++++++++ 38 files changed, 2438 insertions(+), 749 deletions(-) create mode 100644 js/web/plan.md delete mode 100644 js/web/src/hooks/use-live-user.ts create mode 100644 js/web/src/hooks/use-live-users.ts delete mode 100644 js/web/src/hooks/use-platform.ts delete mode 100644 js/web/src/hooks/use-sidebar-control.ts delete mode 100644 js/web/src/hooks/use-streamplace-node.ts create mode 100644 js/web/src/routes/chat-popout.$user.tsx create mode 100644 js/web/src/routes/search.tsx diff --git a/js/core/src/index.ts b/js/core/src/index.ts index b071bbb23..40ef4fc2e 100644 --- a/js/core/src/index.ts +++ b/js/core/src/index.ts @@ -1,10 +1,4 @@ -// Public API of @streamplace/core. -// Only platform-agnostic code lives here. No react-native, no expo-*. -// -// During the extraction phase, some modules still pull a couple of -// "leaves" from @streamplace/components (e.g. useDID, usePDSAgent). -// Those will move here in subsequent refactors. Anything imported from -// @streamplace/components in this file is by design temporary. +// Public, platform-agnostic React code of @streamplace/core. export * from "./vod-store"; export * from "./livestream-store"; diff --git a/js/web/index.html b/js/web/index.html index cc75191ee..3f7d0903b 100644 --- a/js/web/index.html +++ b/js/web/index.html @@ -1,10 +1,21 @@ - + Streamplace +
diff --git a/js/web/package.json b/js/web/package.json index 78156e9b7..a7480f3a6 100644 --- a/js/web/package.json +++ b/js/web/package.json @@ -16,9 +16,11 @@ "@base-ui/react": "^1.5.0", "@fontsource/atkinson-hyperlegible-next": "^5.2.7", "@hello-pangea/dnd": "^18.0.1", + "@sentry/react": "^10.57.0", "@streamplace/core": "workspace:*", "@streamplace/i18n": "workspace:*", "@tailwindcss/typography": "^0.5.19", + "@tanstack/react-query": "^5.90.21", "@tanstack/react-router": "^1.170.0", "@tiptap/extension-mention": "^3.26.0", "@tiptap/extension-placeholder": "^3.26.0", @@ -44,6 +46,7 @@ "zustand": "^5.0.5" }, "devDependencies": { + "@sentry/vite-plugin": "^5.3.0", "@tailwindcss/vite": "^4.3.0", "@tanstack/router-plugin": "^1.168.0", "@types/react": "^19.2.0", diff --git a/js/web/plan.md b/js/web/plan.md new file mode 100644 index 000000000..e04693792 --- /dev/null +++ b/js/web/plan.md @@ -0,0 +1,488 @@ +# Streamplace Web App: Migration Plan + +## What We're Doing + +The existing React Native app (`js/app`) is the source of truth. The new web app (`js/web`) is a fresh Vite + TanStack Router SPA built with true DOM, Tailwind, and Base UI. It's already a solid foundation but has explicit Phase 3/4 stubs for core streaming features. This plan prioritizes reaching full feature parity with the RN app, then layering on web-native advantages. + +## Where We Are Today + +### Web App: What Works (Phase 1-2) + +- Home feed with live user grid +- Single live stream viewer (HLS + WebRTC) +- Single VOD viewer +- VOD browse +- OAuth login/registration +- Chat (send/receive, mentions, emoji) +- Settings: account, streaming (read-only keys), recommendations, webhooks, multistream, privacy, backup, branding, badges, languages, advanced, about +- Player with stats overlay, keyboard shortcuts, quality selector +- i18n (7 locales via `@streamplace/i18n`) + +### Web App: Explicitly Stubbed (Phase 3/4) + +From `blueskySlice.ts` header comments: + +- `createStreamKeyRecord` - throws +- `createLivestreamRecord` - throws +- `updateLivestreamRecord` - throws +- `golivePost` - throws +- `createBlockRecord` - throws + +### Web App: Missing Entirely + +- Go-live flow (no route, no UI, no broadcaster backend) +- Stream key creation (keys.tsx is read-only delete) +- Following feed (sidebar "Following" is disabled) +- Notifications surface (no route, no header bell) +- Search (no route) +- Chat popout route (`/chat-popout/:handle` linked but no route file) +- Upload VOD +- Multi-stream viewer +- Embed screens (stream, VOD, info widget, danmu OBS) +- Popout windows (livestream, multistream, stream monitor, info widget) +- Download screen +- Support screen +- "What is Streamplace?" about screen +- Error boundary +- Suspense fallback +- Theme provider (useColorScheme is hardcoded "dark") +- TooltipProvider (not mounted globally) +- FullscreenProvider (declared but not mounted) +- VideoElementProvider (declared but not mounted) +- React Query (all fetching is hand-rolled useState/useEffect) + +### RN App: Feature Inventory + +All screens in `js/app/src/screens/`: + +| Screen | Purpose | +| --------------------------- | ------------------------------------------ | +| `home.tsx` | Live stream grid with pull-to-refresh | +| `mobile-stream.tsx` | Live stream viewer (full-screen on mobile) | +| `mobile-go-live.tsx` | Go-live with ingest player | +| `launch-go-live.tsx` | "Ready to go live?" prompt | +| `live-dashboard.tsx` | BentoGrid broadcaster dashboard | +| `video-list.tsx` | VOD browse | +| `video.tsx` | Single VOD playback | +| `vod.tsx` | VOD screen | +| `upload.tsx` | VOD upload (1484 lines, tus-js-client) | +| `chat-popout.tsx` | Popout chat window | +| `multi.tsx` | Multi-stream viewer | +| `about.tsx` | "What is Streamplace?" | +| `download.tsx` | Download app | +| `embed.tsx` | Stream embed | +| `vod-embed.tsx` | VOD embed | +| `danmu-obs.tsx` | Danmu OBS overlay | +| `info-widget-embed.tsx` | Info widget embed | +| `popout-livestream.tsx` | Popout livestream window | +| `popout-multistream.tsx` | Popout multistream window | +| `popout-stream-monitor.tsx` | Stream monitor popout | +| `popout-info-widget.tsx` | Info widget popout | +| `support.tsx` | Support page | +| `app-return.tsx` | OAuth return handling | + +### RN App: Navigation Tree + +``` +RootStack +├── MainTabs +│ ├── HomeTab → HomeNavigator +│ │ ├── HomeMain (home.tsx) +│ │ ├── About +│ │ ├── Download +│ │ ├── LiveDashboard +│ │ ├── Login +│ │ ├── Multi +│ │ ├── Support +│ │ └── Upload (web only) +│ ├── VideosTab → VideosNavigator +│ │ ├── VideoList +│ │ └── UserVideoList +│ ├── GoLiveTab → LaunchGoLive +│ └── SettingsTab → SettingsNavigator +│ ├── MainSettings +│ ├── AboutCategory +│ ├── AccountCategory +│ ├── StreamingCategory +│ ├── WebhooksSettings +│ ├── BackupSettings +│ ├── RecommendationsSettings +│ ├── PrivacyCategory +│ ├── DanmuCategory +│ ├── AdvancedCategory +│ ├── MultistreamCategory +│ ├── LanguagesCategory +│ ├── KeyManagement +│ ├── BadgeSelection +│ ├── BadgeIssuer +│ └── BrandingAdmin +├── Stream (MobileStream) +├── MobileGoLive +├── Video +├── Vod +├── PopoutChat +├── Embed / VodEmbed / InfoWidgetEmbed / DanmuOBS +├── PopoutStreamMonitor / PopoutInfoWidget / PopoutMultistream / PopoutLivestream +└── AppReturn +``` + +### Shared Packages + +| Package | Web Safe? | Used by Web? | Notes | +| ------------------------------- | ------------ | ------------ | -------------------------------------------------------------------------------------- | +| `@streamplace/core` | Mostly yes | Yes | LivestreamStore, handleWebSocketMessages, reduceChat, segmentize, Facet | +| `@streamplace/i18n` | Yes | Yes | manifest, createI18nextConfig, locale resources | +| `@streamplace/components` | No (RN deps) | No | Contains Player, settings panels, hooks, but depends on react-native, expo-video, etc. | +| `streamplace` | Yes | Yes | PlaceStream\* types, agent methods | +| `js/playback-router` | Likely yes | No | Not imported by web, worker-specific | +| `js/config-react-native-webrtc` | No | No | RN-specific | + +### RN Platform Dependencies in Active Use + +| Dependency | Used In (RN) | Web Equivalent | +| --------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------- | +| `expo-video` | Player components | Native `