feat(rbac): no role at registration; invitation-based membership; nav gating
- Registration no longer asks for a role/persona (removed the role select + allottee block); crm.account.register sends no persona. - New users have no permissions → the sidebar now shows only Dashboard + Profile for them, gated on crm.account.me (membership + permissions). Members see the areas their permissions allow. - Add /portal/invite?token=… : accepts the invite for a signed-in registered user, or routes an unregistered invitee through register/onboarding, which redeems the stashed token on completion (granting the invited role). - Team Management: 'Copy link' on pending invites builds the invite link from the invitation token (no email delivery yet).
This commit is contained in:
@@ -301,6 +301,13 @@ export function TeamManagement() {
|
||||
</div>
|
||||
<RoleChips roleIds={inv.roleIds} roleById={roleById} />
|
||||
<div className="tm-invite-actions">
|
||||
{inv.token && (
|
||||
<Btn variant="soft" size="sm" icon="copy" onClick={async () => {
|
||||
const link = `${window.location.origin}/portal/invite?token=${inv.token}`;
|
||||
try { await navigator.clipboard.writeText(link); toast.push({ tone: "success", title: "Invite link copied", desc: `Send it to ${inv.email} to join.` }); }
|
||||
catch { toast.push({ tone: "info", title: "Invite link", desc: link }); }
|
||||
}}>Copy link</Btn>
|
||||
)}
|
||||
<Btn variant="soft" size="sm" icon="refresh" onClick={async () => {
|
||||
try { await team.resendInvite(inv.id); toast.push({ tone: "success", title: "Invite resent", desc: `A fresh link was sent to ${inv.email}.` }); }
|
||||
catch (e) { toast.push({ tone: "error", title: "Couldn't resend", desc: (e as Error).message }); }
|
||||
|
||||
Reference in New Issue
Block a user