drop/server/composables/community-friends.ts
wdunn001 180241c266
Some checks failed
Server CI / Lint (push) Has been cancelled
Server CI / Typecheck (push) Has been cancelled
community: wire server registry deep links + main nav (friends widget, Community submenu, profile link)
- Resolve gameServerRegistry.json's null deep_link entries against the
  live drop-db catalog (WoW, EverQuest, Among Us match real Game rows;
  OpenDAoC and the Goldberg relay genuinely have none, left null and
  documented why).
- Fix the "0 online now" panel bug: the community landing page's
  persistent-world quick-strip was inferring presence from PlaySession
  name-matching (presenceService.getServerPresence), which hardcodes
  available=true even with zero matches -- always showing a fake "0"
  for EQEmu instead of the honest unavailable state. Switched it to the
  same probe-backed GameServer feed ServerStatusPanel already uses
  (joined by the shared wow/eqemu/daoc slug), so known-zero and
  count-unavailable never render the same.
- Header people icon now opens a friends flyout (list, incoming
  requests with accept/decline, entry into chat with a friend) instead
  of going nowhere, mirroring the existing notifications bell's
  Menu/MenuButton/MenuItems pattern; badge shows pending request count.
  Mobile sidebar links it straight to /community/friends.
- Community gets a hover submenu in the main nav (desktop) / inline
  sublist (mobile) listing Friends, Chat, Devices, Mods, Servers,
  Issues, Achievements.
- User dropdown menu gets a "Your profile" entry resolved from the
  signed-in user's own username (/community/profile/<username>), not
  hardcoded.
2026-08-03 11:02:58 -04:00

43 lines
1.5 KiB
TypeScript

// Small shared state for the header's friends widget (list + pending
// requests) -- same useState pattern as composables/notifications.ts, but
// fetched lazily (only once a logged-in UserHeader mounts) rather than
// connecting eagerly at module scope, since it's a plain $dropFetch call
// rather than its own websocket. Mirrors the shape server/pages/community/
// friends.vue already fetches inline; kept here too so the header widget
// and that full page can eventually share one source without a second
// redesign -- see server/server/internal/community/friendsService.ts for
// the API this reads.
export interface CommunityUserSummary {
id: string;
username: string;
displayName: string;
avatarUrl: string | null;
}
export interface FriendshipRequestSummary {
id: string;
createdAt: string;
user: CommunityUserSummary;
}
export interface FriendsListResult {
friends: CommunityUserSummary[];
incomingRequests: FriendshipRequestSummary[];
outgoingRequests: FriendshipRequestSummary[];
}
export const useCommunityFriends = () =>
useState<FriendsListResult | null>("community-friends", () => null);
export async function refreshCommunityFriends() {
const state = useCommunityFriends();
try {
state.value = await $dropFetch<FriendsListResult>(
"/api/v1/community/friends",
);
} catch {
// Signed out (403) or a transient fetch error -- leave whatever was
// there before rather than throwing out of the header chrome.
}
return state.value;
}