All files / src/hooks useGroupHierarchy.ts

85.13% Statements 63/74
85.71% Branches 12/14
100% Functions 1/1
85.13% Lines 63/74

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 921x 1x               1x 2x 2x 2x   2x 1x 1x 1x 1x 1x 1x 1x 1x 1x   1x 1x 1x 2x   2x 1x 2x   2x 2x 2x 2x   2x 2x 2x 2x   2x 2x 1x 2x 2x   2x   2x 2x             2x 2x   2x 2x         2x 2x   2x 2x 2x 2x   2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x  
import { useState, useEffect, useCallback, useMemo } from "react";
import {
	getGroupHierarchy,
	getPinnedGroups,
	pinGroup as pinGroupApi,
	unpinGroup as unpinGroupApi,
} from "@/lib/tauri";
import type { GroupHierarchyEntry, PinnedGroup } from "@/lib/types";
 
export const useGroupHierarchy = (providerId: string | null, contentType: string) => {
	const [entries, setEntries] = useState<GroupHierarchyEntry[]>([]);
	const [pinnedGroups, setPinnedGroups] = useState<PinnedGroup[]>([]);
	const [loaded, setLoaded] = useState(false);
 
	const load = useCallback(async () => {
		if (!providerId) return;
		try {
			const [h, p] = await Promise.all([
				getGroupHierarchy(providerId, contentType),
				getPinnedGroups(providerId, contentType),
			]);
			setEntries(h);
			setPinnedGroups(p);
		} catch (err) {
			console.error("Failed to load group hierarchy:", err);
		} finally {
			setLoaded(true);
		}
	}, [providerId, contentType]);
 
	useEffect(() => {
		load();
	}, [load]);
 
	const superCategories = useMemo(
		() => [...new Set(entries.filter((e) => e.superCategory).map((e) => e.superCategory!))],
		[entries]
	);
 
	const topLevelGroups = useMemo(
		() => entries.filter((e) => !e.superCategory).map((e) => e.groupName),
		[entries]
	);
 
	const getGroupsForCategory = useCallback(
		(category: string) =>
			entries.filter((e) => e.superCategory === category).map((e) => e.groupName),
		[entries]
	);
 
	const hasHierarchy = superCategories.length > 0;
 
	const pinGroup = useCallback(
		async (groupName: string) => {
			if (!providerId) return;
			const nextOrder =
				pinnedGroups.length > 0 ? pinnedGroups[pinnedGroups.length - 1].sortOrder + 100 : 0;
			await pinGroupApi(providerId, contentType, groupName, nextOrder);
			await load();
		},
		[providerId, contentType, pinnedGroups, load]
	);
 
	const unpinGroup = useCallback(
		async (groupName: string) => {
			if (!providerId) return;
			await unpinGroupApi(providerId, contentType, groupName);
			await load();
		},
		[providerId, contentType, load]
	);
 
	const isPinned = useCallback(
		(groupName: string) => pinnedGroups.some((p) => p.groupName === groupName),
		[pinnedGroups]
	);
 
	return {
		entries,
		pinnedGroups,
		loaded,
		superCategories,
		topLevelGroups,
		hasHierarchy,
		getGroupsForCategory,
		pinGroup,
		unpinGroup,
		isPinned,
		reload: load,
	};
};