SkateSpots/src/hooks/useCrewRole.ts
shakespeare.diy 40e4a27565 Add crew NIP-05 (any-domain, founder-verified) + founder/delegated-admin governance
- 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>
2026-07-24 16:46:20 +07:00

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,
};
}