@burdenoff/microfe-tours 2026.527.2 → 2026.527.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/tours/ToursUserRoutes.js +2 -4
  2. package/dist/tours/ToursUserRoutes.js.map +1 -1
  3. package/dist/tours/components/RouteHelpers.js +4 -4
  4. package/dist/tours/components/RouteHelpers.js.map +1 -1
  5. package/dist/tours/hooks/useTourPreview.js +39 -39
  6. package/dist/tours/hooks/useTourPreview.js.map +1 -1
  7. package/dist/tours/hooks/useToursList.js.map +1 -1
  8. package/dist/tours/pages/MediaLibraryPage.js +11 -8
  9. package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
  10. package/dist/tours/pages/MyToursPage.js +59 -57
  11. package/dist/tours/pages/MyToursPage.js.map +1 -1
  12. package/dist/tours/pages/MyToursProgressPage.js +65 -61
  13. package/dist/tours/pages/MyToursProgressPage.js.map +1 -1
  14. package/dist/tours/pages/SchedulerPage.js +18 -4
  15. package/dist/tours/pages/SchedulerPage.js.map +1 -1
  16. package/dist/tours/pages/StepEditorPage.js +330 -276
  17. package/dist/tours/pages/StepEditorPage.js.map +1 -1
  18. package/dist/tours/pages/TemplateLibraryPage.js +7 -2
  19. package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
  20. package/dist/tours/pages/TourBuilderPage.js +25 -11
  21. package/dist/tours/pages/TourBuilderPage.js.map +1 -1
  22. package/dist/tours/pages/TourPreviewPage.js +12 -4
  23. package/dist/tours/pages/TourPreviewPage.js.map +1 -1
  24. package/dist/tours/pages/ToursListPage.js +165 -149
  25. package/dist/tours/pages/ToursListPage.js.map +1 -1
  26. package/dist/tours/providers/ToursProvider.js +1 -1
  27. package/dist/tours/providers/ToursProvider.js.map +1 -1
  28. package/dist/tours/utils/index.js.map +1 -1
  29. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"StepEditorPage.js","names":[],"sources":["../../../src/tours/pages/StepEditorPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n Plus,\n Save,\n Trash2,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n ChevronDown,\n Menu,\n Paperclip,\n X,\n} from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useStepSequencer } from '../hooks/useStepSequencer';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useMediaLibrary } from '../hooks/useMediaLibrary';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\n\n/**\n * Step editor page\n * Manage tour steps with sequencer and editor\n * Responsive: sidebar drawer on mobile, side panel on desktop\n */\nexport function StepEditorPage() {\n const { tr } = useToursI18n();\n\n const { tourId, stepId } = useParams();\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canCreateStep = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_CREATE);\n const canUpdateStep = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_UPDATE);\n const canDeleteStep = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_DELETE);\n\n const { tour, loadTour, syncSteps, saving } = useTourBuilder(tourId);\n const { steps, selectedStep, selectStep, createStep, deleteStep, updateStepField, moveStep } =\n useStepSequencer();\n const { media, fetchMedia, attachToStep, loading: mediaLoading } = useMediaLibrary();\n\n // Mobile sidebar state\n const [isSidebarOpen, setIsSidebarOpen] = useState(false);\n const [isMobile, setIsMobile] = useState(false);\n const [attachmentMediaId, setAttachmentMediaId] = useState('');\n const [attachmentPosition, setAttachmentPosition] = useState<'header' | 'body' | 'footer'>(\n 'body'\n );\n const [attachingMedia, setAttachingMedia] = useState(false);\n\n // Detect mobile viewport\n useEffect(() => {\n const checkMobile = () => {\n const mobile = window.innerWidth < 768;\n setIsMobile(mobile);\n // Auto-close sidebar on desktop\n if (!mobile) {\n setIsSidebarOpen(false);\n }\n };\n checkMobile();\n window.addEventListener('resize', checkMobile);\n return () => window.removeEventListener('resize', checkMobile);\n }, []);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n void fetchMedia();\n }, [fetchMedia]);\n\n useEffect(() => {\n const selectedStepId = stepId || selectedStep?.id;\n if (selectedStepId && steps.length > 0) {\n const step = steps.find((s) => s.id === selectedStepId);\n if (step) {\n selectStep(step);\n }\n }\n }, [stepId, steps, selectStep, selectedStep?.id]);\n\n const handleAddStep = () => {\n createStep();\n };\n\n const handleSaveSteps = async () => {\n if (tourId) {\n try {\n await syncSteps(tourId, steps);\n } catch {\n emitToursApiFailed(eventBus, 'step.save', toursContext);\n }\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const handleAttachMedia = async () => {\n if (!selectedStep || !tourId || !attachmentMediaId) return;\n if (selectedStep.id.startsWith('temp_')) {\n window.alert('Save your steps before attaching media to them.');\n return;\n }\n\n try {\n setAttachingMedia(true);\n await attachToStep(\n selectedStep.id,\n attachmentMediaId,\n attachmentPosition,\n (selectedStep.media?.length ?? 0) + 1\n );\n await loadTour(tourId);\n setAttachmentMediaId('');\n } catch {\n emitToursApiFailed(eventBus, 'media.attach', toursContext);\n } finally {\n setAttachingMedia(false);\n }\n };\n\n const handleSelectStep = (step: (typeof steps)[0]) => {\n selectStep(step);\n // Close sidebar on mobile after selecting\n if (isMobile) {\n setIsSidebarOpen(false);\n }\n };\n\n return (\n <div className=\"flex flex-col h-full bg-background\">\n {/* Header */}\n <div className=\"border-b border-border p-3 sm:p-4 flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4 bg-card\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={handleBack}\n className=\"p-2 hover:bg-accent rounded-md shrink-0\"\n aria-label={tr('stepEditor.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-base sm:text-lg font-semibold truncate\">\n {tour?.name || tr('stepEditor.tourFallback')} - {tr('stepEditor.stepsLabel')}\n </h1>\n <p className=\"text-xs sm:text-sm text-muted-foreground\">\n {steps.length} {tr('stepEditor.stepsCount')}\n </p>\n </div>\n </div>\n\n {/* Action buttons */}\n <div className=\"flex items-center gap-2 sm:gap-3 ml-auto\">\n {/* Mobile: Toggle sidebar button */}\n {isMobile && (\n <button\n onClick={() => setIsSidebarOpen(!isSidebarOpen)}\n className=\"px-3 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 sm:hidden\"\n >\n <Menu size={18} />\n <span className=\"text-sm\">{tr('stepEditor.steps')}</span>\n {steps.length > 0 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-primary/20 rounded-full\">\n {steps.length}\n </span>\n )}\n </button>\n )}\n\n {canCreateStep && (\n <button\n onClick={handleAddStep}\n className=\"px-3 sm:px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 text-sm sm:text-base\"\n >\n <Plus size={18} />\n <span className=\"hidden xs:inline\">{tr('stepEditor.addStep')}</span>\n </button>\n )}\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_STEP_UPDATE}>\n <button\n onClick={handleSaveSteps}\n disabled={saving || !canUpdateStep}\n className=\"px-3 sm:px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center gap-2 text-sm sm:text-base\"\n >\n <Save size={18} />\n <span className=\"hidden xs:inline\">\n {saving ? tr('stepEditor.saving') : tr('stepEditor.save')}\n </span>\n </button>\n </PermissionGate>\n </div>\n </div>\n\n <div className=\"flex-1 flex overflow-hidden relative\">\n {/* Mobile Sidebar Overlay */}\n {isMobile && isSidebarOpen && (\n <div\n className=\"fixed inset-0 bg-foreground/40 z-40 md:hidden\"\n onClick={() => setIsSidebarOpen(false)}\n />\n )}\n\n {/* Step List Sidebar */}\n <div\n className={`\n ${isMobile ? 'fixed inset-y-0 left-0 z-50 w-[min(18rem,calc(100vw-2rem))] transform transition-transform duration-300' : 'w-64 lg:w-80 shrink-0'}\n ${isMobile && !isSidebarOpen ? '-translate-x-full' : 'translate-x-0'}\n border-r border-border overflow-y-auto bg-card\n `}\n >\n {/* Mobile sidebar header */}\n {isMobile && (\n <div className=\"flex items-center justify-between p-4 border-b border-border sticky top-0 bg-card z-10\">\n <h2 className=\"font-semibold\">{tr('stepEditor.tourSteps')}</h2>\n <button\n onClick={() => setIsSidebarOpen(false)}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('stepEditor.closeSteps')}\n >\n <X size={20} />\n </button>\n </div>\n )}\n\n <div className=\"p-3 sm:p-4 space-y-2\">\n {steps.length === 0 ? (\n <div className=\"text-center py-8 text-muted-foreground\">\n <p className=\"text-sm\">{tr('stepEditor.noStepsYet')}</p>\n <p className=\"text-xs mt-1\">{tr('stepEditor.clickAddStep')}</p>\n </div>\n ) : (\n steps.map((step, index) => (\n <div\n key={step.id}\n onClick={() => handleSelectStep(step)}\n className={`p-3 border rounded-md cursor-pointer transition-colors ${\n selectedStep?.id === step.id\n ? 'border-primary bg-primary/10'\n : 'border-border hover:bg-accent'\n }`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-xs text-muted-foreground mb-1\">\n {tr('stepEditor.stepNumber')} {index + 1}\n </div>\n <div className=\"font-medium text-sm truncate\">\n {step.title || tr('stepEditor.untitled')}\n </div>\n {step.targetSelector && (\n <div className=\"text-xs text-muted-foreground mt-1 truncate font-mono\">\n {step.targetSelector}\n </div>\n )}\n </div>\n {canDeleteStep && (\n <div className=\"flex items-center gap-1 shrink-0\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n if (index > 0) {\n moveStep(index, index - 1);\n }\n }}\n className=\"p-1.5 sm:p-2 min-h-[32px] min-w-[32px] sm:min-h-[40px] sm:min-w-[40px] hover:bg-accent rounded\"\n title=\"Move step up\"\n aria-label=\"Move step up\"\n disabled={index === 0}\n >\n <ChevronUp size={14} />\n </button>\n <button\n onClick={(e) => {\n e.stopPropagation();\n if (index < steps.length - 1) {\n moveStep(index, index + 1);\n }\n }}\n className=\"p-1.5 sm:p-2 min-h-[32px] min-w-[32px] sm:min-h-[40px] sm:min-w-[40px] hover:bg-accent rounded\"\n title=\"Move step down\"\n aria-label=\"Move step down\"\n disabled={index === steps.length - 1}\n >\n <ChevronDown size={14} />\n </button>\n <button\n onClick={(e) => {\n e.stopPropagation();\n deleteStep(step.id);\n }}\n className=\"p-1.5 sm:p-2 min-h-[32px] min-w-[32px] sm:min-h-[40px] sm:min-w-[40px] hover:bg-destructive/10 rounded text-destructive\"\n title={tr('stepEditor.deleteStep')}\n aria-label={tr('stepEditor.deleteStep')}\n >\n <Trash2 size={14} />\n </button>\n </div>\n )}\n </div>\n </div>\n ))\n )}\n </div>\n </div>\n\n {/* Step Editor */}\n <div className=\"flex-1 overflow-y-auto p-4 sm:p-6\">\n {selectedStep ? (\n <div className=\"max-w-2xl mx-auto space-y-4 sm:space-y-6\">\n {/* Mobile: Step navigation */}\n {isMobile && steps.length > 1 && (\n <div className=\"flex items-center justify-between bg-muted/50 rounded-lg p-2 mb-4\">\n <button\n onClick={() => {\n const currentIndex = steps.findIndex((s) => s.id === selectedStep.id);\n if (currentIndex > 0) {\n selectStep(steps[currentIndex - 1]);\n }\n }}\n disabled={steps.findIndex((s) => s.id === selectedStep.id) === 0}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md disabled:opacity-30\"\n aria-label={tr('stepEditor.previousStep')}\n >\n <ChevronLeft size={20} />\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {tr('stepEditor.stepNumber')}{' '}\n {steps.findIndex((s) => s.id === selectedStep.id) + 1} {tr('stepEditor.of')}{' '}\n {steps.length}\n </span>\n <button\n onClick={() => {\n const currentIndex = steps.findIndex((s) => s.id === selectedStep.id);\n if (currentIndex < steps.length - 1) {\n selectStep(steps[currentIndex + 1]);\n }\n }}\n disabled={steps.findIndex((s) => s.id === selectedStep.id) === steps.length - 1}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md disabled:opacity-30\"\n aria-label={tr('stepEditor.nextStep')}\n >\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n\n <h2 className=\"text-lg sm:text-xl font-semibold\">{tr('stepEditor.editStep')}</h2>\n\n {/* Title */}\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('stepEditor.stepTitle')} *\n </label>\n <input\n type=\"text\"\n value={selectedStep.title}\n onChange={(e) => updateStepField(selectedStep.id, 'title', e.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm sm:text-base\"\n placeholder={tr('stepEditor.stepTitlePlaceholder')}\n />\n </div>\n\n {/* Content */}\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('stepEditor.content')} *\n </label>\n <textarea\n value={selectedStep.content}\n onChange={(e) => updateStepField(selectedStep.id, 'content', e.target.value)}\n rows={4}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm sm:text-base resize-y min-h-[100px]\"\n placeholder={tr('stepEditor.contentPlaceholder')}\n />\n </div>\n\n {/* Selector */}\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('stepEditor.cssSelector')} *\n <span className=\"text-muted-foreground font-normal ml-2\">\n ({tr('stepEditor.targetElement')})\n </span>\n </label>\n <input\n type=\"text\"\n value={selectedStep.targetSelector || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelector', e.target.value)\n }\n placeholder={tr('stepEditor.cssSelectorPlaceholder')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background font-mono text-sm\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr('stepEditor.dataTourHint')}\n </p>\n </div>\n\n {/* Placement */}\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('stepEditor.tooltipPlacement')}\n </label>\n <select\n value={selectedStep.placement}\n onChange={(e) => updateStepField(selectedStep.id, 'placement', e.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm sm:text-base\"\n >\n <option value=\"AUTO\">{tr('stepEditor.placementAuto')}</option>\n <option value=\"TOP\">{tr('stepEditor.placementTop')}</option>\n <option value=\"BOTTOM\">{tr('stepEditor.placementBottom')}</option>\n <option value=\"LEFT\">{tr('stepEditor.placementLeft')}</option>\n <option value=\"RIGHT\">{tr('stepEditor.placementRight')}</option>\n <option value=\"CENTER\">{tr('stepEditor.placementCenter')}</option>\n </select>\n </div>\n\n {/* Device-specific selectors */}\n <details className=\"border border-border rounded-md\">\n <summary className=\"px-4 py-3 cursor-pointer font-medium text-sm hover:bg-accent/50 rounded-t-md\">\n {tr('stepEditor.deviceSpecificSelectors')}\n </summary>\n <div className=\"p-4 pt-0 space-y-3 border-t border-border\">\n <p className=\"text-xs text-muted-foreground mb-3\">\n {tr('stepEditor.deviceSelectorHint')}\n </p>\n <div>\n <label className=\"block text-xs font-medium mb-1\">\n {tr('stepEditor.mobileSelector')}\n </label>\n <input\n type=\"text\"\n value={selectedStep.targetSelectorMobile || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelectorMobile', e.target.value)\n }\n placeholder={tr('stepEditor.leaveEmptyDefault')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">\n {tr('stepEditor.tabletSelector')}\n </label>\n <input\n type=\"text\"\n value={selectedStep.targetSelectorTablet || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelectorTablet', e.target.value)\n }\n placeholder={tr('stepEditor.leaveEmptyDefault')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">\n {tr('stepEditor.desktopSelector')}\n </label>\n <input\n type=\"text\"\n value={selectedStep.targetSelectorDesktop || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelectorDesktop', e.target.value)\n }\n placeholder={tr('stepEditor.leaveEmptyDefault')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n />\n </div>\n </div>\n </details>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <label className=\"flex items-center gap-3 cursor-pointer rounded-md border border-border p-3\">\n <input\n type=\"checkbox\"\n checked={selectedStep.requireInteraction ?? false}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'requireInteraction', e.target.checked)\n }\n className=\"w-4 h-4 rounded\"\n />\n <div>\n <div className=\"text-sm font-medium\">Require interaction</div>\n <div className=\"text-xs text-muted-foreground\">\n User must interact with the highlighted element before advancing.\n </div>\n </div>\n </label>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\">Wait for timeout (ms)</label>\n <input\n type=\"number\"\n min=\"0\"\n value={selectedStep.waitForTimeout ?? ''}\n onChange={(e) =>\n updateStepField(\n selectedStep.id,\n 'waitForTimeout',\n e.target.value ? Number(e.target.value) : undefined\n )\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n placeholder=\"1500\"\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\">Wait for selector</label>\n <input\n type=\"text\"\n value={selectedStep.waitForSelector || ''}\n onChange={(e) =>\n updateStepField(\n selectedStep.id,\n 'waitForSelector',\n e.target.value || undefined\n )\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n placeholder=\"[data-tour='agents-tabs']\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\">Wait for event</label>\n <input\n type=\"text\"\n value={selectedStep.waitForEvent || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'waitForEvent', e.target.value || undefined)\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n placeholder=\"tour:ready\"\n />\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\">Skip conditions (JSON)</label>\n <textarea\n value={\n selectedStep.skipConditions\n ? JSON.stringify(selectedStep.skipConditions, null, 2)\n : ''\n }\n onChange={(e) => {\n const rawValue = e.target.value.trim();\n if (!rawValue) {\n updateStepField(selectedStep.id, 'skipConditions', undefined);\n return;\n }\n\n try {\n updateStepField(selectedStep.id, 'skipConditions', JSON.parse(rawValue));\n } catch {\n updateStepField(selectedStep.id, 'skipConditions', rawValue);\n }\n }}\n rows={4}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n placeholder='{\"selectorMissing\":\"[data-tour=\\\"missing\\\"]\"}'\n />\n </div>\n\n <div className=\"border border-border rounded-md p-4 space-y-4\">\n <div className=\"flex items-center gap-2\">\n <Paperclip size={18} />\n <h3 className=\"text-sm font-semibold\">Step media</h3>\n </div>\n\n {selectedStep.media && selectedStep.media.length > 0 ? (\n <div className=\"space-y-2\">\n {selectedStep.media.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between rounded-md border border-border p-2 text-sm\"\n >\n <div>\n <div className=\"font-medium\">{item.media.name}</div>\n <div className=\"text-xs text-muted-foreground\">{item.position}</div>\n </div>\n <span className=\"text-xs text-muted-foreground\">{item.media.type}</span>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n No media attached to this step yet.\n </p>\n )}\n\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-[minmax(0,1fr)_160px_auto]\">\n <select\n value={attachmentMediaId}\n onChange={(e) => setAttachmentMediaId(e.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n >\n <option value=\"\">\n {mediaLoading ? 'Loading media...' : 'Select uploaded media'}\n </option>\n {media.map((item) => (\n <option key={item.id} value={item.id}>\n {item.name} ({item.type})\n </option>\n ))}\n </select>\n\n <select\n value={attachmentPosition}\n onChange={(e) =>\n setAttachmentPosition(e.target.value as 'header' | 'body' | 'footer')\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n >\n <option value=\"header\">Header</option>\n <option value=\"body\">Body</option>\n <option value=\"footer\">Footer</option>\n </select>\n\n <button\n type=\"button\"\n onClick={handleAttachMedia}\n disabled={attachingMedia || !attachmentMediaId}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50\"\n >\n Attach\n </button>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center h-full text-center px-4\">\n <div className=\"w-16 h-16 bg-muted rounded-full flex items-center justify-center mb-4\">\n <Plus size={24} className=\"text-muted-foreground\" />\n </div>\n <p className=\"text-muted-foreground mb-2\">{tr('stepEditor.noStepSelected')}</p>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {steps.length > 0\n ? tr('stepEditor.selectStepToEdit')\n : tr('stepEditor.createFirstStep')}\n </p>\n {steps.length === 0 && canCreateStep && (\n <button\n onClick={handleAddStep}\n className=\"px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 flex items-center gap-2\"\n >\n <Plus size={18} />\n {tr('stepEditor.addFirstStep')}\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StepEditorPage.js","names":[],"sources":["../../../src/tours/pages/StepEditorPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n Plus,\n Save,\n Trash2,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n ChevronDown,\n Menu,\n Paperclip,\n X,\n} from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useStepSequencer } from '../hooks/useStepSequencer';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useMediaLibrary } from '../hooks/useMediaLibrary';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\n\n/**\n * Step editor page\n * Manage tour steps with sequencer and editor\n * Responsive: sidebar drawer on mobile, side panel on desktop\n */\nexport function StepEditorPage() {\n const { tr } = useToursI18n();\n\n const { tourId, stepId } = useParams();\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canCreateStep = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_CREATE);\n const canUpdateStep = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_UPDATE);\n const canDeleteStep = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_DELETE);\n\n const { tour, loadTour, syncSteps, saving } = useTourBuilder(tourId);\n const { steps, selectedStep, selectStep, createStep, deleteStep, updateStepField, moveStep } =\n useStepSequencer();\n const { media, fetchMedia, attachToStep, loading: mediaLoading } = useMediaLibrary();\n\n // Mobile sidebar state\n const [isSidebarOpen, setIsSidebarOpen] = useState(false);\n const [isMobile, setIsMobile] = useState(\n () => typeof window !== 'undefined' && window.innerWidth < 768\n );\n const [attachmentMediaId, setAttachmentMediaId] = useState('');\n const [attachmentPosition, setAttachmentPosition] = useState<'header' | 'body' | 'footer'>(\n 'body'\n );\n const [attachingMedia, setAttachingMedia] = useState(false);\n\n // Detect mobile viewport\n useEffect(() => {\n const checkMobile = () => {\n const mobile = window.innerWidth < 768;\n setIsMobile(mobile);\n // Auto-close sidebar on desktop\n if (!mobile) {\n setIsSidebarOpen(false);\n }\n };\n window.addEventListener('resize', checkMobile);\n return () => window.removeEventListener('resize', checkMobile);\n }, []);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n void fetchMedia();\n }, [fetchMedia]);\n\n useEffect(() => {\n const selectedStepId = stepId || selectedStep?.id;\n if (selectedStepId && steps.length > 0) {\n const step = steps.find((s) => s.id === selectedStepId);\n if (step) {\n selectStep(step);\n }\n }\n }, [stepId, steps, selectStep, selectedStep?.id]);\n\n const handleAddStep = () => {\n createStep();\n };\n\n const handleSaveSteps = async () => {\n if (tourId) {\n try {\n await syncSteps(tourId, steps);\n } catch {\n emitToursApiFailed(eventBus, 'step.save', toursContext);\n }\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const handleAttachMedia = async () => {\n if (!selectedStep || !tourId || !attachmentMediaId) return;\n if (selectedStep.id.startsWith('temp_')) {\n window.alert('Save your steps before attaching media to them.');\n return;\n }\n\n try {\n setAttachingMedia(true);\n await attachToStep(\n selectedStep.id,\n attachmentMediaId,\n attachmentPosition,\n (selectedStep.media?.length ?? 0) + 1\n );\n await loadTour(tourId);\n setAttachmentMediaId('');\n } catch {\n emitToursApiFailed(eventBus, 'media.attach', toursContext);\n } finally {\n setAttachingMedia(false);\n }\n };\n\n const handleSelectStep = (step: (typeof steps)[0]) => {\n selectStep(step);\n // Close sidebar on mobile after selecting\n if (isMobile) {\n setIsSidebarOpen(false);\n }\n };\n\n return (\n <div className=\"flex flex-col h-full bg-background\">\n {/* Header */}\n <div className=\"border-b border-border p-3 sm:p-4 flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4 bg-card\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 hover:bg-accent rounded-md shrink-0\"\n aria-label={tr('stepEditor.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-base sm:text-lg font-semibold truncate\">\n {tour?.name || tr('stepEditor.tourFallback')} - {tr('stepEditor.stepsLabel')}\n </h1>\n <p className=\"text-xs sm:text-sm text-muted-foreground\">\n {steps.length} {tr('stepEditor.stepsCount')}\n </p>\n </div>\n </div>\n\n {/* Action buttons */}\n <div className=\"flex items-center gap-2 sm:gap-3 ml-auto\">\n {/* Mobile: Toggle sidebar button */}\n {isMobile && (\n <button\n type=\"button\"\n onClick={() => setIsSidebarOpen(!isSidebarOpen)}\n className=\"px-3 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 sm:hidden\"\n >\n <Menu size={18} />\n <span className=\"text-sm\">{tr('stepEditor.steps')}</span>\n {steps.length > 0 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-primary/20 rounded-full\">\n {steps.length}\n </span>\n )}\n </button>\n )}\n\n {canCreateStep && (\n <button\n type=\"button\"\n onClick={handleAddStep}\n className=\"px-3 sm:px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 text-sm sm:text-base\"\n >\n <Plus size={18} />\n <span className=\"hidden xs:inline\">{tr('stepEditor.addStep')}</span>\n </button>\n )}\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_STEP_UPDATE}>\n <button\n type=\"button\"\n onClick={handleSaveSteps}\n disabled={saving || !canUpdateStep}\n className=\"px-3 sm:px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center gap-2 text-sm sm:text-base\"\n >\n <Save size={18} />\n <span className=\"hidden xs:inline\">\n {saving ? tr('stepEditor.saving') : tr('stepEditor.save')}\n </span>\n </button>\n </PermissionGate>\n </div>\n </div>\n\n <div className=\"flex-1 flex overflow-hidden relative\">\n {/* Mobile Sidebar Overlay */}\n {isMobile && isSidebarOpen && (\n <button\n type=\"button\"\n aria-label={tr('stepEditor.closeSteps')}\n className=\"fixed inset-0 bg-foreground/40 z-40 md:hidden\"\n onClick={() => setIsSidebarOpen(false)}\n />\n )}\n\n {/* Step List Sidebar */}\n <div\n className={`\n ${isMobile ? 'fixed inset-y-0 left-0 z-50 w-[min(18rem,calc(100vw-2rem))] transform transition-transform duration-300' : 'w-64 lg:w-80 shrink-0'}\n ${isMobile && !isSidebarOpen ? '-translate-x-full' : 'translate-x-0'}\n border-r border-border overflow-y-auto bg-card\n `}\n >\n {/* Mobile sidebar header */}\n {isMobile && (\n <div className=\"flex items-center justify-between p-4 border-b border-border sticky top-0 bg-card z-10\">\n <h2 className=\"font-semibold\">{tr('stepEditor.tourSteps')}</h2>\n <button\n type=\"button\"\n onClick={() => setIsSidebarOpen(false)}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('stepEditor.closeSteps')}\n >\n <X size={20} />\n </button>\n </div>\n )}\n\n <div className=\"p-3 sm:p-4 space-y-2\">\n {steps.length === 0 ? (\n <div className=\"text-center py-8 text-muted-foreground\">\n <p className=\"text-sm\">{tr('stepEditor.noStepsYet')}</p>\n <p className=\"text-xs mt-1\">{tr('stepEditor.clickAddStep')}</p>\n </div>\n ) : (\n steps.map((step, index) => (\n <div\n key={step.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => handleSelectStep(step)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelectStep(step);\n }\n }}\n className={`p-3 border rounded-md cursor-pointer transition-colors ${\n selectedStep?.id === step.id\n ? 'border-primary bg-primary/10'\n : 'border-border hover:bg-accent'\n }`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-xs text-muted-foreground mb-1\">\n {tr('stepEditor.stepNumber')} {index + 1}\n </div>\n <div className=\"font-medium text-sm truncate\">\n {step.title || tr('stepEditor.untitled')}\n </div>\n {step.targetSelector && (\n <div className=\"text-xs text-muted-foreground mt-1 truncate font-mono\">\n {step.targetSelector}\n </div>\n )}\n </div>\n {canDeleteStep && (\n <div className=\"flex items-center gap-1 shrink-0\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n if (index > 0) {\n moveStep(index, index - 1);\n }\n }}\n className=\"p-1.5 sm:p-2 min-h-[32px] min-w-[32px] sm:min-h-[40px] sm:min-w-[40px] hover:bg-accent rounded\"\n title=\"Move step up\"\n aria-label=\"Move step up\"\n disabled={index === 0}\n >\n <ChevronUp size={14} />\n </button>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n if (index < steps.length - 1) {\n moveStep(index, index + 1);\n }\n }}\n className=\"p-1.5 sm:p-2 min-h-[32px] min-w-[32px] sm:min-h-[40px] sm:min-w-[40px] hover:bg-accent rounded\"\n title=\"Move step down\"\n aria-label=\"Move step down\"\n disabled={index === steps.length - 1}\n >\n <ChevronDown size={14} />\n </button>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n deleteStep(step.id);\n }}\n className=\"p-1.5 sm:p-2 min-h-[32px] min-w-[32px] sm:min-h-[40px] sm:min-w-[40px] hover:bg-destructive/10 rounded text-destructive\"\n title={tr('stepEditor.deleteStep')}\n aria-label={tr('stepEditor.deleteStep')}\n >\n <Trash2 size={14} />\n </button>\n </div>\n )}\n </div>\n </div>\n ))\n )}\n </div>\n </div>\n\n {/* Step Editor */}\n <div className=\"flex-1 overflow-y-auto p-4 sm:p-6\">\n {selectedStep ? (\n <div className=\"max-w-2xl mx-auto space-y-4 sm:space-y-6\">\n {/* Mobile: Step navigation */}\n {isMobile && steps.length > 1 && (\n <div className=\"flex items-center justify-between bg-muted/50 rounded-lg p-2 mb-4\">\n <button\n type=\"button\"\n onClick={() => {\n const currentIndex = steps.findIndex((s) => s.id === selectedStep.id);\n if (currentIndex > 0) {\n selectStep(steps[currentIndex - 1]);\n }\n }}\n disabled={steps.findIndex((s) => s.id === selectedStep.id) === 0}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md disabled:opacity-30\"\n aria-label={tr('stepEditor.previousStep')}\n >\n <ChevronLeft size={20} />\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {tr('stepEditor.stepNumber')}{' '}\n {steps.findIndex((s) => s.id === selectedStep.id) + 1} {tr('stepEditor.of')}{' '}\n {steps.length}\n </span>\n <button\n type=\"button\"\n onClick={() => {\n const currentIndex = steps.findIndex((s) => s.id === selectedStep.id);\n if (currentIndex < steps.length - 1) {\n selectStep(steps[currentIndex + 1]);\n }\n }}\n disabled={steps.findIndex((s) => s.id === selectedStep.id) === steps.length - 1}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md disabled:opacity-30\"\n aria-label={tr('stepEditor.nextStep')}\n >\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n\n <h2 className=\"text-lg sm:text-xl font-semibold\">{tr('stepEditor.editStep')}</h2>\n\n {/* Title */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"step-editor-title\">\n {tr('stepEditor.stepTitle')} *\n </label>\n <input\n id=\"step-editor-title\"\n type=\"text\"\n value={selectedStep.title}\n onChange={(e) => updateStepField(selectedStep.id, 'title', e.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm sm:text-base\"\n placeholder={tr('stepEditor.stepTitlePlaceholder')}\n aria-label={tr('stepEditor.stepTitle')}\n />\n </div>\n\n {/* Content */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"step-editor-content\">\n {tr('stepEditor.content')} *\n </label>\n <textarea\n id=\"step-editor-content\"\n value={selectedStep.content}\n onChange={(e) => updateStepField(selectedStep.id, 'content', e.target.value)}\n rows={4}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm sm:text-base resize-y min-h-[100px]\"\n placeholder={tr('stepEditor.contentPlaceholder')}\n aria-label={tr('stepEditor.content')}\n />\n </div>\n\n {/* Selector */}\n <div>\n <label\n className=\"block text-sm font-medium mb-2\"\n htmlFor=\"step-editor-css-selector\"\n >\n {tr('stepEditor.cssSelector')} *\n <span className=\"text-muted-foreground font-normal ml-2\">\n ({tr('stepEditor.targetElement')})\n </span>\n </label>\n <input\n id=\"step-editor-css-selector\"\n type=\"text\"\n value={selectedStep.targetSelector || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelector', e.target.value)\n }\n placeholder={tr('stepEditor.cssSelectorPlaceholder')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background font-mono text-sm\"\n aria-label=\"{tr('stepEditor.cssSelector')} *\n \n ({tr('stepEditor.targetElement')})\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr('stepEditor.dataTourHint')}\n </p>\n </div>\n\n {/* Placement */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"step-editor-placement\">\n {tr('stepEditor.tooltipPlacement')}\n </label>\n <select\n id=\"step-editor-placement\"\n value={selectedStep.placement}\n onChange={(e) => updateStepField(selectedStep.id, 'placement', e.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm sm:text-base\"\n aria-label={tr('stepEditor.tooltipPlacement')}\n >\n <option value=\"AUTO\">{tr('stepEditor.placementAuto')}</option>\n <option value=\"TOP\">{tr('stepEditor.placementTop')}</option>\n <option value=\"BOTTOM\">{tr('stepEditor.placementBottom')}</option>\n <option value=\"LEFT\">{tr('stepEditor.placementLeft')}</option>\n <option value=\"RIGHT\">{tr('stepEditor.placementRight')}</option>\n <option value=\"CENTER\">{tr('stepEditor.placementCenter')}</option>\n </select>\n </div>\n\n {/* Device-specific selectors */}\n <details className=\"border border-border rounded-md\">\n <summary className=\"px-4 py-3 cursor-pointer font-medium text-sm hover:bg-accent/50 rounded-t-md\">\n {tr('stepEditor.deviceSpecificSelectors')}\n </summary>\n <div className=\"p-4 pt-0 space-y-3 border-t border-border\">\n <p className=\"text-xs text-muted-foreground mb-3\">\n {tr('stepEditor.deviceSelectorHint')}\n </p>\n <div>\n <label\n className=\"block text-xs font-medium mb-1\"\n htmlFor=\"step-editor-mobile-selector\"\n >\n {tr('stepEditor.mobileSelector')}\n </label>\n <input\n id=\"step-editor-mobile-selector\"\n type=\"text\"\n value={selectedStep.targetSelectorMobile || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelectorMobile', e.target.value)\n }\n placeholder={tr('stepEditor.leaveEmptyDefault')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n aria-label={tr('stepEditor.mobileSelector')}\n />\n </div>\n <div>\n <label\n className=\"block text-xs font-medium mb-1\"\n htmlFor=\"step-editor-tablet-selector\"\n >\n {tr('stepEditor.tabletSelector')}\n </label>\n <input\n id=\"step-editor-tablet-selector\"\n type=\"text\"\n value={selectedStep.targetSelectorTablet || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelectorTablet', e.target.value)\n }\n placeholder={tr('stepEditor.leaveEmptyDefault')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n aria-label={tr('stepEditor.tabletSelector')}\n />\n </div>\n <div>\n <label\n className=\"block text-xs font-medium mb-1\"\n htmlFor=\"step-editor-desktop-selector\"\n >\n {tr('stepEditor.desktopSelector')}\n </label>\n <input\n id=\"step-editor-desktop-selector\"\n type=\"text\"\n value={selectedStep.targetSelectorDesktop || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'targetSelectorDesktop', e.target.value)\n }\n placeholder={tr('stepEditor.leaveEmptyDefault')}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n aria-label={tr('stepEditor.desktopSelector')}\n />\n </div>\n </div>\n </details>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <label className=\"flex items-center gap-3 cursor-pointer rounded-md border border-border p-3\">\n <input\n type=\"checkbox\"\n checked={selectedStep.requireInteraction ?? false}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'requireInteraction', e.target.checked)\n }\n className=\"size-4 rounded\"\n aria-label=\"Require interaction\"\n />\n <div>\n <div className=\"text-sm font-medium\">Require interaction</div>\n <div className=\"text-xs text-muted-foreground\">\n User must interact with the highlighted element before advancing.\n </div>\n </div>\n </label>\n\n <div>\n <label\n className=\"block text-sm font-medium mb-2\"\n htmlFor=\"step-editor-wait-timeout\"\n >\n Wait for timeout (ms)\n </label>\n <input\n id=\"step-editor-wait-timeout\"\n type=\"number\"\n min=\"0\"\n value={selectedStep.waitForTimeout ?? ''}\n onChange={(e) =>\n updateStepField(\n selectedStep.id,\n 'waitForTimeout',\n e.target.value ? Number(e.target.value) : undefined\n )\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n placeholder=\"1500\"\n aria-label=\"Wait for timeout (ms)\"\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label\n className=\"block text-sm font-medium mb-2\"\n htmlFor=\"step-editor-wait-selector\"\n >\n Wait for selector\n </label>\n <input\n id=\"step-editor-wait-selector\"\n type=\"text\"\n value={selectedStep.waitForSelector || ''}\n onChange={(e) =>\n updateStepField(\n selectedStep.id,\n 'waitForSelector',\n e.target.value || undefined\n )\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n placeholder=\"[data-tour='agents-tabs']\"\n aria-label=\"Wait for selector\"\n />\n </div>\n\n <div>\n <label\n className=\"block text-sm font-medium mb-2\"\n htmlFor=\"step-editor-wait-event\"\n >\n Wait for event\n </label>\n <input\n id=\"step-editor-wait-event\"\n type=\"text\"\n value={selectedStep.waitForEvent || ''}\n onChange={(e) =>\n updateStepField(selectedStep.id, 'waitForEvent', e.target.value || undefined)\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n placeholder=\"tour:ready\"\n aria-label=\"Wait for event\"\n />\n </div>\n </div>\n\n <div>\n <label\n className=\"block text-sm font-medium mb-2\"\n htmlFor=\"step-editor-skip-conditions\"\n >\n Skip conditions (JSON)\n </label>\n <textarea\n id=\"step-editor-skip-conditions\"\n value={\n selectedStep.skipConditions\n ? JSON.stringify(selectedStep.skipConditions, null, 2)\n : ''\n }\n onChange={(e) => {\n const rawValue = e.target.value.trim();\n if (!rawValue) {\n updateStepField(selectedStep.id, 'skipConditions', undefined);\n return;\n }\n\n try {\n updateStepField(selectedStep.id, 'skipConditions', JSON.parse(rawValue));\n } catch {\n updateStepField(selectedStep.id, 'skipConditions', rawValue);\n }\n }}\n rows={4}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm font-mono\"\n placeholder='{\"selectorMissing\":\"[data-tour=\\\"missing\\\"]\"}'\n aria-label=\"Skip conditions (JSON)\"\n />\n </div>\n\n <div className=\"border border-border rounded-md p-4 space-y-4\">\n <div className=\"flex items-center gap-2\">\n <Paperclip size={18} />\n <h3 className=\"text-sm font-semibold\">Step media</h3>\n </div>\n\n {selectedStep.media && selectedStep.media.length > 0 ? (\n <div className=\"space-y-2\">\n {selectedStep.media.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between rounded-md border border-border p-2 text-sm\"\n >\n <div>\n <div className=\"font-medium\">{item.media.name}</div>\n <div className=\"text-xs text-muted-foreground\">{item.position}</div>\n </div>\n <span className=\"text-xs text-muted-foreground\">{item.media.type}</span>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n No media attached to this step yet.\n </p>\n )}\n\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-[minmax(0,1fr)_160px_auto]\">\n <select\n value={attachmentMediaId}\n onChange={(e) => setAttachmentMediaId(e.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n aria-label=\"Select media to attach\"\n >\n <option value=\"\">\n {mediaLoading ? 'Loading media...' : 'Select uploaded media'}\n </option>\n {media.map((item) => (\n <option key={item.id} value={item.id}>\n {item.name} ({item.type})\n </option>\n ))}\n </select>\n\n <select\n value={attachmentPosition}\n onChange={(e) =>\n setAttachmentPosition(e.target.value as 'header' | 'body' | 'footer')\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-sm\"\n aria-label=\"Attachment position\"\n >\n <option value=\"header\">Header</option>\n <option value=\"body\">Body</option>\n <option value=\"footer\">Footer</option>\n </select>\n\n <button\n type=\"button\"\n onClick={handleAttachMedia}\n disabled={attachingMedia || !attachmentMediaId}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50\"\n >\n Attach\n </button>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center h-full text-center px-4\">\n <div className=\"size-16 bg-muted rounded-full flex items-center justify-center mb-4\">\n <Plus size={24} className=\"text-muted-foreground\" />\n </div>\n <p className=\"text-muted-foreground mb-2\">{tr('stepEditor.noStepSelected')}</p>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {steps.length > 0\n ? tr('stepEditor.selectStepToEdit')\n : tr('stepEditor.createFirstStep')}\n </p>\n {steps.length === 0 && canCreateStep && (\n <button\n type=\"button\"\n onClick={handleAddStep}\n className=\"px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 flex items-center gap-2\"\n >\n <Plus size={18} />\n {tr('stepEditor.addFirstStep')}\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AA+BA,SAAgB,IAAiB;CAC/B,IAAM,EAAE,UAAO,IAAc,EAEvB,EAAE,WAAQ,cAAW,GAAW,EAChC,KAAW,GAAa,EACxB,IAAe,GAAiB,EAChC,EAAE,eAAW,QAAQ,GACrB,IAAW,IAAa,EACxB,EAAE,qBAAkB,GAA0B,EAC9C,IAAgB,EAAc,EAAiB,iBAAiB,EAChE,IAAgB,EAAc,EAAiB,iBAAiB,EAChE,IAAgB,EAAc,EAAiB,iBAAiB,EAEhE,EAAE,SAAM,aAAU,cAAW,cAAW,EAAe,EAAO,EAC9D,EAAE,UAAO,iBAAc,eAAY,eAAY,eAAY,oBAAiB,gBAChF,GAAkB,EACd,EAAE,UAAO,eAAY,iBAAc,SAAS,MAAiB,IAAiB,EAG9E,CAAC,GAAe,KAAoB,EAAS,GAAM,EACnD,CAAC,GAAU,MAAe,QACxB,OAAO,SAAW,OAAe,OAAO,aAAa,IAC5D,EACK,CAAC,GAAmB,KAAwB,EAAS,GAAG,EACxD,CAAC,GAAoB,KAAyB,EAClD,OACD,EACK,CAAC,IAAgB,KAAqB,EAAS,GAAM;AA0B3D,CAvBA,QAAgB;EACd,IAAM,UAAoB;GACxB,IAAM,IAAS,OAAO,aAAa;AAGnC,GAFA,GAAY,EAAO,EAEd,KACH,EAAiB,GAAM;;AAI3B,SADA,OAAO,iBAAiB,UAAU,EAAY,QACjC,OAAO,oBAAoB,UAAU,EAAY;IAC7D,EAAE,CAAC,EAEN,QAAgB;AACd,EAAI,KACF,EAAS,EAAO;IAEjB,CAAC,GAAQ,EAAS,CAAC,EAEtB,QAAgB;AACT,KAAY;IAChB,CAAC,EAAW,CAAC,EAEhB,QAAgB;EACd,IAAM,IAAiB,KAAU,GAAc;AAC/C,MAAI,KAAkB,EAAM,SAAS,GAAG;GACtC,IAAM,IAAO,EAAM,MAAM,MAAM,EAAE,OAAO,EAAe;AACvD,GAAI,KACF,EAAW,EAAK;;IAGnB;EAAC;EAAQ;EAAO;EAAY,GAAc;EAAG,CAAC;CAEjD,IAAM,UAAsB;AAC1B,KAAY;IAGR,KAAkB,YAAY;AAClC,MAAI,EACF,KAAI;AACF,SAAM,EAAU,GAAQ,EAAM;UACxB;AACN,KAAmB,GAAU,aAAa,EAAa;;IAKvD,WAAmB;AACvB,KAAS,GAAG,GAAS,GAAG,EAAO,OAAO;IAGlC,KAAoB,YAAY;AAChC,SAAC,KAAgB,CAAC,KAAU,CAAC,IACjC;OAAI,EAAa,GAAG,WAAW,QAAQ,EAAE;AACvC,WAAO,MAAM,kDAAkD;AAC/D;;AAGF,OAAI;AASF,IARA,EAAkB,GAAK,EACvB,MAAM,EACJ,EAAa,IACb,GACA,IACC,EAAa,OAAO,UAAU,KAAK,EACrC,EACD,MAAM,EAAS,EAAO,EACtB,EAAqB,GAAG;WAClB;AACN,MAAmB,GAAU,gBAAgB,EAAa;aAClD;AACR,MAAkB,GAAM;;;IAItB,KAAoB,MAA4B;AAGpD,EAFA,EAAW,EAAK,EAEZ,KACF,EAAiB,GAAM;;AAI3B,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CAEE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;KACV,cAAY,EAAG,oBAAoB;eAEnC,kBAAC,IAAD,EAAW,MAAM,IAAM,CAAA;KAChB,CAAA,EACT,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAAd;OACG,GAAM,QAAQ,EAAG,0BAA0B;OAAC;OAAI,EAAG,wBAAwB;OACzE;SACL,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAM;OAAO;OAAE,EAAG,wBAAwB;OACzC;QACA;OACF;OAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KAEG,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAiB,CAAC,EAAc;MAC/C,WAAU;gBAHZ;OAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;OAClB,kBAAC,QAAD;QAAM,WAAU;kBAAW,EAAG,mBAAmB;QAAQ,CAAA;OACxD,EAAM,SAAS,KACd,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAM;QACF,CAAA;OAEF;;KAGV,KACC,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EAClB,kBAAC,QAAD;OAAM,WAAU;iBAAoB,EAAG,qBAAqB;OAAQ,CAAA,CAC7D;;KAEX,kBAAC,IAAD;MAAgB,YAAY,EAAiB;gBAC3C,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,UAAU,KAAU,CAAC;OACrB,WAAU;iBAJZ,CAME,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EAClB,kBAAC,QAAD;QAAM,WAAU;kBACJ,EAAT,IAAY,sBAA0B,kBAAkB;QACpD,CAAA,CACA;;MACM,CAAA;KACb;MACF;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEG,KAAY,KACX,kBAAC,UAAD;KACE,MAAK;KACL,cAAY,EAAG,wBAAwB;KACvC,WAAU;KACV,eAAe,EAAiB,GAAM;KACtC,CAAA;IAIJ,kBAAC,OAAD;KACE,WAAW;cACP,IAAW,4GAA4G,wBAAwB;cAC/I,KAAY,CAAC,IAAgB,sBAAsB,gBAAgB;;;eAHzE,CAQG,KACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAiB,EAAG,uBAAuB;OAAM,CAAA,EAC/D,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAiB,GAAM;OACtC,WAAU;OACV,cAAY,EAAG,wBAAwB;iBAEvC,kBAAC,GAAD,EAAG,MAAM,IAAM,CAAA;OACR,CAAA,CACL;SAGR,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAM,WAAW,IAChB,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAW,EAAG,wBAAwB;QAAK,CAAA,EACxD,kBAAC,KAAD;QAAG,WAAU;kBAAgB,EAAG,0BAA0B;QAAK,CAAA,CAC3D;WAEN,EAAM,KAAK,GAAM,MACf,kBAAC,OAAD;OAEE,MAAK;OACL,UAAU;OACV,eAAe,EAAiB,EAAK;OACrC,YAAY,MAAM;AAChB,SAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,EAAiB,EAAK;;OAG1B,WAAW,0DACT,GAAc,OAAO,EAAK,KACtB,iCACA;iBAGN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACG,EAAG,wBAAwB;YAAC;YAAE,IAAQ;YACnC;;UACN,kBAAC,OAAD;WAAK,WAAU;qBACZ,EAAK,SAAS,EAAG,sBAAsB;WACpC,CAAA;UACL,EAAK,kBACJ,kBAAC,OAAD;WAAK,WAAU;qBACZ,EAAK;WACF,CAAA;UAEJ;YACL,KACC,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,UAAD;WACE,MAAK;WACL,UAAU,MAAM;AAEd,YADA,EAAE,iBAAiB,EACf,IAAQ,KACV,EAAS,GAAO,IAAQ,EAAE;;WAG9B,WAAU;WACV,OAAM;WACN,cAAW;WACX,UAAU,MAAU;qBAEpB,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;WAChB,CAAA;UACT,kBAAC,UAAD;WACE,MAAK;WACL,UAAU,MAAM;AAEd,YADA,EAAE,iBAAiB,EACf,IAAQ,EAAM,SAAS,KACzB,EAAS,GAAO,IAAQ,EAAE;;WAG9B,WAAU;WACV,OAAM;WACN,cAAW;WACX,UAAU,MAAU,EAAM,SAAS;qBAEnC,kBAAC,IAAD,EAAa,MAAM,IAAM,CAAA;WAClB,CAAA;UACT,kBAAC,UAAD;WACE,MAAK;WACL,UAAU,MAAM;AAEd,YADA,EAAE,iBAAiB,EACnB,EAAW,EAAK,GAAG;;WAErB,WAAU;WACV,OAAO,EAAG,wBAAwB;WAClC,cAAY,EAAG,wBAAwB;qBAEvC,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;WACb,CAAA;UACL;WAEJ;;OACF,EA7EC,EAAK,GA6EN,CACN;MAEA,CAAA,CACF;;IAGN,kBAAC,OAAD;KAAK,WAAU;eACZ,IACC,kBAAC,OAAD;MAAK,WAAU;gBAAf;OAEG,KAAY,EAAM,SAAS,KAC1B,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,UAAD;UACE,MAAK;UACL,eAAe;WACb,IAAM,IAAe,EAAM,WAAW,MAAM,EAAE,OAAO,EAAa,GAAG;AACrE,WAAI,IAAe,KACjB,EAAW,EAAM,IAAe,GAAG;;UAGvC,UAAU,EAAM,WAAW,MAAM,EAAE,OAAO,EAAa,GAAG,KAAK;UAC/D,WAAU;UACV,cAAY,EAAG,0BAA0B;oBAEzC,kBAAC,IAAD,EAAa,MAAM,IAAM,CAAA;UAClB,CAAA;SACT,kBAAC,QAAD;UAAM,WAAU;oBAAhB;WACG,EAAG,wBAAwB;WAAE;WAC7B,EAAM,WAAW,MAAM,EAAE,OAAO,EAAa,GAAG,GAAG;WAAE;WAAE,EAAG,gBAAgB;WAAE;WAC5E,EAAM;WACF;;SACP,kBAAC,UAAD;UACE,MAAK;UACL,eAAe;WACb,IAAM,IAAe,EAAM,WAAW,MAAM,EAAE,OAAO,EAAa,GAAG;AACrE,WAAI,IAAe,EAAM,SAAS,KAChC,EAAW,EAAM,IAAe,GAAG;;UAGvC,UAAU,EAAM,WAAW,MAAM,EAAE,OAAO,EAAa,GAAG,KAAK,EAAM,SAAS;UAC9E,WAAU;UACV,cAAY,EAAG,sBAAsB;oBAErC,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA;UACnB,CAAA;SACL;;OAGR,kBAAC,MAAD;QAAI,WAAU;kBAAoC,EAAG,sBAAsB;QAAM,CAAA;OAGjF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;QAAiC,SAAQ;kBAA1D,CACG,EAAG,uBAAuB,EAAC,KACtB;WACR,kBAAC,SAAD;QACE,IAAG;QACH,MAAK;QACL,OAAO,EAAa;QACpB,WAAW,MAAM,EAAgB,EAAa,IAAI,SAAS,EAAE,OAAO,MAAM;QAC1E,WAAU;QACV,aAAa,EAAG,kCAAkC;QAClD,cAAY,EAAG,uBAAuB;QACtC,CAAA,CACE,EAAA,CAAA;OAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;QAAiC,SAAQ;kBAA1D,CACG,EAAG,qBAAqB,EAAC,KACpB;WACR,kBAAC,YAAD;QACE,IAAG;QACH,OAAO,EAAa;QACpB,WAAW,MAAM,EAAgB,EAAa,IAAI,WAAW,EAAE,OAAO,MAAM;QAC5E,MAAM;QACN,WAAU;QACV,aAAa,EAAG,gCAAgC;QAChD,cAAY,EAAG,qBAAqB;QACpC,CAAA,CACE,EAAA,CAAA;OAGN,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,SAAD;SACE,WAAU;SACV,SAAQ;mBAFV;UAIG,EAAG,yBAAyB;UAAC;UAC9B,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YAAyD;YACrD,EAAG,2BAA2B;YAAC;YAC5B;;UACD;;QACR,kBAAC,SAAD;SACE,IAAG;SACH,MAAK;SACL,OAAO,EAAa,kBAAkB;SACtC,WAAW,MACT,EAAgB,EAAa,IAAI,kBAAkB,EAAE,OAAO,MAAM;SAEpE,aAAa,EAAG,oCAAoC;SACpD,WAAU;SACV,cAAW;SAGX,CAAA;QACF,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAG,0BAA0B;SAC5B,CAAA;QACA,EAAA,CAAA;OAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;QAAiC,SAAQ;kBACvD,EAAG,8BAA8B;QAC5B,CAAA,EACR,kBAAC,UAAD;QACE,IAAG;QACH,OAAO,EAAa;QACpB,WAAW,MAAM,EAAgB,EAAa,IAAI,aAAa,EAAE,OAAO,MAAM;QAC9E,WAAU;QACV,cAAY,EAAG,8BAA8B;kBAL/C;SAOE,kBAAC,UAAD;UAAQ,OAAM;oBAAQ,EAAG,2BAA2B;UAAU,CAAA;SAC9D,kBAAC,UAAD;UAAQ,OAAM;oBAAO,EAAG,0BAA0B;UAAU,CAAA;SAC5D,kBAAC,UAAD;UAAQ,OAAM;oBAAU,EAAG,6BAA6B;UAAU,CAAA;SAClE,kBAAC,UAAD;UAAQ,OAAM;oBAAQ,EAAG,2BAA2B;UAAU,CAAA;SAC9D,kBAAC,UAAD;UAAQ,OAAM;oBAAS,EAAG,4BAA4B;UAAU,CAAA;SAChE,kBAAC,UAAD;UAAQ,OAAM;oBAAU,EAAG,6BAA6B;UAAU,CAAA;SAC3D;UACL,EAAA,CAAA;OAGN,kBAAC,WAAD;QAAS,WAAU;kBAAnB,CACE,kBAAC,WAAD;SAAS,WAAU;mBAChB,EAAG,qCAAqC;SACjC,CAAA,EACV,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAG,gCAAgC;WAClC,CAAA;UACJ,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;WACE,WAAU;WACV,SAAQ;qBAEP,EAAG,4BAA4B;WAC1B,CAAA,EACR,kBAAC,SAAD;WACE,IAAG;WACH,MAAK;WACL,OAAO,EAAa,wBAAwB;WAC5C,WAAW,MACT,EAAgB,EAAa,IAAI,wBAAwB,EAAE,OAAO,MAAM;WAE1E,aAAa,EAAG,+BAA+B;WAC/C,WAAU;WACV,cAAY,EAAG,4BAA4B;WAC3C,CAAA,CACE,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;WACE,WAAU;WACV,SAAQ;qBAEP,EAAG,4BAA4B;WAC1B,CAAA,EACR,kBAAC,SAAD;WACE,IAAG;WACH,MAAK;WACL,OAAO,EAAa,wBAAwB;WAC5C,WAAW,MACT,EAAgB,EAAa,IAAI,wBAAwB,EAAE,OAAO,MAAM;WAE1E,aAAa,EAAG,+BAA+B;WAC/C,WAAU;WACV,cAAY,EAAG,4BAA4B;WAC3C,CAAA,CACE,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;WACE,WAAU;WACV,SAAQ;qBAEP,EAAG,6BAA6B;WAC3B,CAAA,EACR,kBAAC,SAAD;WACE,IAAG;WACH,MAAK;WACL,OAAO,EAAa,yBAAyB;WAC7C,WAAW,MACT,EAAgB,EAAa,IAAI,yBAAyB,EAAE,OAAO,MAAM;WAE3E,aAAa,EAAG,+BAA+B;WAC/C,WAAU;WACV,cAAY,EAAG,6BAA6B;WAC5C,CAAA,CACE,EAAA,CAAA;UACF;WACE;;OAEV,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,SAAD;SAAO,WAAU;mBAAjB,CACE,kBAAC,SAAD;UACE,MAAK;UACL,SAAS,EAAa,sBAAsB;UAC5C,WAAW,MACT,EAAgB,EAAa,IAAI,sBAAsB,EAAE,OAAO,QAAQ;UAE1E,WAAU;UACV,cAAW;UACX,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAsB;UAAyB,CAAA,EAC9D,kBAAC,OAAD;UAAK,WAAU;oBAAgC;UAEzC,CAAA,CACF,EAAA,CAAA,CACA;YAER,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SACE,WAAU;SACV,SAAQ;mBACT;SAEO,CAAA,EACR,kBAAC,SAAD;SACE,IAAG;SACH,MAAK;SACL,KAAI;SACJ,OAAO,EAAa,kBAAkB;SACtC,WAAW,MACT,EACE,EAAa,IACb,kBACA,EAAE,OAAO,QAAQ,OAAO,EAAE,OAAO,MAAM,GAAG,KAAA,EAC3C;SAEH,WAAU;SACV,aAAY;SACZ,cAAW;SACX,CAAA,CACE,EAAA,CAAA,CACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SACE,WAAU;SACV,SAAQ;mBACT;SAEO,CAAA,EACR,kBAAC,SAAD;SACE,IAAG;SACH,MAAK;SACL,OAAO,EAAa,mBAAmB;SACvC,WAAW,MACT,EACE,EAAa,IACb,mBACA,EAAE,OAAO,SAAS,KAAA,EACnB;SAEH,WAAU;SACV,aAAY;SACZ,cAAW;SACX,CAAA,CACE,EAAA,CAAA,EAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SACE,WAAU;SACV,SAAQ;mBACT;SAEO,CAAA,EACR,kBAAC,SAAD;SACE,IAAG;SACH,MAAK;SACL,OAAO,EAAa,gBAAgB;SACpC,WAAW,MACT,EAAgB,EAAa,IAAI,gBAAgB,EAAE,OAAO,SAAS,KAAA,EAAU;SAE/E,WAAU;SACV,aAAY;SACZ,cAAW;SACX,CAAA,CACE,EAAA,CAAA,CACF;;OAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QACE,WAAU;QACV,SAAQ;kBACT;QAEO,CAAA,EACR,kBAAC,YAAD;QACE,IAAG;QACH,OACE,EAAa,iBACT,KAAK,UAAU,EAAa,gBAAgB,MAAM,EAAE,GACpD;QAEN,WAAW,MAAM;SACf,IAAM,IAAW,EAAE,OAAO,MAAM,MAAM;AACtC,aAAI,CAAC,GAAU;AACb,YAAgB,EAAa,IAAI,kBAAkB,KAAA,EAAU;AAC7D;;AAGF,aAAI;AACF,YAAgB,EAAa,IAAI,kBAAkB,KAAK,MAAM,EAAS,CAAC;iBAClE;AACN,YAAgB,EAAa,IAAI,kBAAkB,EAAS;;;QAGhE,MAAM;QACN,WAAU;QACV,aAAY;QACZ,cAAW;QACX,CAAA,CACE,EAAA,CAAA;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EACvB,kBAAC,MAAD;WAAI,WAAU;qBAAwB;WAAe,CAAA,CACjD;;SAEL,EAAa,SAAS,EAAa,MAAM,SAAS,IACjD,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAa,MAAM,KAAK,MACvB,kBAAC,OAAD;WAEE,WAAU;qBAFZ,CAIE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;YAAK,WAAU;sBAAe,EAAK,MAAM;YAAW,CAAA,EACpD,kBAAC,OAAD;YAAK,WAAU;sBAAiC,EAAK;YAAe,CAAA,CAChE,EAAA,CAAA,EACN,kBAAC,QAAD;YAAM,WAAU;sBAAiC,EAAK,MAAM;YAAY,CAAA,CACpE;aARC,EAAK,GAQN,CACN;UACE,CAAA,GAEN,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAEzC,CAAA;SAGN,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,UAAD;YACE,OAAO;YACP,WAAW,MAAM,EAAqB,EAAE,OAAO,MAAM;YACrD,WAAU;YACV,cAAW;sBAJb,CAME,kBAAC,UAAD;aAAQ,OAAM;uBACX,IAAe,qBAAqB;aAC9B,CAAA,EACR,EAAM,KAAK,MACV,kBAAC,UAAD;aAAsB,OAAO,EAAK;uBAAlC;cACG,EAAK;cAAK;cAAG,EAAK;cAAK;cACjB;eAFI,EAAK,GAET,CACT,CACK;;WAET,kBAAC,UAAD;YACE,OAAO;YACP,WAAW,MACT,EAAsB,EAAE,OAAO,MAAsC;YAEvE,WAAU;YACV,cAAW;sBANb;aAQE,kBAAC,UAAD;cAAQ,OAAM;wBAAS;cAAe,CAAA;aACtC,kBAAC,UAAD;cAAQ,OAAM;wBAAO;cAAa,CAAA;aAClC,kBAAC,UAAD;cAAQ,OAAM;wBAAS;cAAe,CAAA;aAC/B;;WAET,kBAAC,UAAD;YACE,MAAK;YACL,SAAS;YACT,UAAU,MAAkB,CAAC;YAC7B,WAAU;sBACX;YAEQ,CAAA;WACL;;SACF;;OACF;UAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD;SAAM,MAAM;SAAI,WAAU;SAA0B,CAAA;QAChD,CAAA;OACN,kBAAC,KAAD;QAAG,WAAU;kBAA8B,EAAG,4BAA4B;QAAK,CAAA;OAC/E,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAM,SAAS,IACZ,EAAG,8BAA8B,GACjC,EAAG,6BAA6B;QAClC,CAAA;OACH,EAAM,WAAW,KAAK,KACrB,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,0BAA0B,CACvB;;OAEP;;KAEJ,CAAA;IACF;KACF"}
@@ -66,13 +66,15 @@ function S() {
66
66
  placeholder: S("templateLibrary.searchPlaceholder"),
67
67
  value: j,
68
68
  onChange: (e) => M(e.target.value),
69
- className: "w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border rounded-md bg-background"
69
+ className: "w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border rounded-md bg-background",
70
+ "aria-label": S("templateLibrary.searchPlaceholder")
70
71
  })]
71
72
  }),
72
73
  /* @__PURE__ */ y("select", {
73
74
  value: N,
74
75
  onChange: (e) => P(e.target.value),
75
76
  className: "px-4 py-2 min-h-[44px] border border-border rounded-md bg-background",
77
+ "aria-label": S("templateLibrary.allCategories"),
76
78
  children: [
77
79
  /* @__PURE__ */ v("option", {
78
80
  value: "all",
@@ -102,7 +104,8 @@ function S() {
102
104
  type: "checkbox",
103
105
  checked: F,
104
106
  onChange: (e) => I(e.target.checked),
105
- className: "rounded"
107
+ className: "rounded",
108
+ "aria-label": S("templateLibrary.publicOnly")
106
109
  }), /* @__PURE__ */ v("span", {
107
110
  className: "text-sm",
108
111
  children: S("templateLibrary.publicOnly")
@@ -170,11 +173,13 @@ function S() {
170
173
  }), /* @__PURE__ */ y("div", {
171
174
  className: "flex items-center gap-2",
172
175
  children: [A && /* @__PURE__ */ v("button", {
176
+ type: "button",
173
177
  onClick: () => void W(e.id),
174
178
  className: "p-2 min-h-[44px] min-w-[44px] text-muted-foreground hover:text-destructive rounded-md",
175
179
  "aria-label": S("templateLibrary.deleteTemplate"),
176
180
  children: /* @__PURE__ */ v(_, { size: 16 })
177
181
  }), k && /* @__PURE__ */ v("button", {
182
+ type: "button",
178
183
  onClick: () => V(e.id),
179
184
  className: "px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 text-sm",
180
185
  children: S("templateLibrary.useTemplate")
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateLibraryPage.js","names":[],"sources":["../../../src/tours/pages/TemplateLibraryPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Search, LayoutTemplate, Star, Globe, Lock, Trash2 } from 'lucide-react';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport {\n useGetTourTemplatesQuery,\n useCreateTourFromTemplateMutation,\n useDeleteTourTemplateMutation,\n} from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TemplateCategory } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\n\n/**\n * Template library page\n * Browse and use tour templates\n */\nexport function TemplateLibraryPage() {\n const { tr } = useToursI18n();\n\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canListTemplates = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_LIST);\n const canUseTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_USE);\n const canDeleteTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_DELETE);\n\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategory | 'all'>('all');\n const [publicOnly, setPublicOnly] = useState(false);\n\n const { data, loading } = useGetTourTemplatesQuery({\n skip: !canListTemplates,\n variables: {\n isPublic: publicOnly || undefined,\n category: categoryFilter === 'all' ? undefined : categoryFilter,\n },\n });\n const templates = data?.tourTemplates ?? [];\n\n const filteredTemplates = templates.filter(\n (t: (typeof templates)[number]) =>\n !searchQuery || t.name.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const [createFromTemplate] = useCreateTourFromTemplateMutation();\n\n const handleUseTemplate = async (templateId: string) => {\n nativeImpact('light');\n try {\n const { data } = await createFromTemplate({\n variables: { templateId },\n });\n if (data?.createTourFromTemplate) {\n void nativeNotify('success');\n navigate(`${basePath}/${data.createTourFromTemplate.id}/edit`);\n }\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.create_from_template', toursContext);\n }\n };\n\n const [deleteTemplate] = useDeleteTourTemplateMutation();\n\n const handleDeleteTemplate = async (templateId: string) => {\n try {\n await deleteTemplate({\n variables: { id: templateId },\n refetchQueries: ['GetTourTemplates'],\n });\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.delete', toursContext);\n }\n };\n\n const handleDeleteTemplateClick = async (templateId: string) => {\n nativeImpact('medium');\n const message = tr('templateLibrary.deleteConfirm');\n const nativeResult = await nativeConfirm({\n title: tr('templateLibrary.deleteConfirm'),\n message,\n });\n const confirmed = nativeResult === null ? window.confirm(message) : nativeResult;\n if (confirmed) await handleDeleteTemplate(templateId);\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\">{tr('templateLibrary.title')}</h1>\n <p className=\"text-sm text-muted-foreground\">{tr('templateLibrary.subtitle')}</p>\n </div>\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-muted-foreground\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('templateLibrary.searchPlaceholder')}\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 rounded-md bg-background\"\n />\n </div>\n <select\n value={categoryFilter}\n onChange={(e) => setCategoryFilter(e.target.value as TemplateCategory | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n >\n <option value=\"all\">{tr('templateLibrary.allCategories')}</option>\n <option value=\"ONBOARDING\">{tr('templateLibrary.categoryOnboarding')}</option>\n <option value=\"FEATURE_ANNOUNCEMENT\">\n {tr('templateLibrary.categoryFeatureAnnouncement')}\n </option>\n <option value=\"HELP\">{tr('templateLibrary.categoryHelp')}</option>\n <option value=\"CUSTOM\">{tr('templateLibrary.categoryCustom')}</option>\n </select>\n <label className=\"flex items-center gap-2 px-4 py-2 min-h-[44px] border border-border rounded-md bg-background cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={publicOnly}\n onChange={(e) => setPublicOnly(e.target.checked)}\n className=\"rounded\"\n />\n <span className=\"text-sm\">{tr('templateLibrary.publicOnly')}</span>\n </label>\n </div>\n\n {/* Templates Grid */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-muted-foreground\">{tr('templateLibrary.loading')}</p>\n </div>\n ) : filteredTemplates.length > 0 ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredTemplates.map((template: (typeof filteredTemplates)[number]) => (\n <div\n key={template.id}\n className=\"border border-border rounded-md overflow-hidden hover:shadow-md transition-shadow\"\n >\n {/* Thumbnail */}\n <div className=\"aspect-video bg-muted flex items-center justify-center\">\n {template.thumbnail ? (\n <img\n src={template.thumbnail}\n alt={template.name}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <LayoutTemplate className=\"text-muted-foreground\" size={48} />\n )}\n </div>\n\n {/* Content */}\n <div className=\"p-4\">\n <div className=\"flex items-start justify-between mb-2\">\n <h3 className=\"font-semibold\">{template.name}</h3>\n <div className=\"flex gap-1\">\n {template.isPremium && <Star className=\"text-warning\" size={16} />}\n {template.isPublic ? (\n <Globe className=\"text-muted-foreground\" size={16} />\n ) : (\n <Lock className=\"text-muted-foreground\" size={16} />\n )}\n </div>\n </div>\n\n {template.description && (\n <p className=\"text-sm text-muted-foreground mb-3 line-clamp-2\">\n {template.description}\n </p>\n )}\n\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">\n {tr('templateLibrary.usedTimes')} {template.useCount}{' '}\n {tr('templateLibrary.times')}\n </span>\n <div className=\"flex items-center gap-2\">\n {canDeleteTemplate && (\n <button\n onClick={() => void handleDeleteTemplateClick(template.id)}\n className=\"p-2 min-h-[44px] min-w-[44px] text-muted-foreground hover:text-destructive rounded-md\"\n aria-label={tr('templateLibrary.deleteTemplate')}\n >\n <Trash2 size={16} />\n </button>\n )}\n {canUseTemplate && (\n <button\n onClick={() => handleUseTemplate(template.id)}\n className=\"px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 text-sm\"\n >\n {tr('templateLibrary.useTemplate')}\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-12 border border-dashed border-border rounded-md\">\n <LayoutTemplate className=\"mx-auto mb-4 text-muted-foreground\" size={48} />\n <p className=\"text-muted-foreground mb-2\">{tr('templateLibrary.noTemplatesFound')}</p>\n <p className=\"text-sm text-muted-foreground\">{tr('templateLibrary.adjustFilters')}</p>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TemplateLibraryPage.js","names":[],"sources":["../../../src/tours/pages/TemplateLibraryPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Search, LayoutTemplate, Star, Globe, Lock, Trash2 } from 'lucide-react';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport {\n useGetTourTemplatesQuery,\n useCreateTourFromTemplateMutation,\n useDeleteTourTemplateMutation,\n} from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TemplateCategory } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\n\n/**\n * Template library page\n * Browse and use tour templates\n */\nexport function TemplateLibraryPage() {\n const { tr } = useToursI18n();\n\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canListTemplates = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_LIST);\n const canUseTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_USE);\n const canDeleteTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_DELETE);\n\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategory | 'all'>('all');\n const [publicOnly, setPublicOnly] = useState(false);\n\n const { data, loading } = useGetTourTemplatesQuery({\n skip: !canListTemplates,\n variables: {\n isPublic: publicOnly || undefined,\n category: categoryFilter === 'all' ? undefined : categoryFilter,\n },\n });\n const templates = data?.tourTemplates ?? [];\n\n const filteredTemplates = templates.filter(\n (t: (typeof templates)[number]) =>\n !searchQuery || t.name.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const [createFromTemplate] = useCreateTourFromTemplateMutation();\n\n const handleUseTemplate = async (templateId: string) => {\n nativeImpact('light');\n try {\n const { data } = await createFromTemplate({\n variables: { templateId },\n });\n if (data?.createTourFromTemplate) {\n void nativeNotify('success');\n navigate(`${basePath}/${data.createTourFromTemplate.id}/edit`);\n }\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.create_from_template', toursContext);\n }\n };\n\n const [deleteTemplate] = useDeleteTourTemplateMutation();\n\n const handleDeleteTemplate = async (templateId: string) => {\n try {\n await deleteTemplate({\n variables: { id: templateId },\n refetchQueries: ['GetTourTemplates'],\n });\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.delete', toursContext);\n }\n };\n\n const handleDeleteTemplateClick = async (templateId: string) => {\n nativeImpact('medium');\n const message = tr('templateLibrary.deleteConfirm');\n const nativeResult = await nativeConfirm({\n title: tr('templateLibrary.deleteConfirm'),\n message,\n });\n const confirmed = nativeResult === null ? window.confirm(message) : nativeResult;\n if (confirmed) await handleDeleteTemplate(templateId);\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\">{tr('templateLibrary.title')}</h1>\n <p className=\"text-sm text-muted-foreground\">{tr('templateLibrary.subtitle')}</p>\n </div>\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-muted-foreground\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('templateLibrary.searchPlaceholder')}\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 rounded-md bg-background\"\n aria-label={tr('templateLibrary.searchPlaceholder')}\n />\n </div>\n <select\n value={categoryFilter}\n onChange={(e) => setCategoryFilter(e.target.value as TemplateCategory | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n aria-label={tr('templateLibrary.allCategories')}\n >\n <option value=\"all\">{tr('templateLibrary.allCategories')}</option>\n <option value=\"ONBOARDING\">{tr('templateLibrary.categoryOnboarding')}</option>\n <option value=\"FEATURE_ANNOUNCEMENT\">\n {tr('templateLibrary.categoryFeatureAnnouncement')}\n </option>\n <option value=\"HELP\">{tr('templateLibrary.categoryHelp')}</option>\n <option value=\"CUSTOM\">{tr('templateLibrary.categoryCustom')}</option>\n </select>\n <label className=\"flex items-center gap-2 px-4 py-2 min-h-[44px] border border-border rounded-md bg-background cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={publicOnly}\n onChange={(e) => setPublicOnly(e.target.checked)}\n className=\"rounded\"\n aria-label={tr('templateLibrary.publicOnly')}\n />\n <span className=\"text-sm\">{tr('templateLibrary.publicOnly')}</span>\n </label>\n </div>\n\n {/* Templates Grid */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-muted-foreground\">{tr('templateLibrary.loading')}</p>\n </div>\n ) : filteredTemplates.length > 0 ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredTemplates.map((template: (typeof filteredTemplates)[number]) => (\n <div\n key={template.id}\n className=\"border border-border rounded-md overflow-hidden hover:shadow-md transition-shadow\"\n >\n {/* Thumbnail */}\n <div className=\"aspect-video bg-muted flex items-center justify-center\">\n {template.thumbnail ? (\n <img\n src={template.thumbnail}\n alt={template.name}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <LayoutTemplate className=\"text-muted-foreground\" size={48} />\n )}\n </div>\n\n {/* Content */}\n <div className=\"p-4\">\n <div className=\"flex items-start justify-between mb-2\">\n <h3 className=\"font-semibold\">{template.name}</h3>\n <div className=\"flex gap-1\">\n {template.isPremium && <Star className=\"text-warning\" size={16} />}\n {template.isPublic ? (\n <Globe className=\"text-muted-foreground\" size={16} />\n ) : (\n <Lock className=\"text-muted-foreground\" size={16} />\n )}\n </div>\n </div>\n\n {template.description && (\n <p className=\"text-sm text-muted-foreground mb-3 line-clamp-2\">\n {template.description}\n </p>\n )}\n\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">\n {tr('templateLibrary.usedTimes')} {template.useCount}{' '}\n {tr('templateLibrary.times')}\n </span>\n <div className=\"flex items-center gap-2\">\n {canDeleteTemplate && (\n <button\n type=\"button\"\n onClick={() => void handleDeleteTemplateClick(template.id)}\n className=\"p-2 min-h-[44px] min-w-[44px] text-muted-foreground hover:text-destructive rounded-md\"\n aria-label={tr('templateLibrary.deleteTemplate')}\n >\n <Trash2 size={16} />\n </button>\n )}\n {canUseTemplate && (\n <button\n type=\"button\"\n onClick={() => handleUseTemplate(template.id)}\n className=\"px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 text-sm\"\n >\n {tr('templateLibrary.useTemplate')}\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-12 border border-dashed border-border rounded-md\">\n <LayoutTemplate className=\"mx-auto mb-4 text-muted-foreground\" size={48} />\n <p className=\"text-muted-foreground mb-2\">{tr('templateLibrary.noTemplatesFound')}</p>\n <p className=\"text-sm text-muted-foreground\">{tr('templateLibrary.adjustFilters')}</p>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -298,11 +298,11 @@ function ye(e) {
298
298
  }
299
299
  function be(e, t) {
300
300
  let n = m(t);
301
- return n ? h(e).filter((e) => e.moduleId === n).map((e) => ({
301
+ return n ? h(e).flatMap((e) => e.moduleId === n ? [{
302
302
  pageId: e.pageId,
303
303
  label: e.pageLabel,
304
304
  path: e.path
305
- })) : [];
305
+ }] : []) : [];
306
306
  }
307
307
  function g() {
308
308
  let { tr: f } = ee(), { tourId: p } = pe(), m = fe(), h = e(), { basePath: g = "/" } = h, _ = he(), xe = me("global"), { hasPermission: v, isLoading: y } = r(), b = !p || p === "new", x = v(i.TOUR_CREATE), S = v(i.TOUR_UPDATE), Se = v(i.TOUR_TEMPLATE_CREATE), C = b ? x : S, w = x && S, { tour: T, loadTour: E, createTour: Ce, updateTour: we, saving: D, validationErrors: O, error: k } = te(p), { saveAsTemplate: Te } = n(), { data: A, loading: j } = t({
@@ -432,6 +432,7 @@ function g() {
432
432
  /* @__PURE__ */ d("div", {
433
433
  className: "flex items-center gap-4",
434
434
  children: [/* @__PURE__ */ u("button", {
435
+ type: "button",
435
436
  onClick: Ae,
436
437
  className: "p-2 hover:bg-accent rounded-md",
437
438
  "aria-label": f("tourBuilder.goBack"),
@@ -514,7 +515,8 @@ function g() {
514
515
  name: e.target.value
515
516
  }),
516
517
  className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
517
- required: !0
518
+ required: !0,
519
+ "aria-label": f("tourBuilder.labelName")
518
520
  })] }),
519
521
  /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("label", {
520
522
  className: "block text-sm font-medium mb-2",
@@ -528,7 +530,8 @@ function g() {
528
530
  description: e.target.value
529
531
  }),
530
532
  rows: 3,
531
- className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground"
533
+ className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
534
+ "aria-label": f("tourBuilder.labelDescription")
532
535
  })] }),
533
536
  /* @__PURE__ */ d("div", { children: [
534
537
  /* @__PURE__ */ u("label", {
@@ -558,6 +561,7 @@ function g() {
558
561
  },
559
562
  className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
560
563
  required: !0,
564
+ "aria-label": f("tourBuilder.labelProductId"),
561
565
  children: [
562
566
  /* @__PURE__ */ u("option", {
563
567
  value: "",
@@ -565,7 +569,7 @@ function g() {
565
569
  }),
566
570
  j ? /* @__PURE__ */ u("option", {
567
571
  disabled: !0,
568
- children: "Loading products..."
572
+ children: "Loading products…"
569
573
  }) : null,
570
574
  q.map((e) => /* @__PURE__ */ d("option", {
571
575
  value: e.slug,
@@ -588,6 +592,7 @@ function g() {
588
592
  }),
589
593
  P ? /* @__PURE__ */ u("input", {
590
594
  id: "product-id-custom",
595
+ "aria-label": "Custom product slug",
591
596
  type: "text",
592
597
  value: M.productId || "",
593
598
  onChange: (e) => N({
@@ -629,6 +634,7 @@ function g() {
629
634
  },
630
635
  className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
631
636
  disabled: !M.productId,
637
+ "aria-label": "Module ID",
632
638
  children: [
633
639
  /* @__PURE__ */ u("option", {
634
640
  value: "",
@@ -655,6 +661,7 @@ function g() {
655
661
  }),
656
662
  I ? /* @__PURE__ */ u("input", {
657
663
  id: "module-id-custom",
664
+ "aria-label": "Custom module ID",
658
665
  type: "text",
659
666
  value: M.moduleId || "",
660
667
  onChange: (e) => N({
@@ -689,6 +696,7 @@ function g() {
689
696
  },
690
697
  className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
691
698
  disabled: !M.productId,
699
+ "aria-label": "Page ID",
692
700
  children: [
693
701
  /* @__PURE__ */ u("option", {
694
702
  value: "",
@@ -715,6 +723,7 @@ function g() {
715
723
  }),
716
724
  R ? /* @__PURE__ */ u("input", {
717
725
  id: "page-id-custom",
726
+ "aria-label": "Custom page ID",
718
727
  type: "text",
719
728
  value: M.pageId || "",
720
729
  onChange: (e) => N({
@@ -735,7 +744,8 @@ function g() {
735
744
  ...M,
736
745
  isActive: e.target.checked
737
746
  }),
738
- className: "w-4 h-4 rounded"
747
+ className: "size-4 rounded",
748
+ "aria-label": "Active"
739
749
  }), /* @__PURE__ */ u("span", {
740
750
  className: "text-sm font-medium",
741
751
  children: "Active"
@@ -764,6 +774,7 @@ function g() {
764
774
  triggerType: e.target.value
765
775
  }),
766
776
  className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
777
+ "aria-label": f("tourBuilder.labelTriggerType"),
767
778
  children: [
768
779
  /* @__PURE__ */ u("option", {
769
780
  value: "MANUAL",
@@ -804,7 +815,8 @@ function g() {
804
815
  priority: t
805
816
  });
806
817
  },
807
- className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground"
818
+ className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
819
+ "aria-label": f("tourBuilder.labelPriority")
808
820
  })] }),
809
821
  /* @__PURE__ */ d("div", {
810
822
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
@@ -820,7 +832,8 @@ function g() {
820
832
  ...M,
821
833
  startDate: e.target.value ? new Date(e.target.value).toISOString() : void 0
822
834
  }),
823
- className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground"
835
+ className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
836
+ "aria-label": "Start Date"
824
837
  })] }), /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("label", {
825
838
  className: "block text-sm font-medium mb-2",
826
839
  htmlFor: "tour-end-date",
@@ -833,7 +846,8 @@ function g() {
833
846
  ...M,
834
847
  endDate: e.target.value ? new Date(e.target.value).toISOString() : void 0
835
848
  }),
836
- className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground"
849
+ className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground",
850
+ "aria-label": "End Date"
837
851
  })] })]
838
852
  })
839
853
  ]
@@ -856,10 +870,10 @@ function g() {
856
870
  children: f("tourBuilder.validationErrorsTitle")
857
871
  }), /* @__PURE__ */ u("ul", {
858
872
  className: "list-disc list-inside space-y-1",
859
- children: O.map((e, t) => /* @__PURE__ */ u("li", {
873
+ children: O.map((e) => /* @__PURE__ */ u("li", {
860
874
  className: "text-sm text-destructive",
861
875
  children: e.message
862
- }, t))
876
+ }, e.message))
863
877
  })]
864
878
  }),
865
879
  /* @__PURE__ */ d("div", {