@burdenoff/microfe-tours 2026.1014.1 → 2026.1109.1
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/constants/featureFlags.d.ts +24 -0
- package/dist/constants/featureFlags.js +1 -2
- package/dist/constants/featureFlags.js.map +1 -1
- package/dist/constants/permissions.d.ts +48 -0
- package/dist/constants/permissions.js +1 -2
- package/dist/constants/permissions.js.map +1 -1
- package/dist/dev/main.d.ts +0 -0
- package/dist/generated/global-operations.d.ts +1318 -0
- package/dist/generated/global-operations.js +2 -3
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.d.ts +26469 -0
- package/dist/generated/wspace-operations.d.ts +1 -0
- package/dist/generated/wspace-types.d.ts +108647 -0
- package/dist/index.d.ts +5 -0
- package/dist/test/happydom.d.ts +1 -0
- package/dist/test/testing-library.d.ts +1 -0
- package/dist/tours/ToursAdminRoot.d.ts +14 -0
- package/dist/tours/ToursAdminRoot.js +14 -13
- package/dist/tours/ToursAdminRoot.js.map +1 -1
- package/dist/tours/ToursAdminRoutes.d.ts +11 -0
- package/dist/tours/ToursAdminRoutes.js +12 -13
- package/dist/tours/ToursAdminRoutes.js.map +1 -1
- package/dist/tours/ToursRoot.d.ts +9 -0
- package/dist/tours/ToursRoot.js +1 -1
- package/dist/tours/ToursUserRoot.d.ts +13 -0
- package/dist/tours/ToursUserRoot.js +14 -13
- package/dist/tours/ToursUserRoot.js.map +1 -1
- package/dist/tours/ToursUserRoutes.d.ts +14 -0
- package/dist/tours/ToursUserRoutes.js +13 -13
- package/dist/tours/ToursUserRoutes.js.map +1 -1
- package/dist/tours/components/MarkdownEditor.d.ts +12 -0
- package/dist/tours/components/MarkdownEditor.js +1 -2
- package/dist/tours/components/MarkdownEditor.js.map +1 -1
- package/dist/tours/components/RouteHelpers.d.ts +31 -0
- package/dist/tours/components/RouteHelpers.js +1 -2
- package/dist/tours/components/RouteHelpers.js.map +1 -1
- package/dist/tours/components/ToursAdminNavRegistrar.d.ts +23 -0
- package/dist/tours/components/ToursAdminNavRegistrar.js +4 -3
- package/dist/tours/components/ToursAdminNavRegistrar.js.map +1 -1
- package/dist/tours/hooks/useMediaLibrary.d.ts +20 -0
- package/dist/tours/hooks/useMediaLibrary.js +1 -2
- package/dist/tours/hooks/useMediaLibrary.js.map +1 -1
- package/dist/tours/hooks/useStepSequencer.d.ts +18 -0
- package/dist/tours/hooks/useStepSequencer.js +16 -13
- package/dist/tours/hooks/useStepSequencer.js.map +1 -1
- package/dist/tours/hooks/useTourAnalytics.d.ts +30 -0
- package/dist/tours/hooks/useTourAnalytics.js +1 -2
- package/dist/tours/hooks/useTourAnalytics.js.map +1 -1
- package/dist/tours/hooks/useTourBuilder.d.ts +59 -0
- package/dist/tours/hooks/useTourBuilder.js +10 -6
- package/dist/tours/hooks/useTourBuilder.js.map +1 -1
- package/dist/tours/hooks/useTourLifecycle.d.ts +21 -0
- package/dist/tours/hooks/useTourLifecycle.js +4 -5
- package/dist/tours/hooks/useTourLifecycle.js.map +1 -1
- package/dist/tours/hooks/useTourPreview.d.ts +31 -0
- package/dist/tours/hooks/useTourPreview.js +5 -6
- package/dist/tours/hooks/useTourPreview.js.map +1 -1
- package/dist/tours/hooks/useToursList.d.ts +15 -0
- package/dist/tours/hooks/useToursList.js +1 -2
- package/dist/tours/hooks/useToursList.js.map +1 -1
- package/dist/tours/hooks/useToursPermissionAccess.d.ts +15 -0
- package/dist/tours/hooks/useToursPermissionAccess.js +1 -2
- package/dist/tours/hooks/useToursPermissionAccess.js.map +1 -1
- package/dist/tours/i18n.d.ts +413 -0
- package/dist/tours/i18n.js +1 -2
- package/dist/tours/i18n.js.map +1 -1
- package/dist/tours/index.d.ts +21 -0
- package/dist/tours/index.js +6 -5
- package/dist/tours/pages/AnalyticsDashboardPage.d.ts +5 -0
- package/dist/tours/pages/AnalyticsDashboardPage.js +6 -7
- package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.d.ts +5 -0
- package/dist/tours/pages/MediaLibraryPage.js +10 -11
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/MyToursPage.d.ts +10 -0
- package/dist/tours/pages/MyToursPage.js +5 -6
- package/dist/tours/pages/MyToursPage.js.map +1 -1
- package/dist/tours/pages/MyToursProgressPage.d.ts +5 -0
- package/dist/tours/pages/MyToursProgressPage.js +5 -6
- package/dist/tours/pages/MyToursProgressPage.js.map +1 -1
- package/dist/tours/pages/SchedulerPage.d.ts +5 -0
- package/dist/tours/pages/SchedulerPage.js +10 -11
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.d.ts +6 -0
- package/dist/tours/pages/StepEditorPage.js +302 -309
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/SystemAnalyticsPage.d.ts +5 -0
- package/dist/tours/pages/SystemAnalyticsPage.js +1 -2
- package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.d.ts +5 -0
- package/dist/tours/pages/TemplateLibraryPage.js +15 -16
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
- package/dist/tours/pages/TourBuilderPage.d.ts +1 -0
- package/dist/tours/pages/TourBuilderPage.js +273 -300
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.d.ts +5 -0
- package/dist/tours/pages/TourPreviewPage.js +9 -10
- package/dist/tours/pages/TourPreviewPage.js.map +1 -1
- package/dist/tours/pages/ToursListPage.d.ts +5 -0
- package/dist/tours/pages/ToursListPage.js +157 -157
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/dist/tours/providers/ToursProvider.d.ts +25 -0
- package/dist/tours/providers/ToursProvider.js +1 -2
- package/dist/tours/providers/ToursProvider.js.map +1 -1
- package/dist/tours/store/toursStore.d.ts +40 -0
- package/dist/tours/store/toursStore.js +5 -6
- package/dist/tours/store/toursStore.js.map +1 -1
- package/dist/tours/telemetry.d.ts +7 -0
- package/dist/tours/telemetry.js +1 -2
- package/dist/tours/telemetry.js.map +1 -1
- package/dist/tours/types/index.d.ts +348 -0
- package/dist/tours/utils/index.d.ts +28 -0
- package/dist/tours/utils/index.js +3 -4
- package/dist/tours/utils/index.js.map +1 -1
- package/dist/tours/utils/joinPath.d.ts +8 -0
- package/dist/tours/utils/joinPath.js +1 -2
- package/dist/tours/utils/joinPath.js.map +1 -1
- package/dist/utils/nativeBridge.d.ts +2 -0
- package/dist/utils/nativeBridge.js +1 -2
- package/package.json +62 -51
package/dist/tours/i18n.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.js","names":[],"sources":["../../src/tours/i18n.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nconst toursTranslationFallbacks = {\n 'stepEditor.addFirstStep': 'Add First Step',\n 'stepEditor.addStep': 'Add Step',\n 'stepEditor.clickAddStep': 'Click \"Add Step\" to create one',\n 'stepEditor.closeSteps': 'Close steps',\n 'stepEditor.content': 'Content',\n 'stepEditor.contentPlaceholder': 'Enter step content or instructions',\n 'stepEditor.createFirstStep': 'Create your first step to get started',\n 'stepEditor.cssSelector': 'CSS Selector',\n 'stepEditor.cssSelectorPlaceholder': \"[data-tour='element-name'] or #id or .class\",\n 'stepEditor.dataTourHint': \"Use data-tour attributes like [data-tour='sidenav'] for best results\",\n 'stepEditor.deleteStep': 'Delete step',\n 'stepEditor.desktopSelector': 'Desktop Selector',\n 'stepEditor.deviceSelectorHint': 'Override the default selector for specific device types',\n 'stepEditor.deviceSpecificSelectors': 'Device-Specific Selectors (Advanced)',\n 'stepEditor.editStep': 'Edit Step',\n 'stepEditor.goBack': 'Go back',\n 'stepEditor.leaveEmptyDefault': 'Leave empty to use default',\n 'stepEditor.mobileSelector': 'Mobile Selector',\n 'stepEditor.noStepSelected': 'No step selected',\n 'stepEditor.noStepsYet': 'No steps yet',\n 'stepEditor.of': 'of',\n 'stepEditor.nextStep': 'Next step',\n 'stepEditor.placementAuto': 'Auto (recommended)',\n 'stepEditor.placementBottom': 'Bottom',\n 'stepEditor.placementCenter': 'Center (modal style)',\n 'stepEditor.placementLeft': 'Left',\n 'stepEditor.placementRight': 'Right',\n 'stepEditor.placementTop': 'Top',\n 'stepEditor.previousStep': 'Previous step',\n 'stepEditor.save': 'Save',\n 'stepEditor.saving': 'Saving...',\n 'stepEditor.selectStepToEdit': 'Select a step from the list to edit it',\n 'stepEditor.stepNumber': 'Step',\n 'stepEditor.steps': 'Steps',\n 'stepEditor.stepsCount': 'steps',\n 'stepEditor.stepsLabel': 'Steps',\n 'stepEditor.stepTitle': 'Step Title',\n 'stepEditor.stepTitlePlaceholder': 'Enter step title',\n 'stepEditor.tabletSelector': 'Tablet Selector',\n 'stepEditor.targetElement': 'target element',\n 'stepEditor.tooltipPlacement': 'Tooltip Placement',\n 'stepEditor.tourFallback': 'Tour',\n 'stepEditor.tourSteps': 'Tour Steps',\n 'stepEditor.untitled': 'Untitled',\n\n // Step editor additions (BOFF-7116)\n 'stepEditor.moveStepUp': 'Move step up',\n 'stepEditor.moveStepDown': 'Move step down',\n 'stepEditor.requireInteraction': 'Require interaction',\n 'stepEditor.requireInteractionDescription':\n 'User must interact with the highlighted element before advancing.',\n 'stepEditor.waitForTimeout': 'Wait for timeout (ms)',\n 'stepEditor.advancedSettings': 'Advanced settings',\n 'stepEditor.advancedSettingsDescription':\n 'Step-timing waits, skip conditions, and analytics tags.',\n 'stepEditor.waitForSelector': 'Wait for selector',\n 'stepEditor.waitForEvent': 'Wait for event',\n 'stepEditor.skipConditions': 'Skip conditions (JSON)',\n 'stepEditor.stepMedia': 'Step media',\n 'stepEditor.noMediaAttached': 'No media attached to this step yet.',\n 'stepEditor.loadingMedia': 'Loading media...',\n 'stepEditor.selectUploadedMedia': 'Select uploaded media',\n 'stepEditor.positionHeader': 'Header',\n 'stepEditor.positionBody': 'Body',\n 'stepEditor.positionFooter': 'Footer',\n 'stepEditor.attach': 'Attach',\n 'stepEditor.saveBeforeAttach': 'Save your steps before attaching media to them.',\n 'stepEditor.newStep': 'New Step',\n 'stepEditor.copySuffix': '(Copy)',\n\n 'templateLibrary.adjustFilters': 'Try adjusting your filters or search query',\n 'templateLibrary.allCategories': 'All Categories',\n 'templateLibrary.categoryCustom': 'Custom',\n 'templateLibrary.categoryFeatureAnnouncement': 'Feature Announcement',\n 'templateLibrary.categoryHelp': 'Help',\n 'templateLibrary.categoryOnboarding': 'Onboarding',\n 'templateLibrary.deleteConfirm': 'Delete this template?',\n 'templateLibrary.deleteTemplate': 'Delete template',\n 'templateLibrary.loading': 'Loading templates...',\n 'templateLibrary.noTemplatesFound': 'No templates found',\n 'templateLibrary.publicOnly': 'Public only',\n 'templateLibrary.searchPlaceholder': 'Search templates...',\n 'templateLibrary.subtitle': 'Browse and use pre-built tour templates',\n 'templateLibrary.times': 'times',\n 'templateLibrary.title': 'Tour Templates',\n 'templateLibrary.useTemplate': 'Use Template',\n 'templateLibrary.usedTimes': 'Used',\n\n 'tourBuilder.accessDeniedTitle': 'Access Denied',\n 'tourBuilder.analytics': 'Analytics',\n 'tourBuilder.createAndAddSteps': 'Create & Add Steps',\n 'tourBuilder.createAccessDeniedMessage': 'You do not have permission to create tours.',\n 'tourBuilder.editSteps': 'Edit Steps',\n 'tourBuilder.errorTitle': 'Error',\n 'tourBuilder.goBack': 'Go back',\n 'tourBuilder.labelDescription': 'Description',\n 'tourBuilder.labelName': 'Tour Name *',\n 'tourBuilder.labelPriority': 'Priority (1-100)',\n 'tourBuilder.labelProductId': 'Product ID *',\n 'tourBuilder.labelTriggerType': 'Trigger Type',\n 'tourBuilder.loading': 'Loading...',\n 'tourBuilder.preview': 'Preview',\n 'tourBuilder.saving': 'Saving...',\n 'tourBuilder.sectionBasicInfo': 'Basic Information',\n 'tourBuilder.sectionTriggerSettings': 'Trigger Settings',\n\n 'tourBuilder.seedVibeControls.button': 'Seed VibeControls user tours',\n 'tourBuilder.seedVibeControls.confirm':\n 'This will overwrite the built-in Support, Notifications, and Conversations user tours from the service seed file. Continue?',\n 'tourBuilder.seedVibeControls.description':\n 'Overwrites the built-in Support, Notifications, and Conversations user tours from the service seed file.',\n 'tourBuilder.seedVibeControls.error': 'Failed to seed VibeControls user tours.',\n 'tourBuilder.seedVibeControls.loading': 'Seeding...',\n 'tourBuilder.seedVibeControls.permissionHint':\n 'Requires tour create and update permissions. The service also enforces RBAC when the seed mutation runs.',\n 'tourBuilder.seedVibeControls.result':\n 'Seeded {{totalCount}} tours for {{productId}} in workspace {{workspaceId}}: {{createdCount}} created, {{updatedCount}} updated.',\n 'tourBuilder.seedVibeControls.title': 'Seed VibeControls user tours',\n\n 'tourBuilder.seedBuildmyiq.button': 'Seed Buildmyiq user tours',\n 'tourBuilder.seedBuildmyiq.confirm':\n 'This will overwrite the built-in Buildmyiq dashboard user tour from the service seed file. Continue?',\n 'tourBuilder.seedBuildmyiq.description':\n 'Overwrites the built-in Buildmyiq dashboard user tour from the service seed file.',\n 'tourBuilder.seedBuildmyiq.error': 'Failed to seed Buildmyiq user tours.',\n 'tourBuilder.seedBuildmyiq.loading': 'Seeding...',\n 'tourBuilder.seedBuildmyiq.permissionHint':\n 'Requires tour create and update permissions. The service also enforces RBAC when the seed mutation runs.',\n 'tourBuilder.seedBuildmyiq.result':\n 'Seeded {{totalCount}} tours for {{productId}} in workspace {{workspaceId}}: {{createdCount}} created, {{updatedCount}} updated.',\n 'tourBuilder.seedBuildmyiq.title': 'Seed Buildmyiq user tours',\n 'tourBuilder.seedBigconsole.button': 'Seed BigConsole user tours',\n 'tourBuilder.seedBigconsole.confirm':\n 'This will overwrite the built-in BigConsole onboarding tours from the service seed file. Continue?',\n 'tourBuilder.seedBigconsole.description':\n 'Overwrites the built-in BigConsole onboarding tours from the service seed file.',\n 'tourBuilder.seedBigconsole.error': 'Failed to seed BigConsole user tours.',\n 'tourBuilder.seedBigconsole.loading': 'Seeding...',\n 'tourBuilder.seedBigconsole.permissionHint':\n 'Requires tour create and update permissions. The service also enforces RBAC when the seed mutation runs.',\n 'tourBuilder.seedBigconsole.result':\n 'Seeded {{totalCount}} tours for {{productId}} in workspace {{workspaceId}}: {{createdCount}} created, {{updatedCount}} updated.',\n 'tourBuilder.seedBigconsole.title': 'Seed BigConsole user tours',\n\n 'tourBuilder.subtitle': 'Configure tour details and settings',\n 'tourBuilder.titleCreate': 'Create Tour',\n 'tourBuilder.titleEdit': 'Edit Tour',\n 'tourBuilder.triggerAutoAlways': 'Auto (Always)',\n 'tourBuilder.triggerAutoFirstVisit': 'Auto (First Visit)',\n 'tourBuilder.triggerManual': 'Manual',\n 'tourBuilder.triggerOnEvent': 'On Event',\n 'tourBuilder.triggerScheduled': 'Scheduled',\n 'tourBuilder.updateTour': 'Update Tour',\n 'tourBuilder.updateAccessDeniedMessage': 'You do not have permission to update this tour.',\n 'tourBuilder.validationErrorsTitle': 'Validation Errors',\n\n // Tour builder additions (BOFF-7116)\n 'tourBuilder.schedule': 'Schedule',\n 'tourBuilder.saveAsTemplate': 'Save as Template',\n 'tourBuilder.templateDefaultName': '{{name}} Template',\n 'tourBuilder.templateNamePrompt': 'Template name',\n 'tourBuilder.templateCategoryPrompt':\n 'Template category (ONBOARDING, FEATURE_ANNOUNCEMENT, HELP, CUSTOM)',\n 'tourBuilder.seedMutationErrors': 'Seed mutation returned errors.',\n 'tourBuilder.seedMutationNoResult': 'Seed mutation returned no result.',\n 'tourBuilder.selectProduct': 'Select product',\n 'tourBuilder.loadingProducts': 'Loading products…',\n 'tourBuilder.currentValue': 'Current: {{value}}',\n 'tourBuilder.customProductSlug': 'Custom product slug',\n 'tourBuilder.productSlugPlaceholder': 'vibecontrols',\n 'tourBuilder.labelModuleId': 'Module ID',\n 'tourBuilder.allModules': 'All modules',\n 'tourBuilder.customModuleId': 'Custom module ID',\n 'tourBuilder.moduleSlugPlaceholder': 'vibecontrols',\n 'tourBuilder.labelPageId': 'Page ID',\n 'tourBuilder.allPages': 'All pages',\n 'tourBuilder.customPageId': 'Custom page ID',\n 'tourBuilder.pageSlugPlaceholder': 'agents',\n 'tourBuilder.labelActive': 'Active',\n 'tourBuilder.labelStartDate': 'Start Date',\n 'tourBuilder.labelEndDate': 'End Date',\n 'tourBuilder.errorLoadTour': 'Failed to load tour',\n 'tourBuilder.errorCreateTour': 'Failed to create tour',\n 'tourBuilder.errorUpdateTour': 'Failed to update tour',\n 'tourBuilder.errorDeleteTour': 'Failed to delete tour',\n 'tourBuilder.errorSyncSteps': 'Failed to sync steps',\n 'tourBuilder.errorValidationFailed': 'Validation failed',\n 'tourBuilder.errorNoTourSelected': 'No tour selected',\n\n 'tourPreview.accessDeniedMessage': 'You do not have permission to preview this tour.',\n 'tourPreview.accessDeniedTitle': 'Access Denied',\n 'tourPreview.deviceDesktop': 'Desktop preview',\n 'tourPreview.deviceMobile': 'Mobile preview',\n 'tourPreview.deviceTablet': 'Tablet preview',\n 'tourPreview.finish': 'Finish',\n 'tourPreview.loading': 'Loading tour...',\n 'tourPreview.next': 'Next',\n 'tourPreview.nextFooter': 'Next',\n 'tourPreview.previewSuffix': 'Preview',\n 'tourPreview.previous': 'Previous',\n 'tourPreview.readyHint': 'Click \"Start Preview\" to begin',\n 'tourPreview.readyTitle': 'Preview ready',\n 'tourPreview.startPreview': 'Start Preview',\n 'tourPreview.stepOf': 'Step',\n 'tourPreview.stepOfConnector': 'of',\n 'tourPreview.stopPreview': 'Stop Preview',\n 'tourPreview.validationErrorsTitle': 'Validation Errors',\n 'tourPreview.warningsTitle': 'Warnings',\n\n // Tour preview validation additions (BOFF-7116)\n 'tourPreview.errorNoTour': 'No tour selected',\n 'tourPreview.errorNoSteps': 'Tour has no steps',\n 'tourPreview.errorStepNoSelector': 'Step {{number}} has no selector',\n 'tourPreview.warningStepEmptyContent': 'Step {{number}} has empty content',\n 'tourPreview.warningStepNoMobileSelector': 'Step {{number}} has no mobile selector',\n 'tourPreview.warningStepNoTabletSelector': 'Step {{number}} has no tablet selector',\n 'tourPreview.warningStepNoDesktopSelector': 'Step {{number}} has no desktop selector',\n 'tourPreview.errorStepMediaNoUrl': 'Step {{number}}, media {{mediaNumber}} has no URL',\n 'tourPreview.warningStepMediaMissingAlt':\n 'Step {{number}}, media {{mediaNumber}} missing alt text',\n\n 'toursList.accessDeniedMessage': 'You do not have permission to view product tours.',\n 'toursList.accessDeniedTitle': 'Access Denied',\n 'toursList.actionArchive': 'Archive',\n 'toursList.actionDelete': 'Delete',\n 'toursList.actionDuplicate': 'Duplicate',\n 'toursList.actionPublish': 'Publish',\n 'toursList.actionUnpublish': 'Unpublish',\n 'toursList.confirmDelete': 'Are you sure you want to delete this tour?',\n 'toursList.createTour': 'Create Tour',\n 'toursList.editStepsTitle': 'Edit Steps',\n 'toursList.emptySubtitle': 'Create your first tour to get started',\n 'toursList.emptyTitle': 'No tours found',\n 'toursList.errorArchive': 'Failed to archive tour',\n 'toursList.errorDelete': 'Failed to delete tour',\n 'toursList.errorDuplicate': 'Failed to duplicate tour',\n 'toursList.errorPublish': 'Failed to publish tour',\n 'toursList.errorUnpublish': 'Failed to unpublish tour',\n 'toursList.gridView': 'Grid view',\n 'toursList.listView': 'List view',\n 'toursList.loading': 'Loading tours...',\n 'toursList.moreActionsTitle': 'More actions',\n 'toursList.previewButton': 'Preview',\n 'toursList.previewTitle': 'Preview Tour',\n 'toursList.searchPlaceholder': 'Search tours...',\n 'toursList.settingsTitle': 'Settings',\n 'toursList.statusAll': 'All Statuses',\n 'toursList.statusArchived': 'Archived',\n 'toursList.statusDraft': 'Draft',\n 'toursList.statusPublished': 'Published',\n 'toursList.statusScheduled': 'Scheduled',\n 'toursList.steps': 'steps',\n 'toursList.stepsButton': 'Steps',\n 'toursList.subtitle': 'Create and manage interactive product tours',\n 'toursList.title': 'Product Tours',\n 'toursList.views': 'views',\n\n // User-facing surface (BOFF-2391: My Tours + My Progress).\n 'userTours.loadError': 'Your tours could not be loaded. Please try again.',\n 'myTours.title': 'My Tours',\n 'myTours.subtitle': 'Walkthroughs available in this product. Take a tour to learn a feature.',\n 'myTours.loading': 'Loading...',\n 'myTours.empty': 'No tours are available in this context yet.',\n 'myTours.status.completed': 'Completed',\n 'myTours.status.inProgress': 'In progress',\n 'myTours.status.skipped': 'Skipped',\n 'myTours.status.notStarted': 'Not started',\n 'myTours.notFoundTitle': 'Page not found',\n 'myTours.notFoundBody': \"That tour page isn't available — returning to My Tours.\",\n\n 'myToursProgress.title': 'My Progress',\n 'myToursProgress.subtitle': 'Tours you have started, completed, or skipped.',\n 'myToursProgress.loading': 'Loading...',\n 'myToursProgress.inProgress': 'In progress',\n 'myToursProgress.completed': 'Completed',\n 'myToursProgress.skipped': 'Skipped or dismissed',\n 'myToursProgress.emptyInProgress': 'No tours in progress.',\n 'myToursProgress.emptyCompleted': 'No completed tours yet.',\n 'myToursProgress.emptySkipped': 'No skipped tours.',\n 'myToursProgress.other': 'Other',\n 'myToursProgress.emptyOther': 'No tours in other states.',\n 'myToursProgress.empty':\n \"You haven't started any tours yet. Open My Tours and take a walkthrough — your progress will show up here.\",\n\n // Page-purpose (\"what is this page for\") + next-step guidance copy.\n 'toursList.purpose':\n 'Author and manage the interactive product tours users see in-app — onboarding flows, feature spotlights, and help walkthroughs. Create a tour, add steps that point at real UI elements, then publish it so it appears for the right product, module, and page.',\n 'myTours.purpose':\n 'Browse the guided walkthroughs available right here in this product. Take a tour to learn a feature step by step — your progress is saved so you can pick up where you left off.',\n 'myToursProgress.purpose':\n 'Track every tour you have interacted with, grouped by status. See what you have completed, what is still in progress, and what you skipped so you know which walkthroughs are left to finish.',\n 'templateLibrary.purpose':\n 'Start from a pre-built tour template instead of a blank canvas. Pick an onboarding, feature-announcement, or help template, then customise its steps — a fast way to ship a consistent walkthrough.',\n\n 'tourBuilder.purpose':\n 'Set up a tour: give it a name, choose where it appears (product, module, page) and how it triggers (manually, on first visit, or scheduled). Save it, then add the steps users will walk through.',\n 'tourBuilder.nextStepsTitle': 'Recommended next steps',\n 'tourBuilder.nextStepEditSteps': 'Add the steps',\n 'tourBuilder.nextStepEditStepsDesc': 'Define the tooltips and target elements users will see.',\n 'tourBuilder.nextStepPreview': 'Preview it',\n 'tourBuilder.nextStepPreviewDesc': 'Walk through the tour on mobile, tablet, and desktop.',\n 'tourBuilder.nextStepSchedule': 'Schedule activation',\n 'tourBuilder.nextStepScheduleDesc': 'Choose when this tour goes live and how often it recurs.',\n 'tourBuilder.nextStepAnalytics': 'Check analytics',\n 'tourBuilder.nextStepAnalyticsDesc': 'See views, completion, and drop-off once it is live.',\n\n 'stepEditor.purpose':\n 'Build the actual walkthrough. Each step is a tooltip anchored to a real UI element via a CSS or data-tour selector. Add steps, reorder them, attach media, and set placement so the tour guides users exactly where you intend.',\n 'stepEditor.emptyTitle': 'No step selected',\n\n 'tourPreview.purpose':\n 'Walk through this tour exactly as your users will, on simulated mobile, tablet, and desktop viewports. Validate that every step finds its target element before you publish.',\n\n // Analytics dashboard (BOFF-7116)\n 'analyticsDashboard.accessDenied': 'Access Denied',\n 'analyticsDashboard.noPermission': 'You do not have permission to view tour analytics.',\n 'analyticsDashboard.loading': 'Loading analytics...',\n 'analyticsDashboard.noData': 'No analytics data available',\n 'analyticsDashboard.noDataHint':\n 'Analytics appear once this tour has been published and seen by users. Publish the tour and check back after it starts collecting views.',\n 'analyticsDashboard.title': 'Tour Analytics',\n 'analyticsDashboard.subtitle': 'Performance metrics and insights',\n 'analyticsDashboard.purpose':\n 'See how this specific tour is performing: how many people viewed it, how many finished versus skipped, and exactly which step they drop off on. Use the per-step drop-off to find and fix the weak point in your walkthrough.',\n 'analyticsDashboard.totalViews': 'Total Views',\n 'analyticsDashboard.completionRate': 'Completion Rate',\n 'analyticsDashboard.skipRate': 'Skip Rate',\n 'analyticsDashboard.avgDuration': 'Avg Duration',\n 'analyticsDashboard.deviceBreakdown': 'Device Breakdown',\n 'analyticsDashboard.stepPerformance': 'Step Performance',\n 'analyticsDashboard.tableStep': 'Step',\n 'analyticsDashboard.tableViews': 'Views',\n 'analyticsDashboard.tableCompletions': 'Completions',\n 'analyticsDashboard.tableDropOffRate': 'Drop-off Rate',\n 'analyticsDashboard.stepLabel': 'Step',\n\n // System analytics (BOFF-7116)\n 'systemAnalytics.accessDenied': 'Access Denied',\n 'systemAnalytics.noPermission': 'You do not have permission to view system analytics.',\n 'systemAnalytics.loading': 'Loading analytics...',\n 'systemAnalytics.noData': 'No analytics data available',\n 'systemAnalytics.noDataHint':\n 'Workspace-wide tour metrics appear once you have published tours and users have started seeing them. Publish a tour to begin collecting data.',\n 'systemAnalytics.title': 'System Analytics',\n 'systemAnalytics.subtitle': 'Workspace-wide tour performance overview',\n 'systemAnalytics.purpose':\n 'Get the big-picture health of onboarding across the whole workspace: how many tours exist, how many are live, total reach, and the overall completion rate. Use it to judge whether your guided experiences are actually landing.',\n 'systemAnalytics.completionRate': 'Completion Rate',\n 'systemAnalytics.completionRateHint':\n 'The share of started tours that users finished across this workspace.',\n 'systemAnalytics.totalTours': 'Total Tours',\n 'systemAnalytics.publishedTours': 'Published Tours',\n 'systemAnalytics.totalViews': 'Total Views',\n 'systemAnalytics.totalCompletions': 'Total Completions',\n\n // Tour scheduler (BOFF-7116)\n 'tourScheduler.goBack': 'Go back',\n 'tourScheduler.title': 'Schedule Tour',\n 'tourScheduler.subtitle': 'Configure when this tour should be activated',\n 'tourScheduler.purpose':\n 'Decide exactly when this tour goes live and how often it repeats — for example, run an onboarding tour every Monday, or activate a feature-announcement tour for a single launch window. Set a start (and optional end) date plus a recurrence pattern, and the tour will surface to users automatically on schedule.',\n 'tourScheduler.existingSchedules': 'Existing Schedules',\n 'tourScheduler.noEndDate': 'No end date',\n 'tourScheduler.oneTime': 'One-time',\n 'tourScheduler.active': 'Active',\n 'tourScheduler.inactive': 'Inactive',\n 'tourScheduler.runs': 'Runs',\n 'tourScheduler.sectionDateRange': 'Date Range',\n 'tourScheduler.labelStartDate': 'Start Date *',\n 'tourScheduler.labelEndDate': 'End Date (Optional)',\n 'tourScheduler.sectionRecurrence': 'Recurrence',\n 'tourScheduler.labelRecurrencePattern': 'Recurrence Pattern',\n 'tourScheduler.recurrenceDaily': 'Daily',\n 'tourScheduler.recurrenceWeekly': 'Weekly',\n 'tourScheduler.recurrenceMonthly': 'Monthly',\n 'tourScheduler.recurrenceCustom': 'Custom',\n 'tourScheduler.labelTimezone': 'Timezone',\n 'tourScheduler.statusActiveLabel': 'Active',\n 'tourScheduler.statusActiveDescription': 'Enable this schedule immediately after creation',\n 'tourScheduler.cancel': 'Cancel',\n 'tourScheduler.creating': 'Creating...',\n 'tourScheduler.createSchedule': 'Create Schedule',\n\n // Media library (BOFF-7116)\n 'mediaLibrary.title': 'Media Library',\n 'mediaLibrary.subtitle': 'Upload and manage media for tour steps',\n 'mediaLibrary.uploadMedia': 'Upload Media',\n 'mediaLibrary.purpose':\n 'Store and organise the images, videos, audio, and documents you attach to tour steps. Upload an asset here once, then reference it from any step — handy for product screenshots, short demo clips, or callout graphics that make a walkthrough clearer.',\n 'mediaLibrary.searchPlaceholder': 'Search media...',\n 'mediaLibrary.filterByType': 'Filter by media type',\n 'mediaLibrary.allTypes': 'All Types',\n 'mediaLibrary.typeImages': 'Images',\n 'mediaLibrary.typeVideos': 'Videos',\n 'mediaLibrary.typeAudio': 'Audio',\n 'mediaLibrary.typeDocuments': 'Documents',\n 'mediaLibrary.uploading': 'Uploading...',\n 'mediaLibrary.deleteConfirm': 'Delete this media?',\n 'mediaLibrary.delete': 'Delete',\n 'mediaLibrary.noMedia': 'No media files',\n 'mediaLibrary.uploadFirstMedia': 'Upload your first media file to get started',\n\n // Markdown editor (BOFF-7116)\n 'markdownEditor.bold': 'Bold',\n 'markdownEditor.italic': 'Italic',\n 'markdownEditor.link': 'Link',\n 'markdownEditor.inlineCode': 'Inline code',\n 'markdownEditor.bulletList': 'Bullet list',\n 'markdownEditor.linkTextPlaceholder': 'link text',\n 'markdownEditor.writeTab': 'Write',\n 'markdownEditor.previewTab': 'Preview',\n 'markdownEditor.nothingToPreview': 'Nothing to preview',\n 'markdownEditor.tabsAriaLabel': 'Markdown editor tabs',\n\n // Tours shell / nav (BOFF-7116)\n 'toursNav.allTours': 'All Tours',\n 'toursNav.createTour': 'Create Tour',\n 'toursNav.templates': 'Templates',\n 'toursNav.analytics': 'Analytics',\n 'toursNav.mediaLibrary': 'Media Library',\n\n 'toursShell.productToursReady': 'Product Tours Ready',\n 'toursShell.moduleError': 'Something went wrong loading this module. Please refresh the page.',\n\n // Route-level errors (BOFF-7116)\n 'routeErrors.failedToLoadPage': 'Failed to load page',\n 'routeErrors.chunkLoadRetry':\n 'The page chunk could not be loaded. This may be due to a network issue.',\n 'routeErrors.chunkLoadRefresh':\n 'The page chunk could not be loaded after multiple attempts. Please refresh the page.',\n 'routeErrors.tryAgain': 'Try Again',\n 'routeErrors.refreshPage': 'Refresh Page',\n\n // Feature disabled fallback (BOFF-7116)\n 'featureDisabled.title': 'Feature Not Available',\n 'featureDisabled.description':\n 'This feature is not currently enabled. Redirecting you to the tours list…',\n\n // User tours unavailable fallback (BOFF-7116)\n 'userTours.unavailable': 'Tours are not available for this workspace right now.',\n\n // Device type labels (BOFF-7116)\n 'deviceType.mobile': 'Mobile',\n 'deviceType.tablet': 'Tablet',\n 'deviceType.desktop': 'Desktop',\n\n // Common unit labels (BOFF-7116)\n 'common.fileSize.bytes': 'Bytes',\n 'common.fileSize.kb': 'KB',\n 'common.fileSize.mb': 'MB',\n 'common.fileSize.gb': 'GB',\n 'common.duration.seconds': 's',\n 'common.duration.minutes': 'm',\n 'common.duration.hours': 'h',\n\n // Validation messages returned by the store and rendered by the builder (BOFF-7116)\n 'validation.noTourSelected': 'No tour selected',\n 'validation.tourNameRequired': 'Tour name is required',\n 'validation.productIdRequired': 'Product ID is required',\n 'validation.stepsRequired': 'At least one step is required',\n 'validation.stepTitleRequired': 'Step {{number}} title is required',\n 'validation.stepContentRequired': 'Step {{number}} content is required',\n 'validation.stepSelectorRequired': 'Step {{number}} selector is required',\n\n // Tours list async error (BOFF-7116)\n 'toursList.errorFetch': 'Failed to fetch tours',\n\n // Analytics dashboard labels still needed after first pass (BOFF-7116)\n 'analyticsDashboard.deviceViews': 'views',\n} as const;\n\nexport type ToursTranslationKey = keyof typeof toursTranslationFallbacks;\n\ntype TranslationParams = Record<string, string | number>;\n\nexport function useToursI18n() {\n const i18n = useI18n();\n // The installed fe-libs typings still expose the older 2-argument shape, but the\n // runtime provider supports fallback strings. Narrow locally so this MFE can rely\n // on fallback-backed translations without changing the shared package here.\n const translateWithFallback = i18n.t as (key: string, fallback?: string) => string;\n\n const tr = useCallback(\n (\n key: ToursTranslationKey,\n fallbackOrParams?: string | TranslationParams,\n params?: TranslationParams\n ): string => {\n const fallbackString =\n typeof fallbackOrParams === 'string'\n ? fallbackOrParams\n : (toursTranslationFallbacks[key] as string | undefined);\n const interpolationParams = typeof fallbackOrParams === 'object' ? fallbackOrParams : params;\n\n const resolved = translateWithFallback(key, fallbackString);\n\n if (!interpolationParams) {\n return resolved;\n }\n\n return Object.entries(interpolationParams).reduce(\n (value, [paramKey, paramValue]) =>\n value.replace(new RegExp(`\\\\{\\\\{${paramKey}\\\\}\\\\}`, 'g'), String(paramValue)),\n resolved\n );\n },\n [translateWithFallback]\n );\n\n return {\n ...i18n,\n tr,\n };\n}\n\n/**\n * `useTr` — VibeControls-style translation hook with inline English fallback.\n *\n * Wraps the MFE's typed `useToursI18n()` so call sites can keep a readable\n * fallback string next to the key, matching the pattern used by\n * `microfe-vibecontrols/src/shared/hooks/useTr.ts`.\n *\n * @example\n * const tr = useTr();\n * return <h1>{tr('toursList.title', 'Product Tours')}</h1>;\n * return <p>{tr('toursList.selectedCount', '{{count}} tours selected', { count: 5 })}</p>;\n */\nexport function useTr(): (key: string, fallback: string, params?: TranslationParams) => string {\n const { tr } = useToursI18n();\n return useCallback(\n (key: string, fallback: string, params?: TranslationParams): string =>\n tr(key as ToursTranslationKey, fallback, params),\n [tr]\n );\n}\n\nexport function getToursTranslationFallback(key: ToursTranslationKey) {\n return toursTranslationFallbacks[key];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"i18n.js","names":["toursTranslationFallbacks","useToursI18n","i18n","useI18n","translateWithFallback","tr","useCallback","fallbackString","fallbackOrParams","key","interpolationParams","params","resolved","paramKey","paramValue","value","useTr","fallback"],"sources":["../../src/tours/i18n.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nconst toursTranslationFallbacks = {\n 'stepEditor.addFirstStep': 'Add First Step',\n 'stepEditor.addStep': 'Add Step',\n 'stepEditor.clickAddStep': 'Click \"Add Step\" to create one',\n 'stepEditor.closeSteps': 'Close steps',\n 'stepEditor.content': 'Content',\n 'stepEditor.contentPlaceholder': 'Enter step content or instructions',\n 'stepEditor.createFirstStep': 'Create your first step to get started',\n 'stepEditor.cssSelector': 'CSS Selector',\n 'stepEditor.cssSelectorPlaceholder': \"[data-tour='element-name'] or #id or .class\",\n 'stepEditor.dataTourHint': \"Use data-tour attributes like [data-tour='sidenav'] for best results\",\n 'stepEditor.deleteStep': 'Delete step',\n 'stepEditor.desktopSelector': 'Desktop Selector',\n 'stepEditor.deviceSelectorHint': 'Override the default selector for specific device types',\n 'stepEditor.deviceSpecificSelectors': 'Device-Specific Selectors (Advanced)',\n 'stepEditor.editStep': 'Edit Step',\n 'stepEditor.goBack': 'Go back',\n 'stepEditor.leaveEmptyDefault': 'Leave empty to use default',\n 'stepEditor.mobileSelector': 'Mobile Selector',\n 'stepEditor.noStepSelected': 'No step selected',\n 'stepEditor.noStepsYet': 'No steps yet',\n 'stepEditor.of': 'of',\n 'stepEditor.nextStep': 'Next step',\n 'stepEditor.placementAuto': 'Auto (recommended)',\n 'stepEditor.placementBottom': 'Bottom',\n 'stepEditor.placementCenter': 'Center (modal style)',\n 'stepEditor.placementLeft': 'Left',\n 'stepEditor.placementRight': 'Right',\n 'stepEditor.placementTop': 'Top',\n 'stepEditor.previousStep': 'Previous step',\n 'stepEditor.save': 'Save',\n 'stepEditor.saving': 'Saving...',\n 'stepEditor.selectStepToEdit': 'Select a step from the list to edit it',\n 'stepEditor.stepNumber': 'Step',\n 'stepEditor.steps': 'Steps',\n 'stepEditor.stepsCount': 'steps',\n 'stepEditor.stepsLabel': 'Steps',\n 'stepEditor.stepTitle': 'Step Title',\n 'stepEditor.stepTitlePlaceholder': 'Enter step title',\n 'stepEditor.tabletSelector': 'Tablet Selector',\n 'stepEditor.targetElement': 'target element',\n 'stepEditor.tooltipPlacement': 'Tooltip Placement',\n 'stepEditor.tourFallback': 'Tour',\n 'stepEditor.tourSteps': 'Tour Steps',\n 'stepEditor.untitled': 'Untitled',\n\n // Step editor additions (BOFF-7116)\n 'stepEditor.moveStepUp': 'Move step up',\n 'stepEditor.moveStepDown': 'Move step down',\n 'stepEditor.requireInteraction': 'Require interaction',\n 'stepEditor.requireInteractionDescription':\n 'User must interact with the highlighted element before advancing.',\n 'stepEditor.waitForTimeout': 'Wait for timeout (ms)',\n 'stepEditor.advancedSettings': 'Advanced settings',\n 'stepEditor.advancedSettingsDescription':\n 'Step-timing waits, skip conditions, and analytics tags.',\n 'stepEditor.waitForSelector': 'Wait for selector',\n 'stepEditor.waitForEvent': 'Wait for event',\n 'stepEditor.skipConditions': 'Skip conditions (JSON)',\n 'stepEditor.stepMedia': 'Step media',\n 'stepEditor.noMediaAttached': 'No media attached to this step yet.',\n 'stepEditor.loadingMedia': 'Loading media...',\n 'stepEditor.selectUploadedMedia': 'Select uploaded media',\n 'stepEditor.positionHeader': 'Header',\n 'stepEditor.positionBody': 'Body',\n 'stepEditor.positionFooter': 'Footer',\n 'stepEditor.attach': 'Attach',\n 'stepEditor.saveBeforeAttach': 'Save your steps before attaching media to them.',\n 'stepEditor.newStep': 'New Step',\n 'stepEditor.copySuffix': '(Copy)',\n\n 'templateLibrary.adjustFilters': 'Try adjusting your filters or search query',\n 'templateLibrary.allCategories': 'All Categories',\n 'templateLibrary.categoryCustom': 'Custom',\n 'templateLibrary.categoryFeatureAnnouncement': 'Feature Announcement',\n 'templateLibrary.categoryHelp': 'Help',\n 'templateLibrary.categoryOnboarding': 'Onboarding',\n 'templateLibrary.deleteConfirm': 'Delete this template?',\n 'templateLibrary.deleteTemplate': 'Delete template',\n 'templateLibrary.loading': 'Loading templates...',\n 'templateLibrary.noTemplatesFound': 'No templates found',\n 'templateLibrary.publicOnly': 'Public only',\n 'templateLibrary.searchPlaceholder': 'Search templates...',\n 'templateLibrary.subtitle': 'Browse and use pre-built tour templates',\n 'templateLibrary.times': 'times',\n 'templateLibrary.title': 'Tour Templates',\n 'templateLibrary.useTemplate': 'Use Template',\n 'templateLibrary.usedTimes': 'Used',\n\n 'tourBuilder.accessDeniedTitle': 'Access Denied',\n 'tourBuilder.analytics': 'Analytics',\n 'tourBuilder.createAndAddSteps': 'Create & Add Steps',\n 'tourBuilder.createAccessDeniedMessage': 'You do not have permission to create tours.',\n 'tourBuilder.editSteps': 'Edit Steps',\n 'tourBuilder.errorTitle': 'Error',\n 'tourBuilder.goBack': 'Go back',\n 'tourBuilder.labelDescription': 'Description',\n 'tourBuilder.labelName': 'Tour Name *',\n 'tourBuilder.labelPriority': 'Priority (1-100)',\n 'tourBuilder.labelProductId': 'Product ID *',\n 'tourBuilder.labelTriggerType': 'Trigger Type',\n 'tourBuilder.loading': 'Loading...',\n 'tourBuilder.preview': 'Preview',\n 'tourBuilder.saving': 'Saving...',\n 'tourBuilder.sectionBasicInfo': 'Basic Information',\n 'tourBuilder.sectionTriggerSettings': 'Trigger Settings',\n\n 'tourBuilder.seedVibeControls.button': 'Seed VibeControls user tours',\n 'tourBuilder.seedVibeControls.confirm':\n 'This will overwrite the built-in Support, Notifications, and Conversations user tours from the service seed file. Continue?',\n 'tourBuilder.seedVibeControls.description':\n 'Overwrites the built-in Support, Notifications, and Conversations user tours from the service seed file.',\n 'tourBuilder.seedVibeControls.error': 'Failed to seed VibeControls user tours.',\n 'tourBuilder.seedVibeControls.loading': 'Seeding...',\n 'tourBuilder.seedVibeControls.permissionHint':\n 'Requires tour create and update permissions. The service also enforces RBAC when the seed mutation runs.',\n 'tourBuilder.seedVibeControls.result':\n 'Seeded {{totalCount}} tours for {{productId}} in workspace {{workspaceId}}: {{createdCount}} created, {{updatedCount}} updated.',\n 'tourBuilder.seedVibeControls.title': 'Seed VibeControls user tours',\n\n 'tourBuilder.seedBuildmyiq.button': 'Seed Buildmyiq user tours',\n 'tourBuilder.seedBuildmyiq.confirm':\n 'This will overwrite the built-in Buildmyiq dashboard user tour from the service seed file. Continue?',\n 'tourBuilder.seedBuildmyiq.description':\n 'Overwrites the built-in Buildmyiq dashboard user tour from the service seed file.',\n 'tourBuilder.seedBuildmyiq.error': 'Failed to seed Buildmyiq user tours.',\n 'tourBuilder.seedBuildmyiq.loading': 'Seeding...',\n 'tourBuilder.seedBuildmyiq.permissionHint':\n 'Requires tour create and update permissions. The service also enforces RBAC when the seed mutation runs.',\n 'tourBuilder.seedBuildmyiq.result':\n 'Seeded {{totalCount}} tours for {{productId}} in workspace {{workspaceId}}: {{createdCount}} created, {{updatedCount}} updated.',\n 'tourBuilder.seedBuildmyiq.title': 'Seed Buildmyiq user tours',\n 'tourBuilder.seedBigconsole.button': 'Seed BigConsole user tours',\n 'tourBuilder.seedBigconsole.confirm':\n 'This will overwrite the built-in BigConsole onboarding tours from the service seed file. Continue?',\n 'tourBuilder.seedBigconsole.description':\n 'Overwrites the built-in BigConsole onboarding tours from the service seed file.',\n 'tourBuilder.seedBigconsole.error': 'Failed to seed BigConsole user tours.',\n 'tourBuilder.seedBigconsole.loading': 'Seeding...',\n 'tourBuilder.seedBigconsole.permissionHint':\n 'Requires tour create and update permissions. The service also enforces RBAC when the seed mutation runs.',\n 'tourBuilder.seedBigconsole.result':\n 'Seeded {{totalCount}} tours for {{productId}} in workspace {{workspaceId}}: {{createdCount}} created, {{updatedCount}} updated.',\n 'tourBuilder.seedBigconsole.title': 'Seed BigConsole user tours',\n\n 'tourBuilder.subtitle': 'Configure tour details and settings',\n 'tourBuilder.titleCreate': 'Create Tour',\n 'tourBuilder.titleEdit': 'Edit Tour',\n 'tourBuilder.triggerAutoAlways': 'Auto (Always)',\n 'tourBuilder.triggerAutoFirstVisit': 'Auto (First Visit)',\n 'tourBuilder.triggerManual': 'Manual',\n 'tourBuilder.triggerOnEvent': 'On Event',\n 'tourBuilder.triggerScheduled': 'Scheduled',\n 'tourBuilder.updateTour': 'Update Tour',\n 'tourBuilder.updateAccessDeniedMessage': 'You do not have permission to update this tour.',\n 'tourBuilder.validationErrorsTitle': 'Validation Errors',\n\n // Tour builder additions (BOFF-7116)\n 'tourBuilder.schedule': 'Schedule',\n 'tourBuilder.saveAsTemplate': 'Save as Template',\n 'tourBuilder.templateDefaultName': '{{name}} Template',\n 'tourBuilder.templateNamePrompt': 'Template name',\n 'tourBuilder.templateCategoryPrompt':\n 'Template category (ONBOARDING, FEATURE_ANNOUNCEMENT, HELP, CUSTOM)',\n 'tourBuilder.seedMutationErrors': 'Seed mutation returned errors.',\n 'tourBuilder.seedMutationNoResult': 'Seed mutation returned no result.',\n 'tourBuilder.selectProduct': 'Select product',\n 'tourBuilder.loadingProducts': 'Loading products…',\n 'tourBuilder.currentValue': 'Current: {{value}}',\n 'tourBuilder.customProductSlug': 'Custom product slug',\n 'tourBuilder.productSlugPlaceholder': 'vibecontrols',\n 'tourBuilder.labelModuleId': 'Module ID',\n 'tourBuilder.allModules': 'All modules',\n 'tourBuilder.customModuleId': 'Custom module ID',\n 'tourBuilder.moduleSlugPlaceholder': 'vibecontrols',\n 'tourBuilder.labelPageId': 'Page ID',\n 'tourBuilder.allPages': 'All pages',\n 'tourBuilder.customPageId': 'Custom page ID',\n 'tourBuilder.pageSlugPlaceholder': 'agents',\n 'tourBuilder.labelActive': 'Active',\n 'tourBuilder.labelStartDate': 'Start Date',\n 'tourBuilder.labelEndDate': 'End Date',\n 'tourBuilder.errorLoadTour': 'Failed to load tour',\n 'tourBuilder.errorCreateTour': 'Failed to create tour',\n 'tourBuilder.errorUpdateTour': 'Failed to update tour',\n 'tourBuilder.errorDeleteTour': 'Failed to delete tour',\n 'tourBuilder.errorSyncSteps': 'Failed to sync steps',\n 'tourBuilder.errorValidationFailed': 'Validation failed',\n 'tourBuilder.errorNoTourSelected': 'No tour selected',\n\n 'tourPreview.accessDeniedMessage': 'You do not have permission to preview this tour.',\n 'tourPreview.accessDeniedTitle': 'Access Denied',\n 'tourPreview.deviceDesktop': 'Desktop preview',\n 'tourPreview.deviceMobile': 'Mobile preview',\n 'tourPreview.deviceTablet': 'Tablet preview',\n 'tourPreview.finish': 'Finish',\n 'tourPreview.loading': 'Loading tour...',\n 'tourPreview.next': 'Next',\n 'tourPreview.nextFooter': 'Next',\n 'tourPreview.previewSuffix': 'Preview',\n 'tourPreview.previous': 'Previous',\n 'tourPreview.readyHint': 'Click \"Start Preview\" to begin',\n 'tourPreview.readyTitle': 'Preview ready',\n 'tourPreview.startPreview': 'Start Preview',\n 'tourPreview.stepOf': 'Step',\n 'tourPreview.stepOfConnector': 'of',\n 'tourPreview.stopPreview': 'Stop Preview',\n 'tourPreview.validationErrorsTitle': 'Validation Errors',\n 'tourPreview.warningsTitle': 'Warnings',\n\n // Tour preview validation additions (BOFF-7116)\n 'tourPreview.errorNoTour': 'No tour selected',\n 'tourPreview.errorNoSteps': 'Tour has no steps',\n 'tourPreview.errorStepNoSelector': 'Step {{number}} has no selector',\n 'tourPreview.warningStepEmptyContent': 'Step {{number}} has empty content',\n 'tourPreview.warningStepNoMobileSelector': 'Step {{number}} has no mobile selector',\n 'tourPreview.warningStepNoTabletSelector': 'Step {{number}} has no tablet selector',\n 'tourPreview.warningStepNoDesktopSelector': 'Step {{number}} has no desktop selector',\n 'tourPreview.errorStepMediaNoUrl': 'Step {{number}}, media {{mediaNumber}} has no URL',\n 'tourPreview.warningStepMediaMissingAlt':\n 'Step {{number}}, media {{mediaNumber}} missing alt text',\n\n 'toursList.accessDeniedMessage': 'You do not have permission to view product tours.',\n 'toursList.accessDeniedTitle': 'Access Denied',\n 'toursList.actionArchive': 'Archive',\n 'toursList.actionDelete': 'Delete',\n 'toursList.actionDuplicate': 'Duplicate',\n 'toursList.actionPublish': 'Publish',\n 'toursList.actionUnpublish': 'Unpublish',\n 'toursList.confirmDelete': 'Are you sure you want to delete this tour?',\n 'toursList.createTour': 'Create Tour',\n 'toursList.editStepsTitle': 'Edit Steps',\n 'toursList.emptySubtitle': 'Create your first tour to get started',\n 'toursList.emptyTitle': 'No tours found',\n 'toursList.errorArchive': 'Failed to archive tour',\n 'toursList.errorDelete': 'Failed to delete tour',\n 'toursList.errorDuplicate': 'Failed to duplicate tour',\n 'toursList.errorPublish': 'Failed to publish tour',\n 'toursList.errorUnpublish': 'Failed to unpublish tour',\n 'toursList.gridView': 'Grid view',\n 'toursList.listView': 'List view',\n 'toursList.loading': 'Loading tours...',\n 'toursList.moreActionsTitle': 'More actions',\n 'toursList.previewButton': 'Preview',\n 'toursList.previewTitle': 'Preview Tour',\n 'toursList.searchPlaceholder': 'Search tours...',\n 'toursList.settingsTitle': 'Settings',\n 'toursList.statusAll': 'All Statuses',\n 'toursList.statusArchived': 'Archived',\n 'toursList.statusDraft': 'Draft',\n 'toursList.statusPublished': 'Published',\n 'toursList.statusScheduled': 'Scheduled',\n 'toursList.steps': 'steps',\n 'toursList.stepsButton': 'Steps',\n 'toursList.subtitle': 'Create and manage interactive product tours',\n 'toursList.title': 'Product Tours',\n 'toursList.views': 'views',\n\n // User-facing surface (BOFF-2391: My Tours + My Progress).\n 'userTours.loadError': 'Your tours could not be loaded. Please try again.',\n 'myTours.title': 'My Tours',\n 'myTours.subtitle': 'Walkthroughs available in this product. Take a tour to learn a feature.',\n 'myTours.loading': 'Loading...',\n 'myTours.empty': 'No tours are available in this context yet.',\n 'myTours.status.completed': 'Completed',\n 'myTours.status.inProgress': 'In progress',\n 'myTours.status.skipped': 'Skipped',\n 'myTours.status.notStarted': 'Not started',\n 'myTours.notFoundTitle': 'Page not found',\n 'myTours.notFoundBody': \"That tour page isn't available — returning to My Tours.\",\n\n 'myToursProgress.title': 'My Progress',\n 'myToursProgress.subtitle': 'Tours you have started, completed, or skipped.',\n 'myToursProgress.loading': 'Loading...',\n 'myToursProgress.inProgress': 'In progress',\n 'myToursProgress.completed': 'Completed',\n 'myToursProgress.skipped': 'Skipped or dismissed',\n 'myToursProgress.emptyInProgress': 'No tours in progress.',\n 'myToursProgress.emptyCompleted': 'No completed tours yet.',\n 'myToursProgress.emptySkipped': 'No skipped tours.',\n 'myToursProgress.other': 'Other',\n 'myToursProgress.emptyOther': 'No tours in other states.',\n 'myToursProgress.empty':\n \"You haven't started any tours yet. Open My Tours and take a walkthrough — your progress will show up here.\",\n\n // Page-purpose (\"what is this page for\") + next-step guidance copy.\n 'toursList.purpose':\n 'Author and manage the interactive product tours users see in-app — onboarding flows, feature spotlights, and help walkthroughs. Create a tour, add steps that point at real UI elements, then publish it so it appears for the right product, module, and page.',\n 'myTours.purpose':\n 'Browse the guided walkthroughs available right here in this product. Take a tour to learn a feature step by step — your progress is saved so you can pick up where you left off.',\n 'myToursProgress.purpose':\n 'Track every tour you have interacted with, grouped by status. See what you have completed, what is still in progress, and what you skipped so you know which walkthroughs are left to finish.',\n 'templateLibrary.purpose':\n 'Start from a pre-built tour template instead of a blank canvas. Pick an onboarding, feature-announcement, or help template, then customise its steps — a fast way to ship a consistent walkthrough.',\n\n 'tourBuilder.purpose':\n 'Set up a tour: give it a name, choose where it appears (product, module, page) and how it triggers (manually, on first visit, or scheduled). Save it, then add the steps users will walk through.',\n 'tourBuilder.nextStepsTitle': 'Recommended next steps',\n 'tourBuilder.nextStepEditSteps': 'Add the steps',\n 'tourBuilder.nextStepEditStepsDesc': 'Define the tooltips and target elements users will see.',\n 'tourBuilder.nextStepPreview': 'Preview it',\n 'tourBuilder.nextStepPreviewDesc': 'Walk through the tour on mobile, tablet, and desktop.',\n 'tourBuilder.nextStepSchedule': 'Schedule activation',\n 'tourBuilder.nextStepScheduleDesc': 'Choose when this tour goes live and how often it recurs.',\n 'tourBuilder.nextStepAnalytics': 'Check analytics',\n 'tourBuilder.nextStepAnalyticsDesc': 'See views, completion, and drop-off once it is live.',\n\n 'stepEditor.purpose':\n 'Build the actual walkthrough. Each step is a tooltip anchored to a real UI element via a CSS or data-tour selector. Add steps, reorder them, attach media, and set placement so the tour guides users exactly where you intend.',\n 'stepEditor.emptyTitle': 'No step selected',\n\n 'tourPreview.purpose':\n 'Walk through this tour exactly as your users will, on simulated mobile, tablet, and desktop viewports. Validate that every step finds its target element before you publish.',\n\n // Analytics dashboard (BOFF-7116)\n 'analyticsDashboard.accessDenied': 'Access Denied',\n 'analyticsDashboard.noPermission': 'You do not have permission to view tour analytics.',\n 'analyticsDashboard.loading': 'Loading analytics...',\n 'analyticsDashboard.noData': 'No analytics data available',\n 'analyticsDashboard.noDataHint':\n 'Analytics appear once this tour has been published and seen by users. Publish the tour and check back after it starts collecting views.',\n 'analyticsDashboard.title': 'Tour Analytics',\n 'analyticsDashboard.subtitle': 'Performance metrics and insights',\n 'analyticsDashboard.purpose':\n 'See how this specific tour is performing: how many people viewed it, how many finished versus skipped, and exactly which step they drop off on. Use the per-step drop-off to find and fix the weak point in your walkthrough.',\n 'analyticsDashboard.totalViews': 'Total Views',\n 'analyticsDashboard.completionRate': 'Completion Rate',\n 'analyticsDashboard.skipRate': 'Skip Rate',\n 'analyticsDashboard.avgDuration': 'Avg Duration',\n 'analyticsDashboard.deviceBreakdown': 'Device Breakdown',\n 'analyticsDashboard.stepPerformance': 'Step Performance',\n 'analyticsDashboard.tableStep': 'Step',\n 'analyticsDashboard.tableViews': 'Views',\n 'analyticsDashboard.tableCompletions': 'Completions',\n 'analyticsDashboard.tableDropOffRate': 'Drop-off Rate',\n 'analyticsDashboard.stepLabel': 'Step',\n\n // System analytics (BOFF-7116)\n 'systemAnalytics.accessDenied': 'Access Denied',\n 'systemAnalytics.noPermission': 'You do not have permission to view system analytics.',\n 'systemAnalytics.loading': 'Loading analytics...',\n 'systemAnalytics.noData': 'No analytics data available',\n 'systemAnalytics.noDataHint':\n 'Workspace-wide tour metrics appear once you have published tours and users have started seeing them. Publish a tour to begin collecting data.',\n 'systemAnalytics.title': 'System Analytics',\n 'systemAnalytics.subtitle': 'Workspace-wide tour performance overview',\n 'systemAnalytics.purpose':\n 'Get the big-picture health of onboarding across the whole workspace: how many tours exist, how many are live, total reach, and the overall completion rate. Use it to judge whether your guided experiences are actually landing.',\n 'systemAnalytics.completionRate': 'Completion Rate',\n 'systemAnalytics.completionRateHint':\n 'The share of started tours that users finished across this workspace.',\n 'systemAnalytics.totalTours': 'Total Tours',\n 'systemAnalytics.publishedTours': 'Published Tours',\n 'systemAnalytics.totalViews': 'Total Views',\n 'systemAnalytics.totalCompletions': 'Total Completions',\n\n // Tour scheduler (BOFF-7116)\n 'tourScheduler.goBack': 'Go back',\n 'tourScheduler.title': 'Schedule Tour',\n 'tourScheduler.subtitle': 'Configure when this tour should be activated',\n 'tourScheduler.purpose':\n 'Decide exactly when this tour goes live and how often it repeats — for example, run an onboarding tour every Monday, or activate a feature-announcement tour for a single launch window. Set a start (and optional end) date plus a recurrence pattern, and the tour will surface to users automatically on schedule.',\n 'tourScheduler.existingSchedules': 'Existing Schedules',\n 'tourScheduler.noEndDate': 'No end date',\n 'tourScheduler.oneTime': 'One-time',\n 'tourScheduler.active': 'Active',\n 'tourScheduler.inactive': 'Inactive',\n 'tourScheduler.runs': 'Runs',\n 'tourScheduler.sectionDateRange': 'Date Range',\n 'tourScheduler.labelStartDate': 'Start Date *',\n 'tourScheduler.labelEndDate': 'End Date (Optional)',\n 'tourScheduler.sectionRecurrence': 'Recurrence',\n 'tourScheduler.labelRecurrencePattern': 'Recurrence Pattern',\n 'tourScheduler.recurrenceDaily': 'Daily',\n 'tourScheduler.recurrenceWeekly': 'Weekly',\n 'tourScheduler.recurrenceMonthly': 'Monthly',\n 'tourScheduler.recurrenceCustom': 'Custom',\n 'tourScheduler.labelTimezone': 'Timezone',\n 'tourScheduler.statusActiveLabel': 'Active',\n 'tourScheduler.statusActiveDescription': 'Enable this schedule immediately after creation',\n 'tourScheduler.cancel': 'Cancel',\n 'tourScheduler.creating': 'Creating...',\n 'tourScheduler.createSchedule': 'Create Schedule',\n\n // Media library (BOFF-7116)\n 'mediaLibrary.title': 'Media Library',\n 'mediaLibrary.subtitle': 'Upload and manage media for tour steps',\n 'mediaLibrary.uploadMedia': 'Upload Media',\n 'mediaLibrary.purpose':\n 'Store and organise the images, videos, audio, and documents you attach to tour steps. Upload an asset here once, then reference it from any step — handy for product screenshots, short demo clips, or callout graphics that make a walkthrough clearer.',\n 'mediaLibrary.searchPlaceholder': 'Search media...',\n 'mediaLibrary.filterByType': 'Filter by media type',\n 'mediaLibrary.allTypes': 'All Types',\n 'mediaLibrary.typeImages': 'Images',\n 'mediaLibrary.typeVideos': 'Videos',\n 'mediaLibrary.typeAudio': 'Audio',\n 'mediaLibrary.typeDocuments': 'Documents',\n 'mediaLibrary.uploading': 'Uploading...',\n 'mediaLibrary.deleteConfirm': 'Delete this media?',\n 'mediaLibrary.delete': 'Delete',\n 'mediaLibrary.noMedia': 'No media files',\n 'mediaLibrary.uploadFirstMedia': 'Upload your first media file to get started',\n\n // Markdown editor (BOFF-7116)\n 'markdownEditor.bold': 'Bold',\n 'markdownEditor.italic': 'Italic',\n 'markdownEditor.link': 'Link',\n 'markdownEditor.inlineCode': 'Inline code',\n 'markdownEditor.bulletList': 'Bullet list',\n 'markdownEditor.linkTextPlaceholder': 'link text',\n 'markdownEditor.writeTab': 'Write',\n 'markdownEditor.previewTab': 'Preview',\n 'markdownEditor.nothingToPreview': 'Nothing to preview',\n 'markdownEditor.tabsAriaLabel': 'Markdown editor tabs',\n\n // Tours shell / nav (BOFF-7116)\n 'toursNav.allTours': 'All Tours',\n 'toursNav.createTour': 'Create Tour',\n 'toursNav.templates': 'Templates',\n 'toursNav.analytics': 'Analytics',\n 'toursNav.mediaLibrary': 'Media Library',\n\n 'toursShell.productToursReady': 'Product Tours Ready',\n 'toursShell.moduleError': 'Something went wrong loading this module. Please refresh the page.',\n\n // Route-level errors (BOFF-7116)\n 'routeErrors.failedToLoadPage': 'Failed to load page',\n 'routeErrors.chunkLoadRetry':\n 'The page chunk could not be loaded. This may be due to a network issue.',\n 'routeErrors.chunkLoadRefresh':\n 'The page chunk could not be loaded after multiple attempts. Please refresh the page.',\n 'routeErrors.tryAgain': 'Try Again',\n 'routeErrors.refreshPage': 'Refresh Page',\n\n // Feature disabled fallback (BOFF-7116)\n 'featureDisabled.title': 'Feature Not Available',\n 'featureDisabled.description':\n 'This feature is not currently enabled. Redirecting you to the tours list…',\n\n // User tours unavailable fallback (BOFF-7116)\n 'userTours.unavailable': 'Tours are not available for this workspace right now.',\n\n // Device type labels (BOFF-7116)\n 'deviceType.mobile': 'Mobile',\n 'deviceType.tablet': 'Tablet',\n 'deviceType.desktop': 'Desktop',\n\n // Common unit labels (BOFF-7116)\n 'common.fileSize.bytes': 'Bytes',\n 'common.fileSize.kb': 'KB',\n 'common.fileSize.mb': 'MB',\n 'common.fileSize.gb': 'GB',\n 'common.duration.seconds': 's',\n 'common.duration.minutes': 'm',\n 'common.duration.hours': 'h',\n\n // Validation messages returned by the store and rendered by the builder (BOFF-7116)\n 'validation.noTourSelected': 'No tour selected',\n 'validation.tourNameRequired': 'Tour name is required',\n 'validation.productIdRequired': 'Product ID is required',\n 'validation.stepsRequired': 'At least one step is required',\n 'validation.stepTitleRequired': 'Step {{number}} title is required',\n 'validation.stepContentRequired': 'Step {{number}} content is required',\n 'validation.stepSelectorRequired': 'Step {{number}} selector is required',\n\n // Tours list async error (BOFF-7116)\n 'toursList.errorFetch': 'Failed to fetch tours',\n\n // Analytics dashboard labels still needed after first pass (BOFF-7116)\n 'analyticsDashboard.deviceViews': 'views',\n} as const;\n\nexport type ToursTranslationKey = keyof typeof toursTranslationFallbacks;\n\ntype TranslationParams = Record<string, string | number>;\n\nexport function useToursI18n() {\n const i18n = useI18n();\n // The installed fe-libs typings still expose the older 2-argument shape, but the\n // runtime provider supports fallback strings. Narrow locally so this MFE can rely\n // on fallback-backed translations without changing the shared package here.\n const translateWithFallback = i18n.t as (key: string, fallback?: string) => string;\n\n const tr = useCallback(\n (\n key: ToursTranslationKey,\n fallbackOrParams?: string | TranslationParams,\n params?: TranslationParams\n ): string => {\n const fallbackString =\n typeof fallbackOrParams === 'string'\n ? fallbackOrParams\n : (toursTranslationFallbacks[key] as string | undefined);\n const interpolationParams = typeof fallbackOrParams === 'object' ? fallbackOrParams : params;\n\n const resolved = translateWithFallback(key, fallbackString);\n\n if (!interpolationParams) {\n return resolved;\n }\n\n return Object.entries(interpolationParams).reduce(\n (value, [paramKey, paramValue]) =>\n value.replace(new RegExp(`\\\\{\\\\{${paramKey}\\\\}\\\\}`, 'g'), String(paramValue)),\n resolved\n );\n },\n [translateWithFallback]\n );\n\n return {\n ...i18n,\n tr,\n };\n}\n\n/**\n * `useTr` — VibeControls-style translation hook with inline English fallback.\n *\n * Wraps the MFE's typed `useToursI18n()` so call sites can keep a readable\n * fallback string next to the key, matching the pattern used by\n * `microfe-vibecontrols/src/shared/hooks/useTr.ts`.\n *\n * @example\n * const tr = useTr();\n * return <h1>{tr('toursList.title', 'Product Tours')}</h1>;\n * return <p>{tr('toursList.selectedCount', '{{count}} tours selected', { count: 5 })}</p>;\n */\nexport function useTr(): (key: string, fallback: string, params?: TranslationParams) => string {\n const { tr } = useToursI18n();\n return useCallback(\n (key: string, fallback: string, params?: TranslationParams): string =>\n tr(key as ToursTranslationKey, fallback, params),\n [tr]\n );\n}\n\nexport function getToursTranslationFallback(key: ToursTranslationKey) {\n return toursTranslationFallbacks[key];\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tours Microfrontend
|
|
3
|
+
*
|
|
4
|
+
* Provides UIs for product tours and onboarding. Two surfaces are exported:
|
|
5
|
+
*
|
|
6
|
+
* - `ToursAdminRoot` — full authoring suite (CRUD, builder, step editor,
|
|
7
|
+
* media library, analytics, templates, scheduler, preview). Mount in
|
|
8
|
+
* admin-app.
|
|
9
|
+
* - `ToursUserRoot` — read-only "My Tours" + "My Progress" surface. Mount
|
|
10
|
+
* in product user shells (vibecontrols-app, etc.).
|
|
11
|
+
*
|
|
12
|
+
* `ToursRoot` is kept as a back-compat alias of `ToursAdminRoot` so callers
|
|
13
|
+
* that imported `ToursRoot` before the BOFF-2391 split continue to work.
|
|
14
|
+
*/
|
|
15
|
+
export { ToursRoot } from './ToursRoot';
|
|
16
|
+
export { ToursAdminRoot } from './ToursAdminRoot';
|
|
17
|
+
export { ToursUserRoot } from './ToursUserRoot';
|
|
18
|
+
export type { ToursRootProps, ToursVariant } from './types';
|
|
19
|
+
export { useToursContext } from './providers/ToursProvider';
|
|
20
|
+
export { useToursStore } from './store/toursStore';
|
|
21
|
+
export { TOURS_RYBBIT_ALLOWLIST } from './telemetry';
|
package/dist/tours/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import "./providers/ToursProvider.js";
|
|
2
|
-
import "./store/toursStore.js";
|
|
3
|
-
import "./ToursAdminRoot.js";
|
|
4
1
|
import "./ToursRoot.js";
|
|
5
|
-
import "./
|
|
6
|
-
import "./
|
|
2
|
+
import { ToursAdminRoot as e } from "./ToursAdminRoot.js";
|
|
3
|
+
import { ToursUserRoot as t } from "./ToursUserRoot.js";
|
|
4
|
+
import { useToursContext as n } from "./providers/ToursProvider.js";
|
|
5
|
+
import { useToursStore as r } from "./store/toursStore.js";
|
|
6
|
+
import { TOURS_RYBBIT_ALLOWLIST as i } from "./telemetry.js";
|
|
7
|
+
export { i as TOURS_RYBBIT_ALLOWLIST, e as ToursAdminRoot, e as ToursRoot, t as ToursUserRoot, n as useToursContext, r as useToursStore };
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { useToursI18n as e } from "../i18n.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { useTourAnalytics as t } from "../hooks/useTourAnalytics.js";
|
|
3
|
+
import { useToursPermissionAccess as n } from "../hooks/useToursPermissionAccess.js";
|
|
4
|
+
import { TOUR_PERMISSIONS as r } from "../../constants/permissions.js";
|
|
5
5
|
import { useToursFormatters as i } from "../utils/index.js";
|
|
6
6
|
import { useEffect as a } from "react";
|
|
7
7
|
import { BarChart3 as o, Timer as s, TrendingUp as c, Users as l } from "lucide-react";
|
|
8
8
|
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
9
9
|
import { useParams as f } from "react-router";
|
|
10
10
|
import { EmphasisPanel as p, GlassCard as m, IllustratedEmptyState as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
|
|
11
|
-
|
|
11
|
+
// src/tours/pages/AnalyticsDashboardPage.tsx
|
|
12
12
|
function _() {
|
|
13
|
-
let { tr: _ } = e(), { tourId: v } = f(), { hasPermission: y, isLoading: b } =
|
|
13
|
+
let { tr: _ } = e(), { tourId: v } = f(), { hasPermission: y, isLoading: b } = n(), x = y(r.TOUR_ANALYTICS_READ), { analytics: S, loading: C, fetchAnalytics: w, getCompletionRate: T, getSkipRate: E } = t(v), { formatNumber: D, formatPercentage: O, formatDuration: k } = i();
|
|
14
14
|
return a(() => {
|
|
15
|
-
b
|
|
15
|
+
!b && x && w();
|
|
16
16
|
}, [
|
|
17
17
|
w,
|
|
18
18
|
b,
|
|
@@ -231,7 +231,6 @@ function _() {
|
|
|
231
231
|
})
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
|
-
//#endregion
|
|
235
234
|
export { _ as AnalyticsDashboardPage };
|
|
236
235
|
|
|
237
236
|
//# sourceMappingURL=AnalyticsDashboardPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsDashboardPage.js","names":[],"sources":["../../../src/tours/pages/AnalyticsDashboardPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { BarChart3, TrendingUp, Users, Timer } from 'lucide-react';\nimport {\n GlassCard,\n EmphasisPanel,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useToursI18n } from '../i18n';\nimport { useTourAnalytics } from '../hooks/useTourAnalytics';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursFormatters } from '../utils';\n\n/**\n * Analytics dashboard page\n * Display tour performance metrics and charts\n */\nexport function AnalyticsDashboardPage() {\n const { tr } = useToursI18n();\n\n const { tourId } = useParams();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canViewAnalytics = hasPermission(TOUR_PERMISSIONS.TOUR_ANALYTICS_READ);\n\n const { analytics, loading, fetchAnalytics, getCompletionRate, getSkipRate } =\n useTourAnalytics(tourId);\n const { formatNumber, formatPercentage, formatDuration } = useToursFormatters();\n\n useEffect(() => {\n if (permissionsLoading || !canViewAnalytics) return;\n fetchAnalytics();\n }, [fetchAnalytics, permissionsLoading, canViewAnalytics]);\n\n if (!permissionsLoading && !canViewAnalytics) {\n return (\n <div className=\"flex items-center justify-center h-full p-3 sm:p-6\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('analyticsDashboard.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'analyticsDashboard.noPermission',\n 'You do not have permission to view tour analytics.'\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <p className=\"text-text-secondary\">\n {tr('analyticsDashboard.loading', 'Loading analytics...')}\n </p>\n </div>\n );\n }\n\n if (!analytics) {\n return (\n <div className=\"p-3 sm:p-6\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('analyticsDashboard.noData', 'No analytics data available')}\n description={tr(\n 'analyticsDashboard.noDataHint',\n 'Analytics appear once this tour has been published and seen by users. Publish the tour and check back after it starts collecting views.'\n )}\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('analyticsDashboard.title', 'Tour Analytics')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.subtitle', 'Performance metrics and insights')}\n </p>\n </div>\n\n <PagePurpose>\n {tr(\n 'analyticsDashboard.purpose',\n 'See how this specific tour is performing: how many people viewed it, how many finished versus skipped, and exactly which step they drop off on. Use the per-step drop-off to find and fix the weak point in your walkthrough.'\n )}\n </PagePurpose>\n\n {/* Summary Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <GlassCard treatment=\"glass\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-md\">\n <Users className=\"text-primary\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.totalViews', 'Total Views')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatNumber(analytics.totalViews)}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-success/10 rounded-md\">\n <TrendingUp className=\"text-success\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.completionRate', 'Completion Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatPercentage(getCompletionRate())}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-warning/10 rounded-md\">\n <BarChart3 className=\"text-warning\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.skipRate', 'Skip Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">{formatPercentage(getSkipRate())}</div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-info/10 rounded-md\">\n <Timer className=\"text-info\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.avgDuration', 'Avg Duration')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatDuration(analytics.averageDuration)}\n </div>\n </GlassCard>\n </div>\n\n {/* Device Breakdown — the key soft-glow data-viz zone */}\n <EmphasisPanel className=\"p-4 sm:p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.deviceBreakdown', 'Device Breakdown')}\n </h2>\n <div className=\"space-y-3\">\n {analytics.byDeviceType.map((device) => (\n <div key={device.deviceType}>\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-sm\">\n {tr(`deviceType.${device.deviceType}` as const, device.deviceType)}\n </span>\n <span className=\"text-sm text-text-secondary tabular-nums\">\n {formatNumber(device.count)} {tr('analyticsDashboard.deviceViews', 'views')} (\n {formatPercentage(device.completionRate)})\n </span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full shadow-[var(--shadow-pop)]\"\n style={{ width: `${device.completionRate}%` }}\n />\n </div>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n {/* Step Analytics */}\n {analytics.stepAnalytics && analytics.stepAnalytics.length > 0 && (\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.stepPerformance', 'Step Performance')}\n </h2>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n <th className=\"text-left py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableStep', 'Step')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableViews', 'Views')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableCompletions', 'Completions')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableDropOffRate', 'Drop-off Rate')}\n </th>\n </tr>\n </thead>\n <tbody>\n {analytics.stepAnalytics.map((step) => (\n <tr key={step.stepId} className=\"border-b border-border-seam\">\n <td className=\"py-2 px-4 text-sm\">\n {tr('analyticsDashboard.stepLabel', 'Step')} {step.stepOrder}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.views)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.completions)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatPercentage(step.dropOffRate)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnalyticsDashboardPage.js","names":["AnalyticsDashboardPage","useToursI18n","useParams","permissionsLoading","useToursPermissionAccess","canViewAnalytics","hasPermission","TOUR_PERMISSIONS","useTourAnalytics","tourId","useToursFormatters","useEffect","fetchAnalytics","tr","loading","analytics","PagePurpose","GlassCard","Users","formatNumber","TrendingUp","formatPercentage","getCompletionRate","BarChart3","getSkipRate","Timer","formatDuration","EmphasisPanel","device","step","IllustratedEmptyState"],"sources":["../../../src/tours/pages/AnalyticsDashboardPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { BarChart3, TrendingUp, Users, Timer } from 'lucide-react';\nimport {\n GlassCard,\n EmphasisPanel,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useToursI18n } from '../i18n';\nimport { useTourAnalytics } from '../hooks/useTourAnalytics';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursFormatters } from '../utils';\n\n/**\n * Analytics dashboard page\n * Display tour performance metrics and charts\n */\nexport function AnalyticsDashboardPage() {\n const { tr } = useToursI18n();\n\n const { tourId } = useParams();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canViewAnalytics = hasPermission(TOUR_PERMISSIONS.TOUR_ANALYTICS_READ);\n\n const { analytics, loading, fetchAnalytics, getCompletionRate, getSkipRate } =\n useTourAnalytics(tourId);\n const { formatNumber, formatPercentage, formatDuration } = useToursFormatters();\n\n useEffect(() => {\n if (permissionsLoading || !canViewAnalytics) return;\n fetchAnalytics();\n }, [fetchAnalytics, permissionsLoading, canViewAnalytics]);\n\n if (!permissionsLoading && !canViewAnalytics) {\n return (\n <div className=\"flex items-center justify-center h-full p-3 sm:p-6\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('analyticsDashboard.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'analyticsDashboard.noPermission',\n 'You do not have permission to view tour analytics.'\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <p className=\"text-text-secondary\">\n {tr('analyticsDashboard.loading', 'Loading analytics...')}\n </p>\n </div>\n );\n }\n\n if (!analytics) {\n return (\n <div className=\"p-3 sm:p-6\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('analyticsDashboard.noData', 'No analytics data available')}\n description={tr(\n 'analyticsDashboard.noDataHint',\n 'Analytics appear once this tour has been published and seen by users. Publish the tour and check back after it starts collecting views.'\n )}\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('analyticsDashboard.title', 'Tour Analytics')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.subtitle', 'Performance metrics and insights')}\n </p>\n </div>\n\n <PagePurpose>\n {tr(\n 'analyticsDashboard.purpose',\n 'See how this specific tour is performing: how many people viewed it, how many finished versus skipped, and exactly which step they drop off on. Use the per-step drop-off to find and fix the weak point in your walkthrough.'\n )}\n </PagePurpose>\n\n {/* Summary Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <GlassCard treatment=\"glass\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-md\">\n <Users className=\"text-primary\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.totalViews', 'Total Views')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatNumber(analytics.totalViews)}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-success/10 rounded-md\">\n <TrendingUp className=\"text-success\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.completionRate', 'Completion Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatPercentage(getCompletionRate())}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-warning/10 rounded-md\">\n <BarChart3 className=\"text-warning\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.skipRate', 'Skip Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">{formatPercentage(getSkipRate())}</div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-info/10 rounded-md\">\n <Timer className=\"text-info\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.avgDuration', 'Avg Duration')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatDuration(analytics.averageDuration)}\n </div>\n </GlassCard>\n </div>\n\n {/* Device Breakdown — the key soft-glow data-viz zone */}\n <EmphasisPanel className=\"p-4 sm:p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.deviceBreakdown', 'Device Breakdown')}\n </h2>\n <div className=\"space-y-3\">\n {analytics.byDeviceType.map((device) => (\n <div key={device.deviceType}>\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-sm\">\n {tr(`deviceType.${device.deviceType}` as const, device.deviceType)}\n </span>\n <span className=\"text-sm text-text-secondary tabular-nums\">\n {formatNumber(device.count)} {tr('analyticsDashboard.deviceViews', 'views')} (\n {formatPercentage(device.completionRate)})\n </span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full shadow-[var(--shadow-pop)]\"\n style={{ width: `${device.completionRate}%` }}\n />\n </div>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n {/* Step Analytics */}\n {analytics.stepAnalytics && analytics.stepAnalytics.length > 0 && (\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.stepPerformance', 'Step Performance')}\n </h2>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n <th className=\"text-left py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableStep', 'Step')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableViews', 'Views')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableCompletions', 'Completions')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableDropOffRate', 'Drop-off Rate')}\n </th>\n </tr>\n </thead>\n <tbody>\n {analytics.stepAnalytics.map((step) => (\n <tr key={step.stepId} className=\"border-b border-border-seam\">\n <td className=\"py-2 px-4 text-sm\">\n {tr('analyticsDashboard.stepLabel', 'Step')} {step.stepOrder}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.views)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.completions)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatPercentage(step.dropOffRate)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAmBA,SAAgBA,IAAyB;CACvC,IAAM,EAAE,UAAOC,EAAa,GAEtB,EAAE,cAAWC,EAAU,GACvB,EAAE,kBAAe,WAAWC,MAAuBC,EAAyB,GAC5EC,IAAmBC,EAAcC,EAAiB,mBAAmB,GAErE,EAAE,cAAW,YAAS,mBAAgB,sBAAmB,mBAC7DC,EAAiBC,CAAM,GACnB,EAAE,iBAAc,qBAAkB,sBAAmBC,EAAmB;CAkD9E,OAhDAC,QAAgB;EACd,AAAI,MAAuBN,KAC3BO,EAAe;CACjB,GAAG;EAACA;EAAgBT;EAAoBE;CAAgB,CAAC,GAErD,CAACF,KAAsB,CAACE,IAExB,kBAAC,OAAD;EAAK,WAAU;EACb,UAAA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;IACX,UAAAQ,EAAG,mCAAmC,eAAe;GACpD,CAAA,GACJ,kBAAC,KAAD;IAAG,WAAU;IACV,UAAAA,EACC,mCACA,oDACF;GACC,CAAA,CACA;;CACF,CAAA,IAILC,IAEA,kBAAC,OAAD;EAAK,WAAU;EACb,UAAA,kBAAC,KAAD;GAAG,WAAU;GACV,UAAAD,EAAG,8BAA8B,sBAAsB;EACvD,CAAA;CACA,CAAA,IAIJE,IAgBH,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;IACX,UAAAF,EAAG,4BAA4B,gBAAgB;GAC9C,CAAA,GACJ,kBAAC,KAAD;IAAG,WAAU;IACV,UAAAA,EAAG,+BAA+B,kCAAkC;GACpE,CAAA,CACA,EAAA,CAAA;GAEL,kBAACG,GAAD,EAAA,UACGH,EACC,8BACA,+NACF,EACW,CAAA;GAGb,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAACI,GAAD;MAAW,WAAU;MAAQ,WAAU;MAAvC,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,kBAAC,OAAD;QAAK,WAAU;QACb,UAAA,kBAACC,GAAD;SAAO,WAAU;SAAe,MAAM;QAAK,CAAA;OACxC,CAAA,GACL,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAL,EAAG,iCAAiC,aAAa;OAC9C,CAAA,CACH;MACL,CAAA,GAAA,kBAAC,OAAD;OAAK,WAAU;OACZ,UAAAM,EAAaJ,EAAU,UAAU;MAC/B,CAAA,CACI;;KAEX,kBAACE,GAAD;MAAW,WAAU;MAAS,WAAU;MAAxC,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,kBAAC,OAAD;QAAK,WAAU;QACb,UAAA,kBAACG,GAAD;SAAY,WAAU;SAAe,MAAM;QAAK,CAAA;OAC7C,CAAA,GACL,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAP,EAAG,qCAAqC,iBAAiB;OACtD,CAAA,CACH;MACL,CAAA,GAAA,kBAAC,OAAD;OAAK,WAAU;OACZ,UAAAQ,EAAiBC,EAAkB,CAAC;MAClC,CAAA,CACI;;KAEX,kBAACL,GAAD;MAAW,WAAU;MAAS,WAAU;MAAxC,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,kBAAC,OAAD;QAAK,WAAU;QACb,UAAA,kBAACM,GAAD;SAAW,WAAU;SAAe,MAAM;QAAK,CAAA;OAC5C,CAAA,GACL,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAV,EAAG,+BAA+B,WAAW;OAC1C,CAAA,CACH;MACL,CAAA,GAAA,kBAAC,OAAD;OAAK,WAAU;OAAmC,UAAAQ,EAAiBG,EAAY,CAAC;MAAO,CAAA,CAC9E;;KAEX,kBAACP,GAAD;MAAW,WAAU;MAAS,WAAU;MAAxC,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,kBAAC,OAAD;QAAK,WAAU;QACb,UAAA,kBAACQ,GAAD;SAAO,WAAU;SAAY,MAAM;QAAK,CAAA;OACrC,CAAA,GACL,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAZ,EAAG,kCAAkC,cAAc;OAChD,CAAA,CACH;MACL,CAAA,GAAA,kBAAC,OAAD;OAAK,WAAU;OACZ,UAAAa,EAAeX,EAAU,eAAe;MACtC,CAAA,CACI;;IACR;;GAGL,kBAACY,GAAD;IAAe,WAAU;IAAzB,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KACX,UAAAd,EAAG,sCAAsC,kBAAkB;IAC1D,CAAA,GACJ,kBAAC,OAAD;KAAK,WAAU;KACZ,UAAAE,EAAU,aAAa,KAAK,MAC3B,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC,QAAD;OAAM,WAAU;OACb,UAAAF,EAAG,cAAce,EAAO,cAAuBA,EAAO,UAAU;MAC7D,CAAA,GACN,kBAAC,QAAD;OAAM,WAAU;OAAhB,UAAA;QACGT,EAAaS,EAAO,KAAK;QAAE;QAAEf,EAAG,kCAAkC,OAAO;QAAE;QAC3EQ,EAAiBO,EAAO,cAAc;QAAE;OACrC;MACH,CAAA,CAAA;KACL,CAAA,GAAA,kBAAC,OAAD;MAAK,WAAU;MACb,UAAA,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,OAAO,GAAGA,EAAO,eAAe,GAAG;MAC7C,CAAA;KACE,CAAA,CACF,EAAA,GAhBKA,EAAO,UAgBZ,CACN;IACE,CAAA,CACQ;;GAGdb,EAAU,iBAAiBA,EAAU,cAAc,SAAS,KAC3D,kBAACE,GAAD;IAAW,WAAU;IAAQ,WAAU;IAAvC,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KACX,UAAAJ,EAAG,sCAAsC,kBAAkB;IAC1D,CAAA,GACJ,kBAAC,OAAD;KAAK,WAAU;KACb,UAAA,kBAAC,SAAD;MAAO,WAAU;MAAjB,UAAA,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;OAAI,WAAU;OAAd,UAAA;QACE,kBAAC,MAAD;SAAI,WAAU;SACX,UAAAA,EAAG,gCAAgC,MAAM;QACxC,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;SACX,UAAAA,EAAG,iCAAiC,OAAO;QAC1C,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;SACX,UAAAA,EAAG,uCAAuC,aAAa;QACtD,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;SACX,UAAAA,EAAG,uCAAuC,eAAe;QACxD,CAAA;OACF;MACC,CAAA,EAAA,CAAA,GACP,kBAAC,SAAD,EAAA,UACGE,EAAU,cAAc,KAAK,MAC5B,kBAAC,MAAD;OAAsB,WAAU;OAAhC,UAAA;QACE,kBAAC,MAAD;SAAI,WAAU;SAAd,UAAA;UACGF,EAAG,gCAAgC,MAAM;UAAE;UAAEgB,EAAK;SACjD;;QACJ,kBAAC,MAAD;SAAI,WAAU;SACX,UAAAV,EAAaU,EAAK,KAAK;QACtB,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;SACX,UAAAV,EAAaU,EAAK,WAAW;QAC5B,CAAA;QACJ,kBAAC,MAAD;SAAI,WAAU;SACX,UAAAR,EAAiBQ,EAAK,WAAW;QAChC,CAAA;OACF;MAbK,GAAAA,EAAK,MAaV,CACL,EACI,CAAA,CACF;;IACJ,CAAA,CACI;;EAEV;C,KAnKH,kBAAC,OAAD;EAAK,WAAU;EACb,UAAA,kBAACC,GAAD;GACE,cAAa;GACb,OAAOjB,EAAG,6BAA6B,6BAA6B;GACpE,aAAaA,EACX,iCACA,yIACF;EACD,CAAA;CACE,CAAA;AA4JX"}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { useToursI18n as e } from "../i18n.js";
|
|
2
|
-
import {
|
|
2
|
+
import { useMediaLibrary as t } from "../hooks/useMediaLibrary.js";
|
|
3
3
|
import { useToursPermissionAccess as n } from "../hooks/useToursPermissionAccess.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { useToursContext as r } from "../providers/ToursProvider.js";
|
|
5
|
+
import { TOUR_PERMISSIONS as i } from "../../constants/permissions.js";
|
|
6
6
|
import { useToursFormatters as a } from "../utils/index.js";
|
|
7
|
-
import {
|
|
7
|
+
import { emitToursApiFailed as o } from "../telemetry.js";
|
|
8
8
|
import { useEffect as s, useState as c } from "react";
|
|
9
9
|
import { PermissionGate as l } from "@burdenoff/fe-libs/shared/components";
|
|
10
10
|
import { FileText as u, Image as d, Music as f, Search as p, Trash2 as m, Upload as h, Video as g } from "lucide-react";
|
|
11
11
|
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
12
12
|
import { GlassCard as y, IllustratedEmptyState as b, PagePurpose as x } from "@burdenoff/fe-libs/ui";
|
|
13
13
|
import { useEventBus as S } from "@burdenoff/fe-libs/shared/events";
|
|
14
|
-
|
|
14
|
+
// src/tours/pages/MediaLibraryPage.tsx
|
|
15
15
|
function C() {
|
|
16
|
-
let { tr: C } = e(), w =
|
|
16
|
+
let { tr: C } = e(), w = r(), T = S(), { hasPermission: E, isLoading: D } = n(), O = E(i.TOUR_MEDIA_LIST), k = E(i.TOUR_MEDIA_DELETE), { media: A, fetchMedia: j, uploadMedia: M, deleteMedia: N, uploadProgress: P } = t(), { formatFileSize: F } = a(), [I, L] = c(""), [R, z] = c("all");
|
|
17
17
|
s(() => {
|
|
18
|
-
D
|
|
18
|
+
!D && O && j(R === "all" ? void 0 : R, I);
|
|
19
19
|
}, [
|
|
20
20
|
j,
|
|
21
21
|
R,
|
|
@@ -28,7 +28,7 @@ function C() {
|
|
|
28
28
|
try {
|
|
29
29
|
await M(e);
|
|
30
30
|
} catch {
|
|
31
|
-
|
|
31
|
+
o(T, "media.upload", w);
|
|
32
32
|
}
|
|
33
33
|
})), j(R === "all" ? void 0 : R, I));
|
|
34
34
|
}, V = (e) => {
|
|
@@ -51,7 +51,7 @@ function C() {
|
|
|
51
51
|
className: "text-sm text-text-secondary",
|
|
52
52
|
children: C("mediaLibrary.subtitle", "Upload and manage media for tour steps")
|
|
53
53
|
})] }), /* @__PURE__ */ _(l, {
|
|
54
|
-
permission:
|
|
54
|
+
permission: i.TOUR_MEDIA_CREATE,
|
|
55
55
|
children: /* @__PURE__ */ v("label", {
|
|
56
56
|
className: "w-full sm:w-auto px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 cursor-pointer flex items-center justify-center gap-2",
|
|
57
57
|
children: [
|
|
@@ -178,7 +178,7 @@ function C() {
|
|
|
178
178
|
title: C("mediaLibrary.noMedia", "No media files"),
|
|
179
179
|
description: C("mediaLibrary.uploadFirstMedia", "Upload your first media file to get started"),
|
|
180
180
|
action: /* @__PURE__ */ _(l, {
|
|
181
|
-
permission:
|
|
181
|
+
permission: i.TOUR_MEDIA_CREATE,
|
|
182
182
|
children: /* @__PURE__ */ v("label", {
|
|
183
183
|
className: "px-4 py-2 min-h-[44px] bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 cursor-pointer inline-flex items-center justify-center gap-2",
|
|
184
184
|
children: [
|
|
@@ -199,7 +199,6 @@ function C() {
|
|
|
199
199
|
]
|
|
200
200
|
});
|
|
201
201
|
}
|
|
202
|
-
//#endregion
|
|
203
202
|
export { C as MediaLibraryPage };
|
|
204
203
|
|
|
205
204
|
//# sourceMappingURL=MediaLibraryPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaLibraryPage.js","names":[],"sources":["../../../src/tours/pages/MediaLibraryPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Upload, Search, Image as ImageIcon, Video, Music, FileText, Trash2 } from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursI18n } from '../i18n';\nimport { useMediaLibrary } from '../hooks/useMediaLibrary';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursFormatters } from '../utils';\nimport type { TourMediaType } from '../types';\nimport { emitToursApiFailed } from '../telemetry';\n\n/**\n * Media library page\n * Browse, upload, and manage tour media\n */\nexport function MediaLibraryPage() {\n const { tr } = useToursI18n();\n\n const toursContext = useToursContext();\n const eventBus = useEventBus();\n\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canListMedia = hasPermission(TOUR_PERMISSIONS.TOUR_MEDIA_LIST);\n const canDeleteMedia = hasPermission(TOUR_PERMISSIONS.TOUR_MEDIA_DELETE);\n\n const { media, fetchMedia, uploadMedia, deleteMedia, uploadProgress } = useMediaLibrary();\n const { formatFileSize } = useToursFormatters();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [typeFilter, setTypeFilter] = useState<TourMediaType | 'all'>('all');\n\n useEffect(() => {\n if (permissionsLoading || !canListMedia) return;\n fetchMedia(typeFilter === 'all' ? undefined : typeFilter, searchQuery);\n }, [fetchMedia, typeFilter, searchQuery, permissionsLoading, canListMedia]);\n\n const handleFileUpload = async (files: FileList | null) => {\n if (!files) return;\n\n await Promise.all(\n Array.from(files).map(async (file) => {\n try {\n await uploadMedia(file);\n } catch {\n emitToursApiFailed(eventBus, 'media.upload', toursContext);\n }\n })\n );\n\n // Refresh media list\n fetchMedia(typeFilter === 'all' ? undefined : typeFilter, searchQuery);\n };\n\n const getMediaIcon = (type: TourMediaType) => {\n switch (type) {\n case 'IMAGE':\n return <ImageIcon size={20} />;\n case 'VIDEO':\n return <Video size={20} />;\n case 'AUDIO':\n return <Music size={20} />;\n case 'DOCUMENT':\n return <FileText size={20} />;\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('mediaLibrary.title', 'Media Library')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr('mediaLibrary.subtitle', 'Upload and manage media for tour steps')}\n </p>\n </div>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_MEDIA_CREATE}>\n <label className=\"w-full sm:w-auto px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 cursor-pointer flex items-center justify-center gap-2\">\n <Upload size={20} />\n {tr('mediaLibrary.uploadMedia', 'Upload Media')}\n <input\n type=\"file\"\n multiple\n accept=\"image/*,video/*,audio/*,.pdf,.doc,.docx\"\n onChange={(e) => handleFileUpload(e.target.files)}\n className=\"hidden\"\n aria-label={tr('mediaLibrary.uploadMedia', 'Upload Media')}\n />\n </label>\n </PermissionGate>\n </div>\n\n <PagePurpose>\n {tr(\n 'mediaLibrary.purpose',\n 'Store and organise the images, videos, audio, and documents you attach to tour steps. Upload an asset here once, then reference it from any step — handy for product screenshots, short demo clips, or callout graphics that make a walkthrough clearer.'\n )}\n </PagePurpose>\n\n {/* Filters */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <div className=\"flex-1 relative\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('mediaLibrary.searchPlaceholder', 'Search media...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface\"\n aria-label={tr('mediaLibrary.searchPlaceholder', 'Search media...')}\n />\n </div>\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as TourMediaType | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n aria-label={tr('mediaLibrary.filterByType', 'Filter by media type')}\n >\n <option value=\"all\">{tr('mediaLibrary.allTypes', 'All Types')}</option>\n <option value=\"IMAGE\">{tr('mediaLibrary.typeImages', 'Images')}</option>\n <option value=\"VIDEO\">{tr('mediaLibrary.typeVideos', 'Videos')}</option>\n <option value=\"AUDIO\">{tr('mediaLibrary.typeAudio', 'Audio')}</option>\n <option value=\"DOCUMENT\">{tr('mediaLibrary.typeDocuments', 'Documents')}</option>\n </select>\n </div>\n\n {/* Upload Progress */}\n {Object.keys(uploadProgress).length > 0 && (\n <div className=\"space-y-2\">\n {Object.entries(uploadProgress).map(([fileId, progress]) => (\n <div key={fileId} className=\"border border-border-subtle rounded-md p-3\">\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-sm\">{tr('mediaLibrary.uploading', 'Uploading...')}</span>\n <span className=\"text-sm text-text-secondary\">{progress}%</span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full transition-all\"\n style={{ width: `${progress}%` }}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Media Grid */}\n {media.length > 0 ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4\">\n {media.map((item) => (\n <GlassCard\n key={item.id}\n treatment=\"plain\"\n className=\"overflow-hidden p-0 border-border-seam shadow-[var(--shadow-pop)]\"\n >\n {/* Thumbnail */}\n <div className=\"aspect-video bg-bg-sunken flex items-center justify-center\">\n {item.type === 'IMAGE' ? (\n <img\n src={item.cdnUrl}\n alt={item.altText || item.name}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <div className=\"text-text-secondary\">{getMediaIcon(item.type)}</div>\n )}\n </div>\n\n {/* Info */}\n <div className=\"p-3\">\n <h3 className=\"font-medium text-sm truncate\">{item.name}</h3>\n <div className=\"flex items-center justify-between mt-2 text-xs text-text-secondary\">\n <span>{item.type}</span>\n <span>{formatFileSize(item.size)}</span>\n </div>\n {canDeleteMedia && (\n <button\n onClick={() => {\n if (window.confirm(tr('mediaLibrary.deleteConfirm', 'Delete this media?')))\n deleteMedia(item.id);\n }}\n type=\"button\"\n className=\"mt-2 w-full p-2 min-h-[44px] text-xs text-status-error-text border border-status-error-border/30 rounded hover:bg-status-error-bg/10 flex items-center justify-center gap-1\"\n >\n <Trash2 size={12} />\n {tr('mediaLibrary.delete', 'Delete')}\n </button>\n )}\n </div>\n </GlassCard>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title={tr('mediaLibrary.noMedia', 'No media files')}\n description={tr(\n 'mediaLibrary.uploadFirstMedia',\n 'Upload your first media file to get started'\n )}\n action={\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_MEDIA_CREATE}>\n <label className=\"px-4 py-2 min-h-[44px] bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 cursor-pointer inline-flex items-center justify-center gap-2\">\n <Upload size={20} />\n {tr('mediaLibrary.uploadMedia', 'Upload Media')}\n <input\n type=\"file\"\n multiple\n accept=\"image/*,video/*,audio/*,.pdf,.doc,.docx\"\n onChange={(e) => handleFileUpload(e.target.files)}\n className=\"hidden\"\n aria-label={tr('mediaLibrary.uploadMedia', 'Upload Media')}\n />\n </label>\n </PermissionGate>\n }\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MediaLibraryPage.js","names":["ImageIcon","MediaLibraryPage","useToursI18n","toursContext","useToursContext","eventBus","useEventBus","permissionsLoading","useToursPermissionAccess","canListMedia","hasPermission","TOUR_PERMISSIONS","canDeleteMedia","useMediaLibrary","useToursFormatters","searchQuery","setSearchQuery","useState","typeFilter","setTypeFilter","fetchMedia","handleFileUpload","files","uploadMedia","file","getMediaIcon","type","Image","Video","Music","FileText","tr","PermissionGate","Upload","PagePurpose","Search","uploadProgress","fileId","progress","media","GlassCard","item","formatFileSize","deleteMedia","Trash2","IllustratedEmptyState"],"sources":["../../../src/tours/pages/MediaLibraryPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Upload, Search, Image as ImageIcon, Video, Music, FileText, Trash2 } from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursI18n } from '../i18n';\nimport { useMediaLibrary } from '../hooks/useMediaLibrary';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursFormatters } from '../utils';\nimport type { TourMediaType } from '../types';\nimport { emitToursApiFailed } from '../telemetry';\n\n/**\n * Media library page\n * Browse, upload, and manage tour media\n */\nexport function MediaLibraryPage() {\n const { tr } = useToursI18n();\n\n const toursContext = useToursContext();\n const eventBus = useEventBus();\n\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canListMedia = hasPermission(TOUR_PERMISSIONS.TOUR_MEDIA_LIST);\n const canDeleteMedia = hasPermission(TOUR_PERMISSIONS.TOUR_MEDIA_DELETE);\n\n const { media, fetchMedia, uploadMedia, deleteMedia, uploadProgress } = useMediaLibrary();\n const { formatFileSize } = useToursFormatters();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [typeFilter, setTypeFilter] = useState<TourMediaType | 'all'>('all');\n\n useEffect(() => {\n if (permissionsLoading || !canListMedia) return;\n fetchMedia(typeFilter === 'all' ? undefined : typeFilter, searchQuery);\n }, [fetchMedia, typeFilter, searchQuery, permissionsLoading, canListMedia]);\n\n const handleFileUpload = async (files: FileList | null) => {\n if (!files) return;\n\n await Promise.all(\n Array.from(files).map(async (file) => {\n try {\n await uploadMedia(file);\n } catch {\n emitToursApiFailed(eventBus, 'media.upload', toursContext);\n }\n })\n );\n\n // Refresh media list\n fetchMedia(typeFilter === 'all' ? undefined : typeFilter, searchQuery);\n };\n\n const getMediaIcon = (type: TourMediaType) => {\n switch (type) {\n case 'IMAGE':\n return <ImageIcon size={20} />;\n case 'VIDEO':\n return <Video size={20} />;\n case 'AUDIO':\n return <Music size={20} />;\n case 'DOCUMENT':\n return <FileText size={20} />;\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('mediaLibrary.title', 'Media Library')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr('mediaLibrary.subtitle', 'Upload and manage media for tour steps')}\n </p>\n </div>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_MEDIA_CREATE}>\n <label className=\"w-full sm:w-auto px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 cursor-pointer flex items-center justify-center gap-2\">\n <Upload size={20} />\n {tr('mediaLibrary.uploadMedia', 'Upload Media')}\n <input\n type=\"file\"\n multiple\n accept=\"image/*,video/*,audio/*,.pdf,.doc,.docx\"\n onChange={(e) => handleFileUpload(e.target.files)}\n className=\"hidden\"\n aria-label={tr('mediaLibrary.uploadMedia', 'Upload Media')}\n />\n </label>\n </PermissionGate>\n </div>\n\n <PagePurpose>\n {tr(\n 'mediaLibrary.purpose',\n 'Store and organise the images, videos, audio, and documents you attach to tour steps. Upload an asset here once, then reference it from any step — handy for product screenshots, short demo clips, or callout graphics that make a walkthrough clearer.'\n )}\n </PagePurpose>\n\n {/* Filters */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <div className=\"flex-1 relative\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('mediaLibrary.searchPlaceholder', 'Search media...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface\"\n aria-label={tr('mediaLibrary.searchPlaceholder', 'Search media...')}\n />\n </div>\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as TourMediaType | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n aria-label={tr('mediaLibrary.filterByType', 'Filter by media type')}\n >\n <option value=\"all\">{tr('mediaLibrary.allTypes', 'All Types')}</option>\n <option value=\"IMAGE\">{tr('mediaLibrary.typeImages', 'Images')}</option>\n <option value=\"VIDEO\">{tr('mediaLibrary.typeVideos', 'Videos')}</option>\n <option value=\"AUDIO\">{tr('mediaLibrary.typeAudio', 'Audio')}</option>\n <option value=\"DOCUMENT\">{tr('mediaLibrary.typeDocuments', 'Documents')}</option>\n </select>\n </div>\n\n {/* Upload Progress */}\n {Object.keys(uploadProgress).length > 0 && (\n <div className=\"space-y-2\">\n {Object.entries(uploadProgress).map(([fileId, progress]) => (\n <div key={fileId} className=\"border border-border-subtle rounded-md p-3\">\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-sm\">{tr('mediaLibrary.uploading', 'Uploading...')}</span>\n <span className=\"text-sm text-text-secondary\">{progress}%</span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full transition-all\"\n style={{ width: `${progress}%` }}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Media Grid */}\n {media.length > 0 ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4\">\n {media.map((item) => (\n <GlassCard\n key={item.id}\n treatment=\"plain\"\n className=\"overflow-hidden p-0 border-border-seam shadow-[var(--shadow-pop)]\"\n >\n {/* Thumbnail */}\n <div className=\"aspect-video bg-bg-sunken flex items-center justify-center\">\n {item.type === 'IMAGE' ? (\n <img\n src={item.cdnUrl}\n alt={item.altText || item.name}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <div className=\"text-text-secondary\">{getMediaIcon(item.type)}</div>\n )}\n </div>\n\n {/* Info */}\n <div className=\"p-3\">\n <h3 className=\"font-medium text-sm truncate\">{item.name}</h3>\n <div className=\"flex items-center justify-between mt-2 text-xs text-text-secondary\">\n <span>{item.type}</span>\n <span>{formatFileSize(item.size)}</span>\n </div>\n {canDeleteMedia && (\n <button\n onClick={() => {\n if (window.confirm(tr('mediaLibrary.deleteConfirm', 'Delete this media?')))\n deleteMedia(item.id);\n }}\n type=\"button\"\n className=\"mt-2 w-full p-2 min-h-[44px] text-xs text-status-error-text border border-status-error-border/30 rounded hover:bg-status-error-bg/10 flex items-center justify-center gap-1\"\n >\n <Trash2 size={12} />\n {tr('mediaLibrary.delete', 'Delete')}\n </button>\n )}\n </div>\n </GlassCard>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title={tr('mediaLibrary.noMedia', 'No media files')}\n description={tr(\n 'mediaLibrary.uploadFirstMedia',\n 'Upload your first media file to get started'\n )}\n action={\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_MEDIA_CREATE}>\n <label className=\"px-4 py-2 min-h-[44px] bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 cursor-pointer inline-flex items-center justify-center gap-2\">\n <Upload size={20} />\n {tr('mediaLibrary.uploadMedia', 'Upload Media')}\n <input\n type=\"file\"\n multiple\n accept=\"image/*,video/*,audio/*,.pdf,.doc,.docx\"\n onChange={(e) => handleFileUpload(e.target.files)}\n className=\"hidden\"\n aria-label={tr('mediaLibrary.uploadMedia', 'Upload Media')}\n />\n </label>\n </PermissionGate>\n }\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MyToursPage — user-facing browse for available tours.
|
|
3
|
+
*
|
|
4
|
+
* Lists tours returned by `toursForContext` (filtered to the current
|
|
5
|
+
* product/module/page surface) and decorates each with the requesting
|
|
6
|
+
* user's `TourUserProgress` status (Completed / In progress / Skipped /
|
|
7
|
+
* Not started). Read-only — tours are actually played via the SDK overlay,
|
|
8
|
+
* not via mutations on this page.
|
|
9
|
+
*/
|
|
10
|
+
export declare function MyToursPage(): import('react').JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useGetToursForContextQuery as e } from "../../generated/global-operations.js";
|
|
2
2
|
import { useToursContext as t } from "../providers/ToursProvider.js";
|
|
3
|
-
import {
|
|
3
|
+
import { useToursI18n as n } from "../i18n.js";
|
|
4
4
|
import { useEffect as r, useRef as i } from "react";
|
|
5
5
|
import { Markdown as a } from "@burdenoff/fe-libs/shared/components";
|
|
6
6
|
import { CheckCircle2 as o, Circle as s, MinusCircle as c, Play as l } from "lucide-react";
|
|
@@ -8,7 +8,7 @@ import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
|
8
8
|
import { useSearchParams as f } from "react-router";
|
|
9
9
|
import { EmphasisPanel as p, GlassCard as m, GradientText as h, IllustratedEmptyState as g, PagePurpose as _ } from "@burdenoff/fe-libs/ui";
|
|
10
10
|
import { useEventBus as v } from "@burdenoff/fe-libs/shared/events";
|
|
11
|
-
|
|
11
|
+
// src/tours/pages/MyToursPage.tsx
|
|
12
12
|
var y = /^[a-zA-Z0-9_-]+$/, b = /^[a-zA-Z0-9_\-/]+$/;
|
|
13
13
|
function x(e, t) {
|
|
14
14
|
return e && y.test(e) ? e : t;
|
|
@@ -17,7 +17,7 @@ function S(e, t) {
|
|
|
17
17
|
return e && b.test(e) ? e : t;
|
|
18
18
|
}
|
|
19
19
|
function C() {
|
|
20
|
-
let { tr: o } =
|
|
20
|
+
let { tr: o } = n(), { productId: s, moduleId: c, pageId: l, workspaceId: y, currentUser: b } = t(), [C] = f(), T = v(), E = i(!1);
|
|
21
21
|
r(() => {
|
|
22
22
|
E.current || (E.current = !0, T.emit("tours.page.viewed", {
|
|
23
23
|
page: "/tours",
|
|
@@ -33,7 +33,7 @@ function C() {
|
|
|
33
33
|
l,
|
|
34
34
|
y
|
|
35
35
|
]);
|
|
36
|
-
let D = x(s, void 0) ?? x(C.get("productId"), void 0), O = x(c, void 0) ?? x(C.get("moduleId"), void 0), k = S(l, void 0) ?? S(C.get("pageId"), void 0), { data: A, loading: j, error: M, refetch: N } =
|
|
36
|
+
let D = x(s, void 0) ?? x(C.get("productId"), void 0), O = x(c, void 0) ?? x(C.get("moduleId"), void 0), k = S(l, void 0) ?? S(C.get("pageId"), void 0), { data: A, loading: j, error: M, refetch: N } = e({
|
|
37
37
|
variables: D ? { context: {
|
|
38
38
|
productId: D,
|
|
39
39
|
moduleId: O,
|
|
@@ -138,7 +138,6 @@ function w({ status: e, tr: t }) {
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
-
//#endregion
|
|
142
141
|
export { C as MyToursPage };
|
|
143
142
|
|
|
144
143
|
//# sourceMappingURL=MyToursPage.js.map
|