61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
/**
|
|
* The user a profile page is about comes through this hook, which loads them
|
|
* by the name in the URL and keeps them live. Each tab of the profile loads
|
|
* its own lists, by the user's id.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
import type { PublicUser } from "../../../shared/user.ts";
|
|
import { fetchPublicUser } from "../../utils/shared/fetchPublicUser.ts";
|
|
import { useAuth } from "../auth/useAuth.ts";
|
|
import { useWS } from "../ws/useWS.ts";
|
|
import { type FetchState, useFetchState } from "../shared/useFetchState.ts";
|
|
|
|
/** Returned by {@link useProfile} to `UserPublicProfile`. */
|
|
export interface UseProfileResult {
|
|
state: FetchState<PublicUser>;
|
|
/** It is false while the profile loads. */
|
|
isOwnProfile: boolean;
|
|
/** It shows the header's edits, which the server echoes to other browsers. */
|
|
setUser: (fn: (user: PublicUser) => PublicUser) => void;
|
|
}
|
|
|
|
/**
|
|
* Returns the user named `username`, from `GET /api/users/@:username`, which
|
|
* answers a former name or another case too. The profile then puts the
|
|
* current name in its URL, and that path, naming the user on screen, fetches
|
|
* nothing; another user's does. The socket's `user_updated` keeps them live.
|
|
*/
|
|
export function useProfile(username: string | undefined): UseProfileResult {
|
|
const { user: me } = useAuth();
|
|
const { lastUserEvent } = useWS();
|
|
|
|
// The name last fetched, which the URL may leave for the current one.
|
|
const [target, setTarget] = useState(username);
|
|
const { state, setData } = useFetchState(
|
|
target,
|
|
(signal) => fetchPublicUser(target!, signal),
|
|
);
|
|
const user = state.status === "loaded" ? state.data : null;
|
|
if (
|
|
target !== username &&
|
|
user?.username.toLowerCase() !== username?.toLowerCase()
|
|
) {
|
|
setTarget(username);
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (!lastUserEvent) return;
|
|
setData((u) => u.id === lastUserEvent.user.id ? lastUserEvent.user : u);
|
|
}, [lastUserEvent, setData]);
|
|
|
|
return {
|
|
state,
|
|
isOwnProfile: !!me && me.id === user?.id,
|
|
setUser: setData,
|
|
};
|
|
}
|