2f0597c81b
Includes c2-core (FastAPI/MQTT/Firestore), discord-bot (slash commands), frontend (Next.js admin UI), and mosquitto config.
49 lines
1.4 KiB
TypeScript
49 lines
1.4 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { collection, onSnapshot, query, FirestoreError } from "firebase/firestore";
|
|
import { onAuthStateChanged } from "firebase/auth";
|
|
import { db, auth } from "@/lib/firebase";
|
|
import type { NodeRecord } from "@/lib/types";
|
|
|
|
export function useNodes() {
|
|
const [nodes, setNodes] = useState<NodeRecord[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
let unsubFirestore: (() => void) | undefined;
|
|
|
|
const unsubAuth = onAuthStateChanged(auth, (user) => {
|
|
if (unsubFirestore) { unsubFirestore(); unsubFirestore = undefined; }
|
|
|
|
if (!user) {
|
|
setNodes([]);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
const q = query(collection(db, "nodes"));
|
|
unsubFirestore = onSnapshot(q, (snap) => {
|
|
setNodes(snap.docs.map((d) => d.data() as NodeRecord));
|
|
setLoading(false);
|
|
}, (err: FirestoreError) => { console.error("useNodes:", err); setError(err.message); setLoading(false); });
|
|
});
|
|
|
|
return () => {
|
|
unsubAuth();
|
|
if (unsubFirestore) unsubFirestore();
|
|
};
|
|
}, []);
|
|
|
|
return { nodes, loading, error };
|
|
}
|
|
|
|
export function useUnconfiguredNodes() {
|
|
const { nodes, loading } = useNodes();
|
|
return {
|
|
nodes: nodes.filter((n) => !n.configured),
|
|
loading,
|
|
};
|
|
}
|