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}