101 lines
3.2 KiB
TypeScript
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
|
|
};
|
|
}
|