Compare commits

..

2 Commits

Author SHA1 Message Date
Codex Agent
31a5148263 Update help system issue status
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
2026-01-23 09:20:07 +01:00
Codex Agent
35f28fd48d Add contextual help links to admin pages 2026-01-23 09:18:46 +01:00
9 changed files with 81 additions and 6 deletions

View File

@@ -1,4 +1,3 @@
{"id":"--stealth-d39","title":"Superadmin control surface spec and access matrix","description":"Define the minimal superadmin control surface, permissions, and mapping to tenant/guest responsibilities. Document scope and non-goals.","status":"tombstone","priority":2,"issue_type":"task","created_at":"2026-01-01T14:16:06.994379577+01:00","updated_at":"2026-01-01T17:23:28.230936323+01:00","close_reason":"Duplicate of fotospiel-app-ihd after beads re-init","deleted_at":"2026-01-01T17:23:28.230936323+01:00","deleted_by":"soeren","delete_reason":"Remove stray stealth issue id","original_type":"task"}
{"id":"fotospiel-app-097","title":"Tenant announcements / release notes","description":"Broadcast announcements to tenants/admins with targeting and scheduling.","status":"closed","priority":3,"issue_type":"feature","created_at":"2026-01-01T14:20:21.68206312+01:00","updated_at":"2026-01-02T14:18:31.676816348+01:00","closed_at":"2026-01-02T14:18:31.676816348+01:00","close_reason":"Closed"}
{"id":"fotospiel-app-0h0","title":"SEC-BILL-02 Signature freshness + retry policies for Paddle webhooks","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-01T15:53:37.618780852+01:00","created_by":"soeren","updated_at":"2026-01-01T15:53:37.618780852+01:00"}
{"id":"fotospiel-app-0rb","title":"Tenant admin onboarding: inline checkout integration in welcome flow","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T16:08:22.434997456+01:00","created_by":"soeren","updated_at":"2026-01-01T16:08:28.026795975+01:00","closed_at":"2026-01-01T16:08:28.026795975+01:00","close_reason":"Completed in codebase (verified)"}
@@ -17,7 +16,7 @@
{"id":"fotospiel-app-38f","title":"Paddle catalog sync: surface last sync error/log context in admin","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T15:59:14.865414785+01:00","created_by":"soeren","updated_at":"2026-01-02T21:16:09.109922491+01:00","closed_at":"2026-01-02T21:16:09.109922491+01:00","close_reason":"Completed"}
{"id":"fotospiel-app-3ut","title":"SEC-API-03 Synthetic monitoring + alert config","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-01T15:52:46.793875724+01:00","created_by":"soeren","updated_at":"2026-01-01T15:52:46.793875724+01:00"}
{"id":"fotospiel-app-3xa","title":"Security review: event admin code audit (policies, PKCE, file handling)","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-01T16:05:20.115675149+01:00","created_by":"soeren","updated_at":"2026-01-01T16:05:20.115675149+01:00"}
{"id":"fotospiel-app-43mp","title":"Help-System für Event Admin PWA planen","status":"open","priority":2,"issue_type":"task","owner":"codex-agent@example.com","created_at":"2026-01-23T08:21:47.812129626+01:00","created_by":"Codex Agent","updated_at":"2026-01-23T08:21:47.812129626+01:00"}
{"id":"fotospiel-app-43mp","title":"Help-System für Event Admin PWA planen","notes":"Context help links wired into priority admin pages.","status":"in_progress","priority":2,"issue_type":"task","owner":"codex-agent@example.com","created_at":"2026-01-23T08:21:47.812129626+01:00","created_by":"Codex Agent","updated_at":"2026-01-23T09:19:45.828239299+01:00"}
{"id":"fotospiel-app-4ar","title":"SEC-BILL-03 Failed capture notifications + ledger hook","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-01T15:54:33.266516715+01:00","created_by":"soeren","updated_at":"2026-01-01T15:54:33.266516715+01:00"}
{"id":"fotospiel-app-4en","title":"Add translations for Mobile Package Shop","description":"The new MobilePackageShopPage.tsx uses translation keys like 'shop.title', 'shop.legal.agb', etc. Ensure these are added to the management.json files for de and en.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-06T18:05:50.469751088+01:00","created_by":"soeren","updated_at":"2026-01-06T18:14:19.984343737+01:00","closed_at":"2026-01-06T18:14:19.984346372+01:00"}
{"id":"fotospiel-app-4i4","title":"Security review: map roles/data","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T16:02:58.370301875+01:00","created_by":"soeren","updated_at":"2026-01-01T16:03:03.997327414+01:00","closed_at":"2026-01-01T16:03:03.997327414+01:00","close_reason":"Completed in codebase (verified)"}

View File

@@ -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() {
</MobileCard>
) : null}
<XStack justifyContent="flex-end">
<ContextHelpLink slug="event-prep-checklist" />
</XStack>
<MobileCard space="$2">
<XStack space="$2">
<TabButton label={t('events.branding.titleShort', 'Branding')} active={activeTab === 'branding'} onPress={() => setActiveTab('branding')} />

View File

@@ -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={<ContextHelpLink slug="tenant-dashboard-overview" />}
/>
</YStack>
<Separator backgroundColor={theme.border} opacity={0.6} />

View File

@@ -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<TenantPhoto[]>([]);
@@ -1069,7 +1070,10 @@ export default function MobileEventControlRoomPage() {
value={activeTab}
onValueChange={(val) => setActiveTab(val as 'moderation' | 'live')}
header={(
<YStack space="$2">
<XStack justifyContent="flex-end">
<ContextHelpLink slug="live-ops-control" />
</XStack>
<MobileCard>
<Accordion type="single" collapsible>
<Accordion.Item value="upload-settings">
@@ -1333,6 +1337,7 @@ export default function MobileEventControlRoomPage() {
</Accordion.Item>
</Accordion>
</MobileCard>
</YStack>
)}
tabs={[
{

View File

@@ -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<LiveShowSettings['moderation_mode']>;
@@ -279,6 +280,10 @@ export default function MobileEventLiveShowSettingsPage() {
</MobileCard>
) : null}
<XStack justifyContent="flex-end">
<ContextHelpLink slug="live-show-setup" />
</XStack>
{loading ? (
<YStack space="$2">
{Array.from({ length: 3 }).map((_, idx) => (

View File

@@ -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%"
>
<XStack justifyContent="flex-end" marginBottom="$2">
<ContextHelpLink slug="event-prep-checklist" />
</XStack>
<Tabs.List
borderRadius={16}
borderWidth={1}

View File

@@ -23,6 +23,7 @@ import { ADMIN_BASE_PATH, adminPath } from '../constants';
import { resolveLayoutForFormat } from './qr/utils';
import { useBackNavigation } from './hooks/useBackNavigation';
import { useAdminTheme } from './theme';
import { ContextHelpLink } from './components/ContextHelpLink';
export default function MobileQrPrintPage() {
const { slug: slugParam } = useParams<{ slug?: string }>();
@@ -101,6 +102,10 @@ export default function MobileQrPrintPage() {
</MobileCard>
) : null}
<XStack justifyContent="flex-end">
<ContextHelpLink slug="event-prep-checklist" />
</XStack>
<MobileCard space="$3" alignItems="center">
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{t('events.qr.heroTitle', 'Entrance QR Code')}

View File

@@ -65,6 +65,14 @@ vi.mock('../components/Primitives', () => ({
</button>
),
SkeletonCard: () => <div>Loading...</div>,
ContentTabs: ({ header, tabs }: { header?: React.ReactNode; tabs: Array<{ value: string; content: React.ReactNode }> }) => (
<div>
{header}
{tabs.map((tab) => (
<div key={tab.value}>{tab.content}</div>
))}
</div>
),
}));
vi.mock('../components/FormControls', () => ({

View File

@@ -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 (
<Pressable
onPress={() => navigate(adminPath(`/mobile/help/${encodeURIComponent(slug)}`))}
aria-label={label}
>
<XStack
alignItems="center"
space="$1.5"
paddingHorizontal="$2.5"
paddingVertical="$1.5"
borderRadius={999}
borderWidth={1}
borderColor={border}
backgroundColor={surfaceMuted}
>
<HelpCircle size={14} color={primary} />
<Text fontSize="$xs" fontWeight="700" color={textStrong}>
{label}
</Text>
</XStack>
</Pressable>
);
}