diff --git a/web/src/components/user-info.tsx b/web/src/components/user-info.tsx index fc94be9..51de80d 100644 --- a/web/src/components/user-info.tsx +++ b/web/src/components/user-info.tsx @@ -15,7 +15,8 @@ import { export function UserInfo() { const { user } = useUser(); - const { party, members, isConnecting, isReconnecting } = useParty(); + const { party, members, isConnecting, isReconnecting, resetParty } = + useParty(); return ( @@ -37,8 +38,15 @@ export function UserInfo() { - {party && members.length > 1 && ( - + {party && ( + )} diff --git a/web/src/hooks/use-party.ts b/web/src/hooks/use-party.ts index 37ca048..bce0b18 100644 --- a/web/src/hooks/use-party.ts +++ b/web/src/hooks/use-party.ts @@ -1,4 +1,13 @@ -import { useCallback, useMemo, useState } from "react"; +import { + createContext, + createElement, + type ReactNode, + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from "react"; import type { PartySocketEvent, PartyState, @@ -6,14 +15,34 @@ import type { import { usePartySocket } from "./use-party-socket"; import { useUser } from "./user"; +const emptyPartyState: PartyState = { + party: null, + members: [], +}; + +type PartyContextValue = PartyState & { + connectionState: "disconnected" | "connecting" | "connected" | "reconnecting"; + isConnected: boolean; + isConnecting: boolean; + isReconnecting: boolean; + setPartyState: (state: PartyState) => void; + resetParty: () => void; +}; + +const PartyContext = createContext(null); + function reducePartyState( state: PartyState, event: PartySocketEvent, + userId: string, ): PartyState { switch (event.type) { - case "snapshot": - case "party_status": + case "party_status": { + if (!event.party) return emptyPartyState; + const isMember = event.members.some((member) => member.userId === userId); + if (!isMember) return emptyPartyState; return { party: event.party, members: event.members }; + } case "member_payload": case "pong": case "error": @@ -28,16 +57,18 @@ function getApiUrl(): string | null { return `${window.location.protocol}//${window.location.host}`; } -export function useParty() { - const { session } = useUser(); - const [state, setState] = useState({ - party: null, - members: [], - }); +export function PartyProvider({ children }: { children: ReactNode }) { + const { user } = useUser(); + const userId = user?.id ?? null; + const [state, setState] = useState(emptyPartyState); - const handleMessage = useCallback((event: PartySocketEvent) => { - setState((prev: PartyState) => reducePartyState(prev, event)); - }, []); + const handleMessage = useCallback( + (event: PartySocketEvent) => { + if (!userId) return; + setState((prev: PartyState) => reducePartyState(prev, event, userId)); + }, + [userId], + ); const apiUrl = useMemo(() => { const url = getApiUrl(); @@ -45,13 +76,36 @@ export function useParty() { return url; }, []); + const resetParty = useCallback(() => { + setState(emptyPartyState); + }, []); + + useEffect(() => { + if (!userId) resetParty(); + }, [resetParty, userId]); + const wsState = usePartySocket({ - apiUrl, - onMessage: session ? handleMessage : null, + apiUrl: userId ? apiUrl : null, + onMessage: userId ? handleMessage : null, }); - return { - ...state, - ...wsState, - }; + const value = useMemo( + () => ({ + ...state, + ...wsState, + setPartyState: setState, + resetParty, + }), + [state, wsState, resetParty], + ); + + return createElement(PartyContext.Provider, { value }, children); +} + +export function useParty() { + const context = useContext(PartyContext); + if (!context) { + throw new Error("useParty must be used within PartyProvider"); + } + return context; } diff --git a/web/src/lib/eden.ts b/web/src/lib/eden.ts index 664c729..9311f15 100644 --- a/web/src/lib/eden.ts +++ b/web/src/lib/eden.ts @@ -1,4 +1,8 @@ import { treaty } from "@elysiajs/eden"; import type { App } from "../../../api/src/index"; -export const client = treaty("aura.rpi1.danbulant.cloud", {}); +// export const client = treaty("aura.rpi1.danbulant.cloud", {}); +export const client = treaty( + process.env.VITE_BETTER_AUTH_URL || "127.0.0.1:3000", + {}, +); diff --git a/web/src/routes/__root.tsx b/web/src/routes/__root.tsx index e40b640..9555a19 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/routes/__root.tsx @@ -10,6 +10,7 @@ import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"; import type * as React from "react"; import { useEffect } from "react"; import { toast } from "sonner"; +import { PartyProvider } from "#/hooks/use-party"; import type { AuthSession } from "#/lib/auth.serverfn"; import { fetchSession, sessionQueryKey } from "#/lib/auth-client"; import { client } from "#/lib/eden"; @@ -131,7 +132,7 @@ function RootDocument({ children }: { children: React.ReactNode }) { - {children} + {children}