feat: roles/permissions system and Nostr profile display on admin users
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>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"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 };
|
||||
}
|
||||
Reference in New Issue
Block a user