Compare commits
2 Commits
53a90fec33
...
31a5148263
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31a5148263 | ||
|
|
35f28fd48d |
@@ -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)"}
|
||||
|
||||
@@ -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')} />
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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={[
|
||||
{
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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')}
|
||||
|
||||
@@ -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', () => ({
|
||||
|
||||
42
resources/js/admin/mobile/components/ContextHelpLink.tsx
Normal file
42
resources/js/admin/mobile/components/ContextHelpLink.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user