small improvements
This commit is contained in:
parent
3dfc773590
commit
a7a7eeac0c
4 changed files with 90 additions and 23 deletions
|
|
@ -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 (
|
||||
<Item>
|
||||
<ItemMedia>
|
||||
|
|
@ -37,8 +38,15 @@ export function UserInfo() {
|
|||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<ItemActions>
|
||||
{party && members.length > 1 && (
|
||||
<Button onClick={() => client.api.party.leave.post()}>Leave</Button>
|
||||
{party && (
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await client.api.party.leave.post();
|
||||
resetParty();
|
||||
}}
|
||||
>
|
||||
Leave
|
||||
</Button>
|
||||
)}
|
||||
</ItemActions>
|
||||
</Item>
|
||||
|
|
|
|||
|
|
@ -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<PartyContextValue | null>(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<PartyState>({
|
||||
party: null,
|
||||
members: [],
|
||||
});
|
||||
export function PartyProvider({ children }: { children: ReactNode }) {
|
||||
const { user } = useUser();
|
||||
const userId = user?.id ?? null;
|
||||
const [state, setState] = useState<PartyState>(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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
import { treaty } from "@elysiajs/eden";
|
||||
import type { App } from "../../../api/src/index";
|
||||
|
||||
export const client = treaty<App>("aura.rpi1.danbulant.cloud", {});
|
||||
// export const client = treaty<App>("aura.rpi1.danbulant.cloud", {});
|
||||
export const client = treaty<App>(
|
||||
process.env.VITE_BETTER_AUTH_URL || "127.0.0.1:3000",
|
||||
{},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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 }) {
|
|||
<HeadContent />
|
||||
</head>
|
||||
<body className="font-sans antialiased wrap-anywhere dark">
|
||||
{children}
|
||||
<PartyProvider>{children}</PartyProvider>
|
||||
<Toaster />
|
||||
<TanStackDevtools
|
||||
config={{
|
||||
|
|
|
|||
Loading…
Reference in a new issue