fiddy/apps/web/features/groups/hooks/use-groups.ts

101 lines
3.2 KiB
TypeScript

import { useCallback, useEffect, useState } from "react";
import type { Group } from "@/lib/shared/types";
import { groupsActive, groupsCreate, groupsJoin, groupsList, groupsSetActive } from "@/lib/client/groups";
import type { ApiResult } from "@/lib/client/fetch-json";
type CreateGroupInput = {
name: string;
};
type JoinGroupInput = {
inviteCode: string;
};
export default function useGroups() {
const [groups, setGroups] = useState<Group[]>([]);
const [activeGroupId, setActiveGroupId] = useState<number | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
function isError<T>(result: ApiResult<T>): result is { error: { code: string; message: string } } {
return "error" in result;
}
const load = useCallback(async () => {
setError("");
setLoading(true);
try {
const res = await groupsList();
if (!isError(res)) setGroups(res.data.groups || []);
const activeRes = await groupsActive();
if (!isError(activeRes)) setActiveGroupId(activeRes.data.active?.id || null);
} finally {
setLoading(false);
}
}, []);
const createGroup = useCallback(async (input: CreateGroupInput) => {
setError("");
setLoading(true);
try {
const result = await groupsCreate(input);
if (isError(result)) {
setError(result.error.message || "");
return null as { id: number; name: string; inviteCode?: string } | null;
}
const group = result.data.group as { id: number; name: string; inviteCode?: string };
setGroups(prev => [{ id: group.id, name: group.name, role: "GROUP_ADMIN" }, ...prev]);
setActiveGroupId(group.id);
await setActiveGroup(group.id);
return group;
} finally {
setLoading(false);
}
}, []);
const joinGroup = useCallback(async (input: JoinGroupInput) => {
setError("");
setLoading(true);
try {
const result = await groupsJoin(input);
if (isError(result)) {
setError(result.error.message || "");
return null as { id: number; name: string } | null;
}
const group = result.data.group as { id: number; name: string };
setGroups(prev => prev.some(g => g.id === group.id) ? prev : [{ id: group.id, name: group.name, role: "MEMBER" }, ...prev]);
setActiveGroupId(group.id);
await setActiveGroup(group.id);
return group;
} finally {
setLoading(false);
}
}, []);
const setActiveGroup = useCallback(async (groupId: number) => {
setError("");
const result = await groupsSetActive({ groupId });
if (isError(result)) {
setError(result.error.message || "");
return false;
}
setActiveGroupId(groupId);
return true;
}, []);
useEffect(() => {
load();
}, [load]);
return {
groups,
activeGroupId,
loading,
error,
createGroup,
joinGroup,
setActiveGroup,
reload: load
};
}