feat: only show streams visible to me

This commit is contained in:
talksik
2026-03-19 15:36:09 -07:00
parent e7031edd9a
commit 40548a1169
3 changed files with 32 additions and 2 deletions
@@ -197,6 +197,23 @@ function StreamRow({
); );
} }
// Generates the scopes for filtering particles to those that the user has access to
function useVisibilityScopes(
userEmail?: string,
networkId?: string,
) {
return useMemo(() => {
let scopes: string[] = [];
if (userEmail) {
scopes.push(`human:${userEmail}`);
}
if (networkId) {
scopes.push(`network:${networkId}`);
}
return scopes;
}, [userEmail, networkId]);
}
interface ParticleListViewProps { interface ParticleListViewProps {
path: ParticlePath; path: ParticlePath;
} }
@@ -205,8 +222,11 @@ interface ParticleListViewProps {
* List of stream particles for a container (network root, folder, etc.). * List of stream particles for a container (network root, folder, etc.).
*/ */
export function ParticleListView({ path }: ParticleListViewProps) { export function ParticleListView({ path }: ParticleListViewProps) {
const { children, isLoading } = useLiveParticleChildren(path, "last_child_created_at", "desc");
const { networkId } = parseParticlePath(path); const { networkId } = parseParticlePath(path);
const user = useAuthStore((s) => s.user);
const visibilityScopes = useVisibilityScopes(user?.email, networkId);
const { children, isLoading } = useLiveParticleChildren(path, "last_child_created_at", "desc", visibilityScopes);
const navigate = useNavigate(); const navigate = useNavigate();
const streams = useMemo( const streams = useMemo(
+2
View File
@@ -59,6 +59,7 @@ export function useLiveParticleChildren(
path: ParticlePath, path: ParticlePath,
orderByField: string = "created_at", orderByField: string = "created_at",
orderDirection: "asc" | "desc" = "desc", orderDirection: "asc" | "desc" = "desc",
visibilityScopes?: string[],
): UseLiveParticleChildrenResult { ): UseLiveParticleChildrenResult {
const [children, setChildren] = useState<Particle[]>([]); const [children, setChildren] = useState<Particle[]>([]);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
@@ -81,6 +82,7 @@ export function useLiveParticleChildren(
setError(err); setError(err);
setIsLoading(false); setIsLoading(false);
}, },
visibilityScopes,
orderByField, orderByField,
orderDirection, orderDirection,
); );
+9 -1
View File
@@ -9,6 +9,7 @@ import {
orderBy, orderBy,
limit, limit,
serverTimestamp, serverTimestamp,
where,
Timestamp, Timestamp,
type DocumentData, type DocumentData,
type FirestoreDataConverter, type FirestoreDataConverter,
@@ -128,10 +129,17 @@ export function subscribeToParticleChildren(
collectionPath: string, collectionPath: string,
onData: (children: Particle[]) => void, onData: (children: Particle[]) => void,
onError: (error: Error) => void, onError: (error: Error) => void,
visibilityScopes: string[] = [],
orderByField: string = "created_at", orderByField: string = "created_at",
orderDirection: "asc" | "desc" = "desc", orderDirection: "asc" | "desc" = "desc",
): Unsubscribe { ): Unsubscribe {
const q = query(typedCollection(collectionPath), orderBy(orderByField, orderDirection)); let q = query(typedCollection(collectionPath), orderBy(orderByField, orderDirection));
if (visibilityScopes.length > 0) {
q = query(
q,
where("visible_to", "array-contains-any", visibilityScopes),
);
}
return onSnapshot( return onSnapshot(
q, q,
(snap) => { (snap) => {