diff --git a/js/app/components/activity-picker.tsx b/js/app/components/activity-picker.tsx index d80bf910..d310c200 100644 --- a/js/app/components/activity-picker.tsx +++ b/js/app/components/activity-picker.tsx @@ -9,6 +9,7 @@ import { zero, } from "@streamplace/components"; import { ACTIVITY_LABELS } from "@streamplace/components/src/lib/metadata-constants"; +import { useStreamplaceStore } from "@streamplace/components/src/streamplace-store/streamplace-store"; import { usePDSAgent } from "@streamplace/components/src/streamplace-store/xrpc"; import { Image } from "expo-image"; import { X } from "lucide-react-native"; @@ -50,10 +51,14 @@ export default function ActivityPicker({ const agent = usePDSAgent(); const { theme, zero: z } = useTheme(); const c = theme.colors; + const gamesEnabled = useStreamplaceStore((s) => s.gamesEnabled); - const [mode, setMode] = useState<"game" | "label">( - value?.$type === "place.stream.defs#activityLabel" ? "label" : "game", - ); + const [mode, setMode] = useState<"game" | "label">(() => { + if (value?.$type === "place.stream.defs#activityLabel") return "label"; + if (value?.$type === "place.stream.defs#activityGame" && gamesEnabled) + return "game"; + return gamesEnabled ? "game" : "label"; + }); const [query, setQuery] = useState(""); const [results, setResults] = useState([]); const [searching, setSearching] = useState(false); @@ -209,34 +214,36 @@ export default function ActivityPicker({ return ( - {(["game", "label"] as const).map((m) => ( - { - setMode(m); - if (m === "game" && selectedLabel) onChange(undefined); - if (m === "label" && selectedGame) onChange(undefined); - }} - style={[ - px[3], - borders.width.thin, - { paddingVertical: 6, borderRadius: 6 }, - { borderColor: mode === m ? c.border : c.border }, - { - backgroundColor: mode === m ? c.card : "transparent", - }, - ]} - > - m !== "game" || gamesEnabled) + .map((m) => ( + { + setMode(m); + if (m === "game" && selectedLabel) onChange(undefined); + if (m === "label" && selectedGame) onChange(undefined); }} + style={[ + px[3], + borders.width.thin, + { paddingVertical: 6, borderRadius: 6 }, + { borderColor: mode === m ? c.border : c.border }, + { + backgroundColor: mode === m ? c.card : "transparent", + }, + ]} > - {m === "game" ? "Game" : "Other Activity"} - - - ))} + + {m === "game" ? "Game" : "Other Activity"} + + + ))} {mode === "game" && ( diff --git a/js/components/src/streamplace-store/branding.tsx b/js/components/src/streamplace-store/branding.tsx index 6cf1ccb3..ddc01b70 100644 --- a/js/components/src/streamplace-store/branding.tsx +++ b/js/components/src/streamplace-store/branding.tsx @@ -119,6 +119,7 @@ export function useFetchEnvConfig() { if (result.data.playbackWorkerUrl) { store.setState({ playbackWorkerUrl: result.data.playbackWorkerUrl }); } + store.setState({ gamesEnabled: result.data.gamesEnabled ?? false }); } catch (err) { console.error("Failed to fetch env config:", err); } diff --git a/js/components/src/streamplace-store/streamplace-store.tsx b/js/components/src/streamplace-store/streamplace-store.tsx index 3a3912a6..8a3c4c1d 100644 --- a/js/components/src/streamplace-store/streamplace-store.tsx +++ b/js/components/src/streamplace-store/streamplace-store.tsx @@ -62,6 +62,9 @@ export interface StreamplaceState { playbackWorkerUrl: string | null; setPlaybackWorkerUrl: (url: string | null) => void; + gamesEnabled: boolean; + setGamesEnabled: (enabled: boolean) => void; + // Branding state branding: Record | null; brandingLoading: boolean; @@ -138,6 +141,9 @@ export const makeStreamplaceStore = ({ setPlaybackWorkerUrl: (playbackWorkerUrl: string | null) => set({ playbackWorkerUrl }), + gamesEnabled: false, + setGamesEnabled: (gamesEnabled: boolean) => set({ gamesEnabled }), + // Content metadata contentMetadata: null, setContentMetadata: (metadata) => set({ contentMetadata: metadata }), diff --git a/lexicons/place/stream/config/getEnv.json b/lexicons/place/stream/config/getEnv.json index ac009806..5cf632a4 100644 --- a/lexicons/place/stream/config/getEnv.json +++ b/lexicons/place/stream/config/getEnv.json @@ -19,6 +19,10 @@ "playbackWorkerUrl": { "type": "string", "description": "URL of the Cloudflare playback router worker" + }, + "gamesEnabled": { + "type": "boolean", + "description": "Whether the games API is configured and available" } } } diff --git a/pkg/spxrpc/place_stream_config.go b/pkg/spxrpc/place_stream_config.go index 992f9c8f..7719d651 100644 --- a/pkg/spxrpc/place_stream_config.go +++ b/pkg/spxrpc/place_stream_config.go @@ -11,5 +11,9 @@ func (s *Server) handlePlaceStreamConfigGetEnv(ctx context.Context) (*placestrea if s.cli.PlaybackWorkerURL != "" { out.PlaybackWorkerUrl = &s.cli.PlaybackWorkerURL } + if s.cli.GamesAPIURL != "" { + t := true + out.GamesEnabled = &t + } return out, nil } diff --git a/pkg/streamplace/configgetEnv.go b/pkg/streamplace/configgetEnv.go index 86911af4..1682d1c5 100644 --- a/pkg/streamplace/configgetEnv.go +++ b/pkg/streamplace/configgetEnv.go @@ -14,6 +14,8 @@ import ( type ConfigGetEnv_Output struct { // playbackWorkerUrl: URL of the Cloudflare playback router worker PlaybackWorkerUrl *string `json:"playbackWorkerUrl,omitempty" cborgen:"playbackWorkerUrl,omitempty"` + // gamesEnabled: Whether the games API is configured and available + GamesEnabled *bool `json:"gamesEnabled,omitempty" cborgen:"gamesEnabled,omitempty"` } // ConfigGetEnv calls the XRPC method "place.stream.config.getEnv".