feat: Groups info page and store

This commit is contained in:
2026-06-28 00:17:59 +07:00
parent aeff519ae0
commit a4f052727a
19 changed files with 529 additions and 35 deletions
+32 -10
View File
@@ -1,18 +1,40 @@
import type { Group } from "../../shared/types/group";
import { toGroup } from "./mappers";
import { toGroup, toGroupDetail } from "./mappers";
import { cachedRead } from "./cachedRead";
import { groupStore } from "../store/groupStore";
import { cacheKeys, policies } from "../cache/policies";
export function getUserGroups(userId: string): Promise<Group[]> {
return cachedRead(cacheKeys.userGroups(userId), policies.userGroups, async (vrc) => {
const { data } = await vrc.getUserGroups({ path: { userId }, throwOnError: true });
return data.map(toGroup).filter((g) => g.id);
export async function getGroup(groupId: string): Promise<Group> {
const group = await cachedRead(cacheKeys.group(groupId), policies.group, async (vrc) => {
const { data } = await vrc.getGroup({ path: { groupId }, throwOnError: true });
return toGroupDetail(data);
});
groupStore.addGroup(group);
return group;
}
export function getRepresentedGroup(userId: string): Promise<Group | null> {
return cachedRead(cacheKeys.representedGroup(userId), policies.representedGroup, async (vrc) => {
const { data } = await vrc.getUserRepresentedGroup({ path: { userId }, throwOnError: true });
return data?.groupId ? toGroup(data) : null;
});
export async function getUserGroups(userId: string): Promise<Group[]> {
const groups = await cachedRead(
cacheKeys.userGroups(userId),
policies.userGroups,
async (vrc) => {
const { data } = await vrc.getUserGroups({ path: { userId }, throwOnError: true });
return data.map(toGroup).filter((g) => g.id);
},
);
groupStore.setUserGroups(userId, groups);
return groups;
}
export async function getRepresentedGroup(userId: string): Promise<Group | null> {
const group = await cachedRead(
cacheKeys.representedGroup(userId),
policies.representedGroup,
async (vrc) => {
const { data } = await vrc.getUserRepresentedGroup({ path: { userId }, throwOnError: true });
return data?.groupId ? toGroup(data) : null;
},
);
groupStore.setRepresented(userId, group);
return group;
}
+24
View File
@@ -4,6 +4,7 @@ import type {
FavoritedWorld,
LimitedUserGroups,
RepresentedGroup,
Group as SdkGroup,
User,
CurrentUser,
LimitedUserFriend,
@@ -208,6 +209,29 @@ export function toGroup(raw: LimitedUserGroups | RepresentedGroup): Group {
};
}
export function toGroupDetail(raw: SdkGroup): Group {
return {
id: raw.id ?? "",
detailed: true,
name: raw.name ?? "",
shortCode: raw.shortCode ?? undefined,
description: raw.description || undefined,
iconUrl: raw.iconUrl ?? undefined,
bannerUrl: raw.bannerUrl ?? undefined,
ownerId: raw.ownerId ?? undefined,
memberCount: raw.memberCount,
privacy: raw.privacy ?? undefined,
onlineMemberCount: raw.onlineMemberCount,
joinState: raw.joinState ?? undefined,
isVerified: raw.isVerified ?? undefined,
rules: raw.rules || undefined,
languages: raw.languages ?? undefined,
links: raw.links ?? undefined,
tags: raw.tags ?? undefined,
createdAt: toIso(raw.createdAt as unknown as string),
};
}
function platformsOf(pkgs: ReadonlyArray<{ platform: string }>): WorldPlatforms {
let pc = false;
let android = false;