From 35f28fd48d8cedee4d68ea1c836ab44ed3cfea08 Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Fri, 23 Jan 2026 09:18:46 +0100 Subject: [PATCH] Add contextual help links to admin pages --- resources/js/admin/mobile/BrandingPage.tsx | 5 +++ resources/js/admin/mobile/DashboardPage.tsx | 2 + .../js/admin/mobile/EventControlRoomPage.tsx | 13 ++++-- .../mobile/EventLiveShowSettingsPage.tsx | 5 +++ resources/js/admin/mobile/EventTasksPage.tsx | 4 ++ resources/js/admin/mobile/QrPrintPage.tsx | 5 +++ .../__tests__/EventControlRoomPage.test.tsx | 8 ++++ .../mobile/components/ContextHelpLink.tsx | 42 +++++++++++++++++++ 8 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 resources/js/admin/mobile/components/ContextHelpLink.tsx diff --git a/resources/js/admin/mobile/BrandingPage.tsx b/resources/js/admin/mobile/BrandingPage.tsx index 49734f3..19f6fc0 100644 --- a/resources/js/admin/mobile/BrandingPage.tsx +++ b/resources/js/admin/mobile/BrandingPage.tsx @@ -18,6 +18,7 @@ import toast from 'react-hot-toast'; import { adminPath } from '../constants'; import { useBackNavigation } from './hooks/useBackNavigation'; import { ADMIN_GRADIENTS, useAdminTheme } from './theme'; +import { ContextHelpLink } from './components/ContextHelpLink'; import { extractBrandingForm, type BrandingFormValues } from '../lib/brandingForm'; import { DEFAULT_EVENT_BRANDING } from '@/guest/context/EventBrandingContext'; import { getContrastingTextColor, relativeLuminance } from '@/guest/lib/color'; @@ -560,6 +561,10 @@ export default function MobileBrandingPage() { ) : null} + + + + setActiveTab('branding')} /> diff --git a/resources/js/admin/mobile/DashboardPage.tsx b/resources/js/admin/mobile/DashboardPage.tsx index 5fec460..1d2eef1 100644 --- a/resources/js/admin/mobile/DashboardPage.tsx +++ b/resources/js/admin/mobile/DashboardPage.tsx @@ -29,6 +29,7 @@ import { useEventReadiness } from './hooks/useEventReadiness'; import { SetupChecklist } from './components/SetupChecklist'; import { KpiStrip, PillBadge } from './components/Primitives'; import { getApiErrorMessage } from '../lib/apiError'; +import { ContextHelpLink } from './components/ContextHelpLink'; // --- HELPERS --- @@ -212,6 +213,7 @@ export default function MobileDashboardPage() { title={t('dashboard:overview.title', 'At a glance')} showSeparator={false} compact + action={} /> diff --git a/resources/js/admin/mobile/EventControlRoomPage.tsx b/resources/js/admin/mobile/EventControlRoomPage.tsx index 17511ae..a2a8787 100644 --- a/resources/js/admin/mobile/EventControlRoomPage.tsx +++ b/resources/js/admin/mobile/EventControlRoomPage.tsx @@ -45,6 +45,7 @@ import { useAdminTheme } from './theme'; import { useOnlineStatus } from './hooks/useOnlineStatus'; import { useAuth } from '../auth/context'; import { withAlpha } from './components/colors'; +import { ContextHelpLink } from './components/ContextHelpLink'; import { enqueuePhotoAction, loadPhotoQueue, @@ -279,7 +280,7 @@ export default function MobileEventControlRoomPage() { const isMember = user?.role === 'member'; const slug = slugParam ?? activeEvent?.slug ?? null; const online = useOnlineStatus(); - const { textStrong, text, muted, border, primary, surfaceMuted, surface } = useAdminTheme(); + const { textStrong, text, muted, border, primary, danger, accent, surfaceMuted, surface } = useAdminTheme(); const [activeTab, setActiveTab] = React.useState<'moderation' | 'live'>('moderation'); const [moderationPhotos, setModerationPhotos] = React.useState([]); @@ -1069,8 +1070,11 @@ export default function MobileEventControlRoomPage() { value={activeTab} onValueChange={(val) => setActiveTab(val as 'moderation' | 'live')} header={( - - + + + + + - + + )} tabs={[ { diff --git a/resources/js/admin/mobile/EventLiveShowSettingsPage.tsx b/resources/js/admin/mobile/EventLiveShowSettingsPage.tsx index d0f4da5..4ec8c86 100644 --- a/resources/js/admin/mobile/EventLiveShowSettingsPage.tsx +++ b/resources/js/admin/mobile/EventLiveShowSettingsPage.tsx @@ -17,6 +17,7 @@ import { resolveEventDisplayName } from '../lib/events'; import { adminPath } from '../constants'; import { useBackNavigation } from './hooks/useBackNavigation'; import { useAdminTheme } from './theme'; +import { ContextHelpLink } from './components/ContextHelpLink'; type LiveShowFormState = { moderation_mode: NonNullable; @@ -279,6 +280,10 @@ export default function MobileEventLiveShowSettingsPage() { ) : null} + + + + {loading ? ( {Array.from({ length: 3 }).map((_, idx) => ( diff --git a/resources/js/admin/mobile/EventTasksPage.tsx b/resources/js/admin/mobile/EventTasksPage.tsx index 54f1b97..68d8fe2 100644 --- a/resources/js/admin/mobile/EventTasksPage.tsx +++ b/resources/js/admin/mobile/EventTasksPage.tsx @@ -51,6 +51,7 @@ import { withAlpha } from './components/colors'; import { useAdminTheme } from './theme'; import { resolveEngagementMode } from '../lib/events'; import { useAuth } from '../auth/context'; +import { ContextHelpLink } from './components/ContextHelpLink'; function allowPermission(permissions: string[], permission: string): boolean { if (permissions.includes('*') || permissions.includes(permission)) { @@ -1162,6 +1163,9 @@ export default function MobileEventTasksPage() { alignItems="stretch" width="100%" > + + + (); @@ -101,6 +102,10 @@ export default function MobileQrPrintPage() { ) : null} + + + + {t('events.qr.heroTitle', 'Entrance QR Code')} diff --git a/resources/js/admin/mobile/__tests__/EventControlRoomPage.test.tsx b/resources/js/admin/mobile/__tests__/EventControlRoomPage.test.tsx index 5518347..1055f8b 100644 --- a/resources/js/admin/mobile/__tests__/EventControlRoomPage.test.tsx +++ b/resources/js/admin/mobile/__tests__/EventControlRoomPage.test.tsx @@ -65,6 +65,14 @@ vi.mock('../components/Primitives', () => ({ ), SkeletonCard: () =>
Loading...
, + ContentTabs: ({ header, tabs }: { header?: React.ReactNode; tabs: Array<{ value: string; content: React.ReactNode }> }) => ( +
+ {header} + {tabs.map((tab) => ( +
{tab.content}
+ ))} +
+ ), })); vi.mock('../components/FormControls', () => ({ diff --git a/resources/js/admin/mobile/components/ContextHelpLink.tsx b/resources/js/admin/mobile/components/ContextHelpLink.tsx new file mode 100644 index 0000000..d3224b5 --- /dev/null +++ b/resources/js/admin/mobile/components/ContextHelpLink.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { HelpCircle } from 'lucide-react'; +import { XStack } from '@tamagui/stacks'; +import { SizableText as Text } from '@tamagui/text'; +import { Pressable } from '@tamagui/react-native-web-lite'; + +import { adminPath } from '../../constants'; +import { useAdminTheme } from '../theme'; + +type ContextHelpLinkProps = { + slug: string; + label?: string; +}; + +export function ContextHelpLink({ slug, label = 'Help' }: ContextHelpLinkProps) { + const navigate = useNavigate(); + const { border, primary, surfaceMuted, textStrong } = useAdminTheme(); + + return ( + navigate(adminPath(`/mobile/help/${encodeURIComponent(slug)}`))} + aria-label={label} + > + + + + {label} + + + + ); +}