@burdenoff/microfe-tours 2026.527.1 → 2026.527.3
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.
- package/dist/tours/ToursUserRoutes.js +2 -4
- package/dist/tours/ToursUserRoutes.js.map +1 -1
- package/dist/tours/components/RouteHelpers.js +4 -4
- package/dist/tours/components/RouteHelpers.js.map +1 -1
- package/dist/tours/hooks/useTourPreview.js +39 -39
- package/dist/tours/hooks/useTourPreview.js.map +1 -1
- package/dist/tours/hooks/useToursList.js.map +1 -1
- package/dist/tours/i18n.js +4 -0
- package/dist/tours/i18n.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.js +11 -8
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/MyToursPage.js +59 -57
- package/dist/tours/pages/MyToursPage.js.map +1 -1
- package/dist/tours/pages/MyToursProgressPage.js +65 -61
- package/dist/tours/pages/MyToursProgressPage.js.map +1 -1
- package/dist/tours/pages/SchedulerPage.js +18 -4
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.js +330 -276
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.js +7 -2
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
- package/dist/tours/pages/TourBuilderPage.js +144 -101
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.js +12 -4
- package/dist/tours/pages/TourPreviewPage.js.map +1 -1
- package/dist/tours/pages/ToursListPage.js +165 -149
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/dist/tours/providers/ToursProvider.js +1 -1
- package/dist/tours/providers/ToursProvider.js.map +1 -1
- package/dist/tours/utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourBuilderPage.js","names":[],"sources":["../../../src/tours/pages/TourBuilderPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n Save,\n ArrowLeft,\n Eye,\n ListOrdered,\n BarChart3,\n Calendar,\n LayoutTemplate,\n Sparkles,\n} from 'lucide-react';\nimport { gql } from '@apollo/client/core';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { Tour, TourTriggerType } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\nimport { useGetPlatformProductsForToursQuery } from '../../generated/global-operations';\n\n// Covers the current platform catalog with room for planned products; custom slug entry remains the fallback.\nconst PLATFORM_PRODUCTS_QUERY_LIMIT = 250;\n\nconst SEED_VIBECONTROLS_USER_TOURS = gql`\n mutation SeedVibeControlsUserTours {\n seedVibeControlsUserTours {\n productId\n workspaceId\n createdCount\n updatedCount\n totalCount\n tours {\n tourId\n slug\n name\n action\n stepCount\n }\n }\n }\n`;\n\ninterface SeededUserTourResult {\n tourId: string;\n slug: string;\n name: string;\n action: string;\n stepCount: number;\n}\n\ninterface SeedVibeControlsUserToursPayload {\n productId: string;\n workspaceId: string;\n createdCount: number;\n updatedCount: number;\n totalCount: number;\n tours: SeededUserTourResult[];\n}\n\ninterface SeedVibeControlsUserToursMutation {\n seedVibeControlsUserTours: SeedVibeControlsUserToursPayload;\n}\n\nfunction getMutationErrorMessage(result: unknown): string | null {\n if (!result || typeof result !== 'object') return null;\n\n const record = result as Record<string, unknown>;\n const singleError = record.error;\n if (singleError instanceof Error) return singleError.message;\n\n const errors = record.errors;\n if (!Array.isArray(errors) || errors.length === 0) return null;\n\n const messages = errors\n .map((error) => {\n if (error instanceof Error) return error.message;\n if (!error || typeof error !== 'object') return null;\n\n const message = (error as { message?: unknown }).message;\n return typeof message === 'string' ? message : null;\n })\n .filter((message): message is string => Boolean(message));\n\n return messages.length > 0 ? messages.join('; ') : 'Seed mutation returned errors.';\n}\n\ninterface TourRouteModuleOption {\n moduleId: string;\n label: string;\n path: string;\n}\n\ninterface TourRoutePageOption {\n pageId: string;\n label: string;\n path: string;\n}\n\ninterface TourRouteCatalogEntry {\n productId: string;\n moduleId: string;\n moduleLabel: string;\n pageId: string;\n pageLabel: string;\n path: string;\n isModuleHome?: boolean;\n}\n\nconst TOUR_ROUTE_CATALOG: readonly TourRouteCatalogEntry[] = [\n {\n productId: 'vibecontrols',\n moduleId: 'dashboard',\n moduleLabel: 'Dashboard',\n pageId: 'dashboard',\n pageLabel: 'Dashboard',\n path: '/dashboard',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'home',\n pageLabel: 'Overview',\n path: '/vibecontrols',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'agents',\n pageLabel: 'Targets & Agents',\n path: '/vibecontrols/agents',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibes',\n pageLabel: 'Vibes',\n path: '/vibecontrols/vibes',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'sessions',\n pageLabel: 'Sessions',\n path: '/vibecontrols/sessions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'ai',\n pageLabel: 'AI',\n path: '/vibecontrols/ai',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'catalogs',\n pageLabel: 'Catalogs',\n path: '/vibecontrols/catalogs',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'components',\n pageLabel: 'Components',\n path: '/vibecontrols/components',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'templates',\n pageLabel: 'Templates',\n path: '/vibecontrols/templates',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'actions',\n pageLabel: 'Actions',\n path: '/vibecontrols/actions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibedeck',\n pageLabel: 'Decks',\n path: '/vibecontrols/vibedeck',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'calendar',\n pageLabel: 'Calendar',\n path: '/vibecontrols/calendar',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'tunnels',\n pageLabel: 'Tunnels',\n path: '/vibecontrols/tunnels',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'analytics',\n pageLabel: 'Analytics',\n path: '/vibecontrols/analytics',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'audit',\n pageLabel: 'Audit Log',\n path: '/vibecontrols/audit',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'health',\n pageLabel: 'Health',\n path: '/vibecontrols/health',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'settings',\n pageLabel: 'Settings',\n path: '/vibecontrols/settings',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'scheduler',\n moduleLabel: 'Scheduler',\n pageId: 'scheduler',\n pageLabel: 'Scheduler',\n path: '/scheduler',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'sandbox',\n moduleLabel: 'Sandbox',\n pageId: 'sandbox',\n pageLabel: 'Sandbox',\n path: '/sandbox',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'support',\n moduleLabel: 'Support',\n pageId: 'tickets',\n pageLabel: 'Tickets',\n path: '/support/tickets',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'support',\n moduleLabel: 'Support',\n pageId: 'knowledge-base',\n pageLabel: 'Knowledge Base',\n path: '/support/kb',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'notifications',\n moduleLabel: 'Notifications',\n pageId: 'center',\n pageLabel: 'Notification Center',\n path: '/notifications/center',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'notifications',\n moduleLabel: 'Notifications',\n pageId: 'history',\n pageLabel: 'History',\n path: '/notifications/history',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'notifications',\n moduleLabel: 'Notifications',\n pageId: 'preferences',\n pageLabel: 'Preferences',\n path: '/notifications/preferences',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'home',\n pageLabel: 'All Conversations',\n path: '/conversations',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'list',\n pageLabel: 'Conversation List',\n path: '/conversations/list',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'new',\n pageLabel: 'New Conversation',\n path: '/conversations/new',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'settings',\n pageLabel: 'Settings',\n path: '/conversations/settings',\n },\n] as const;\n\nfunction normalizeCatalogValue(value: string | null | undefined): string | undefined {\n const normalized = value?.trim();\n return normalized ? normalized : undefined;\n}\n\nfunction getRouteCatalog(productId: string | null | undefined): TourRouteCatalogEntry[] {\n const productKey = normalizeCatalogValue(productId);\n if (!productKey) return [];\n return TOUR_ROUTE_CATALOG.filter((entry) => entry.productId === productKey);\n}\n\nfunction getTourRouteModules(productId: string | null | undefined): TourRouteModuleOption[] {\n const modules = new Map<string, TourRouteModuleOption>();\n\n for (const entry of getRouteCatalog(productId)) {\n const existing = modules.get(entry.moduleId);\n if (!existing || entry.isModuleHome) {\n modules.set(entry.moduleId, {\n moduleId: entry.moduleId,\n label: entry.moduleLabel,\n path: entry.path,\n });\n }\n }\n\n return [...modules.values()];\n}\n\nfunction getTourRoutePages(\n productId: string | null | undefined,\n moduleId: string | null | undefined\n): TourRoutePageOption[] {\n const moduleKey = normalizeCatalogValue(moduleId);\n if (!moduleKey) return [];\n\n return getRouteCatalog(productId)\n .filter((entry) => entry.moduleId === moduleKey)\n .map((entry) => ({\n pageId: entry.pageId,\n label: entry.pageLabel,\n path: entry.path,\n }));\n}\n\n/**\n * Tour builder page\n * Create or edit tour metadata\n */\nexport function TourBuilderPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const globalClient = useGatewayClient('global');\n const { hasPermission } = useToursPermissionAccess();\n const isNew = !tourId || tourId === 'new';\n const canCreate = hasPermission(TOUR_PERMISSIONS.TOUR_CREATE);\n const canUpdate = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canCreateTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE);\n const canSave = isNew ? canCreate : canUpdate;\n const canSeedVibeControlsUserTours = canCreate && canUpdate;\n\n const { tour, loadTour, createTour, updateTour, saving, validationErrors, error } =\n useTourBuilder(tourId);\n const { saveAsTemplate } = useTourLifecycle();\n const { data: productsData, loading: productsLoading } = useGetPlatformProductsForToursQuery({\n variables: { limit: PLATFORM_PRODUCTS_QUERY_LIMIT, offset: 0 },\n fetchPolicy: 'cache-and-network',\n });\n\n const defaultFormData = {\n name: '',\n description: '',\n productId: '',\n moduleId: '',\n pageId: '',\n isActive: true,\n status: 'DRAFT' as const,\n triggerType: 'MANUAL' as const,\n priority: 50,\n displayOrder: 1,\n startDate: '',\n endDate: '',\n };\n\n const [formData, setFormData] = useState<Partial<Tour>>(defaultFormData);\n const [customProductEntry, setCustomProductEntry] = useState(false);\n const [customModuleEntry, setCustomModuleEntry] = useState(false);\n const [customPageEntry, setCustomPageEntry] = useState(false);\n const [seedLoading, setSeedLoading] = useState(false);\n const [seedResult, setSeedResult] = useState<SeedVibeControlsUserToursPayload | null>(null);\n const [seedError, setSeedError] = useState<string | null>(null);\n\n const formInitializedRef = useRef(false);\n\n const productOptions = useMemo(() => {\n return [...(productsData?.platformProducts.items ?? [])].sort((a, b) =>\n a.name.localeCompare(b.name)\n );\n }, [productsData]);\n\n const productOptionSlugs = useMemo(\n () => new Set(productOptions.map((product) => product.slug)),\n [productOptions]\n );\n\n const moduleOptions = useMemo(\n () => getTourRouteModules(formData.productId),\n [formData.productId]\n );\n\n const moduleOptionIds = useMemo(\n () => new Set(moduleOptions.map((moduleOption) => moduleOption.moduleId)),\n [moduleOptions]\n );\n\n const pageOptions = useMemo(\n () => getTourRoutePages(formData.productId, formData.moduleId),\n [formData.moduleId, formData.productId]\n );\n\n const pageOptionIds = useMemo(\n () => new Set(pageOptions.map((pageOption) => pageOption.pageId)),\n [pageOptions]\n );\n\n useEffect(() => {\n if (tourId && tourId !== 'new') {\n formInitializedRef.current = false;\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour && !formInitializedRef.current) {\n setFormData(tour);\n formInitializedRef.current = true;\n }\n }, [tour]);\n\n useEffect(() => {\n if (!formData.productId || productsLoading) {\n setCustomProductEntry(false);\n return;\n }\n setCustomProductEntry(productOptions.length > 0 && !productOptionSlugs.has(formData.productId));\n }, [formData.productId, productOptionSlugs, productOptions.length, productsLoading]);\n\n useEffect(() => {\n if (!formData.productId || !formData.moduleId) {\n setCustomModuleEntry(false);\n return;\n }\n setCustomModuleEntry(moduleOptions.length === 0 || !moduleOptionIds.has(formData.moduleId));\n }, [formData.moduleId, formData.productId, moduleOptionIds, moduleOptions.length]);\n\n useEffect(() => {\n if (!formData.productId || !formData.pageId) {\n setCustomPageEntry(false);\n return;\n }\n setCustomPageEntry(pageOptions.length === 0 || !pageOptionIds.has(formData.pageId));\n }, [formData.pageId, formData.productId, pageOptionIds, pageOptions.length]);\n\n const showCurrentProductOption = Boolean(\n formData.productId && !customProductEntry && !productOptionSlugs.has(formData.productId)\n );\n const showCurrentModuleOption = Boolean(\n formData.moduleId && !customModuleEntry && !moduleOptionIds.has(formData.moduleId)\n );\n const showCurrentPageOption = Boolean(\n formData.pageId && !customPageEntry && !pageOptionIds.has(formData.pageId)\n );\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n try {\n if (tourId && tourId !== 'new') {\n await updateTour(tourId, formData);\n } else {\n await createTour(formData);\n }\n } catch {\n emitToursApiFailed(eventBus, 'tour.save', toursContext);\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/list`);\n };\n\n const formatDateTimeLocal = (value?: string) => {\n if (!value) return '';\n\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '';\n }\n\n return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, 16);\n };\n\n const handleSaveTemplate = async () => {\n if (!tourId || tourId === 'new') return;\n\n const defaultName = `${formData.name || tour?.name || 'Tour'} Template`;\n const name = window.prompt('Template name', defaultName);\n if (!name) return;\n\n const category =\n window.prompt(\n 'Template category (ONBOARDING, FEATURE_ANNOUNCEMENT, HELP, CUSTOM)',\n 'ONBOARDING'\n ) || 'ONBOARDING';\n\n try {\n await saveAsTemplate(tourId, {\n name,\n description: formData.description,\n category,\n isPublic: false,\n });\n navigate(`${basePath}/templates`);\n } catch {\n emitToursApiFailed(eventBus, 'template.save', toursContext);\n }\n };\n\n const handleSeedVibeControlsUserTours = async () => {\n const confirmed = window.confirm(tr('tourBuilder.seedVibeControls.confirm'));\n if (!confirmed) return;\n\n setSeedLoading(true);\n setSeedResult(null);\n setSeedError(null);\n\n try {\n const result = await globalClient.mutate<SeedVibeControlsUserToursMutation>({\n mutation: SEED_VIBECONTROLS_USER_TOURS,\n });\n\n const mutationErrorMessage = getMutationErrorMessage(result);\n if (mutationErrorMessage) {\n throw new Error(mutationErrorMessage);\n }\n\n const payload = result.data?.seedVibeControlsUserTours;\n if (!payload) {\n throw new Error('Seed mutation returned no result.');\n }\n\n setSeedResult(payload);\n } catch (seedMutationError) {\n const errorMessage =\n seedMutationError instanceof Error\n ? seedMutationError.message\n : tr('tourBuilder.seedVibeControls.error');\n setSeedError(errorMessage);\n eventBus.emit(\n 'tours.api.failed',\n {\n route: '/tours',\n operation: 'tour.seed_vibecontrols_user_tours',\n errorMessage,\n productId: toursContext.productId,\n workspaceId: toursContext.workspaceId,\n },\n { component: 'microfe-tours' }\n );\n } finally {\n setSeedLoading(false);\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6 max-w-4xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-4\">\n <button\n onClick={handleBack}\n className=\"p-2 hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">\n {tourId && tourId !== 'new'\n ? tr('tourBuilder.titleEdit')\n : tr('tourBuilder.titleCreate')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{tr('tourBuilder.subtitle')}</p>\n </div>\n </div>\n\n {isNew ? (\n <div className=\"rounded-md border border-border bg-card p-4 sm:p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('tourBuilder.seedVibeControls.title')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourBuilder.seedVibeControls.description')}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => void handleSeedVibeControlsUserTours()}\n disabled={seedLoading || !canSeedVibeControlsUserTours}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-md border border-border bg-secondary px-4 py-2 text-sm font-medium text-secondary-foreground hover:bg-secondary/80 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Sparkles size={18} />\n {seedLoading\n ? tr('tourBuilder.seedVibeControls.loading')\n : tr('tourBuilder.seedVibeControls.button')}\n </button>\n </div>\n {!canSeedVibeControlsUserTours ? (\n <p className=\"mt-3 text-sm text-muted-foreground\">\n {tr('tourBuilder.seedVibeControls.permissionHint')}\n </p>\n ) : null}\n {seedError ? <p className=\"mt-3 text-sm text-destructive\">{seedError}</p> : null}\n {seedResult ? (\n <div className=\"mt-3 rounded-md border border-border bg-background p-3 text-sm text-muted-foreground\">\n {tr('tourBuilder.seedVibeControls.result', {\n totalCount: seedResult.totalCount,\n productId: seedResult.productId,\n workspaceId: seedResult.workspaceId,\n createdCount: seedResult.createdCount,\n updatedCount: seedResult.updatedCount,\n })}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Basic Info */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionBasicInfo')}</h2>\n\n <div className=\"space-y-4\">\n {/* Name */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-name\">\n {tr('tourBuilder.labelName')}\n </label>\n <input\n id=\"tour-name\"\n type=\"text\"\n value={formData.name || ''}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n />\n </div>\n\n {/* Description */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-description\">\n {tr('tourBuilder.labelDescription')}\n </label>\n <textarea\n id=\"tour-description\"\n value={formData.description || ''}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n {/* Product ID */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"product-id\">\n {tr('tourBuilder.labelProductId')}\n </label>\n <select\n id=\"product-id\"\n value={customProductEntry ? '__custom__' : formData.productId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomProductEntry(true);\n setFormData({\n ...formData,\n productId: '',\n moduleId: undefined,\n pageId: undefined,\n });\n return;\n }\n\n setCustomProductEntry(false);\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n >\n <option value=\"\">Select product</option>\n {productsLoading ? <option disabled>Loading products...</option> : null}\n {productOptions.map((product) => (\n <option key={product.id} value={product.slug}>\n {product.name} ({product.slug})\n </option>\n ))}\n {showCurrentProductOption ? (\n <option value={formData.productId}>Current: {formData.productId}</option>\n ) : null}\n <option value=\"__custom__\">Custom product slug</option>\n </select>\n {customProductEntry ? (\n <input\n id=\"product-id-custom\"\n type=\"text\"\n value={formData.productId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n required\n />\n ) : null}\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"module-id\">\n Module ID\n </label>\n <select\n id=\"module-id\"\n value={customModuleEntry ? '__custom__' : formData.moduleId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomModuleEntry(true);\n setFormData({ ...formData, moduleId: '', pageId: undefined });\n return;\n }\n\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n >\n <option value=\"\">All modules</option>\n {moduleOptions.map((moduleOption) => (\n <option key={moduleOption.moduleId} value={moduleOption.moduleId}>\n {moduleOption.label} ({moduleOption.moduleId})\n </option>\n ))}\n {showCurrentModuleOption ? (\n <option value={formData.moduleId}>Current: {formData.moduleId}</option>\n ) : null}\n <option value=\"__custom__\">Custom module ID</option>\n </select>\n {customModuleEntry ? (\n <input\n id=\"module-id-custom\"\n type=\"text\"\n value={formData.moduleId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n />\n ) : null}\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"page-id\">\n Page ID\n </label>\n <select\n id=\"page-id\"\n value={customPageEntry ? '__custom__' : formData.pageId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomPageEntry(true);\n setFormData({ ...formData, pageId: '' });\n return;\n }\n\n setCustomPageEntry(false);\n setFormData({ ...formData, pageId: e.target.value || undefined });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n >\n <option value=\"\">All pages</option>\n {pageOptions.map((pageOption) => (\n <option key={pageOption.pageId} value={pageOption.pageId}>\n {pageOption.label} ({pageOption.pageId})\n </option>\n ))}\n {showCurrentPageOption ? (\n <option value={formData.pageId}>Current: {formData.pageId}</option>\n ) : null}\n <option value=\"__custom__\">Custom page ID</option>\n </select>\n {customPageEntry ? (\n <input\n id=\"page-id-custom\"\n type=\"text\"\n value={formData.pageId || ''}\n onChange={(e) =>\n setFormData({ ...formData, pageId: e.target.value || undefined })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"agents\"\n />\n ) : null}\n </div>\n </div>\n\n <label className=\"flex items-center gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.isActive ?? true}\n onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}\n className=\"w-4 h-4 rounded\"\n />\n <span className=\"text-sm font-medium\">Active</span>\n </label>\n </div>\n </div>\n\n {/* Trigger Settings */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionTriggerSettings')}</h2>\n\n <div className=\"space-y-4\">\n {/* Trigger Type */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"trigger-type\">\n {tr('tourBuilder.labelTriggerType')}\n </label>\n <select\n id=\"trigger-type\"\n value={formData.triggerType || 'MANUAL'}\n onChange={(e) =>\n setFormData({ ...formData, triggerType: e.target.value as TourTriggerType })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n >\n <option value=\"MANUAL\">{tr('tourBuilder.triggerManual')}</option>\n <option value=\"AUTO_FIRST_VISIT\">{tr('tourBuilder.triggerAutoFirstVisit')}</option>\n <option value=\"AUTO_ALWAYS\">{tr('tourBuilder.triggerAutoAlways')}</option>\n <option value=\"ON_EVENT\">{tr('tourBuilder.triggerOnEvent')}</option>\n <option value=\"SCHEDULED\">{tr('tourBuilder.triggerScheduled')}</option>\n </select>\n </div>\n\n {/* Priority */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"priority\">\n {tr('tourBuilder.labelPriority')}\n </label>\n <input\n id=\"priority\"\n type=\"number\"\n min=\"1\"\n max=\"100\"\n value={formData.priority || 50}\n onChange={(e) => {\n const priority = Number.parseInt(e.target.value, 10) || 50;\n setFormData({ ...formData, priority });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-start-date\">\n Start Date\n </label>\n <input\n id=\"tour-start-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.startDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n startDate: e.target.value\n ? new Date(e.target.value).toISOString()\n : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-end-date\">\n End Date\n </label>\n <input\n id=\"tour-end-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.endDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n endDate: e.target.value ? new Date(e.target.value).toISOString() : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n </div>\n </div>\n </div>\n\n {/* API Error */}\n {error && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">{tr('tourBuilder.errorTitle')}</h3>\n <p className=\"text-sm text-destructive\">{error.message}</p>\n </div>\n )}\n\n {/* Validation Errors */}\n {validationErrors.length > 0 && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">\n {tr('tourBuilder.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationErrors.map((err, index) => (\n <li key={index} className=\"text-sm text-destructive\">\n {err.message}\n </li>\n ))}\n </ul>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap gap-3\">\n <PermissionGate\n permission={isNew ? TOUR_PERMISSIONS.TOUR_CREATE : TOUR_PERMISSIONS.TOUR_UPDATE}\n >\n <button\n type=\"submit\"\n disabled={saving || !canSave}\n className=\"flex-1 min-w-[200px] px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center justify-center gap-2\"\n >\n <Save size={20} />\n {saving\n ? tr('tourBuilder.saving')\n : tourId && tourId !== 'new'\n ? tr('tourBuilder.updateTour')\n : tr('tourBuilder.createAndAddSteps')}\n </button>\n </PermissionGate>\n {tourId && tourId !== 'new' && (\n <>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/steps`)}\n className=\"px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/80 flex items-center gap-2\"\n >\n <ListOrdered size={20} />\n {tr('tourBuilder.editSteps')}\n {tour?.steps && tour.steps.length > 0 && (\n <span className=\"ml-1 px-2 py-0.5 text-xs bg-primary/20 rounded-full\">\n {tour.steps.length}\n </span>\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/preview`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Eye size={20} />\n {tr('tourBuilder.preview')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/analytics`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <BarChart3 size={20} />\n {tr('tourBuilder.analytics')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/schedule`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Calendar size={20} />\n Schedule\n </button>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE}>\n <button\n type=\"button\"\n onClick={handleSaveTemplate}\n disabled={!canCreateTemplate}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 disabled:opacity-50\"\n >\n <LayoutTemplate size={20} />\n Save as Template\n </button>\n </PermissionGate>\n </>\n )}\n </div>\n </form>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,IAAM,KAAgC,KAEhC,KAA+B,CAAG;;;;;;;;;;;;;;;;;;AAwCxC,SAAS,GAAwB,GAAgC;AAC/D,KAAI,CAAC,KAAU,OAAO,KAAW,SAAU,QAAO;CAElD,IAAM,IAAS,GACT,IAAc,EAAO;AAC3B,KAAI,aAAuB,MAAO,QAAO,EAAY;CAErD,IAAM,IAAS,EAAO;AACtB,KAAI,CAAC,MAAM,QAAQ,EAAO,IAAI,EAAO,WAAW,EAAG,QAAO;CAE1D,IAAM,IAAW,EACd,KAAK,MAAU;AACd,MAAI,aAAiB,MAAO,QAAO,EAAM;AACzC,MAAI,CAAC,KAAS,OAAO,KAAU,SAAU,QAAO;EAEhD,IAAM,IAAW,EAAgC;AACjD,SAAO,OAAO,KAAY,WAAW,IAAU;GAC/C,CACD,QAAQ,MAA+B,EAAQ,EAAS;AAE3D,QAAO,EAAS,SAAS,IAAI,EAAS,KAAK,KAAK,GAAG;;AAyBrD,IAAM,IAAuD;CAC3D;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAA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"}
|
|
1
|
+
{"version":3,"file":"TourBuilderPage.js","names":[],"sources":["../../../src/tours/pages/TourBuilderPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n Save,\n ArrowLeft,\n Eye,\n ListOrdered,\n BarChart3,\n Calendar,\n LayoutTemplate,\n Sparkles,\n} from 'lucide-react';\nimport { gql } from '@apollo/client/core';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { Tour, TourTriggerType } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\nimport { useGetPlatformProductsForToursQuery } from '../../generated/global-operations';\n\n// Covers the current platform catalog with room for planned products; custom slug entry remains the fallback.\nconst PLATFORM_PRODUCTS_QUERY_LIMIT = 250;\n\nconst SEED_VIBECONTROLS_USER_TOURS = gql`\n mutation SeedVibeControlsUserTours {\n seedVibeControlsUserTours {\n productId\n workspaceId\n createdCount\n updatedCount\n totalCount\n tours {\n tourId\n slug\n name\n action\n stepCount\n }\n }\n }\n`;\n\ninterface SeededUserTourResult {\n tourId: string;\n slug: string;\n name: string;\n action: string;\n stepCount: number;\n}\n\ninterface SeedVibeControlsUserToursPayload {\n productId: string;\n workspaceId: string;\n createdCount: number;\n updatedCount: number;\n totalCount: number;\n tours: SeededUserTourResult[];\n}\n\ninterface SeedVibeControlsUserToursMutation {\n seedVibeControlsUserTours: SeedVibeControlsUserToursPayload;\n}\n\nfunction getMutationErrorMessage(result: unknown): string | null {\n if (!result || typeof result !== 'object') return null;\n\n const record = result as Record<string, unknown>;\n const singleError = record.error;\n if (singleError instanceof Error) return singleError.message;\n\n const errors = record.errors;\n if (!Array.isArray(errors) || errors.length === 0) return null;\n\n const messages = errors\n .map((error) => {\n if (error instanceof Error) return error.message;\n if (!error || typeof error !== 'object') return null;\n\n const message = (error as { message?: unknown }).message;\n return typeof message === 'string' ? message : null;\n })\n .filter((message): message is string => Boolean(message));\n\n return messages.length > 0 ? messages.join('; ') : 'Seed mutation returned errors.';\n}\n\ninterface TourRouteModuleOption {\n moduleId: string;\n label: string;\n path: string;\n}\n\ninterface TourRoutePageOption {\n pageId: string;\n label: string;\n path: string;\n}\n\ninterface TourRouteCatalogEntry {\n productId: string;\n moduleId: string;\n moduleLabel: string;\n pageId: string;\n pageLabel: string;\n path: string;\n isModuleHome?: boolean;\n}\n\nconst TOUR_ROUTE_CATALOG: readonly TourRouteCatalogEntry[] = [\n {\n productId: 'vibecontrols',\n moduleId: 'dashboard',\n moduleLabel: 'Dashboard',\n pageId: 'dashboard',\n pageLabel: 'Dashboard',\n path: '/dashboard',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'home',\n pageLabel: 'Overview',\n path: '/vibecontrols',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'agents',\n pageLabel: 'Targets & Agents',\n path: '/vibecontrols/agents',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibes',\n pageLabel: 'Vibes',\n path: '/vibecontrols/vibes',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'sessions',\n pageLabel: 'Sessions',\n path: '/vibecontrols/sessions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'ai',\n pageLabel: 'AI',\n path: '/vibecontrols/ai',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'catalogs',\n pageLabel: 'Catalogs',\n path: '/vibecontrols/catalogs',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'components',\n pageLabel: 'Components',\n path: '/vibecontrols/components',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'templates',\n pageLabel: 'Templates',\n path: '/vibecontrols/templates',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'actions',\n pageLabel: 'Actions',\n path: '/vibecontrols/actions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibedeck',\n pageLabel: 'Decks',\n path: '/vibecontrols/vibedeck',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'calendar',\n pageLabel: 'Calendar',\n path: '/vibecontrols/calendar',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'tunnels',\n pageLabel: 'Tunnels',\n path: '/vibecontrols/tunnels',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'analytics',\n pageLabel: 'Analytics',\n path: '/vibecontrols/analytics',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'audit',\n pageLabel: 'Audit Log',\n path: '/vibecontrols/audit',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'health',\n pageLabel: 'Health',\n path: '/vibecontrols/health',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'settings',\n pageLabel: 'Settings',\n path: '/vibecontrols/settings',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'scheduler',\n moduleLabel: 'Scheduler',\n pageId: 'scheduler',\n pageLabel: 'Scheduler',\n path: '/scheduler',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'sandbox',\n moduleLabel: 'Sandbox',\n pageId: 'sandbox',\n pageLabel: 'Sandbox',\n path: '/sandbox',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'support',\n moduleLabel: 'Support',\n pageId: 'tickets',\n pageLabel: 'Tickets',\n path: '/support/tickets',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'support',\n moduleLabel: 'Support',\n pageId: 'knowledge-base',\n pageLabel: 'Knowledge Base',\n path: '/support/kb',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'notifications',\n moduleLabel: 'Notifications',\n pageId: 'center',\n pageLabel: 'Notification Center',\n path: '/notifications/center',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'notifications',\n moduleLabel: 'Notifications',\n pageId: 'history',\n pageLabel: 'History',\n path: '/notifications/history',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'notifications',\n moduleLabel: 'Notifications',\n pageId: 'preferences',\n pageLabel: 'Preferences',\n path: '/notifications/preferences',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'home',\n pageLabel: 'All Conversations',\n path: '/conversations',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'list',\n pageLabel: 'Conversation List',\n path: '/conversations/list',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'new',\n pageLabel: 'New Conversation',\n path: '/conversations/new',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'conversations',\n moduleLabel: 'Conversations',\n pageId: 'settings',\n pageLabel: 'Settings',\n path: '/conversations/settings',\n },\n] as const;\n\nfunction normalizeCatalogValue(value: string | null | undefined): string | undefined {\n const normalized = value?.trim();\n return normalized ? normalized : undefined;\n}\n\nfunction getRouteCatalog(productId: string | null | undefined): TourRouteCatalogEntry[] {\n const productKey = normalizeCatalogValue(productId);\n if (!productKey) return [];\n return TOUR_ROUTE_CATALOG.filter((entry) => entry.productId === productKey);\n}\n\nfunction getTourRouteModules(productId: string | null | undefined): TourRouteModuleOption[] {\n const modules = new Map<string, TourRouteModuleOption>();\n\n for (const entry of getRouteCatalog(productId)) {\n const existing = modules.get(entry.moduleId);\n if (!existing || entry.isModuleHome) {\n modules.set(entry.moduleId, {\n moduleId: entry.moduleId,\n label: entry.moduleLabel,\n path: entry.path,\n });\n }\n }\n\n return [...modules.values()];\n}\n\nfunction getTourRoutePages(\n productId: string | null | undefined,\n moduleId: string | null | undefined\n): TourRoutePageOption[] {\n const moduleKey = normalizeCatalogValue(moduleId);\n if (!moduleKey) return [];\n\n return getRouteCatalog(productId).flatMap((entry) =>\n entry.moduleId === moduleKey\n ? [{ pageId: entry.pageId, label: entry.pageLabel, path: entry.path }]\n : []\n );\n}\n\n/**\n * Tour builder page\n * Create or edit tour metadata\n */\nexport function TourBuilderPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const globalClient = useGatewayClient('global');\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const isNew = !tourId || tourId === 'new';\n const canCreate = hasPermission(TOUR_PERMISSIONS.TOUR_CREATE);\n const canUpdate = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canCreateTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE);\n const canSave = isNew ? canCreate : canUpdate;\n const canSeedVibeControlsUserTours = canCreate && canUpdate;\n\n const { tour, loadTour, createTour, updateTour, saving, validationErrors, error } =\n useTourBuilder(tourId);\n const { saveAsTemplate } = useTourLifecycle();\n const { data: productsData, loading: productsLoading } = useGetPlatformProductsForToursQuery({\n variables: { limit: PLATFORM_PRODUCTS_QUERY_LIMIT, offset: 0 },\n fetchPolicy: 'cache-and-network',\n skip: permissionsLoading || !canSave,\n });\n\n const defaultFormData = {\n name: '',\n description: '',\n productId: '',\n moduleId: '',\n pageId: '',\n isActive: true,\n status: 'DRAFT' as const,\n triggerType: 'MANUAL' as const,\n priority: 50,\n displayOrder: 1,\n startDate: '',\n endDate: '',\n };\n\n const [formData, setFormData] = useState<Partial<Tour>>(defaultFormData);\n const [customProductEntry, setCustomProductEntry] = useState(false);\n const [customModuleEntry, setCustomModuleEntry] = useState(false);\n const [customPageEntry, setCustomPageEntry] = useState(false);\n const [seedLoading, setSeedLoading] = useState(false);\n const [seedResult, setSeedResult] = useState<SeedVibeControlsUserToursPayload | null>(null);\n const [seedError, setSeedError] = useState<string | null>(null);\n\n const formInitializedRef = useRef(false);\n\n const productOptions = useMemo(() => {\n return [...(productsData?.platformProducts.items ?? [])].sort((a, b) =>\n a.name.localeCompare(b.name)\n );\n }, [productsData]);\n\n const productOptionSlugs = useMemo(\n () => new Set(productOptions.map((product) => product.slug)),\n [productOptions]\n );\n\n const moduleOptions = useMemo(\n () => getTourRouteModules(formData.productId),\n [formData.productId]\n );\n\n const moduleOptionIds = useMemo(\n () => new Set(moduleOptions.map((moduleOption) => moduleOption.moduleId)),\n [moduleOptions]\n );\n\n const pageOptions = useMemo(\n () => getTourRoutePages(formData.productId, formData.moduleId),\n [formData.moduleId, formData.productId]\n );\n\n const pageOptionIds = useMemo(\n () => new Set(pageOptions.map((pageOption) => pageOption.pageId)),\n [pageOptions]\n );\n\n useEffect(() => {\n if (formInitializedRef.current) return;\n if (!permissionsLoading && canSave && tourId && tourId !== 'new') {\n loadTour(tourId);\n }\n }, [canSave, loadTour, permissionsLoading, tourId]);\n\n useEffect(() => {\n if (tour && !formInitializedRef.current) {\n setFormData(tour);\n formInitializedRef.current = true;\n }\n }, [tour]);\n\n useEffect(() => {\n if (!formData.productId || productsLoading) {\n setCustomProductEntry(false);\n return;\n }\n setCustomProductEntry(productOptions.length > 0 && !productOptionSlugs.has(formData.productId));\n }, [formData.productId, productOptionSlugs, productOptions.length, productsLoading]);\n\n useEffect(() => {\n if (!formData.productId || !formData.moduleId) {\n setCustomModuleEntry(false);\n return;\n }\n setCustomModuleEntry(moduleOptions.length === 0 || !moduleOptionIds.has(formData.moduleId));\n }, [formData.moduleId, formData.productId, moduleOptionIds, moduleOptions.length]);\n\n useEffect(() => {\n if (!formData.productId || !formData.pageId) {\n setCustomPageEntry(false);\n return;\n }\n setCustomPageEntry(pageOptions.length === 0 || !pageOptionIds.has(formData.pageId));\n }, [formData.pageId, formData.productId, pageOptionIds, pageOptions.length]);\n\n const showCurrentProductOption = Boolean(\n formData.productId && !customProductEntry && !productOptionSlugs.has(formData.productId)\n );\n const showCurrentModuleOption = Boolean(\n formData.moduleId && !customModuleEntry && !moduleOptionIds.has(formData.moduleId)\n );\n const showCurrentPageOption = Boolean(\n formData.pageId && !customPageEntry && !pageOptionIds.has(formData.pageId)\n );\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n try {\n if (tourId && tourId !== 'new') {\n await updateTour(tourId, formData);\n } else {\n await createTour(formData);\n }\n } catch {\n emitToursApiFailed(eventBus, 'tour.save', toursContext);\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/list`);\n };\n\n const formatDateTimeLocal = (value?: string) => {\n if (!value) return '';\n\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '';\n }\n\n return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, 16);\n };\n\n const handleSaveTemplate = async () => {\n if (!tourId || tourId === 'new') return;\n\n const defaultName = `${formData.name || tour?.name || 'Tour'} Template`;\n const name = window.prompt('Template name', defaultName);\n if (!name) return;\n\n const category =\n window.prompt(\n 'Template category (ONBOARDING, FEATURE_ANNOUNCEMENT, HELP, CUSTOM)',\n 'ONBOARDING'\n ) || 'ONBOARDING';\n\n try {\n await saveAsTemplate(tourId, {\n name,\n description: formData.description,\n category,\n isPublic: false,\n });\n navigate(`${basePath}/templates`);\n } catch {\n emitToursApiFailed(eventBus, 'template.save', toursContext);\n }\n };\n\n const handleSeedVibeControlsUserTours = async () => {\n const confirmed = window.confirm(tr('tourBuilder.seedVibeControls.confirm'));\n if (!confirmed) return;\n\n setSeedLoading(true);\n setSeedResult(null);\n setSeedError(null);\n\n try {\n const result = await globalClient.mutate<SeedVibeControlsUserToursMutation>({\n mutation: SEED_VIBECONTROLS_USER_TOURS,\n });\n\n const mutationErrorMessage = getMutationErrorMessage(result);\n if (mutationErrorMessage) {\n throw new Error(mutationErrorMessage);\n }\n\n const payload = result.data?.seedVibeControlsUserTours;\n if (!payload) {\n throw new Error('Seed mutation returned no result.');\n }\n\n setSeedResult(payload);\n } catch (seedMutationError) {\n const errorMessage =\n seedMutationError instanceof Error\n ? seedMutationError.message\n : tr('tourBuilder.seedVibeControls.error');\n setSeedError(errorMessage);\n eventBus.emit(\n 'tours.api.failed',\n {\n route: '/tours',\n operation: 'tour.seed_vibecontrols_user_tours',\n errorMessage,\n productId: toursContext.productId,\n workspaceId: toursContext.workspaceId,\n },\n { component: 'microfe-tours' }\n );\n } finally {\n setSeedLoading(false);\n }\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"flex h-full items-center justify-center p-3 sm:p-6\">\n <p className=\"text-sm text-muted-foreground\">{tr('tourBuilder.loading')}</p>\n </div>\n );\n }\n\n if (!canSave) {\n return (\n <div className=\"flex h-full items-center justify-center p-3 sm:p-6\">\n <div className=\"text-center space-y-4\">\n <div>\n <h2 className=\"text-lg font-semibold text-foreground mb-2\">\n {tr('tourBuilder.accessDeniedTitle')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {isNew\n ? tr('tourBuilder.createAccessDeniedMessage')\n : tr('tourBuilder.updateAccessDeniedMessage')}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"inline-flex items-center justify-center rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-accent\"\n >\n {tr('tourBuilder.goBack')}\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6 max-w-4xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">\n {tourId && tourId !== 'new'\n ? tr('tourBuilder.titleEdit')\n : tr('tourBuilder.titleCreate')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{tr('tourBuilder.subtitle')}</p>\n </div>\n </div>\n\n {isNew ? (\n <div className=\"rounded-md border border-border bg-card p-4 sm:p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('tourBuilder.seedVibeControls.title')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourBuilder.seedVibeControls.description')}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => void handleSeedVibeControlsUserTours()}\n disabled={seedLoading || !canSeedVibeControlsUserTours}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-md border border-border bg-secondary px-4 py-2 text-sm font-medium text-secondary-foreground hover:bg-secondary/80 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Sparkles size={18} />\n {seedLoading\n ? tr('tourBuilder.seedVibeControls.loading')\n : tr('tourBuilder.seedVibeControls.button')}\n </button>\n </div>\n {!canSeedVibeControlsUserTours ? (\n <p className=\"mt-3 text-sm text-muted-foreground\">\n {tr('tourBuilder.seedVibeControls.permissionHint')}\n </p>\n ) : null}\n {seedError ? <p className=\"mt-3 text-sm text-destructive\">{seedError}</p> : null}\n {seedResult ? (\n <div className=\"mt-3 rounded-md border border-border bg-background p-3 text-sm text-muted-foreground\">\n {tr('tourBuilder.seedVibeControls.result', {\n totalCount: seedResult.totalCount,\n productId: seedResult.productId,\n workspaceId: seedResult.workspaceId,\n createdCount: seedResult.createdCount,\n updatedCount: seedResult.updatedCount,\n })}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Basic Info */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionBasicInfo')}</h2>\n\n <div className=\"space-y-4\">\n {/* Name */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-name\">\n {tr('tourBuilder.labelName')}\n </label>\n <input\n id=\"tour-name\"\n type=\"text\"\n value={formData.name || ''}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n aria-label={tr('tourBuilder.labelName')}\n />\n </div>\n\n {/* Description */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-description\">\n {tr('tourBuilder.labelDescription')}\n </label>\n <textarea\n id=\"tour-description\"\n value={formData.description || ''}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n aria-label={tr('tourBuilder.labelDescription')}\n />\n </div>\n\n {/* Product ID */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"product-id\">\n {tr('tourBuilder.labelProductId')}\n </label>\n <select\n id=\"product-id\"\n value={customProductEntry ? '__custom__' : formData.productId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomProductEntry(true);\n setFormData({\n ...formData,\n productId: '',\n moduleId: undefined,\n pageId: undefined,\n });\n return;\n }\n\n setCustomProductEntry(false);\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n aria-label={tr('tourBuilder.labelProductId')}\n >\n <option value=\"\">Select product</option>\n {productsLoading ? <option disabled>Loading products…</option> : null}\n {productOptions.map((product) => (\n <option key={product.id} value={product.slug}>\n {product.name} ({product.slug})\n </option>\n ))}\n {showCurrentProductOption ? (\n <option value={formData.productId}>Current: {formData.productId}</option>\n ) : null}\n <option value=\"__custom__\">Custom product slug</option>\n </select>\n {customProductEntry ? (\n <input\n id=\"product-id-custom\"\n aria-label=\"Custom product slug\"\n type=\"text\"\n value={formData.productId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n required\n />\n ) : null}\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"module-id\">\n Module ID\n </label>\n <select\n id=\"module-id\"\n value={customModuleEntry ? '__custom__' : formData.moduleId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomModuleEntry(true);\n setFormData({ ...formData, moduleId: '', pageId: undefined });\n return;\n }\n\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n aria-label=\"Module ID\"\n >\n <option value=\"\">All modules</option>\n {moduleOptions.map((moduleOption) => (\n <option key={moduleOption.moduleId} value={moduleOption.moduleId}>\n {moduleOption.label} ({moduleOption.moduleId})\n </option>\n ))}\n {showCurrentModuleOption ? (\n <option value={formData.moduleId}>Current: {formData.moduleId}</option>\n ) : null}\n <option value=\"__custom__\">Custom module ID</option>\n </select>\n {customModuleEntry ? (\n <input\n id=\"module-id-custom\"\n aria-label=\"Custom module ID\"\n type=\"text\"\n value={formData.moduleId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n />\n ) : null}\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"page-id\">\n Page ID\n </label>\n <select\n id=\"page-id\"\n value={customPageEntry ? '__custom__' : formData.pageId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomPageEntry(true);\n setFormData({ ...formData, pageId: '' });\n return;\n }\n\n setCustomPageEntry(false);\n setFormData({ ...formData, pageId: e.target.value || undefined });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n aria-label=\"Page ID\"\n >\n <option value=\"\">All pages</option>\n {pageOptions.map((pageOption) => (\n <option key={pageOption.pageId} value={pageOption.pageId}>\n {pageOption.label} ({pageOption.pageId})\n </option>\n ))}\n {showCurrentPageOption ? (\n <option value={formData.pageId}>Current: {formData.pageId}</option>\n ) : null}\n <option value=\"__custom__\">Custom page ID</option>\n </select>\n {customPageEntry ? (\n <input\n id=\"page-id-custom\"\n aria-label=\"Custom page ID\"\n type=\"text\"\n value={formData.pageId || ''}\n onChange={(e) =>\n setFormData({ ...formData, pageId: e.target.value || undefined })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"agents\"\n />\n ) : null}\n </div>\n </div>\n\n <label className=\"flex items-center gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.isActive ?? true}\n onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}\n className=\"size-4 rounded\"\n aria-label=\"Active\"\n />\n <span className=\"text-sm font-medium\">Active</span>\n </label>\n </div>\n </div>\n\n {/* Trigger Settings */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionTriggerSettings')}</h2>\n\n <div className=\"space-y-4\">\n {/* Trigger Type */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"trigger-type\">\n {tr('tourBuilder.labelTriggerType')}\n </label>\n <select\n id=\"trigger-type\"\n value={formData.triggerType || 'MANUAL'}\n onChange={(e) =>\n setFormData({ ...formData, triggerType: e.target.value as TourTriggerType })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n aria-label={tr('tourBuilder.labelTriggerType')}\n >\n <option value=\"MANUAL\">{tr('tourBuilder.triggerManual')}</option>\n <option value=\"AUTO_FIRST_VISIT\">{tr('tourBuilder.triggerAutoFirstVisit')}</option>\n <option value=\"AUTO_ALWAYS\">{tr('tourBuilder.triggerAutoAlways')}</option>\n <option value=\"ON_EVENT\">{tr('tourBuilder.triggerOnEvent')}</option>\n <option value=\"SCHEDULED\">{tr('tourBuilder.triggerScheduled')}</option>\n </select>\n </div>\n\n {/* Priority */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"priority\">\n {tr('tourBuilder.labelPriority')}\n </label>\n <input\n id=\"priority\"\n type=\"number\"\n min=\"1\"\n max=\"100\"\n value={formData.priority || 50}\n onChange={(e) => {\n const priority = Number.parseInt(e.target.value, 10) || 50;\n setFormData({ ...formData, priority });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n aria-label={tr('tourBuilder.labelPriority')}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-start-date\">\n Start Date\n </label>\n <input\n id=\"tour-start-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.startDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n startDate: e.target.value\n ? new Date(e.target.value).toISOString()\n : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n aria-label=\"Start Date\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-end-date\">\n End Date\n </label>\n <input\n id=\"tour-end-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.endDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n endDate: e.target.value ? new Date(e.target.value).toISOString() : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n aria-label=\"End Date\"\n />\n </div>\n </div>\n </div>\n </div>\n\n {/* API Error */}\n {error && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">{tr('tourBuilder.errorTitle')}</h3>\n <p className=\"text-sm text-destructive\">{error.message}</p>\n </div>\n )}\n\n {/* Validation Errors */}\n {validationErrors.length > 0 && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">\n {tr('tourBuilder.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationErrors.map((err) => (\n <li key={err.message} className=\"text-sm text-destructive\">\n {err.message}\n </li>\n ))}\n </ul>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap gap-3\">\n <PermissionGate\n permission={isNew ? TOUR_PERMISSIONS.TOUR_CREATE : TOUR_PERMISSIONS.TOUR_UPDATE}\n >\n <button\n type=\"submit\"\n disabled={saving || !canSave}\n className=\"flex-1 min-w-[200px] px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center justify-center gap-2\"\n >\n <Save size={20} />\n {saving\n ? tr('tourBuilder.saving')\n : tourId && tourId !== 'new'\n ? tr('tourBuilder.updateTour')\n : tr('tourBuilder.createAndAddSteps')}\n </button>\n </PermissionGate>\n {tourId && tourId !== 'new' && (\n <>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/steps`)}\n className=\"px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/80 flex items-center gap-2\"\n >\n <ListOrdered size={20} />\n {tr('tourBuilder.editSteps')}\n {tour?.steps && tour.steps.length > 0 && (\n <span className=\"ml-1 px-2 py-0.5 text-xs bg-primary/20 rounded-full\">\n {tour.steps.length}\n </span>\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/preview`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Eye size={20} />\n {tr('tourBuilder.preview')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/analytics`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <BarChart3 size={20} />\n {tr('tourBuilder.analytics')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/schedule`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Calendar size={20} />\n Schedule\n </button>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE}>\n <button\n type=\"button\"\n onClick={handleSaveTemplate}\n disabled={!canCreateTemplate}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 disabled:opacity-50\"\n >\n <LayoutTemplate size={20} />\n Save as Template\n </button>\n </PermissionGate>\n </>\n )}\n </div>\n </form>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,IAAM,KAAgC,KAEhC,KAA+B,CAAG;;;;;;;;;;;;;;;;;;AAwCxC,SAAS,GAAwB,GAAgC;AAC/D,KAAI,CAAC,KAAU,OAAO,KAAW,SAAU,QAAO;CAElD,IAAM,IAAS,GACT,IAAc,EAAO;AAC3B,KAAI,aAAuB,MAAO,QAAO,EAAY;CAErD,IAAM,IAAS,EAAO;AACtB,KAAI,CAAC,MAAM,QAAQ,EAAO,IAAI,EAAO,WAAW,EAAG,QAAO;CAE1D,IAAM,IAAW,EACd,KAAK,MAAU;AACd,MAAI,aAAiB,MAAO,QAAO,EAAM;AACzC,MAAI,CAAC,KAAS,OAAO,KAAU,SAAU,QAAO;EAEhD,IAAM,IAAW,EAAgC;AACjD,SAAO,OAAO,KAAY,WAAW,IAAU;GAC/C,CACD,QAAQ,MAA+B,EAAQ,EAAS;AAE3D,QAAO,EAAS,SAAS,IAAI,EAAS,KAAK,KAAK,GAAG;;AAyBrD,IAAM,IAAuD;CAC3D;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAA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"}
|
|
@@ -54,6 +54,7 @@ function x() {
|
|
|
54
54
|
className: "border-b border-border bg-background p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4",
|
|
55
55
|
children: [
|
|
56
56
|
/* @__PURE__ */ _("button", {
|
|
57
|
+
type: "button",
|
|
57
58
|
onClick: U,
|
|
58
59
|
className: "p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md",
|
|
59
60
|
"aria-label": x("tourBuilder.goBack"),
|
|
@@ -88,6 +89,7 @@ function x() {
|
|
|
88
89
|
"tablet",
|
|
89
90
|
"desktop"
|
|
90
91
|
].map((e) => /* @__PURE__ */ _("button", {
|
|
92
|
+
type: "button",
|
|
91
93
|
onClick: () => V(e),
|
|
92
94
|
className: `px-3 py-2 min-h-[44px] min-w-[44px] ${k === e ? "bg-primary text-primary-foreground" : "bg-background hover:bg-accent"}`,
|
|
93
95
|
title: x(e === "mobile" ? "tourPreview.deviceMobile" : e === "tablet" ? "tourPreview.deviceTablet" : "tourPreview.deviceDesktop"),
|
|
@@ -96,10 +98,12 @@ function x() {
|
|
|
96
98
|
}, e))
|
|
97
99
|
}),
|
|
98
100
|
A ? /* @__PURE__ */ v("button", {
|
|
101
|
+
type: "button",
|
|
99
102
|
onClick: R,
|
|
100
103
|
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent flex items-center gap-2",
|
|
101
104
|
children: [/* @__PURE__ */ _(g, { size: 20 }), x("tourPreview.stopPreview")]
|
|
102
105
|
}) : /* @__PURE__ */ _("button", {
|
|
106
|
+
type: "button",
|
|
103
107
|
onClick: L,
|
|
104
108
|
disabled: !I?.valid,
|
|
105
109
|
className: "px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50",
|
|
@@ -121,10 +125,10 @@ function x() {
|
|
|
121
125
|
children: x("tourPreview.validationErrorsTitle")
|
|
122
126
|
}), /* @__PURE__ */ _("ul", {
|
|
123
127
|
className: "list-disc list-inside space-y-1",
|
|
124
|
-
children: I.errors.map((e
|
|
128
|
+
children: I.errors.map((e) => /* @__PURE__ */ _("li", {
|
|
125
129
|
className: "text-sm text-destructive",
|
|
126
130
|
children: e
|
|
127
|
-
},
|
|
131
|
+
}, e))
|
|
128
132
|
})]
|
|
129
133
|
})]
|
|
130
134
|
})
|
|
@@ -143,10 +147,10 @@ function x() {
|
|
|
143
147
|
children: x("tourPreview.warningsTitle")
|
|
144
148
|
}), /* @__PURE__ */ _("ul", {
|
|
145
149
|
className: "list-disc list-inside space-y-1",
|
|
146
|
-
children: I.warnings.map((e
|
|
150
|
+
children: I.warnings.map((e) => /* @__PURE__ */ _("li", {
|
|
147
151
|
className: "text-sm text-warning",
|
|
148
152
|
children: e
|
|
149
|
-
},
|
|
153
|
+
}, e))
|
|
150
154
|
})]
|
|
151
155
|
})]
|
|
152
156
|
})
|
|
@@ -171,12 +175,14 @@ function x() {
|
|
|
171
175
|
/* @__PURE__ */ v("div", {
|
|
172
176
|
className: "flex gap-2",
|
|
173
177
|
children: [/* @__PURE__ */ _("button", {
|
|
178
|
+
type: "button",
|
|
174
179
|
onClick: B,
|
|
175
180
|
disabled: !F,
|
|
176
181
|
className: "px-3 py-2 min-h-[44px] min-w-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed",
|
|
177
182
|
"aria-label": x("tourPreview.previous"),
|
|
178
183
|
children: /* @__PURE__ */ _(d, { size: 16 })
|
|
179
184
|
}), /* @__PURE__ */ _("button", {
|
|
185
|
+
type: "button",
|
|
180
186
|
onClick: z,
|
|
181
187
|
disabled: !P,
|
|
182
188
|
className: "flex-1 px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
@@ -211,6 +217,7 @@ function x() {
|
|
|
211
217
|
className: "border-t border-border bg-background p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4",
|
|
212
218
|
children: [
|
|
213
219
|
/* @__PURE__ */ v("button", {
|
|
220
|
+
type: "button",
|
|
214
221
|
onClick: B,
|
|
215
222
|
disabled: !F,
|
|
216
223
|
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
@@ -225,6 +232,7 @@ function x() {
|
|
|
225
232
|
]
|
|
226
233
|
}),
|
|
227
234
|
/* @__PURE__ */ v("button", {
|
|
235
|
+
type: "button",
|
|
228
236
|
onClick: z,
|
|
229
237
|
disabled: !P,
|
|
230
238
|
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourPreviewPage.js","names":[],"sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n ChevronLeft,\n ChevronRight,\n X,\n Smartphone,\n Tablet,\n Monitor,\n CheckCircle,\n AlertCircle,\n} from 'lucide-react';\nimport { useTourPreview } from '../hooks/useTourPreview';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursStore } from '../store/toursStore';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\n\n/**\n * Tour preview page\n * Preview tour with device simulation and validation\n */\nexport function TourPreviewPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const { hasPermission } = useToursPermissionAccess();\n const canReadTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const { tour, loadTour } = useTourBuilder(tourId);\n const { devicePreview } = useToursStore();\n\n const {\n isPreviewActive,\n currentStepIndex,\n currentStep,\n totalSteps,\n canGoNext,\n canGoPrevious,\n validationResults,\n startPreview,\n stopPreview,\n nextStep,\n previousStep,\n changeDevice,\n validateForPreview,\n } = useTourPreview(tour || undefined);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour) {\n validateForPreview();\n }\n }, [tour, devicePreview, validateForPreview]);\n\n if (!canReadTour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-foreground mb-2\">\n {tr('tourPreview.accessDeniedTitle')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{tr('tourPreview.accessDeniedMessage')}</p>\n </div>\n </div>\n );\n }\n\n if (!tour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <p className=\"text-muted-foreground\">{tr('tourPreview.loading')}</p>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const deviceIcons = {\n mobile: <Smartphone size={20} />,\n tablet: <Tablet size={20} />,\n desktop: <Monitor size={20} />,\n };\n\n return (\n <div className=\"flex flex-col h-screen bg-muted\">\n {/* Header */}\n <div className=\"border-b border-border bg-background p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4\">\n <button\n onClick={handleBack}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1 min-w-[12rem]\">\n <h1 className=\"text-base sm:text-lg font-semibold truncate\">\n {tour?.name} - {tr('tourPreview.previewSuffix')}\n </h1>\n {isPreviewActive && (\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourPreview.stepOf')} {currentStepIndex + 1} {tr('tourPreview.stepOfConnector')}{' '}\n {totalSteps}\n </p>\n )}\n </div>\n\n {/* Device Selector */}\n <div className=\"flex gap-2 border border-border rounded-md overflow-hidden\">\n {(['mobile', 'tablet', 'desktop'] as const).map((device) => (\n <button\n key={device}\n onClick={() => changeDevice(device)}\n className={`px-3 py-2 min-h-[44px] min-w-[44px] ${\n devicePreview === device\n ? 'bg-primary text-primary-foreground'\n : 'bg-background hover:bg-accent'\n }`}\n title={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n aria-label={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n >\n {deviceIcons[device]}\n </button>\n ))}\n </div>\n\n {/* Preview Controls */}\n {!isPreviewActive ? (\n <button\n onClick={startPreview}\n disabled={!validationResults?.valid}\n className=\"px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50\"\n >\n {tr('tourPreview.startPreview')}\n </button>\n ) : (\n <button\n onClick={stopPreview}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <X size={20} />\n {tr('tourPreview.stopPreview')}\n </button>\n )}\n </div>\n\n {/* Validation Results */}\n {validationResults && !validationResults.valid && (\n <div className=\"bg-destructive/10 border-b border-destructive px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-destructive flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-destructive mb-1\">\n {tr('tourPreview.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.errors.map((error, index) => (\n <li key={index} className=\"text-sm text-destructive\">\n {error}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Warnings */}\n {validationResults && validationResults.warnings.length > 0 && (\n <div className=\"bg-warning/10 border-b border-warning px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-warning flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-warning mb-1\">{tr('tourPreview.warningsTitle')}</h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.warnings.map((warning, index) => (\n <li key={index} className=\"text-sm text-warning\">\n {warning}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Preview Area */}\n <div className=\"flex-1 flex items-center justify-center p-3 sm:p-6 overflow-auto\">\n <div\n className={`bg-background border-2 rounded-lg shadow-xl overflow-hidden ${\n devicePreview === 'mobile'\n ? 'w-[min(375px,calc(100vw-1.5rem))] h-[667px] max-h-full'\n : devicePreview === 'tablet'\n ? 'w-[min(768px,calc(100vw-1.5rem))] h-[1024px] max-h-full'\n : 'w-full max-w-[1920px] h-full max-h-[1080px]'\n }`}\n >\n {isPreviewActive && currentStep ? (\n <div className=\"h-full flex flex-col items-center justify-center p-4 sm:p-8\">\n {/* Simulated Tour Tooltip */}\n <div className=\"max-w-md border border-border rounded-lg shadow-lg bg-card p-4 sm:p-6\">\n <h3 className=\"text-lg font-semibold mb-3\">{currentStep.title}</h3>\n <p className=\"text-sm text-muted-foreground mb-4 whitespace-pre-wrap\">\n {currentStep.content}\n </p>\n <div className=\"flex gap-2\">\n <button\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-3 py-2 min-h-[44px] min-w-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label={tr('tourPreview.previous')}\n >\n <ChevronLeft size={16} />\n </button>\n <button\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"flex-1 px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {canGoNext ? tr('tourPreview.next') : tr('tourPreview.finish')}\n </button>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"h-full flex items-center justify-center text-muted-foreground\">\n <div className=\"text-center\">\n <CheckCircle className=\"mx-auto mb-4\" size={48} />\n <p className=\"mb-2\">{tr('tourPreview.readyTitle')}</p>\n <p className=\"text-sm\">{tr('tourPreview.readyHint')}</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer Controls */}\n {isPreviewActive && (\n <div className=\"border-t border-border bg-background p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4\">\n <button\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n <ChevronLeft size={20} />\n {tr('tourPreview.previous')}\n </button>\n <div className=\"text-sm text-muted-foreground\">\n {currentStepIndex + 1} / {totalSteps}\n </div>\n <button\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {tr('tourPreview.nextFooter')}\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TourPreviewPage.js","names":[],"sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n ChevronLeft,\n ChevronRight,\n X,\n Smartphone,\n Tablet,\n Monitor,\n CheckCircle,\n AlertCircle,\n} from 'lucide-react';\nimport { useTourPreview } from '../hooks/useTourPreview';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursStore } from '../store/toursStore';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\n\n/**\n * Tour preview page\n * Preview tour with device simulation and validation\n */\nexport function TourPreviewPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const { hasPermission } = useToursPermissionAccess();\n const canReadTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const { tour, loadTour } = useTourBuilder(tourId);\n const { devicePreview } = useToursStore();\n\n const {\n isPreviewActive,\n currentStepIndex,\n currentStep,\n totalSteps,\n canGoNext,\n canGoPrevious,\n validationResults,\n startPreview,\n stopPreview,\n nextStep,\n previousStep,\n changeDevice,\n validateForPreview,\n } = useTourPreview(tour || undefined);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour) {\n validateForPreview();\n }\n }, [tour, devicePreview, validateForPreview]);\n\n if (!canReadTour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-foreground mb-2\">\n {tr('tourPreview.accessDeniedTitle')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{tr('tourPreview.accessDeniedMessage')}</p>\n </div>\n </div>\n );\n }\n\n if (!tour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <p className=\"text-muted-foreground\">{tr('tourPreview.loading')}</p>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const deviceIcons = {\n mobile: <Smartphone size={20} />,\n tablet: <Tablet size={20} />,\n desktop: <Monitor size={20} />,\n };\n\n return (\n <div className=\"flex flex-col h-screen bg-muted\">\n {/* Header */}\n <div className=\"border-b border-border bg-background p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1 min-w-[12rem]\">\n <h1 className=\"text-base sm:text-lg font-semibold truncate\">\n {tour?.name} - {tr('tourPreview.previewSuffix')}\n </h1>\n {isPreviewActive && (\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourPreview.stepOf')} {currentStepIndex + 1} {tr('tourPreview.stepOfConnector')}{' '}\n {totalSteps}\n </p>\n )}\n </div>\n\n {/* Device Selector */}\n <div className=\"flex gap-2 border border-border rounded-md overflow-hidden\">\n {(['mobile', 'tablet', 'desktop'] as const).map((device) => (\n <button\n type=\"button\"\n key={device}\n onClick={() => changeDevice(device)}\n className={`px-3 py-2 min-h-[44px] min-w-[44px] ${\n devicePreview === device\n ? 'bg-primary text-primary-foreground'\n : 'bg-background hover:bg-accent'\n }`}\n title={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n aria-label={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n >\n {deviceIcons[device]}\n </button>\n ))}\n </div>\n\n {/* Preview Controls */}\n {!isPreviewActive ? (\n <button\n type=\"button\"\n onClick={startPreview}\n disabled={!validationResults?.valid}\n className=\"px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50\"\n >\n {tr('tourPreview.startPreview')}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={stopPreview}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <X size={20} />\n {tr('tourPreview.stopPreview')}\n </button>\n )}\n </div>\n\n {/* Validation Results */}\n {validationResults && !validationResults.valid && (\n <div className=\"bg-destructive/10 border-b border-destructive px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-destructive flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-destructive mb-1\">\n {tr('tourPreview.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.errors.map((error) => (\n <li key={error} className=\"text-sm text-destructive\">\n {error}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Warnings */}\n {validationResults && validationResults.warnings.length > 0 && (\n <div className=\"bg-warning/10 border-b border-warning px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-warning flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-warning mb-1\">{tr('tourPreview.warningsTitle')}</h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.warnings.map((warning) => (\n <li key={warning} className=\"text-sm text-warning\">\n {warning}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Preview Area */}\n <div className=\"flex-1 flex items-center justify-center p-3 sm:p-6 overflow-auto\">\n <div\n className={`bg-background border-2 rounded-lg shadow-xl overflow-hidden ${\n devicePreview === 'mobile'\n ? 'w-[min(375px,calc(100vw-1.5rem))] h-[667px] max-h-full'\n : devicePreview === 'tablet'\n ? 'w-[min(768px,calc(100vw-1.5rem))] h-[1024px] max-h-full'\n : 'w-full max-w-[1920px] h-full max-h-[1080px]'\n }`}\n >\n {isPreviewActive && currentStep ? (\n <div className=\"h-full flex flex-col items-center justify-center p-4 sm:p-8\">\n {/* Simulated Tour Tooltip */}\n <div className=\"max-w-md border border-border rounded-lg shadow-lg bg-card p-4 sm:p-6\">\n <h3 className=\"text-lg font-semibold mb-3\">{currentStep.title}</h3>\n <p className=\"text-sm text-muted-foreground mb-4 whitespace-pre-wrap\">\n {currentStep.content}\n </p>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-3 py-2 min-h-[44px] min-w-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label={tr('tourPreview.previous')}\n >\n <ChevronLeft size={16} />\n </button>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"flex-1 px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {canGoNext ? tr('tourPreview.next') : tr('tourPreview.finish')}\n </button>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"h-full flex items-center justify-center text-muted-foreground\">\n <div className=\"text-center\">\n <CheckCircle className=\"mx-auto mb-4\" size={48} />\n <p className=\"mb-2\">{tr('tourPreview.readyTitle')}</p>\n <p className=\"text-sm\">{tr('tourPreview.readyHint')}</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer Controls */}\n {isPreviewActive && (\n <div className=\"border-t border-border bg-background p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4\">\n <button\n type=\"button\"\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n <ChevronLeft size={20} />\n {tr('tourPreview.previous')}\n </button>\n <div className=\"text-sm text-muted-foreground\">\n {currentStepIndex + 1} / {totalSteps}\n </div>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {tr('tourPreview.nextFooter')}\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|