76 lines
1.8 KiB
TypeScript
76 lines
1.8 KiB
TypeScript
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { doc, getDoc } from "firebase/firestore";
|
|
|
|
import { db } from "@/lib/firebase";
|
|
|
|
export type GroupRow = {
|
|
groupId: string;
|
|
displayName: string;
|
|
};
|
|
|
|
type FirestoreStatus = "idle" | "loading" | "error";
|
|
|
|
function parseGroupsDoc(data: { groups?: unknown } | undefined): GroupRow[] {
|
|
const raw = data?.groups;
|
|
if (!Array.isArray(raw)) return [];
|
|
|
|
return raw
|
|
.map((g) => g as Partial<GroupRow>)
|
|
.filter((g) => typeof g.groupId === "string" && g.groupId.length > 0)
|
|
.map((g) => ({
|
|
groupId: g.groupId as string,
|
|
displayName:
|
|
typeof g.displayName === "string" && g.displayName.length > 0
|
|
? g.displayName
|
|
: (g.groupId as string),
|
|
}));
|
|
}
|
|
|
|
export function useSettingsGroups(enabled = true) {
|
|
const [groups, setGroups] = useState<GroupRow[]>([]);
|
|
const [status, setStatus] = useState<FirestoreStatus>("idle");
|
|
const [error, setError] = useState<string>("");
|
|
|
|
const refresh = useCallback(async () => {
|
|
if (!enabled) {
|
|
setGroups([]);
|
|
setStatus("idle");
|
|
setError("");
|
|
return;
|
|
}
|
|
|
|
setStatus("loading");
|
|
setError("");
|
|
|
|
try {
|
|
const snap = await getDoc(doc(db, "settings", "groups"));
|
|
|
|
if (!snap.exists()) {
|
|
setGroups([]);
|
|
setStatus("idle");
|
|
return;
|
|
}
|
|
|
|
setGroups(parseGroupsDoc(snap.data() as { groups?: unknown }));
|
|
setStatus("idle");
|
|
} catch (e) {
|
|
setStatus("error");
|
|
setError(e instanceof Error ? e.message : "Failed to load groups");
|
|
}
|
|
}, [enabled]);
|
|
|
|
useEffect(() => {
|
|
void refresh();
|
|
}, [refresh]);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
groups,
|
|
status,
|
|
error,
|
|
refresh,
|
|
}),
|
|
[error, groups, refresh, status],
|
|
);
|
|
}
|