@burdenoff/microfe-tours 2026.519.1 → 2026.523.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/index.js +2 -1
- package/dist/tours/ToursAdminRoot.d.ts.map +1 -1
- package/dist/tours/ToursAdminRoot.js +23 -20
- package/dist/tours/ToursAdminRoot.js.map +1 -1
- package/dist/tours/ToursUserRoot.d.ts.map +1 -1
- package/dist/tours/ToursUserRoot.js +25 -22
- package/dist/tours/ToursUserRoot.js.map +1 -1
- package/dist/tours/hooks/useMediaLibrary.js +3 -3
- package/dist/tours/hooks/useTourBuilder.js +10 -10
- package/dist/tours/hooks/useTourLifecycle.js +3 -3
- package/dist/tours/i18n.d.ts +5 -1
- package/dist/tours/i18n.d.ts.map +1 -1
- package/dist/tours/i18n.js +4 -0
- package/dist/tours/i18n.js.map +1 -1
- package/dist/tours/index.d.ts +1 -0
- package/dist/tours/index.d.ts.map +1 -1
- package/dist/tours/index.js +1 -0
- package/dist/tours/pages/AnalyticsDashboardPage.d.ts.map +1 -1
- package/dist/tours/pages/AnalyticsDashboardPage.js +5 -5
- package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.d.ts.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.js +97 -96
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/SchedulerPage.d.ts.map +1 -1
- package/dist/tours/pages/SchedulerPage.js +129 -126
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.d.ts.map +1 -1
- package/dist/tours/pages/StepEditorPage.js +133 -128
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/SystemAnalyticsPage.d.ts.map +1 -1
- package/dist/tours/pages/SystemAnalyticsPage.js +3 -3
- package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.d.ts.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.js +97 -94
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
- package/dist/tours/pages/TourBuilderPage.d.ts.map +1 -1
- package/dist/tours/pages/TourBuilderPage.js +232 -230
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.d.ts.map +1 -1
- package/dist/tours/pages/TourPreviewPage.js +20 -18
- package/dist/tours/pages/TourPreviewPage.js.map +1 -1
- package/dist/tours/pages/ToursListPage.js +14 -14
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/dist/tours/store/toursStore.d.ts +1 -0
- package/dist/tours/store/toursStore.d.ts.map +1 -1
- package/dist/tours/store/toursStore.js +14 -0
- package/dist/tours/store/toursStore.js.map +1 -1
- package/dist/tours/telemetry.d.ts +9 -0
- package/dist/tours/telemetry.d.ts.map +1 -0
- package/dist/tours/telemetry.js +19 -0
- package/dist/tours/telemetry.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourBuilderPage.js","names":[],"sources":["../../../src/tours/pages/TourBuilderPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n Save,\n ArrowLeft,\n Eye,\n ListOrdered,\n BarChart3,\n Calendar,\n LayoutTemplate,\n} from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { Tour, TourTriggerType } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { useGetPlatformProductsForToursQuery } from '../../generated/global-operations';\n\n// Covers the current platform catalog with room for planned products; custom slug entry remains the fallback.\nconst PLATFORM_PRODUCTS_QUERY_LIMIT = 250;\n\ninterface TourRouteModuleOption {\n moduleId: string;\n label: string;\n path: string;\n}\n\ninterface TourRoutePageOption {\n pageId: string;\n label: string;\n path: string;\n}\n\ninterface TourRouteCatalogEntry {\n productId: string;\n moduleId: string;\n moduleLabel: string;\n pageId: string;\n pageLabel: string;\n path: string;\n isModuleHome?: boolean;\n}\n\nconst TOUR_ROUTE_CATALOG: readonly TourRouteCatalogEntry[] = [\n {\n productId: 'vibecontrols',\n moduleId: 'dashboard',\n moduleLabel: 'Dashboard',\n pageId: 'dashboard',\n pageLabel: 'Dashboard',\n path: '/dashboard',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'home',\n pageLabel: 'Overview',\n path: '/vibecontrols',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'agents',\n pageLabel: 'Targets & Agents',\n path: '/vibecontrols/agents',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibes',\n pageLabel: 'Vibes',\n path: '/vibecontrols/vibes',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'sessions',\n pageLabel: 'Sessions',\n path: '/vibecontrols/sessions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'ai',\n pageLabel: 'AI',\n path: '/vibecontrols/ai',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'catalogs',\n pageLabel: 'Catalogs',\n path: '/vibecontrols/catalogs',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'components',\n pageLabel: 'Components',\n path: '/vibecontrols/components',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'templates',\n pageLabel: 'Templates',\n path: '/vibecontrols/templates',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'actions',\n pageLabel: 'Actions',\n path: '/vibecontrols/actions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibedeck',\n pageLabel: 'Decks',\n path: '/vibecontrols/vibedeck',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'calendar',\n pageLabel: 'Calendar',\n path: '/vibecontrols/calendar',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'tunnels',\n pageLabel: 'Tunnels',\n path: '/vibecontrols/tunnels',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'analytics',\n pageLabel: 'Analytics',\n path: '/vibecontrols/analytics',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'audit',\n pageLabel: 'Audit Log',\n path: '/vibecontrols/audit',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'health',\n pageLabel: 'Health',\n path: '/vibecontrols/health',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'settings',\n pageLabel: 'Settings',\n path: '/vibecontrols/settings',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'scheduler',\n moduleLabel: 'Scheduler',\n pageId: 'scheduler',\n pageLabel: 'Scheduler',\n path: '/scheduler',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'sandbox',\n moduleLabel: 'Sandbox',\n pageId: 'sandbox',\n pageLabel: 'Sandbox',\n path: '/sandbox',\n isModuleHome: true,\n },\n] as const;\n\nfunction normalizeCatalogValue(value: string | null | undefined): string | undefined {\n const normalized = value?.trim();\n return normalized ? normalized : undefined;\n}\n\nfunction getRouteCatalog(productId: string | null | undefined): TourRouteCatalogEntry[] {\n const productKey = normalizeCatalogValue(productId);\n if (!productKey) return [];\n return TOUR_ROUTE_CATALOG.filter((entry) => entry.productId === productKey);\n}\n\nfunction getTourRouteModules(productId: string | null | undefined): TourRouteModuleOption[] {\n const modules = new Map<string, TourRouteModuleOption>();\n\n for (const entry of getRouteCatalog(productId)) {\n const existing = modules.get(entry.moduleId);\n if (!existing || entry.isModuleHome) {\n modules.set(entry.moduleId, {\n moduleId: entry.moduleId,\n label: entry.moduleLabel,\n path: entry.path,\n });\n }\n }\n\n return [...modules.values()];\n}\n\nfunction getTourRoutePages(\n productId: string | null | undefined,\n moduleId: string | null | undefined\n): TourRoutePageOption[] {\n const moduleKey = normalizeCatalogValue(moduleId);\n if (!moduleKey) return [];\n\n return getRouteCatalog(productId)\n .filter((entry) => entry.moduleId === moduleKey)\n .map((entry) => ({\n pageId: entry.pageId,\n label: entry.pageLabel,\n path: entry.path,\n }));\n}\n\n/**\n * Tour builder page\n * Create or edit tour metadata\n */\nexport function TourBuilderPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const { hasPermission } = useToursPermissionAccess();\n const isNew = !tourId || tourId === 'new';\n const canCreate = hasPermission(TOUR_PERMISSIONS.TOUR_CREATE);\n const canUpdate = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canCreateTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE);\n const canSave = isNew ? canCreate : canUpdate;\n\n const { tour, loadTour, createTour, updateTour, saving, validationErrors, error } =\n useTourBuilder(tourId);\n const { saveAsTemplate } = useTourLifecycle();\n const { data: productsData, loading: productsLoading } = useGetPlatformProductsForToursQuery({\n variables: { limit: PLATFORM_PRODUCTS_QUERY_LIMIT, offset: 0 },\n fetchPolicy: 'cache-and-network',\n });\n\n const defaultFormData = {\n name: '',\n description: '',\n productId: '',\n moduleId: '',\n pageId: '',\n isActive: true,\n status: 'DRAFT' as const,\n triggerType: 'MANUAL' as const,\n priority: 50,\n displayOrder: 1,\n startDate: '',\n endDate: '',\n };\n\n const [formData, setFormData] = useState<Partial<Tour>>(defaultFormData);\n const [customProductEntry, setCustomProductEntry] = useState(false);\n const [customModuleEntry, setCustomModuleEntry] = useState(false);\n const [customPageEntry, setCustomPageEntry] = useState(false);\n\n const formInitializedRef = useRef(false);\n\n const productOptions = useMemo(() => {\n return [...(productsData?.platformProducts.items ?? [])].sort((a, b) =>\n a.name.localeCompare(b.name)\n );\n }, [productsData]);\n\n const productOptionSlugs = useMemo(\n () => new Set(productOptions.map((product) => product.slug)),\n [productOptions]\n );\n\n const moduleOptions = useMemo(\n () => getTourRouteModules(formData.productId),\n [formData.productId]\n );\n\n const moduleOptionIds = useMemo(\n () => new Set(moduleOptions.map((moduleOption) => moduleOption.moduleId)),\n [moduleOptions]\n );\n\n const pageOptions = useMemo(\n () => getTourRoutePages(formData.productId, formData.moduleId),\n [formData.moduleId, formData.productId]\n );\n\n const pageOptionIds = useMemo(\n () => new Set(pageOptions.map((pageOption) => pageOption.pageId)),\n [pageOptions]\n );\n\n useEffect(() => {\n if (tourId && tourId !== 'new') {\n formInitializedRef.current = false;\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour && !formInitializedRef.current) {\n setFormData(tour);\n formInitializedRef.current = true;\n }\n }, [tour]);\n\n useEffect(() => {\n if (!formData.productId || productsLoading) {\n setCustomProductEntry(false);\n return;\n }\n setCustomProductEntry(productOptions.length > 0 && !productOptionSlugs.has(formData.productId));\n }, [formData.productId, productOptionSlugs, productOptions.length, productsLoading]);\n\n useEffect(() => {\n if (!formData.productId || !formData.moduleId) {\n setCustomModuleEntry(false);\n return;\n }\n setCustomModuleEntry(moduleOptions.length === 0 || !moduleOptionIds.has(formData.moduleId));\n }, [formData.moduleId, formData.productId, moduleOptionIds, moduleOptions.length]);\n\n useEffect(() => {\n if (!formData.productId || !formData.pageId) {\n setCustomPageEntry(false);\n return;\n }\n setCustomPageEntry(pageOptions.length === 0 || !pageOptionIds.has(formData.pageId));\n }, [formData.pageId, formData.productId, pageOptionIds, pageOptions.length]);\n\n const showCurrentProductOption = Boolean(\n formData.productId && !customProductEntry && !productOptionSlugs.has(formData.productId)\n );\n const showCurrentModuleOption = Boolean(\n formData.moduleId && !customModuleEntry && !moduleOptionIds.has(formData.moduleId)\n );\n const showCurrentPageOption = Boolean(\n formData.pageId && !customPageEntry && !pageOptionIds.has(formData.pageId)\n );\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n try {\n if (tourId && tourId !== 'new') {\n await updateTour(tourId, formData);\n } else {\n await createTour(formData);\n }\n } catch (error) {\n console.error('Failed to save tour:', error);\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/list`);\n };\n\n const formatDateTimeLocal = (value?: string) => {\n if (!value) return '';\n\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '';\n }\n\n return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, 16);\n };\n\n const handleSaveTemplate = async () => {\n if (!tourId || tourId === 'new') return;\n\n const defaultName = `${formData.name || tour?.name || 'Tour'} Template`;\n const name = window.prompt('Template name', defaultName);\n if (!name) return;\n\n const category =\n window.prompt(\n 'Template category (ONBOARDING, FEATURE_ANNOUNCEMENT, HELP, CUSTOM)',\n 'ONBOARDING'\n ) || 'ONBOARDING';\n\n try {\n await saveAsTemplate(tourId, {\n name,\n description: formData.description,\n category,\n isPublic: false,\n });\n navigate(`${basePath}/templates`);\n } catch (saveTemplateError) {\n console.error('Failed to save template:', saveTemplateError);\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6 max-w-4xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-4\">\n <button\n onClick={handleBack}\n className=\"p-2 hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">\n {tourId && tourId !== 'new'\n ? tr('tourBuilder.titleEdit')\n : tr('tourBuilder.titleCreate')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{tr('tourBuilder.subtitle')}</p>\n </div>\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Basic Info */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionBasicInfo')}</h2>\n\n <div className=\"space-y-4\">\n {/* Name */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-name\">\n {tr('tourBuilder.labelName')}\n </label>\n <input\n id=\"tour-name\"\n type=\"text\"\n value={formData.name || ''}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n />\n </div>\n\n {/* Description */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-description\">\n {tr('tourBuilder.labelDescription')}\n </label>\n <textarea\n id=\"tour-description\"\n value={formData.description || ''}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n {/* Product ID */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"product-id\">\n {tr('tourBuilder.labelProductId')}\n </label>\n <select\n id=\"product-id\"\n value={customProductEntry ? '__custom__' : formData.productId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomProductEntry(true);\n setFormData({\n ...formData,\n productId: '',\n moduleId: undefined,\n pageId: undefined,\n });\n return;\n }\n\n setCustomProductEntry(false);\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n >\n <option value=\"\">Select product</option>\n {productsLoading ? <option disabled>Loading products...</option> : null}\n {productOptions.map((product) => (\n <option key={product.id} value={product.slug}>\n {product.name} ({product.slug})\n </option>\n ))}\n {showCurrentProductOption ? (\n <option value={formData.productId}>Current: {formData.productId}</option>\n ) : null}\n <option value=\"__custom__\">Custom product slug</option>\n </select>\n {customProductEntry ? (\n <input\n id=\"product-id-custom\"\n type=\"text\"\n value={formData.productId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n required\n />\n ) : null}\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"module-id\">\n Module ID\n </label>\n <select\n id=\"module-id\"\n value={customModuleEntry ? '__custom__' : formData.moduleId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomModuleEntry(true);\n setFormData({ ...formData, moduleId: '', pageId: undefined });\n return;\n }\n\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n >\n <option value=\"\">All modules</option>\n {moduleOptions.map((moduleOption) => (\n <option key={moduleOption.moduleId} value={moduleOption.moduleId}>\n {moduleOption.label} ({moduleOption.moduleId})\n </option>\n ))}\n {showCurrentModuleOption ? (\n <option value={formData.moduleId}>Current: {formData.moduleId}</option>\n ) : null}\n <option value=\"__custom__\">Custom module ID</option>\n </select>\n {customModuleEntry ? (\n <input\n id=\"module-id-custom\"\n type=\"text\"\n value={formData.moduleId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n />\n ) : null}\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"page-id\">\n Page ID\n </label>\n <select\n id=\"page-id\"\n value={customPageEntry ? '__custom__' : formData.pageId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomPageEntry(true);\n setFormData({ ...formData, pageId: '' });\n return;\n }\n\n setCustomPageEntry(false);\n setFormData({ ...formData, pageId: e.target.value || undefined });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n >\n <option value=\"\">All pages</option>\n {pageOptions.map((pageOption) => (\n <option key={pageOption.pageId} value={pageOption.pageId}>\n {pageOption.label} ({pageOption.pageId})\n </option>\n ))}\n {showCurrentPageOption ? (\n <option value={formData.pageId}>Current: {formData.pageId}</option>\n ) : null}\n <option value=\"__custom__\">Custom page ID</option>\n </select>\n {customPageEntry ? (\n <input\n id=\"page-id-custom\"\n type=\"text\"\n value={formData.pageId || ''}\n onChange={(e) =>\n setFormData({ ...formData, pageId: e.target.value || undefined })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"agents\"\n />\n ) : null}\n </div>\n </div>\n\n <label className=\"flex items-center gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.isActive ?? true}\n onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}\n className=\"w-4 h-4 rounded\"\n />\n <span className=\"text-sm font-medium\">Active</span>\n </label>\n </div>\n </div>\n\n {/* Trigger Settings */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionTriggerSettings')}</h2>\n\n <div className=\"space-y-4\">\n {/* Trigger Type */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"trigger-type\">\n {tr('tourBuilder.labelTriggerType')}\n </label>\n <select\n id=\"trigger-type\"\n value={formData.triggerType || 'MANUAL'}\n onChange={(e) =>\n setFormData({ ...formData, triggerType: e.target.value as TourTriggerType })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n >\n <option value=\"MANUAL\">{tr('tourBuilder.triggerManual')}</option>\n <option value=\"AUTO_FIRST_VISIT\">{tr('tourBuilder.triggerAutoFirstVisit')}</option>\n <option value=\"AUTO_ALWAYS\">{tr('tourBuilder.triggerAutoAlways')}</option>\n <option value=\"ON_EVENT\">{tr('tourBuilder.triggerOnEvent')}</option>\n <option value=\"SCHEDULED\">{tr('tourBuilder.triggerScheduled')}</option>\n </select>\n </div>\n\n {/* Priority */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"priority\">\n {tr('tourBuilder.labelPriority')}\n </label>\n <input\n id=\"priority\"\n type=\"number\"\n min=\"1\"\n max=\"100\"\n value={formData.priority || 50}\n onChange={(e) => {\n const priority = Number.parseInt(e.target.value, 10) || 50;\n setFormData({ ...formData, priority });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-start-date\">\n Start Date\n </label>\n <input\n id=\"tour-start-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.startDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n startDate: e.target.value\n ? new Date(e.target.value).toISOString()\n : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-end-date\">\n End Date\n </label>\n <input\n id=\"tour-end-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.endDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n endDate: e.target.value ? new Date(e.target.value).toISOString() : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n </div>\n </div>\n </div>\n\n {/* API Error */}\n {error && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">{tr('tourBuilder.errorTitle')}</h3>\n <p className=\"text-sm text-destructive\">{error.message}</p>\n </div>\n )}\n\n {/* Validation Errors */}\n {validationErrors.length > 0 && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">\n {tr('tourBuilder.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationErrors.map((err, index) => (\n <li key={index} className=\"text-sm text-destructive\">\n {err.message}\n </li>\n ))}\n </ul>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap gap-3\">\n <PermissionGate\n permission={isNew ? TOUR_PERMISSIONS.TOUR_CREATE : TOUR_PERMISSIONS.TOUR_UPDATE}\n >\n <button\n type=\"submit\"\n disabled={saving || !canSave}\n className=\"flex-1 min-w-[200px] px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center justify-center gap-2\"\n >\n <Save size={20} />\n {saving\n ? tr('tourBuilder.saving')\n : tourId && tourId !== 'new'\n ? tr('tourBuilder.updateTour')\n : tr('tourBuilder.createAndAddSteps')}\n </button>\n </PermissionGate>\n {tourId && tourId !== 'new' && (\n <>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/steps`)}\n className=\"px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/80 flex items-center gap-2\"\n >\n <ListOrdered size={20} />\n {tr('tourBuilder.editSteps')}\n {tour?.steps && tour.steps.length > 0 && (\n <span className=\"ml-1 px-2 py-0.5 text-xs bg-primary/20 rounded-full\">\n {tour.steps.length}\n </span>\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/preview`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Eye size={20} />\n {tr('tourBuilder.preview')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/analytics`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <BarChart3 size={20} />\n {tr('tourBuilder.analytics')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/schedule`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Calendar size={20} />\n Schedule\n </button>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE}>\n <button\n type=\"button\"\n onClick={handleSaveTemplate}\n disabled={!canCreateTemplate}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 disabled:opacity-50\"\n >\n <LayoutTemplate size={20} />\n Save as Template\n </button>\n </PermissionGate>\n </>\n )}\n </div>\n </form>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAsBA,IAAM,IAAgC,KAwBhC,IAAuD;CAC3D;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;E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"}
|
|
1
|
+
{"version":3,"file":"TourBuilderPage.js","names":[],"sources":["../../../src/tours/pages/TourBuilderPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n Save,\n ArrowLeft,\n Eye,\n ListOrdered,\n BarChart3,\n Calendar,\n LayoutTemplate,\n} from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { Tour, TourTriggerType } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\nimport { useGetPlatformProductsForToursQuery } from '../../generated/global-operations';\n\n// Covers the current platform catalog with room for planned products; custom slug entry remains the fallback.\nconst PLATFORM_PRODUCTS_QUERY_LIMIT = 250;\n\ninterface TourRouteModuleOption {\n moduleId: string;\n label: string;\n path: string;\n}\n\ninterface TourRoutePageOption {\n pageId: string;\n label: string;\n path: string;\n}\n\ninterface TourRouteCatalogEntry {\n productId: string;\n moduleId: string;\n moduleLabel: string;\n pageId: string;\n pageLabel: string;\n path: string;\n isModuleHome?: boolean;\n}\n\nconst TOUR_ROUTE_CATALOG: readonly TourRouteCatalogEntry[] = [\n {\n productId: 'vibecontrols',\n moduleId: 'dashboard',\n moduleLabel: 'Dashboard',\n pageId: 'dashboard',\n pageLabel: 'Dashboard',\n path: '/dashboard',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'home',\n pageLabel: 'Overview',\n path: '/vibecontrols',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'agents',\n pageLabel: 'Targets & Agents',\n path: '/vibecontrols/agents',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibes',\n pageLabel: 'Vibes',\n path: '/vibecontrols/vibes',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'sessions',\n pageLabel: 'Sessions',\n path: '/vibecontrols/sessions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'ai',\n pageLabel: 'AI',\n path: '/vibecontrols/ai',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'catalogs',\n pageLabel: 'Catalogs',\n path: '/vibecontrols/catalogs',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'components',\n pageLabel: 'Components',\n path: '/vibecontrols/components',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'templates',\n pageLabel: 'Templates',\n path: '/vibecontrols/templates',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'actions',\n pageLabel: 'Actions',\n path: '/vibecontrols/actions',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'vibedeck',\n pageLabel: 'Decks',\n path: '/vibecontrols/vibedeck',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'calendar',\n pageLabel: 'Calendar',\n path: '/vibecontrols/calendar',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'tunnels',\n pageLabel: 'Tunnels',\n path: '/vibecontrols/tunnels',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'analytics',\n pageLabel: 'Analytics',\n path: '/vibecontrols/analytics',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'audit',\n pageLabel: 'Audit Log',\n path: '/vibecontrols/audit',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'health',\n pageLabel: 'Health',\n path: '/vibecontrols/health',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'vibecontrols',\n moduleLabel: 'VibeControls',\n pageId: 'settings',\n pageLabel: 'Settings',\n path: '/vibecontrols/settings',\n },\n {\n productId: 'vibecontrols',\n moduleId: 'scheduler',\n moduleLabel: 'Scheduler',\n pageId: 'scheduler',\n pageLabel: 'Scheduler',\n path: '/scheduler',\n isModuleHome: true,\n },\n {\n productId: 'vibecontrols',\n moduleId: 'sandbox',\n moduleLabel: 'Sandbox',\n pageId: 'sandbox',\n pageLabel: 'Sandbox',\n path: '/sandbox',\n isModuleHome: true,\n },\n] as const;\n\nfunction normalizeCatalogValue(value: string | null | undefined): string | undefined {\n const normalized = value?.trim();\n return normalized ? normalized : undefined;\n}\n\nfunction getRouteCatalog(productId: string | null | undefined): TourRouteCatalogEntry[] {\n const productKey = normalizeCatalogValue(productId);\n if (!productKey) return [];\n return TOUR_ROUTE_CATALOG.filter((entry) => entry.productId === productKey);\n}\n\nfunction getTourRouteModules(productId: string | null | undefined): TourRouteModuleOption[] {\n const modules = new Map<string, TourRouteModuleOption>();\n\n for (const entry of getRouteCatalog(productId)) {\n const existing = modules.get(entry.moduleId);\n if (!existing || entry.isModuleHome) {\n modules.set(entry.moduleId, {\n moduleId: entry.moduleId,\n label: entry.moduleLabel,\n path: entry.path,\n });\n }\n }\n\n return [...modules.values()];\n}\n\nfunction getTourRoutePages(\n productId: string | null | undefined,\n moduleId: string | null | undefined\n): TourRoutePageOption[] {\n const moduleKey = normalizeCatalogValue(moduleId);\n if (!moduleKey) return [];\n\n return getRouteCatalog(productId)\n .filter((entry) => entry.moduleId === moduleKey)\n .map((entry) => ({\n pageId: entry.pageId,\n label: entry.pageLabel,\n path: entry.path,\n }));\n}\n\n/**\n * Tour builder page\n * Create or edit tour metadata\n */\nexport function TourBuilderPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const isNew = !tourId || tourId === 'new';\n const canCreate = hasPermission(TOUR_PERMISSIONS.TOUR_CREATE);\n const canUpdate = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canCreateTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE);\n const canSave = isNew ? canCreate : canUpdate;\n\n const { tour, loadTour, createTour, updateTour, saving, validationErrors, error } =\n useTourBuilder(tourId);\n const { saveAsTemplate } = useTourLifecycle();\n const { data: productsData, loading: productsLoading } = useGetPlatformProductsForToursQuery({\n variables: { limit: PLATFORM_PRODUCTS_QUERY_LIMIT, offset: 0 },\n fetchPolicy: 'cache-and-network',\n });\n\n const defaultFormData = {\n name: '',\n description: '',\n productId: '',\n moduleId: '',\n pageId: '',\n isActive: true,\n status: 'DRAFT' as const,\n triggerType: 'MANUAL' as const,\n priority: 50,\n displayOrder: 1,\n startDate: '',\n endDate: '',\n };\n\n const [formData, setFormData] = useState<Partial<Tour>>(defaultFormData);\n const [customProductEntry, setCustomProductEntry] = useState(false);\n const [customModuleEntry, setCustomModuleEntry] = useState(false);\n const [customPageEntry, setCustomPageEntry] = useState(false);\n\n const formInitializedRef = useRef(false);\n\n const productOptions = useMemo(() => {\n return [...(productsData?.platformProducts.items ?? [])].sort((a, b) =>\n a.name.localeCompare(b.name)\n );\n }, [productsData]);\n\n const productOptionSlugs = useMemo(\n () => new Set(productOptions.map((product) => product.slug)),\n [productOptions]\n );\n\n const moduleOptions = useMemo(\n () => getTourRouteModules(formData.productId),\n [formData.productId]\n );\n\n const moduleOptionIds = useMemo(\n () => new Set(moduleOptions.map((moduleOption) => moduleOption.moduleId)),\n [moduleOptions]\n );\n\n const pageOptions = useMemo(\n () => getTourRoutePages(formData.productId, formData.moduleId),\n [formData.moduleId, formData.productId]\n );\n\n const pageOptionIds = useMemo(\n () => new Set(pageOptions.map((pageOption) => pageOption.pageId)),\n [pageOptions]\n );\n\n useEffect(() => {\n if (tourId && tourId !== 'new') {\n formInitializedRef.current = false;\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour && !formInitializedRef.current) {\n setFormData(tour);\n formInitializedRef.current = true;\n }\n }, [tour]);\n\n useEffect(() => {\n if (!formData.productId || productsLoading) {\n setCustomProductEntry(false);\n return;\n }\n setCustomProductEntry(productOptions.length > 0 && !productOptionSlugs.has(formData.productId));\n }, [formData.productId, productOptionSlugs, productOptions.length, productsLoading]);\n\n useEffect(() => {\n if (!formData.productId || !formData.moduleId) {\n setCustomModuleEntry(false);\n return;\n }\n setCustomModuleEntry(moduleOptions.length === 0 || !moduleOptionIds.has(formData.moduleId));\n }, [formData.moduleId, formData.productId, moduleOptionIds, moduleOptions.length]);\n\n useEffect(() => {\n if (!formData.productId || !formData.pageId) {\n setCustomPageEntry(false);\n return;\n }\n setCustomPageEntry(pageOptions.length === 0 || !pageOptionIds.has(formData.pageId));\n }, [formData.pageId, formData.productId, pageOptionIds, pageOptions.length]);\n\n const showCurrentProductOption = Boolean(\n formData.productId && !customProductEntry && !productOptionSlugs.has(formData.productId)\n );\n const showCurrentModuleOption = Boolean(\n formData.moduleId && !customModuleEntry && !moduleOptionIds.has(formData.moduleId)\n );\n const showCurrentPageOption = Boolean(\n formData.pageId && !customPageEntry && !pageOptionIds.has(formData.pageId)\n );\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n try {\n if (tourId && tourId !== 'new') {\n await updateTour(tourId, formData);\n } else {\n await createTour(formData);\n }\n } catch {\n emitToursApiFailed(eventBus, 'tour.save', toursContext);\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/list`);\n };\n\n const formatDateTimeLocal = (value?: string) => {\n if (!value) return '';\n\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '';\n }\n\n return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, 16);\n };\n\n const handleSaveTemplate = async () => {\n if (!tourId || tourId === 'new') return;\n\n const defaultName = `${formData.name || tour?.name || 'Tour'} Template`;\n const name = window.prompt('Template name', defaultName);\n if (!name) return;\n\n const category =\n window.prompt(\n 'Template category (ONBOARDING, FEATURE_ANNOUNCEMENT, HELP, CUSTOM)',\n 'ONBOARDING'\n ) || 'ONBOARDING';\n\n try {\n await saveAsTemplate(tourId, {\n name,\n description: formData.description,\n category,\n isPublic: false,\n });\n navigate(`${basePath}/templates`);\n } catch {\n emitToursApiFailed(eventBus, 'template.save', toursContext);\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6 max-w-4xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-4\">\n <button\n onClick={handleBack}\n className=\"p-2 hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">\n {tourId && tourId !== 'new'\n ? tr('tourBuilder.titleEdit')\n : tr('tourBuilder.titleCreate')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{tr('tourBuilder.subtitle')}</p>\n </div>\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Basic Info */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionBasicInfo')}</h2>\n\n <div className=\"space-y-4\">\n {/* Name */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-name\">\n {tr('tourBuilder.labelName')}\n </label>\n <input\n id=\"tour-name\"\n type=\"text\"\n value={formData.name || ''}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n />\n </div>\n\n {/* Description */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-description\">\n {tr('tourBuilder.labelDescription')}\n </label>\n <textarea\n id=\"tour-description\"\n value={formData.description || ''}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n {/* Product ID */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"product-id\">\n {tr('tourBuilder.labelProductId')}\n </label>\n <select\n id=\"product-id\"\n value={customProductEntry ? '__custom__' : formData.productId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomProductEntry(true);\n setFormData({\n ...formData,\n productId: '',\n moduleId: undefined,\n pageId: undefined,\n });\n return;\n }\n\n setCustomProductEntry(false);\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n required\n >\n <option value=\"\">Select product</option>\n {productsLoading ? <option disabled>Loading products...</option> : null}\n {productOptions.map((product) => (\n <option key={product.id} value={product.slug}>\n {product.name} ({product.slug})\n </option>\n ))}\n {showCurrentProductOption ? (\n <option value={formData.productId}>Current: {formData.productId}</option>\n ) : null}\n <option value=\"__custom__\">Custom product slug</option>\n </select>\n {customProductEntry ? (\n <input\n id=\"product-id-custom\"\n type=\"text\"\n value={formData.productId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n productId: e.target.value,\n moduleId: undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n required\n />\n ) : null}\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"module-id\">\n Module ID\n </label>\n <select\n id=\"module-id\"\n value={customModuleEntry ? '__custom__' : formData.moduleId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomModuleEntry(true);\n setFormData({ ...formData, moduleId: '', pageId: undefined });\n return;\n }\n\n setCustomModuleEntry(false);\n setCustomPageEntry(false);\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n >\n <option value=\"\">All modules</option>\n {moduleOptions.map((moduleOption) => (\n <option key={moduleOption.moduleId} value={moduleOption.moduleId}>\n {moduleOption.label} ({moduleOption.moduleId})\n </option>\n ))}\n {showCurrentModuleOption ? (\n <option value={formData.moduleId}>Current: {formData.moduleId}</option>\n ) : null}\n <option value=\"__custom__\">Custom module ID</option>\n </select>\n {customModuleEntry ? (\n <input\n id=\"module-id-custom\"\n type=\"text\"\n value={formData.moduleId || ''}\n onChange={(e) =>\n setFormData({\n ...formData,\n moduleId: e.target.value || undefined,\n pageId: undefined,\n })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"vibecontrols\"\n />\n ) : null}\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"page-id\">\n Page ID\n </label>\n <select\n id=\"page-id\"\n value={customPageEntry ? '__custom__' : formData.pageId || ''}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomPageEntry(true);\n setFormData({ ...formData, pageId: '' });\n return;\n }\n\n setCustomPageEntry(false);\n setFormData({ ...formData, pageId: e.target.value || undefined });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n disabled={!formData.productId}\n >\n <option value=\"\">All pages</option>\n {pageOptions.map((pageOption) => (\n <option key={pageOption.pageId} value={pageOption.pageId}>\n {pageOption.label} ({pageOption.pageId})\n </option>\n ))}\n {showCurrentPageOption ? (\n <option value={formData.pageId}>Current: {formData.pageId}</option>\n ) : null}\n <option value=\"__custom__\">Custom page ID</option>\n </select>\n {customPageEntry ? (\n <input\n id=\"page-id-custom\"\n type=\"text\"\n value={formData.pageId || ''}\n onChange={(e) =>\n setFormData({ ...formData, pageId: e.target.value || undefined })\n }\n className=\"mt-2 w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n placeholder=\"agents\"\n />\n ) : null}\n </div>\n </div>\n\n <label className=\"flex items-center gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.isActive ?? true}\n onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}\n className=\"w-4 h-4 rounded\"\n />\n <span className=\"text-sm font-medium\">Active</span>\n </label>\n </div>\n </div>\n\n {/* Trigger Settings */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">{tr('tourBuilder.sectionTriggerSettings')}</h2>\n\n <div className=\"space-y-4\">\n {/* Trigger Type */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"trigger-type\">\n {tr('tourBuilder.labelTriggerType')}\n </label>\n <select\n id=\"trigger-type\"\n value={formData.triggerType || 'MANUAL'}\n onChange={(e) =>\n setFormData({ ...formData, triggerType: e.target.value as TourTriggerType })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n >\n <option value=\"MANUAL\">{tr('tourBuilder.triggerManual')}</option>\n <option value=\"AUTO_FIRST_VISIT\">{tr('tourBuilder.triggerAutoFirstVisit')}</option>\n <option value=\"AUTO_ALWAYS\">{tr('tourBuilder.triggerAutoAlways')}</option>\n <option value=\"ON_EVENT\">{tr('tourBuilder.triggerOnEvent')}</option>\n <option value=\"SCHEDULED\">{tr('tourBuilder.triggerScheduled')}</option>\n </select>\n </div>\n\n {/* Priority */}\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"priority\">\n {tr('tourBuilder.labelPriority')}\n </label>\n <input\n id=\"priority\"\n type=\"number\"\n min=\"1\"\n max=\"100\"\n value={formData.priority || 50}\n onChange={(e) => {\n const priority = Number.parseInt(e.target.value, 10) || 50;\n setFormData({ ...formData, priority });\n }}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-start-date\">\n Start Date\n </label>\n <input\n id=\"tour-start-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.startDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n startDate: e.target.value\n ? new Date(e.target.value).toISOString()\n : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\" htmlFor=\"tour-end-date\">\n End Date\n </label>\n <input\n id=\"tour-end-date\"\n type=\"datetime-local\"\n value={formatDateTimeLocal(formData.endDate)}\n onChange={(e) =>\n setFormData({\n ...formData,\n endDate: e.target.value ? new Date(e.target.value).toISOString() : undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground\"\n />\n </div>\n </div>\n </div>\n </div>\n\n {/* API Error */}\n {error && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">{tr('tourBuilder.errorTitle')}</h3>\n <p className=\"text-sm text-destructive\">{error.message}</p>\n </div>\n )}\n\n {/* Validation Errors */}\n {validationErrors.length > 0 && (\n <div className=\"border border-destructive rounded-md p-4 bg-destructive/10\">\n <h3 className=\"font-semibold text-destructive mb-2\">\n {tr('tourBuilder.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationErrors.map((err, index) => (\n <li key={index} className=\"text-sm text-destructive\">\n {err.message}\n </li>\n ))}\n </ul>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap gap-3\">\n <PermissionGate\n permission={isNew ? TOUR_PERMISSIONS.TOUR_CREATE : TOUR_PERMISSIONS.TOUR_UPDATE}\n >\n <button\n type=\"submit\"\n disabled={saving || !canSave}\n className=\"flex-1 min-w-[200px] px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center justify-center gap-2\"\n >\n <Save size={20} />\n {saving\n ? tr('tourBuilder.saving')\n : tourId && tourId !== 'new'\n ? tr('tourBuilder.updateTour')\n : tr('tourBuilder.createAndAddSteps')}\n </button>\n </PermissionGate>\n {tourId && tourId !== 'new' && (\n <>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/steps`)}\n className=\"px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/80 flex items-center gap-2\"\n >\n <ListOrdered size={20} />\n {tr('tourBuilder.editSteps')}\n {tour?.steps && tour.steps.length > 0 && (\n <span className=\"ml-1 px-2 py-0.5 text-xs bg-primary/20 rounded-full\">\n {tour.steps.length}\n </span>\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/preview`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Eye size={20} />\n {tr('tourBuilder.preview')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/analytics`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <BarChart3 size={20} />\n {tr('tourBuilder.analytics')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${tourId}/schedule`)}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <Calendar size={20} />\n Schedule\n </button>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_TEMPLATE_CREATE}>\n <button\n type=\"button\"\n onClick={handleSaveTemplate}\n disabled={!canCreateTemplate}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2 disabled:opacity-50\"\n >\n <LayoutTemplate size={20} />\n Save as Template\n </button>\n </PermissionGate>\n </>\n )}\n </div>\n </form>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwBA,IAAM,IAAgC,KAwBhC,IAAuD;CAC3D;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACN,cAAc;EACf;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW;EACX,UAAU;EACV,aAAa;EACb,QAAQ;EACR,WAAW;EACX,MAAM;EACP;CACD;EACE,WAAW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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourPreviewPage.d.ts","sourceRoot":"","sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"TourPreviewPage.d.ts","sourceRoot":"","sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,wBAAgB,eAAe,4CAmQ9B"}
|
|
@@ -51,17 +51,18 @@ function x() {
|
|
|
51
51
|
className: "flex flex-col h-screen bg-muted",
|
|
52
52
|
children: [
|
|
53
53
|
/* @__PURE__ */ v("div", {
|
|
54
|
-
className: "border-b border-border bg-background p-4 flex items-center gap-4",
|
|
54
|
+
className: "border-b border-border bg-background p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4",
|
|
55
55
|
children: [
|
|
56
56
|
/* @__PURE__ */ _("button", {
|
|
57
57
|
onClick: U,
|
|
58
|
-
className: "p-2 hover:bg-accent rounded-md",
|
|
58
|
+
className: "p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md",
|
|
59
|
+
"aria-label": x("tourBuilder.goBack"),
|
|
59
60
|
children: /* @__PURE__ */ _(l, { size: 20 })
|
|
60
61
|
}),
|
|
61
62
|
/* @__PURE__ */ v("div", {
|
|
62
|
-
className: "flex-1",
|
|
63
|
+
className: "flex-1 min-w-[12rem]",
|
|
63
64
|
children: [/* @__PURE__ */ v("h1", {
|
|
64
|
-
className: "text-lg font-semibold",
|
|
65
|
+
className: "text-base sm:text-lg font-semibold truncate",
|
|
65
66
|
children: [
|
|
66
67
|
D?.name,
|
|
67
68
|
" - ",
|
|
@@ -88,7 +89,7 @@ function x() {
|
|
|
88
89
|
"desktop"
|
|
89
90
|
].map((e) => /* @__PURE__ */ _("button", {
|
|
90
91
|
onClick: () => V(e),
|
|
91
|
-
className: `px-3 py-2 ${k === e ? "bg-primary text-primary-foreground" : "bg-background hover:bg-accent"}`,
|
|
92
|
+
className: `px-3 py-2 min-h-[44px] min-w-[44px] ${k === e ? "bg-primary text-primary-foreground" : "bg-background hover:bg-accent"}`,
|
|
92
93
|
title: x(e === "mobile" ? "tourPreview.deviceMobile" : e === "tablet" ? "tourPreview.deviceTablet" : "tourPreview.deviceDesktop"),
|
|
93
94
|
"aria-label": x(e === "mobile" ? "tourPreview.deviceMobile" : e === "tablet" ? "tourPreview.deviceTablet" : "tourPreview.deviceDesktop"),
|
|
94
95
|
children: W[e]
|
|
@@ -96,18 +97,18 @@ function x() {
|
|
|
96
97
|
}),
|
|
97
98
|
A ? /* @__PURE__ */ v("button", {
|
|
98
99
|
onClick: R,
|
|
99
|
-
className: "px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2",
|
|
100
|
+
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent flex items-center gap-2",
|
|
100
101
|
children: [/* @__PURE__ */ _(g, { size: 20 }), x("tourPreview.stopPreview")]
|
|
101
102
|
}) : /* @__PURE__ */ _("button", {
|
|
102
103
|
onClick: L,
|
|
103
104
|
disabled: !I?.valid,
|
|
104
|
-
className: "px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50",
|
|
105
|
+
className: "px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50",
|
|
105
106
|
children: x("tourPreview.startPreview")
|
|
106
107
|
})
|
|
107
108
|
]
|
|
108
109
|
}),
|
|
109
110
|
I && !I.valid && /* @__PURE__ */ _("div", {
|
|
110
|
-
className: "bg-destructive/10 border-b border-destructive px-6 py-3",
|
|
111
|
+
className: "bg-destructive/10 border-b border-destructive px-3 sm:px-6 py-3",
|
|
111
112
|
children: /* @__PURE__ */ v("div", {
|
|
112
113
|
className: "flex items-start gap-3",
|
|
113
114
|
children: [/* @__PURE__ */ _(c, {
|
|
@@ -129,7 +130,7 @@ function x() {
|
|
|
129
130
|
})
|
|
130
131
|
}),
|
|
131
132
|
I && I.warnings.length > 0 && /* @__PURE__ */ _("div", {
|
|
132
|
-
className: "bg-warning/10 border-b border-warning px-6 py-3",
|
|
133
|
+
className: "bg-warning/10 border-b border-warning px-3 sm:px-6 py-3",
|
|
133
134
|
children: /* @__PURE__ */ v("div", {
|
|
134
135
|
className: "flex items-start gap-3",
|
|
135
136
|
children: [/* @__PURE__ */ _(c, {
|
|
@@ -151,13 +152,13 @@ function x() {
|
|
|
151
152
|
})
|
|
152
153
|
}),
|
|
153
154
|
/* @__PURE__ */ _("div", {
|
|
154
|
-
className: "flex-1 flex items-center justify-center p-6 overflow-auto",
|
|
155
|
+
className: "flex-1 flex items-center justify-center p-3 sm:p-6 overflow-auto",
|
|
155
156
|
children: /* @__PURE__ */ _("div", {
|
|
156
|
-
className: `bg-background border-2 rounded-lg shadow-xl overflow-hidden ${k === "mobile" ? "w-[375px] h-[667px]" : k === "tablet" ? "w-[768px] h-[1024px]" : "w-full max-w-[1920px] h-full max-h-[1080px]"}`,
|
|
157
|
+
className: `bg-background border-2 rounded-lg shadow-xl overflow-hidden ${k === "mobile" ? "w-[min(375px,calc(100vw-1.5rem))] h-[667px] max-h-full" : k === "tablet" ? "w-[min(768px,calc(100vw-1.5rem))] h-[1024px] max-h-full" : "w-full max-w-[1920px] h-full max-h-[1080px]"}`,
|
|
157
158
|
children: A && M ? /* @__PURE__ */ _("div", {
|
|
158
|
-
className: "h-full flex flex-col items-center justify-center p-8",
|
|
159
|
+
className: "h-full flex flex-col items-center justify-center p-4 sm:p-8",
|
|
159
160
|
children: /* @__PURE__ */ v("div", {
|
|
160
|
-
className: "max-w-md border border-border rounded-lg shadow-lg bg-card p-6",
|
|
161
|
+
className: "max-w-md border border-border rounded-lg shadow-lg bg-card p-4 sm:p-6",
|
|
161
162
|
children: [
|
|
162
163
|
/* @__PURE__ */ _("h3", {
|
|
163
164
|
className: "text-lg font-semibold mb-3",
|
|
@@ -172,12 +173,13 @@ function x() {
|
|
|
172
173
|
children: [/* @__PURE__ */ _("button", {
|
|
173
174
|
onClick: B,
|
|
174
175
|
disabled: !F,
|
|
175
|
-
className: "px-3 py-
|
|
176
|
+
className: "px-3 py-2 min-h-[44px] min-w-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed",
|
|
177
|
+
"aria-label": x("tourPreview.previous"),
|
|
176
178
|
children: /* @__PURE__ */ _(d, { size: 16 })
|
|
177
179
|
}), /* @__PURE__ */ _("button", {
|
|
178
180
|
onClick: z,
|
|
179
181
|
disabled: !P,
|
|
180
|
-
className: "flex-1 px-3 py-
|
|
182
|
+
className: "flex-1 px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
181
183
|
children: x(P ? "tourPreview.next" : "tourPreview.finish")
|
|
182
184
|
})]
|
|
183
185
|
})
|
|
@@ -206,12 +208,12 @@ function x() {
|
|
|
206
208
|
})
|
|
207
209
|
}),
|
|
208
210
|
A && /* @__PURE__ */ v("div", {
|
|
209
|
-
className: "border-t border-border bg-background p-4 flex items-center justify-center gap-4",
|
|
211
|
+
className: "border-t border-border bg-background p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4",
|
|
210
212
|
children: [
|
|
211
213
|
/* @__PURE__ */ v("button", {
|
|
212
214
|
onClick: B,
|
|
213
215
|
disabled: !F,
|
|
214
|
-
className: "px-4 py-2 border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
216
|
+
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
215
217
|
children: [/* @__PURE__ */ _(d, { size: 20 }), x("tourPreview.previous")]
|
|
216
218
|
}),
|
|
217
219
|
/* @__PURE__ */ v("div", {
|
|
@@ -225,7 +227,7 @@ function x() {
|
|
|
225
227
|
/* @__PURE__ */ v("button", {
|
|
226
228
|
onClick: z,
|
|
227
229
|
disabled: !P,
|
|
228
|
-
className: "px-4 py-2 border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
230
|
+
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
229
231
|
children: [x("tourPreview.nextFooter"), /* @__PURE__ */ _(f, { size: 20 })]
|
|
230
232
|
})
|
|
231
233
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourPreviewPage.js","names":[],"sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n ChevronLeft,\n ChevronRight,\n X,\n Smartphone,\n Tablet,\n Monitor,\n CheckCircle,\n AlertCircle,\n} from 'lucide-react';\nimport { useTourPreview } from '../hooks/useTourPreview';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursStore } from '../store/toursStore';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\n\n/**\n * Tour preview page\n * Preview tour with device simulation and validation\n */\nexport function TourPreviewPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const { hasPermission } = useToursPermissionAccess();\n const canReadTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const { tour, loadTour } = useTourBuilder(tourId);\n const { devicePreview } = useToursStore();\n\n const {\n isPreviewActive,\n currentStepIndex,\n currentStep,\n totalSteps,\n canGoNext,\n canGoPrevious,\n validationResults,\n startPreview,\n stopPreview,\n nextStep,\n previousStep,\n changeDevice,\n validateForPreview,\n } = useTourPreview(tour || undefined);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour) {\n validateForPreview();\n }\n }, [tour, devicePreview, validateForPreview]);\n\n if (!canReadTour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-foreground mb-2\">\n {tr('tourPreview.accessDeniedTitle')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{tr('tourPreview.accessDeniedMessage')}</p>\n </div>\n </div>\n );\n }\n\n if (!tour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <p className=\"text-muted-foreground\">{tr('tourPreview.loading')}</p>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const deviceIcons = {\n mobile: <Smartphone size={20} />,\n tablet: <Tablet size={20} />,\n desktop: <Monitor size={20} />,\n };\n\n return (\n <div className=\"flex flex-col h-screen bg-muted\">\n {/* Header */}\n <div className=\"border-b border-border bg-background p-4 flex items-center gap-4\">\n <button onClick={handleBack} className=\"p-2 hover:bg-accent rounded-md\">\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1\">\n <h1 className=\"text-lg font-semibold\">\n {tour?.name} - {tr('tourPreview.previewSuffix')}\n </h1>\n {isPreviewActive && (\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourPreview.stepOf')} {currentStepIndex + 1} {tr('tourPreview.stepOfConnector')}{' '}\n {totalSteps}\n </p>\n )}\n </div>\n\n {/* Device Selector */}\n <div className=\"flex gap-2 border border-border rounded-md overflow-hidden\">\n {(['mobile', 'tablet', 'desktop'] as const).map((device) => (\n <button\n key={device}\n onClick={() => changeDevice(device)}\n className={`px-3 py-2 ${\n devicePreview === device\n ? 'bg-primary text-primary-foreground'\n : 'bg-background hover:bg-accent'\n }`}\n title={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n aria-label={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n >\n {deviceIcons[device]}\n </button>\n ))}\n </div>\n\n {/* Preview Controls */}\n {!isPreviewActive ? (\n <button\n onClick={startPreview}\n disabled={!validationResults?.valid}\n className=\"px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50\"\n >\n {tr('tourPreview.startPreview')}\n </button>\n ) : (\n <button\n onClick={stopPreview}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <X size={20} />\n {tr('tourPreview.stopPreview')}\n </button>\n )}\n </div>\n\n {/* Validation Results */}\n {validationResults && !validationResults.valid && (\n <div className=\"bg-destructive/10 border-b border-destructive px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-destructive flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-destructive mb-1\">\n {tr('tourPreview.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.errors.map((error, index) => (\n <li key={index} className=\"text-sm text-destructive\">\n {error}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Warnings */}\n {validationResults && validationResults.warnings.length > 0 && (\n <div className=\"bg-warning/10 border-b border-warning px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-warning flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-warning mb-1\">{tr('tourPreview.warningsTitle')}</h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.warnings.map((warning, index) => (\n <li key={index} className=\"text-sm text-warning\">\n {warning}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Preview Area */}\n <div className=\"flex-1 flex items-center justify-center p-6 overflow-auto\">\n <div\n className={`bg-background border-2 rounded-lg shadow-xl overflow-hidden ${\n devicePreview === 'mobile'\n ? 'w-[375px] h-[667px]'\n : devicePreview === 'tablet'\n ? 'w-[768px] h-[1024px]'\n : 'w-full max-w-[1920px] h-full max-h-[1080px]'\n }`}\n >\n {isPreviewActive && currentStep ? (\n <div className=\"h-full flex flex-col items-center justify-center p-8\">\n {/* Simulated Tour Tooltip */}\n <div className=\"max-w-md border border-border rounded-lg shadow-lg bg-card p-6\">\n <h3 className=\"text-lg font-semibold mb-3\">{currentStep.title}</h3>\n <p className=\"text-sm text-muted-foreground mb-4 whitespace-pre-wrap\">\n {currentStep.content}\n </p>\n <div className=\"flex gap-2\">\n <button\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-3 py-1 border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <ChevronLeft size={16} />\n </button>\n <button\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"flex-1 px-3 py-1 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {canGoNext ? tr('tourPreview.next') : tr('tourPreview.finish')}\n </button>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"h-full flex items-center justify-center text-muted-foreground\">\n <div className=\"text-center\">\n <CheckCircle className=\"mx-auto mb-4\" size={48} />\n <p className=\"mb-2\">{tr('tourPreview.readyTitle')}</p>\n <p className=\"text-sm\">{tr('tourPreview.readyHint')}</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer Controls */}\n {isPreviewActive && (\n <div className=\"border-t border-border bg-background p-4 flex items-center justify-center gap-4\">\n <button\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n <ChevronLeft size={20} />\n {tr('tourPreview.previous')}\n </button>\n <div className=\"text-sm text-muted-foreground\">\n {currentStepIndex + 1} / {totalSteps}\n </div>\n <button\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"px-4 py-2 border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {tr('tourPreview.nextFooter')}\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TourPreviewPage.js","names":[],"sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n ChevronLeft,\n ChevronRight,\n X,\n Smartphone,\n Tablet,\n Monitor,\n CheckCircle,\n AlertCircle,\n} from 'lucide-react';\nimport { useTourPreview } from '../hooks/useTourPreview';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursStore } from '../store/toursStore';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\n\n/**\n * Tour preview page\n * Preview tour with device simulation and validation\n */\nexport function TourPreviewPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const { hasPermission } = useToursPermissionAccess();\n const canReadTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const { tour, loadTour } = useTourBuilder(tourId);\n const { devicePreview } = useToursStore();\n\n const {\n isPreviewActive,\n currentStepIndex,\n currentStep,\n totalSteps,\n canGoNext,\n canGoPrevious,\n validationResults,\n startPreview,\n stopPreview,\n nextStep,\n previousStep,\n changeDevice,\n validateForPreview,\n } = useTourPreview(tour || undefined);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour) {\n validateForPreview();\n }\n }, [tour, devicePreview, validateForPreview]);\n\n if (!canReadTour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-foreground mb-2\">\n {tr('tourPreview.accessDeniedTitle')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{tr('tourPreview.accessDeniedMessage')}</p>\n </div>\n </div>\n );\n }\n\n if (!tour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <p className=\"text-muted-foreground\">{tr('tourPreview.loading')}</p>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const deviceIcons = {\n mobile: <Smartphone size={20} />,\n tablet: <Tablet size={20} />,\n desktop: <Monitor size={20} />,\n };\n\n return (\n <div className=\"flex flex-col h-screen bg-muted\">\n {/* Header */}\n <div className=\"border-b border-border bg-background p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4\">\n <button\n onClick={handleBack}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1 min-w-[12rem]\">\n <h1 className=\"text-base sm:text-lg font-semibold truncate\">\n {tour?.name} - {tr('tourPreview.previewSuffix')}\n </h1>\n {isPreviewActive && (\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourPreview.stepOf')} {currentStepIndex + 1} {tr('tourPreview.stepOfConnector')}{' '}\n {totalSteps}\n </p>\n )}\n </div>\n\n {/* Device Selector */}\n <div className=\"flex gap-2 border border-border rounded-md overflow-hidden\">\n {(['mobile', 'tablet', 'desktop'] as const).map((device) => (\n <button\n key={device}\n onClick={() => changeDevice(device)}\n className={`px-3 py-2 min-h-[44px] min-w-[44px] ${\n devicePreview === device\n ? 'bg-primary text-primary-foreground'\n : 'bg-background hover:bg-accent'\n }`}\n title={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n aria-label={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n >\n {deviceIcons[device]}\n </button>\n ))}\n </div>\n\n {/* Preview Controls */}\n {!isPreviewActive ? (\n <button\n onClick={startPreview}\n disabled={!validationResults?.valid}\n className=\"px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50\"\n >\n {tr('tourPreview.startPreview')}\n </button>\n ) : (\n <button\n onClick={stopPreview}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <X size={20} />\n {tr('tourPreview.stopPreview')}\n </button>\n )}\n </div>\n\n {/* Validation Results */}\n {validationResults && !validationResults.valid && (\n <div className=\"bg-destructive/10 border-b border-destructive px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-destructive flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-destructive mb-1\">\n {tr('tourPreview.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.errors.map((error, index) => (\n <li key={index} className=\"text-sm text-destructive\">\n {error}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Warnings */}\n {validationResults && validationResults.warnings.length > 0 && (\n <div className=\"bg-warning/10 border-b border-warning px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-warning flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-warning mb-1\">{tr('tourPreview.warningsTitle')}</h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.warnings.map((warning, index) => (\n <li key={index} className=\"text-sm text-warning\">\n {warning}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Preview Area */}\n <div className=\"flex-1 flex items-center justify-center p-3 sm:p-6 overflow-auto\">\n <div\n className={`bg-background border-2 rounded-lg shadow-xl overflow-hidden ${\n devicePreview === 'mobile'\n ? 'w-[min(375px,calc(100vw-1.5rem))] h-[667px] max-h-full'\n : devicePreview === 'tablet'\n ? 'w-[min(768px,calc(100vw-1.5rem))] h-[1024px] max-h-full'\n : 'w-full max-w-[1920px] h-full max-h-[1080px]'\n }`}\n >\n {isPreviewActive && currentStep ? (\n <div className=\"h-full flex flex-col items-center justify-center p-4 sm:p-8\">\n {/* Simulated Tour Tooltip */}\n <div className=\"max-w-md border border-border rounded-lg shadow-lg bg-card p-4 sm:p-6\">\n <h3 className=\"text-lg font-semibold mb-3\">{currentStep.title}</h3>\n <p className=\"text-sm text-muted-foreground mb-4 whitespace-pre-wrap\">\n {currentStep.content}\n </p>\n <div className=\"flex gap-2\">\n <button\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-3 py-2 min-h-[44px] min-w-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label={tr('tourPreview.previous')}\n >\n <ChevronLeft size={16} />\n </button>\n <button\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"flex-1 px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {canGoNext ? tr('tourPreview.next') : tr('tourPreview.finish')}\n </button>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"h-full flex items-center justify-center text-muted-foreground\">\n <div className=\"text-center\">\n <CheckCircle className=\"mx-auto mb-4\" size={48} />\n <p className=\"mb-2\">{tr('tourPreview.readyTitle')}</p>\n <p className=\"text-sm\">{tr('tourPreview.readyHint')}</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer Controls */}\n {isPreviewActive && (\n <div className=\"border-t border-border bg-background p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4\">\n <button\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n <ChevronLeft size={20} />\n {tr('tourPreview.previous')}\n </button>\n <div className=\"text-sm text-muted-foreground\">\n {currentStepIndex + 1} / {totalSteps}\n </div>\n <button\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {tr('tourPreview.nextFooter')}\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useToursContext as e } from "../providers/ToursProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { useToursStore as t } from "../store/toursStore.js";
|
|
3
|
+
import { useDeleteTourMutation as n } from "../../generated/global-operations.js";
|
|
4
|
+
import { useToursList as r } from "../hooks/useToursList.js";
|
|
5
5
|
import { useTourLifecycle as i } from "../hooks/useTourLifecycle.js";
|
|
6
6
|
import { useToursPermissionAccess as a } from "../hooks/useToursPermissionAccess.js";
|
|
7
7
|
import { TOUR_PERMISSIONS as o } from "../../constants/permissions.js";
|
|
@@ -14,7 +14,7 @@ import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
|
14
14
|
import { useNavigate as w } from "react-router-dom";
|
|
15
15
|
//#region src/tours/pages/ToursListPage.tsx
|
|
16
16
|
function T() {
|
|
17
|
-
let { tr: T } = s(), E = w(), { basePath: D = "/" } = e(), { viewMode: O, tourFilter: k, toursListRevision: A, setViewMode: j, updateTourFilter: M, notifyToursListChanged: N } =
|
|
17
|
+
let { tr: T } = s(), E = w(), { basePath: D = "/" } = e(), { viewMode: O, tourFilter: k, toursListRevision: A, setViewMode: j, updateTourFilter: M, notifyToursListChanged: N } = t(), { hasPermission: P, isLoading: F } = a(), I = P(o.TOUR_UPDATE), L = P(o.TOUR_STEP_UPDATE), R = P(o.TOUR_DELETE), z = P(o.TOUR_PUBLISH), B = P(o.TOUR_ARCHIVE), V = P(o.TOUR_DUPLICATE), { tours: H, loading: U, fetchTours: W } = r(), { publishTour: G, unpublishTour: K, archiveTour: re, duplicateTour: q } = i(), [J] = n(), [Y, X] = h(""), [ie, ae] = h("all"), [Z, Q] = h(null), $ = m(null);
|
|
18
18
|
p(() => {
|
|
19
19
|
F || W({ ...k });
|
|
20
20
|
}, [
|
|
@@ -208,13 +208,13 @@ function T() {
|
|
|
208
208
|
] })]
|
|
209
209
|
}),
|
|
210
210
|
/* @__PURE__ */ C("div", {
|
|
211
|
-
className: "flex items-center gap-2 pt-3 border-t border-border",
|
|
211
|
+
className: "flex flex-wrap items-center gap-2 pt-3 border-t border-border",
|
|
212
212
|
children: [
|
|
213
213
|
L && /* @__PURE__ */ C("button", {
|
|
214
214
|
onClick: (t) => {
|
|
215
215
|
t.stopPropagation(), E(`${D}/${e.id}/steps`);
|
|
216
216
|
},
|
|
217
|
-
className: "flex-1 px-3 py-
|
|
217
|
+
className: "flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs bg-secondary text-secondary-foreground rounded hover:bg-secondary/80 flex items-center justify-center gap-1.5",
|
|
218
218
|
title: T("toursList.editStepsTitle"),
|
|
219
219
|
children: [/* @__PURE__ */ S(ee, { size: 14 }), T("toursList.stepsButton")]
|
|
220
220
|
}),
|
|
@@ -222,7 +222,7 @@ function T() {
|
|
|
222
222
|
onClick: (t) => {
|
|
223
223
|
t.stopPropagation(), E(`${D}/${e.id}/preview`);
|
|
224
224
|
},
|
|
225
|
-
className: "flex-1 px-3 py-
|
|
225
|
+
className: "flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs border border-border rounded hover:bg-accent flex items-center justify-center gap-1.5",
|
|
226
226
|
title: T("toursList.previewTitle"),
|
|
227
227
|
children: [/* @__PURE__ */ S(_, { size: 14 }), T("toursList.previewButton")]
|
|
228
228
|
}),
|
|
@@ -230,7 +230,7 @@ function T() {
|
|
|
230
230
|
onClick: (t) => {
|
|
231
231
|
t.stopPropagation(), E(`${D}/${e.id}/edit`);
|
|
232
232
|
},
|
|
233
|
-
className: "px-2 py-
|
|
233
|
+
className: "px-2 py-2 min-h-[44px] min-w-[44px] text-xs border border-border rounded hover:bg-accent",
|
|
234
234
|
title: T("toursList.settingsTitle"),
|
|
235
235
|
"aria-label": T("toursList.settingsTitle"),
|
|
236
236
|
children: /* @__PURE__ */ S(x, { size: 14 })
|
|
@@ -242,7 +242,7 @@ function T() {
|
|
|
242
242
|
onClick: (t) => {
|
|
243
243
|
t.stopPropagation(), Q(Z === e.id ? null : e.id);
|
|
244
244
|
},
|
|
245
|
-
className: "px-2 py-
|
|
245
|
+
className: "px-2 py-2 min-h-[44px] min-w-[44px] text-xs border border-border rounded hover:bg-accent",
|
|
246
246
|
title: T("toursList.moreActionsTitle"),
|
|
247
247
|
"aria-label": T("toursList.moreActionsTitle"),
|
|
248
248
|
children: /* @__PURE__ */ S(te, { size: 14 })
|
|
@@ -253,35 +253,35 @@ function T() {
|
|
|
253
253
|
onClick: (t) => {
|
|
254
254
|
t.stopPropagation(), ue(e.id);
|
|
255
255
|
},
|
|
256
|
-
className: "w-full text-left px-3 py-2 text-xs hover:bg-accent",
|
|
256
|
+
className: "w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent",
|
|
257
257
|
children: T("toursList.actionPublish")
|
|
258
258
|
}),
|
|
259
259
|
r && /* @__PURE__ */ S("button", {
|
|
260
260
|
onClick: (t) => {
|
|
261
261
|
t.stopPropagation(), de(e.id);
|
|
262
262
|
},
|
|
263
|
-
className: "w-full text-left px-3 py-2 text-xs hover:bg-accent",
|
|
263
|
+
className: "w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent",
|
|
264
264
|
children: T("toursList.actionUnpublish")
|
|
265
265
|
}),
|
|
266
266
|
V && /* @__PURE__ */ S("button", {
|
|
267
267
|
onClick: (t) => {
|
|
268
268
|
t.stopPropagation(), pe(e.id);
|
|
269
269
|
},
|
|
270
|
-
className: "w-full text-left px-3 py-2 text-xs hover:bg-accent",
|
|
270
|
+
className: "w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent",
|
|
271
271
|
children: T("toursList.actionDuplicate")
|
|
272
272
|
}),
|
|
273
273
|
i && /* @__PURE__ */ S("button", {
|
|
274
274
|
onClick: (t) => {
|
|
275
275
|
t.stopPropagation(), fe(e.id);
|
|
276
276
|
},
|
|
277
|
-
className: "w-full text-left px-3 py-2 text-xs hover:bg-accent",
|
|
277
|
+
className: "w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent",
|
|
278
278
|
children: T("toursList.actionArchive")
|
|
279
279
|
}),
|
|
280
280
|
R && /* @__PURE__ */ S("button", {
|
|
281
281
|
onClick: (t) => {
|
|
282
282
|
t.stopPropagation(), me(e.id);
|
|
283
283
|
},
|
|
284
|
-
className: "w-full text-left px-3 py-2 text-xs text-destructive hover:bg-destructive/10",
|
|
284
|
+
className: "w-full text-left px-3 py-2 min-h-[44px] text-xs text-destructive hover:bg-destructive/10",
|
|
285
285
|
children: T("toursList.actionDelete")
|
|
286
286
|
})
|
|
287
287
|
]
|