Introduce granular role-based permissions with SuperAdmin env override, admin roles UI, and permission-gated API routes. Fix admin user Nostr metadata by batching relay profile fetches, normalizing npub pubkeys to hex, and adding reusable NostrAvatar/useNostrProfile components. Co-authored-by: Cursor <cursoragent@cursor.com>
49 lines
1.1 KiB
TypeScript
49 lines
1.1 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { loadNostrProfile, type NostrProfile } from "@/lib/nostr";
|
|
|
|
export interface UseNostrProfileResult {
|
|
profile: NostrProfile | null;
|
|
loading: boolean;
|
|
}
|
|
|
|
// Fetches a single user's Nostr kind:0 metadata from relays. Concurrent calls
|
|
// across components are batched into one relay query by the shared loader.
|
|
export function useNostrProfile(
|
|
pubkey: string | null | undefined
|
|
): UseNostrProfileResult {
|
|
const [profile, setProfile] = useState<NostrProfile | null>(null);
|
|
const [loading, setLoading] = useState<boolean>(!!pubkey);
|
|
|
|
useEffect(() => {
|
|
if (!pubkey) {
|
|
setProfile(null);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
let cancelled = false;
|
|
setLoading(true);
|
|
loadNostrProfile(pubkey)
|
|
.then((p) => {
|
|
if (!cancelled) {
|
|
setProfile(p);
|
|
setLoading(false);
|
|
}
|
|
})
|
|
.catch(() => {
|
|
if (!cancelled) {
|
|
setProfile({});
|
|
setLoading(false);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [pubkey]);
|
|
|
|
return { profile, loading };
|
|
}
|