From b3c41f6dea05b040da8e89feb95e9494745e9ce3 Mon Sep 17 00:00:00 2001 From: Zak Bearman Date: Tue, 1 Sep 2026 16:51:32 +1200 Subject: [PATCH] Add safe user preview for invites --- frontend/app/admin/invites/page.tsx | 5 ++++ frontend/app/profile/invites/page.tsx | 33 +++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/frontend/app/admin/invites/page.tsx b/frontend/app/admin/invites/page.tsx index c87234a..0354bbd 100644 --- a/frontend/app/admin/invites/page.tsx +++ b/frontend/app/admin/invites/page.tsx @@ -1174,6 +1174,11 @@ export default function AdminInviteManagementPage() { title="Invites" subtitle="Create access links, apply account profiles, deliver invitations, and see what needs attention." rail={inviteManagementRail} + actions={ + + } >
{error &&
{error}
} diff --git a/frontend/app/profile/invites/page.tsx b/frontend/app/profile/invites/page.tsx index e4e14db..bee4440 100644 --- a/frontend/app/profile/invites/page.tsx +++ b/frontend/app/profile/invites/page.tsx @@ -1,7 +1,7 @@ 'use client' -import { useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/navigation' +import { useEffect, useMemo, useState } from 'react' import { authFetch, clearToken, getApiBase, getToken } from '../../lib/auth' type ProfileInfo = { @@ -97,6 +97,7 @@ export default function ProfileInvitesPage() { const [inviteManagedByMaster, setInviteManagedByMaster] = useState(false) const [masterInviteTemplate, setMasterInviteTemplate] = useState(null) const [loading, setLoading] = useState(true) + const [viewAsUser, setViewAsUser] = useState(false) const signupBaseUrl = useMemo(() => { if (typeof window === 'undefined') return '/signup' @@ -135,6 +136,7 @@ export default function ProfileInvitesPage() { } useEffect(() => { + setViewAsUser(new URLSearchParams(window.location.search).get('view') === 'user') if (!getToken()) { router.push('/login') return @@ -307,6 +309,11 @@ export default function ProfileInvitesPage() { const canManageInvites = profile?.role === 'admin' || inviteAccessEnabled + const enterUserView = () => { + setViewAsUser(true) + router.replace('/profile/invites?view=user') + } + if (loading) { return
Loading invite tools...
} @@ -315,17 +322,35 @@ export default function ProfileInvitesPage() {
-

My invites

-

Create invite links, email them directly, and track who you have invited.

+

{viewAsUser ? 'Invites' : 'My invites'}

+

+ {viewAsUser + ? 'Preview the invite workspace exactly as a permitted non-admin user sees it.' + : 'Create invite links, email them directly, and track who you have invited.'} +

+ {profile?.role === 'admin' && !viewAsUser ? ( + + ) : null} + {profile?.role === 'admin' && viewAsUser ? ( + + ) : null}
- {profile ? ( + {profile && viewAsUser ? ( +
+ User view preview. The non-admin presentation is active. Your admin permissions and invite data remain unchanged. +
+ ) : profile ? (
Signed in as {profile.username} ({profile.role}).