spine-framework-portal 0.2.13 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { useState } from 'react'
2
2
  import { NavLink, useNavigate } from 'react-router-dom'
3
- import { Ticket, Users, BookOpen, GraduationCap, Store, LayoutGrid, User, LogOut, Save } from 'lucide-react'
3
+ import { Ticket, Users, BookOpen, GraduationCap, Store, LayoutGrid, User, LogOut, Save, UserPlus } from 'lucide-react'
4
4
  import { useAuth } from '@core/contexts/AuthContext'
5
5
  import { useAppPath } from '@core/hooks/useAppPath'
6
6
  import { Button } from '@core/components/ui/button'
@@ -22,6 +22,10 @@ export function PortalHeader() {
22
22
  const { user, logout } = useAuth()
23
23
  const appPath = useAppPath()
24
24
  const navigate = useNavigate()
25
+
26
+ const isTeamAdmin =
27
+ user?.is_system_admin ||
28
+ user?.roles?.some((r: string) => r === 'member_admin')
25
29
  const [accountOpen, setAccountOpen] = useState(false)
26
30
  const [displayName, setDisplayName] = useState(user?.full_name || user?.email?.split('@')[0] || '')
27
31
 
@@ -68,6 +72,22 @@ export function PortalHeader() {
68
72
  {label}
69
73
  </NavLink>
70
74
  ))}
75
+ {isTeamAdmin && (
76
+ <NavLink
77
+ to={appPath('/team')}
78
+ className={({ isActive }) =>
79
+ [
80
+ 'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-colors',
81
+ isActive
82
+ ? 'bg-accent text-accent-foreground'
83
+ : 'text-muted-foreground hover:text-foreground hover:bg-accent/50',
84
+ ].join(' ')
85
+ }
86
+ >
87
+ <UserPlus size={14} />
88
+ Team
89
+ </NavLink>
90
+ )}
71
91
  </nav>
72
92
 
73
93
  <Button
package/index.tsx CHANGED
@@ -7,6 +7,7 @@ import { PortalFooter } from './components/PortalFooter'
7
7
  import { useCurrentApp } from '@core/contexts/AppContext'
8
8
 
9
9
  const HomePage = lazy(() => import('./pages/HomePage').then(m => ({ default: m.HomePage })))
10
+ const TeamPage = lazy(() => import('./pages/team/TeamPage').then(m => ({ default: m.TeamPage })))
10
11
  const TicketsPage = lazy(() => import('./pages/TicketsPage').then(m => ({ default: m.TicketsPage })))
11
12
  const CommunityPage = lazy(() => import('./pages/CommunityPage').then(m => ({ default: m.CommunityPage })))
12
13
  const CoursesPage = lazy(() => import('./pages/CoursesPage').then(m => ({ default: m.CoursesPage })))
@@ -33,6 +34,7 @@ function PortalLayout() {
33
34
  <Route path="community" element={<CommunityPage />} />
34
35
  <Route path="marketplace" element={<MarketplacePage />} />
35
36
  <Route path="developer" element={<DeveloperSettingsPage />} />
37
+ <Route path="team" element={<TeamPage />} />
36
38
  <Route path="*" element={<Navigate to="." replace />} />
37
39
  </Routes>
38
40
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework-portal",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "private": false,
5
5
  "description": "Customer Portal — self-service portal app for Spine Framework",
6
6
  "type": "module",
@@ -5,8 +5,8 @@
5
5
  * @stability stable
6
6
  *
7
7
  * Portal team management page. Visible to member_admin only.
8
- * Invites are scoped to the current user's account with the 'member' role.
9
- * Renders the shared InviteManager with account scope.
8
+ * Invites are scoped to the current user's account with selectable portal roles.
9
+ * List is filtered to portal roles only (member, member_admin).
10
10
  *
11
11
  * Route: /portal/team
12
12
  *
@@ -17,6 +17,13 @@ import React from 'react'
17
17
  import { InviteManager } from '../../../../.framework/src/components/shared/InviteManager'
18
18
  import { useAuth } from '../../../../.framework/src/contexts/AuthContext'
19
19
 
20
+ const PORTAL_ROLES = [
21
+ { slug: 'member', name: 'Member' },
22
+ { slug: 'member_admin', name: 'Member Admin' },
23
+ ]
24
+
25
+ const PORTAL_ROLE_SLUGS = PORTAL_ROLES.map(r => r.slug).join(',')
26
+
20
27
  export function TeamPage() {
21
28
  const { user } = useAuth()
22
29
 
@@ -37,14 +44,15 @@ export function TeamPage() {
37
44
  <div>
38
45
  <h1 className="text-2xl font-semibold text-slate-900">Team</h1>
39
46
  <p className="mt-1 text-sm text-slate-500">
40
- Invite members and manage access requests for your account.
47
+ Invite members and manage access to your account.
41
48
  </p>
42
49
  </div>
43
50
 
44
51
  <InviteManager
45
52
  scope="account"
46
53
  accountId={user?.account_id}
47
- defaultRoleSlug="member"
54
+ allowedRoles={PORTAL_ROLES}
55
+ roleSlugsFilter={PORTAL_ROLE_SLUGS}
48
56
  />
49
57
  </div>
50
58
  )