- SkateCrew: add nip05 + admins fields; parse `admin` role marker on p tags (admins = subset of members) - CrewForm: NIP-05 input + per-member "Make admin" toggle; write nip05 tag + admin-marked p tags (works on create & edit via shared form) - useCrewNip05: verify crew handle on ANY domain against the founder pubkey (verified/mismatch/unreachable), CORS-proxy fallback + caching - CrewNip05Badge: green ✓ / red ⚠ / muted handle states with tooltips - CollectiveMembers: show Admin chips, sort admins first, admin count in summary - useCrewRole: centralized founder/admin/member/none roles (canManage, canEditProfile) — founder owns identity, admins get delegated powers with their own keys; egalitarian shared-editing intentionally unsupported - CrewDetailPage: NIP-05 badge by crew name, viewer role badges (admin/member) - NIP.md: document crew nip05 verification, admin role marker, and governance/conflict-resolution model Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
import { useCurrentUser } from '@/hooks/useCurrentUser';
|
|
import type { SkateCrew } from '@/lib/types';
|
|
|
|
export type CrewRole = 'founder' | 'admin' | 'member' | 'none';
|
|
|
|
export interface CrewRoleInfo {
|
|
role: CrewRole;
|
|
isFounder: boolean;
|
|
/** Founder OR delegated admin — the set allowed elevated actions. */
|
|
isAdmin: boolean;
|
|
isMember: boolean;
|
|
/** Can invite/vouch members & moderate the crew feed/chat. */
|
|
canManage: boolean;
|
|
/** Can edit the crew's core identity (founder only — addressable event owner). */
|
|
canEditProfile: boolean;
|
|
}
|
|
|
|
/**
|
|
* Resolve the logged-in user's role within a crew.
|
|
*
|
|
* Governance model (see NIP.md):
|
|
* - **founder**: authored the crew's addressable event → sole owner of the
|
|
* crew identity. Only they can edit the profile (Nostr addressable events can
|
|
* only be overwritten by their author's key).
|
|
* - **admin**: a delegated, confirmed member the founder marked with an `admin`
|
|
* role. Admins act with their OWN keys to invite members and moderate the
|
|
* crew feed/chat, but cannot rewrite the profile.
|
|
* - **member**: a claimed member.
|
|
* - **none**: not part of the crew.
|
|
*
|
|
* Egalitarian shared-editing is intentionally unsupported: it would require a
|
|
* shared private key (insecure) or a consensus layer (non-interoperable).
|
|
*/
|
|
export function useCrewRole(crew: SkateCrew | null | undefined): CrewRoleInfo {
|
|
const { user } = useCurrentUser();
|
|
const pubkey = user?.pubkey;
|
|
|
|
if (!crew || !pubkey) {
|
|
return {
|
|
role: 'none',
|
|
isFounder: false,
|
|
isAdmin: false,
|
|
isMember: false,
|
|
canManage: false,
|
|
canEditProfile: false,
|
|
};
|
|
}
|
|
|
|
const isFounder = pubkey === crew.pubkey;
|
|
const isDelegatedAdmin = crew.admins.includes(pubkey);
|
|
const isMember = crew.members.includes(pubkey);
|
|
|
|
const role: CrewRole = isFounder
|
|
? 'founder'
|
|
: isDelegatedAdmin
|
|
? 'admin'
|
|
: isMember
|
|
? 'member'
|
|
: 'none';
|
|
|
|
const isAdmin = isFounder || isDelegatedAdmin;
|
|
|
|
return {
|
|
role,
|
|
isFounder,
|
|
isAdmin,
|
|
isMember,
|
|
canManage: isAdmin,
|
|
canEditProfile: isFounder,
|
|
};
|
|
}
|