@burdenoff/microfe-tours 2026.519.1 → 2026.523.2
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 +13 -1
- package/dist/tours/i18n.d.ts.map +1 -1
- package/dist/tours/i18n.js +12 -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 +645 -467
- 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":"ToursListPage.js","names":[],"sources":["../../../src/tours/pages/ToursListPage.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Plus,\n Search,\n Grid,\n List as ListIcon,\n ListOrdered,\n Eye,\n Settings,\n MoreVertical,\n} from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useToursList } from '../hooks/useToursList';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursStore } from '../store/toursStore';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useDeleteTourMutation } from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TourStatus } from '../types';\nimport type { Tour } from '../../generated/global-types';\nimport { useToursI18n } from '../i18n';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../utils/nativeBridge';\n\n/**\n * Tours list page\n * Displays all tours with filtering and search\n */\nexport function ToursListPage() {\n const { tr } = useToursI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const {\n viewMode,\n tourFilter,\n toursListRevision,\n setViewMode,\n updateTourFilter,\n notifyToursListChanged,\n } = useToursStore();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n\n const canUpdateTour = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canUpdateTourSteps = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_UPDATE);\n const canDeleteTour = hasPermission(TOUR_PERMISSIONS.TOUR_DELETE);\n const canPublishTour = hasPermission(TOUR_PERMISSIONS.TOUR_PUBLISH);\n const canArchiveTour = hasPermission(TOUR_PERMISSIONS.TOUR_ARCHIVE);\n const canDuplicateTour = hasPermission(TOUR_PERMISSIONS.TOUR_DUPLICATE);\n\n // Fetch tours (includes both workspace-specific and global tours)\n const { tours, loading, fetchTours } = useToursList();\n\n const { publishTour, unpublishTour, archiveTour, duplicateTour } = useTourLifecycle();\n const [deleteTourMutation] = useDeleteTourMutation();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<TourStatus | 'all'>('all');\n const [openMenuId, setOpenMenuId] = useState<string | null>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Fetch tours when filter changes. The list page is also the user-facing\n // tour browser, so backend permissions remain authoritative for actions while\n // normal users can still see published tours returned by the API.\n useEffect(() => {\n if (permissionsLoading) return;\n fetchTours({ ...tourFilter });\n }, [fetchTours, tourFilter, toursListRevision, permissionsLoading]);\n\n const handleSearch = (query: string) => {\n setSearchQuery(query);\n updateTourFilter({ search: query });\n };\n\n const handleStatusFilter = (status: TourStatus | 'all') => {\n setStatusFilter(status);\n updateTourFilter({ status });\n };\n\n const handleCreateTour = () => {\n const newPath = basePath.endsWith('/') ? `${basePath}new` : `${basePath}/new`;\n navigate(newPath);\n };\n\n const getStatusLabel = (status: TourStatus) => {\n switch (status) {\n case 'DRAFT':\n return tr('toursList.statusDraft');\n case 'PUBLISHED':\n return tr('toursList.statusPublished');\n case 'ARCHIVED':\n return tr('toursList.statusArchived');\n case 'SCHEDULED':\n return tr('toursList.statusScheduled');\n }\n };\n\n const handlePublish = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await publishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorPublish'));\n else alert(tr('toursList.errorPublish'));\n }\n };\n\n const handleUnpublish = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await unpublishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorUnpublish'));\n else alert(tr('toursList.errorUnpublish'));\n }\n };\n\n const handleArchive = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await archiveTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorArchive'));\n else alert(tr('toursList.errorArchive'));\n }\n };\n\n const handleDuplicate = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await duplicateTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDuplicate'));\n else alert(tr('toursList.errorDuplicate'));\n }\n };\n\n const handleDelete = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('medium');\n const confirmMsg = tr('toursList.confirmDelete');\n const nativeResult = await nativeConfirm({\n title: tr('toursList.actionDelete'),\n message: confirmMsg,\n okButtonTitle: tr('toursList.actionDelete'),\n });\n const confirmed = nativeResult === null ? window.confirm(confirmMsg) : nativeResult;\n if (!confirmed) return;\n try {\n await deleteTourMutation({ variables: { id } });\n notifyToursListChanged();\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDelete'));\n else alert(tr('toursList.errorDelete'));\n }\n };\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n setOpenMenuId(null);\n }\n };\n if (openMenuId) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [openMenuId]);\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">{tr('toursList.title')}</h1>\n <p className=\"text-sm sm:text-base text-muted-foreground\">{tr('toursList.subtitle')}</p>\n </div>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_CREATE}>\n <button\n onClick={handleCreateTour}\n className=\"w-full sm:w-auto px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 active:bg-primary/80 flex items-center justify-center gap-2\"\n >\n <Plus size={20} />\n {tr('toursList.createTour')}\n </button>\n </PermissionGate>\n </div>\n\n {/* Filters and Search */}\n <div className=\"flex flex-col sm:flex-row gap-3 sm:gap-4\">\n {/* Search */}\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('toursList.searchPlaceholder')}\n value={searchQuery}\n onChange={(e) => handleSearch(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n\n {/* Status Filter */}\n <div className=\"flex gap-2\">\n <select\n value={statusFilter}\n onChange={(e) => handleStatusFilter(e.target.value as TourStatus | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md bg-background text-foreground\"\n >\n <option value=\"all\">{tr('toursList.statusAll')}</option>\n <option value=\"DRAFT\">{tr('toursList.statusDraft')}</option>\n <option value=\"PUBLISHED\">{tr('toursList.statusPublished')}</option>\n <option value=\"ARCHIVED\">{tr('toursList.statusArchived')}</option>\n <option value=\"SCHEDULED\">{tr('toursList.statusScheduled')}</option>\n </select>\n\n {/* View Mode Toggle */}\n <div className=\"flex border border-border rounded-md overflow-hidden\">\n <button\n onClick={() => setViewMode('grid')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'grid'\n ? 'bg-primary text-primary-foreground'\n : 'bg-background text-foreground hover:bg-accent'\n }`}\n aria-label={tr('toursList.gridView')}\n title={tr('toursList.gridView')}\n >\n <Grid size={20} />\n </button>\n <button\n onClick={() => setViewMode('list')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'list'\n ? 'bg-primary text-primary-foreground'\n : 'bg-background text-foreground hover:bg-accent'\n }`}\n aria-label={tr('toursList.listView')}\n title={tr('toursList.listView')}\n >\n <ListIcon size={20} />\n </button>\n </div>\n </div>\n </div>\n\n {/* Tours List */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-sm sm:text-base text-muted-foreground\">{tr('toursList.loading')}</p>\n </div>\n ) : tours.length > 0 ? (\n <div\n className={\n viewMode === 'grid'\n ? 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4'\n : 'space-y-3'\n }\n >\n {tours.map((tour: Tour) => {\n const status = tour.status as TourStatus;\n const canShowPublishAction = status === 'DRAFT' && canPublishTour;\n const canShowUnpublishAction = status === 'PUBLISHED' && canPublishTour;\n const canShowArchiveAction = status !== 'ARCHIVED' && canArchiveTour;\n const hasMoreActions =\n canShowPublishAction ||\n canShowUnpublishAction ||\n canDuplicateTour ||\n canShowArchiveAction ||\n canDeleteTour;\n\n return (\n <div\n key={tour.id}\n className=\"border border-border rounded-md p-4 bg-card hover:shadow-md transition-shadow\"\n >\n <div className=\"flex items-start justify-between mb-2\">\n <h3\n className={`font-semibold text-foreground ${\n canUpdateTour ? 'cursor-pointer hover:text-primary' : ''\n }`}\n onClick={() => {\n if (canUpdateTour) navigate(`${basePath}/${tour.id}/edit`);\n }}\n >\n {tour.name}\n </h3>\n <span\n className={`px-2 py-1 text-xs rounded-full ${\n tour.status === 'PUBLISHED'\n ? 'bg-success/10 text-success'\n : tour.status === 'DRAFT'\n ? 'bg-muted text-muted-foreground'\n : 'bg-warning/10 text-warning'\n }`}\n >\n {getStatusLabel(status)}\n </span>\n </div>\n {tour.description && (\n <p className=\"text-sm text-muted-foreground mb-3\">{tour.description}</p>\n )}\n <div className=\"flex items-center justify-between text-xs text-muted-foreground mb-3\">\n <span>\n {tour.steps?.length || 0} {tr('toursList.steps')}\n </span>\n <span>\n {tour.viewCount} {tr('toursList.views')}\n </span>\n </div>\n {/* Quick Actions */}\n <div className=\"flex items-center gap-2 pt-3 border-t border-border\">\n {canUpdateTourSteps && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/steps`);\n }}\n className=\"flex-1 px-3 py-1.5 text-xs bg-secondary text-secondary-foreground rounded hover:bg-secondary/80 flex items-center justify-center gap-1.5\"\n title={tr('toursList.editStepsTitle')}\n >\n <ListOrdered size={14} />\n {tr('toursList.stepsButton')}\n </button>\n )}\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/preview`);\n }}\n className=\"flex-1 px-3 py-1.5 text-xs border border-border rounded hover:bg-accent flex items-center justify-center gap-1.5\"\n title={tr('toursList.previewTitle')}\n >\n <Eye size={14} />\n {tr('toursList.previewButton')}\n </button>\n {canUpdateTour && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/edit`);\n }}\n className=\"px-2 py-1.5 text-xs border border-border rounded hover:bg-accent\"\n title={tr('toursList.settingsTitle')}\n aria-label={tr('toursList.settingsTitle')}\n >\n <Settings size={14} />\n </button>\n )}\n {/* More Actions Dropdown */}\n {hasMoreActions && (\n <div className=\"relative\" ref={openMenuId === tour.id ? menuRef : undefined}>\n <button\n onClick={(e) => {\n e.stopPropagation();\n setOpenMenuId(openMenuId === tour.id ? null : tour.id);\n }}\n className=\"px-2 py-1.5 text-xs border border-border rounded hover:bg-accent\"\n title={tr('toursList.moreActionsTitle')}\n aria-label={tr('toursList.moreActionsTitle')}\n >\n <MoreVertical size={14} />\n </button>\n {openMenuId === tour.id && (\n <div className=\"absolute right-0 top-full mt-1 w-40 bg-card border border-border rounded-md shadow-lg z-10\">\n {canShowPublishAction && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handlePublish(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 text-xs hover:bg-accent\"\n >\n {tr('toursList.actionPublish')}\n </button>\n )}\n {canShowUnpublishAction && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleUnpublish(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 text-xs hover:bg-accent\"\n >\n {tr('toursList.actionUnpublish')}\n </button>\n )}\n {canDuplicateTour && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleDuplicate(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 text-xs hover:bg-accent\"\n >\n {tr('toursList.actionDuplicate')}\n </button>\n )}\n {canShowArchiveAction && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleArchive(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 text-xs hover:bg-accent\"\n >\n {tr('toursList.actionArchive')}\n </button>\n )}\n {canDeleteTour && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 text-xs text-destructive hover:bg-destructive/10\"\n >\n {tr('toursList.actionDelete')}\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n ) : (\n <div className=\"text-center py-12 border border-dashed border-border rounded-md\">\n <p className=\"text-sm sm:text-base text-muted-foreground mb-2\">\n {tr('toursList.emptyTitle')}\n </p>\n <p className=\"text-xs sm:text-sm text-muted-foreground\">\n {tr('toursList.emptySubtitle')}\n </p>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToursListPage.js","names":[],"sources":["../../../src/tours/pages/ToursListPage.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Plus,\n Search,\n Grid,\n List as ListIcon,\n ListOrdered,\n Eye,\n Settings,\n MoreVertical,\n} from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useToursList } from '../hooks/useToursList';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursStore } from '../store/toursStore';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useDeleteTourMutation } from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TourStatus } from '../types';\nimport type { Tour } from '../../generated/global-types';\nimport { useToursI18n } from '../i18n';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../utils/nativeBridge';\n\n/**\n * Tours list page\n * Displays all tours with filtering and search\n */\nexport function ToursListPage() {\n const { tr } = useToursI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const {\n viewMode,\n tourFilter,\n toursListRevision,\n setViewMode,\n updateTourFilter,\n notifyToursListChanged,\n } = useToursStore();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n\n const canUpdateTour = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canUpdateTourSteps = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_UPDATE);\n const canDeleteTour = hasPermission(TOUR_PERMISSIONS.TOUR_DELETE);\n const canPublishTour = hasPermission(TOUR_PERMISSIONS.TOUR_PUBLISH);\n const canArchiveTour = hasPermission(TOUR_PERMISSIONS.TOUR_ARCHIVE);\n const canDuplicateTour = hasPermission(TOUR_PERMISSIONS.TOUR_DUPLICATE);\n\n // Fetch tours (includes both workspace-specific and global tours)\n const { tours, loading, fetchTours } = useToursList();\n\n const { publishTour, unpublishTour, archiveTour, duplicateTour } = useTourLifecycle();\n const [deleteTourMutation] = useDeleteTourMutation();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<TourStatus | 'all'>('all');\n const [openMenuId, setOpenMenuId] = useState<string | null>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Fetch tours when filter changes. The list page is also the user-facing\n // tour browser, so backend permissions remain authoritative for actions while\n // normal users can still see published tours returned by the API.\n useEffect(() => {\n if (permissionsLoading) return;\n fetchTours({ ...tourFilter });\n }, [fetchTours, tourFilter, toursListRevision, permissionsLoading]);\n\n const handleSearch = (query: string) => {\n setSearchQuery(query);\n updateTourFilter({ search: query });\n };\n\n const handleStatusFilter = (status: TourStatus | 'all') => {\n setStatusFilter(status);\n updateTourFilter({ status });\n };\n\n const handleCreateTour = () => {\n const newPath = basePath.endsWith('/') ? `${basePath}new` : `${basePath}/new`;\n navigate(newPath);\n };\n\n const getStatusLabel = (status: TourStatus) => {\n switch (status) {\n case 'DRAFT':\n return tr('toursList.statusDraft');\n case 'PUBLISHED':\n return tr('toursList.statusPublished');\n case 'ARCHIVED':\n return tr('toursList.statusArchived');\n case 'SCHEDULED':\n return tr('toursList.statusScheduled');\n }\n };\n\n const handlePublish = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await publishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorPublish'));\n else alert(tr('toursList.errorPublish'));\n }\n };\n\n const handleUnpublish = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await unpublishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorUnpublish'));\n else alert(tr('toursList.errorUnpublish'));\n }\n };\n\n const handleArchive = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await archiveTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorArchive'));\n else alert(tr('toursList.errorArchive'));\n }\n };\n\n const handleDuplicate = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('light');\n try {\n await duplicateTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDuplicate'));\n else alert(tr('toursList.errorDuplicate'));\n }\n };\n\n const handleDelete = async (id: string) => {\n setOpenMenuId(null);\n nativeImpact('medium');\n const confirmMsg = tr('toursList.confirmDelete');\n const nativeResult = await nativeConfirm({\n title: tr('toursList.actionDelete'),\n message: confirmMsg,\n okButtonTitle: tr('toursList.actionDelete'),\n });\n const confirmed = nativeResult === null ? window.confirm(confirmMsg) : nativeResult;\n if (!confirmed) return;\n try {\n await deleteTourMutation({ variables: { id } });\n notifyToursListChanged();\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDelete'));\n else alert(tr('toursList.errorDelete'));\n }\n };\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n setOpenMenuId(null);\n }\n };\n if (openMenuId) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [openMenuId]);\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">{tr('toursList.title')}</h1>\n <p className=\"text-sm sm:text-base text-muted-foreground\">{tr('toursList.subtitle')}</p>\n </div>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_CREATE}>\n <button\n onClick={handleCreateTour}\n className=\"w-full sm:w-auto px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 active:bg-primary/80 flex items-center justify-center gap-2\"\n >\n <Plus size={20} />\n {tr('toursList.createTour')}\n </button>\n </PermissionGate>\n </div>\n\n {/* Filters and Search */}\n <div className=\"flex flex-col sm:flex-row gap-3 sm:gap-4\">\n {/* Search */}\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('toursList.searchPlaceholder')}\n value={searchQuery}\n onChange={(e) => handleSearch(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n\n {/* Status Filter */}\n <div className=\"flex gap-2\">\n <select\n value={statusFilter}\n onChange={(e) => handleStatusFilter(e.target.value as TourStatus | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md bg-background text-foreground\"\n >\n <option value=\"all\">{tr('toursList.statusAll')}</option>\n <option value=\"DRAFT\">{tr('toursList.statusDraft')}</option>\n <option value=\"PUBLISHED\">{tr('toursList.statusPublished')}</option>\n <option value=\"ARCHIVED\">{tr('toursList.statusArchived')}</option>\n <option value=\"SCHEDULED\">{tr('toursList.statusScheduled')}</option>\n </select>\n\n {/* View Mode Toggle */}\n <div className=\"flex border border-border rounded-md overflow-hidden\">\n <button\n onClick={() => setViewMode('grid')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'grid'\n ? 'bg-primary text-primary-foreground'\n : 'bg-background text-foreground hover:bg-accent'\n }`}\n aria-label={tr('toursList.gridView')}\n title={tr('toursList.gridView')}\n >\n <Grid size={20} />\n </button>\n <button\n onClick={() => setViewMode('list')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'list'\n ? 'bg-primary text-primary-foreground'\n : 'bg-background text-foreground hover:bg-accent'\n }`}\n aria-label={tr('toursList.listView')}\n title={tr('toursList.listView')}\n >\n <ListIcon size={20} />\n </button>\n </div>\n </div>\n </div>\n\n {/* Tours List */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-sm sm:text-base text-muted-foreground\">{tr('toursList.loading')}</p>\n </div>\n ) : tours.length > 0 ? (\n <div\n className={\n viewMode === 'grid'\n ? 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4'\n : 'space-y-3'\n }\n >\n {tours.map((tour: Tour) => {\n const status = tour.status as TourStatus;\n const canShowPublishAction = status === 'DRAFT' && canPublishTour;\n const canShowUnpublishAction = status === 'PUBLISHED' && canPublishTour;\n const canShowArchiveAction = status !== 'ARCHIVED' && canArchiveTour;\n const hasMoreActions =\n canShowPublishAction ||\n canShowUnpublishAction ||\n canDuplicateTour ||\n canShowArchiveAction ||\n canDeleteTour;\n\n return (\n <div\n key={tour.id}\n className=\"border border-border rounded-md p-4 bg-card hover:shadow-md transition-shadow\"\n >\n <div className=\"flex items-start justify-between mb-2\">\n <h3\n className={`font-semibold text-foreground ${\n canUpdateTour ? 'cursor-pointer hover:text-primary' : ''\n }`}\n onClick={() => {\n if (canUpdateTour) navigate(`${basePath}/${tour.id}/edit`);\n }}\n >\n {tour.name}\n </h3>\n <span\n className={`px-2 py-1 text-xs rounded-full ${\n tour.status === 'PUBLISHED'\n ? 'bg-success/10 text-success'\n : tour.status === 'DRAFT'\n ? 'bg-muted text-muted-foreground'\n : 'bg-warning/10 text-warning'\n }`}\n >\n {getStatusLabel(status)}\n </span>\n </div>\n {tour.description && (\n <p className=\"text-sm text-muted-foreground mb-3\">{tour.description}</p>\n )}\n <div className=\"flex items-center justify-between text-xs text-muted-foreground mb-3\">\n <span>\n {tour.steps?.length || 0} {tr('toursList.steps')}\n </span>\n <span>\n {tour.viewCount} {tr('toursList.views')}\n </span>\n </div>\n {/* Quick Actions */}\n <div className=\"flex flex-wrap items-center gap-2 pt-3 border-t border-border\">\n {canUpdateTourSteps && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/steps`);\n }}\n 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\"\n title={tr('toursList.editStepsTitle')}\n >\n <ListOrdered size={14} />\n {tr('toursList.stepsButton')}\n </button>\n )}\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/preview`);\n }}\n 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\"\n title={tr('toursList.previewTitle')}\n >\n <Eye size={14} />\n {tr('toursList.previewButton')}\n </button>\n {canUpdateTour && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/edit`);\n }}\n className=\"px-2 py-2 min-h-[44px] min-w-[44px] text-xs border border-border rounded hover:bg-accent\"\n title={tr('toursList.settingsTitle')}\n aria-label={tr('toursList.settingsTitle')}\n >\n <Settings size={14} />\n </button>\n )}\n {/* More Actions Dropdown */}\n {hasMoreActions && (\n <div className=\"relative\" ref={openMenuId === tour.id ? menuRef : undefined}>\n <button\n onClick={(e) => {\n e.stopPropagation();\n setOpenMenuId(openMenuId === tour.id ? null : tour.id);\n }}\n className=\"px-2 py-2 min-h-[44px] min-w-[44px] text-xs border border-border rounded hover:bg-accent\"\n title={tr('toursList.moreActionsTitle')}\n aria-label={tr('toursList.moreActionsTitle')}\n >\n <MoreVertical size={14} />\n </button>\n {openMenuId === tour.id && (\n <div className=\"absolute right-0 top-full mt-1 w-40 bg-card border border-border rounded-md shadow-lg z-10\">\n {canShowPublishAction && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handlePublish(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent\"\n >\n {tr('toursList.actionPublish')}\n </button>\n )}\n {canShowUnpublishAction && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleUnpublish(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent\"\n >\n {tr('toursList.actionUnpublish')}\n </button>\n )}\n {canDuplicateTour && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleDuplicate(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent\"\n >\n {tr('toursList.actionDuplicate')}\n </button>\n )}\n {canShowArchiveAction && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleArchive(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 min-h-[44px] text-xs hover:bg-accent\"\n >\n {tr('toursList.actionArchive')}\n </button>\n )}\n {canDeleteTour && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(tour.id);\n }}\n className=\"w-full text-left px-3 py-2 min-h-[44px] text-xs text-destructive hover:bg-destructive/10\"\n >\n {tr('toursList.actionDelete')}\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n ) : (\n <div className=\"text-center py-12 border border-dashed border-border rounded-md\">\n <p className=\"text-sm sm:text-base text-muted-foreground mb-2\">\n {tr('toursList.emptyTitle')}\n </p>\n <p className=\"text-xs sm:text-sm text-muted-foreground\">\n {tr('toursList.emptySubtitle')}\n </p>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ interface ToursState {
|
|
|
13
13
|
selectedMedia: TourMedia[];
|
|
14
14
|
uploadProgress: Record<string, number>;
|
|
15
15
|
sidebarOpen: boolean;
|
|
16
|
+
resetTransientState: () => void;
|
|
16
17
|
setSelectedTour: (tour: Tour | null) => void;
|
|
17
18
|
setSelectedStep: (step: TourStep | null) => void;
|
|
18
19
|
setViewMode: (mode: ToursViewMode) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toursStore.d.ts","sourceRoot":"","sources":["../../../src/tours/store/toursStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,WAAW,EACX,eAAe,EACf,aAAa,EACb,UAAU,EACX,MAAM,UAAU,CAAC;AAElB,UAAU,UAAU;IAElB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,CAAC;IACxB,aAAa,EAAE,UAAU,CAAC;IAG1B,UAAU,EAAE,WAAW,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAG1B,YAAY,EAAE,QAAQ,EAAE,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IAGpC,aAAa,EAAE,SAAS,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAGvC,WAAW,EAAE,OAAO,CAAC;IAGrB,eAAe,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,gBAAgB,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAGxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACzD,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,sBAAsB,EAAE,MAAM,IAAI,CAAC;IAGnC,kBAAkB,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IAChD,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAGjE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,MAAM,eAAe,EAAE,CAAC;IACtC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAGlC,WAAW,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD;AAYD,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"toursStore.d.ts","sourceRoot":"","sources":["../../../src/tours/store/toursStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,WAAW,EACX,eAAe,EACf,aAAa,EACb,UAAU,EACX,MAAM,UAAU,CAAC;AAElB,UAAU,UAAU;IAElB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,CAAC;IACxB,aAAa,EAAE,UAAU,CAAC;IAG1B,UAAU,EAAE,WAAW,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAG1B,YAAY,EAAE,QAAQ,EAAE,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IAGpC,aAAa,EAAE,SAAS,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAGvC,WAAW,EAAE,OAAO,CAAC;IAGrB,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAGhC,eAAe,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,gBAAgB,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAGxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACzD,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,sBAAsB,EAAE,MAAM,IAAI,CAAC;IAGnC,kBAAkB,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IAChD,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAGjE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,MAAM,eAAe,EAAE,CAAC;IACtC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAGlC,WAAW,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD;AAYD,eAAO,MAAM,aAAa,yEAgMvB,CAAC"}
|
|
@@ -24,6 +24,20 @@ var t = {
|
|
|
24
24
|
selectedMedia: [],
|
|
25
25
|
uploadProgress: {},
|
|
26
26
|
sidebarOpen: !0,
|
|
27
|
+
resetTransientState: () => e({
|
|
28
|
+
selectedTour: null,
|
|
29
|
+
selectedStep: null,
|
|
30
|
+
viewMode: "grid",
|
|
31
|
+
devicePreview: "desktop",
|
|
32
|
+
tourFilter: t,
|
|
33
|
+
toursListRevision: 0,
|
|
34
|
+
stepSequence: [],
|
|
35
|
+
isDirty: !1,
|
|
36
|
+
validationErrors: [],
|
|
37
|
+
selectedMedia: [],
|
|
38
|
+
uploadProgress: {},
|
|
39
|
+
sidebarOpen: !0
|
|
40
|
+
}),
|
|
27
41
|
setSelectedTour: (t) => e({
|
|
28
42
|
selectedTour: t,
|
|
29
43
|
stepSequence: t?.steps || [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toursStore.js","names":[],"sources":["../../../src/tours/store/toursStore.ts"],"sourcesContent":["import { create } from 'zustand';\nimport type {\n Tour,\n TourStep,\n TourMedia,\n TourFilters,\n ValidationError,\n ToursViewMode,\n DeviceType,\n} from '../types';\n\ninterface ToursState {\n // View state\n selectedTour: Tour | null;\n selectedStep: TourStep | null;\n viewMode: ToursViewMode;\n devicePreview: DeviceType;\n\n // Filters\n tourFilter: TourFilters;\n toursListRevision: number;\n\n // Builder state\n stepSequence: TourStep[];\n isDirty: boolean;\n validationErrors: ValidationError[];\n\n // Media state\n selectedMedia: TourMedia[];\n uploadProgress: Record<string, number>;\n\n // UI state\n sidebarOpen: boolean;\n\n // Actions - View\n setSelectedTour: (tour: Tour | null) => void;\n setSelectedStep: (step: TourStep | null) => void;\n setViewMode: (mode: ToursViewMode) => void;\n setDevicePreview: (device: DeviceType) => void;\n toggleSidebar: () => void;\n setSidebarOpen: (open: boolean) => void;\n\n // Actions - Filters\n updateTourFilter: (filter: Partial<TourFilters>) => void;\n resetTourFilter: () => void;\n notifyToursListChanged: () => void;\n\n // Actions - Steps\n updateStepSequence: (steps: TourStep[]) => void;\n reorderSteps: (startIndex: number, endIndex: number) => void;\n addStep: (step: Partial<TourStep>) => void;\n removeStep: (stepId: string) => void;\n updateStep: (stepId: string, updates: Partial<TourStep>) => void;\n\n // Actions - Validation\n setDirty: (dirty: boolean) => void;\n validateTour: () => ValidationError[];\n clearValidationErrors: () => void;\n\n // Actions - Media\n selectMedia: (media: TourMedia) => void;\n unselectMedia: (mediaId: string) => void;\n clearSelectedMedia: () => void;\n updateUploadProgress: (fileId: string, progress: number) => void;\n removeUploadProgress: (fileId: string) => void;\n}\n\nconst defaultFilter: TourFilters = {\n search: '',\n status: 'all',\n productId: undefined,\n moduleId: undefined,\n pageId: undefined,\n dateRange: { start: null, end: null },\n createdBy: undefined,\n};\n\nexport const useToursStore = create<ToursState>((set, get) => ({\n // Initial state\n selectedTour: null,\n selectedStep: null,\n viewMode: 'grid',\n devicePreview: 'desktop',\n tourFilter: defaultFilter,\n toursListRevision: 0,\n stepSequence: [],\n isDirty: false,\n validationErrors: [],\n selectedMedia: [],\n uploadProgress: {},\n sidebarOpen: true,\n\n // View actions\n setSelectedTour: (tour) =>\n set({\n selectedTour: tour,\n stepSequence: tour?.steps || [],\n isDirty: false,\n validationErrors: [],\n }),\n\n setSelectedStep: (step) => set({ selectedStep: step }),\n\n setViewMode: (mode) => set({ viewMode: mode }),\n\n setDevicePreview: (device) => set({ devicePreview: device }),\n\n toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),\n\n setSidebarOpen: (open) => set({ sidebarOpen: open }),\n\n // Filter actions\n updateTourFilter: (filter) =>\n set((state) => ({\n tourFilter: { ...state.tourFilter, ...filter },\n })),\n\n resetTourFilter: () => set({ tourFilter: defaultFilter }),\n\n notifyToursListChanged: () =>\n set((state) => ({ toursListRevision: state.toursListRevision + 1 })),\n\n // Step actions\n updateStepSequence: (steps) => set({ stepSequence: steps, isDirty: true }),\n\n reorderSteps: (startIndex, endIndex) => {\n const steps = [...get().stepSequence];\n const [removed] = steps.splice(startIndex, 1);\n steps.splice(endIndex, 0, removed);\n const reorderedSteps = steps.map((step, index) => ({\n ...step,\n stepOrder: index + 1,\n }));\n set({ stepSequence: reorderedSteps, isDirty: true });\n },\n\n addStep: (step) => {\n const steps = [...get().stepSequence];\n const newStep: TourStep = {\n id: `temp_${Date.now()}`,\n tourId: get().selectedTour?.id || '',\n title: step.title || 'New Step',\n content: step.content || '',\n stepOrder: steps.length + 1,\n targetSelector: step.targetSelector || '',\n placement: step.placement || 'AUTO',\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n ...step,\n } as TourStep;\n steps.push(newStep);\n set({ stepSequence: steps, isDirty: true });\n },\n\n removeStep: (stepId) => {\n const steps = get().stepSequence.filter((s) => s.id !== stepId);\n const reorderedSteps = steps.map((step, index) => ({\n ...step,\n stepOrder: index + 1,\n }));\n set({ stepSequence: reorderedSteps, isDirty: true });\n },\n\n updateStep: (stepId, updates) => {\n const steps = get().stepSequence.map((step) =>\n step.id === stepId ? { ...step, ...updates } : step\n );\n set({ stepSequence: steps, isDirty: true });\n },\n\n // Validation actions\n setDirty: (dirty) => set({ isDirty: dirty }),\n\n validateTour: () => {\n const errors: ValidationError[] = [];\n const { selectedTour, stepSequence } = get();\n\n if (!selectedTour) {\n errors.push({ field: 'tour', message: 'No tour selected' });\n set({ validationErrors: errors });\n return errors;\n }\n\n if (!selectedTour.name || selectedTour.name.trim() === '') {\n errors.push({ field: 'name', message: 'Tour name is required' });\n }\n\n if (!selectedTour.productId) {\n errors.push({ field: 'productId', message: 'Product ID is required' });\n }\n\n if (stepSequence.length === 0) {\n errors.push({ field: 'steps', message: 'At least one step is required' });\n }\n\n stepSequence.forEach((step, index) => {\n if (!step.title || step.title.trim() === '') {\n errors.push({\n field: `step[${index}].title`,\n message: `Step ${index + 1} title is required`,\n });\n }\n if (!step.content || step.content.trim() === '') {\n errors.push({\n field: `step[${index}].content`,\n message: `Step ${index + 1} content is required`,\n });\n }\n if (\n step.placement !== 'CENTER' &&\n (!step.targetSelector || step.targetSelector.trim() === '')\n ) {\n errors.push({\n field: `step[${index}].targetSelector`,\n message: `Step ${index + 1} selector is required`,\n });\n }\n });\n\n set({ validationErrors: errors });\n return errors;\n },\n\n clearValidationErrors: () => set({ validationErrors: [] }),\n\n // Media actions\n selectMedia: (media) => {\n const selected = [...get().selectedMedia];\n if (!selected.find((m) => m.id === media.id)) {\n selected.push(media);\n set({ selectedMedia: selected });\n }\n },\n\n unselectMedia: (mediaId) => {\n set({\n selectedMedia: get().selectedMedia.filter((m) => m.id !== mediaId),\n });\n },\n\n clearSelectedMedia: () => set({ selectedMedia: [] }),\n\n updateUploadProgress: (fileId, progress) => {\n set({\n uploadProgress: { ...get().uploadProgress, [fileId]: progress },\n });\n },\n\n removeUploadProgress: (fileId) => {\n const progress = { ...get().uploadProgress };\n delete progress[fileId];\n set({ uploadProgress: progress });\n },\n}));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toursStore.js","names":[],"sources":["../../../src/tours/store/toursStore.ts"],"sourcesContent":["import { create } from 'zustand';\nimport type {\n Tour,\n TourStep,\n TourMedia,\n TourFilters,\n ValidationError,\n ToursViewMode,\n DeviceType,\n} from '../types';\n\ninterface ToursState {\n // View state\n selectedTour: Tour | null;\n selectedStep: TourStep | null;\n viewMode: ToursViewMode;\n devicePreview: DeviceType;\n\n // Filters\n tourFilter: TourFilters;\n toursListRevision: number;\n\n // Builder state\n stepSequence: TourStep[];\n isDirty: boolean;\n validationErrors: ValidationError[];\n\n // Media state\n selectedMedia: TourMedia[];\n uploadProgress: Record<string, number>;\n\n // UI state\n sidebarOpen: boolean;\n\n // Lifecycle\n resetTransientState: () => void;\n\n // Actions - View\n setSelectedTour: (tour: Tour | null) => void;\n setSelectedStep: (step: TourStep | null) => void;\n setViewMode: (mode: ToursViewMode) => void;\n setDevicePreview: (device: DeviceType) => void;\n toggleSidebar: () => void;\n setSidebarOpen: (open: boolean) => void;\n\n // Actions - Filters\n updateTourFilter: (filter: Partial<TourFilters>) => void;\n resetTourFilter: () => void;\n notifyToursListChanged: () => void;\n\n // Actions - Steps\n updateStepSequence: (steps: TourStep[]) => void;\n reorderSteps: (startIndex: number, endIndex: number) => void;\n addStep: (step: Partial<TourStep>) => void;\n removeStep: (stepId: string) => void;\n updateStep: (stepId: string, updates: Partial<TourStep>) => void;\n\n // Actions - Validation\n setDirty: (dirty: boolean) => void;\n validateTour: () => ValidationError[];\n clearValidationErrors: () => void;\n\n // Actions - Media\n selectMedia: (media: TourMedia) => void;\n unselectMedia: (mediaId: string) => void;\n clearSelectedMedia: () => void;\n updateUploadProgress: (fileId: string, progress: number) => void;\n removeUploadProgress: (fileId: string) => void;\n}\n\nconst defaultFilter: TourFilters = {\n search: '',\n status: 'all',\n productId: undefined,\n moduleId: undefined,\n pageId: undefined,\n dateRange: { start: null, end: null },\n createdBy: undefined,\n};\n\nexport const useToursStore = create<ToursState>((set, get) => ({\n // Initial state\n selectedTour: null,\n selectedStep: null,\n viewMode: 'grid',\n devicePreview: 'desktop',\n tourFilter: defaultFilter,\n toursListRevision: 0,\n stepSequence: [],\n isDirty: false,\n validationErrors: [],\n selectedMedia: [],\n uploadProgress: {},\n sidebarOpen: true,\n\n resetTransientState: () =>\n set({\n selectedTour: null,\n selectedStep: null,\n viewMode: 'grid',\n devicePreview: 'desktop',\n tourFilter: defaultFilter,\n toursListRevision: 0,\n stepSequence: [],\n isDirty: false,\n validationErrors: [],\n selectedMedia: [],\n uploadProgress: {},\n sidebarOpen: true,\n }),\n\n // View actions\n setSelectedTour: (tour) =>\n set({\n selectedTour: tour,\n stepSequence: tour?.steps || [],\n isDirty: false,\n validationErrors: [],\n }),\n\n setSelectedStep: (step) => set({ selectedStep: step }),\n\n setViewMode: (mode) => set({ viewMode: mode }),\n\n setDevicePreview: (device) => set({ devicePreview: device }),\n\n toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),\n\n setSidebarOpen: (open) => set({ sidebarOpen: open }),\n\n // Filter actions\n updateTourFilter: (filter) =>\n set((state) => ({\n tourFilter: { ...state.tourFilter, ...filter },\n })),\n\n resetTourFilter: () => set({ tourFilter: defaultFilter }),\n\n notifyToursListChanged: () =>\n set((state) => ({ toursListRevision: state.toursListRevision + 1 })),\n\n // Step actions\n updateStepSequence: (steps) => set({ stepSequence: steps, isDirty: true }),\n\n reorderSteps: (startIndex, endIndex) => {\n const steps = [...get().stepSequence];\n const [removed] = steps.splice(startIndex, 1);\n steps.splice(endIndex, 0, removed);\n const reorderedSteps = steps.map((step, index) => ({\n ...step,\n stepOrder: index + 1,\n }));\n set({ stepSequence: reorderedSteps, isDirty: true });\n },\n\n addStep: (step) => {\n const steps = [...get().stepSequence];\n const newStep: TourStep = {\n id: `temp_${Date.now()}`,\n tourId: get().selectedTour?.id || '',\n title: step.title || 'New Step',\n content: step.content || '',\n stepOrder: steps.length + 1,\n targetSelector: step.targetSelector || '',\n placement: step.placement || 'AUTO',\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n ...step,\n } as TourStep;\n steps.push(newStep);\n set({ stepSequence: steps, isDirty: true });\n },\n\n removeStep: (stepId) => {\n const steps = get().stepSequence.filter((s) => s.id !== stepId);\n const reorderedSteps = steps.map((step, index) => ({\n ...step,\n stepOrder: index + 1,\n }));\n set({ stepSequence: reorderedSteps, isDirty: true });\n },\n\n updateStep: (stepId, updates) => {\n const steps = get().stepSequence.map((step) =>\n step.id === stepId ? { ...step, ...updates } : step\n );\n set({ stepSequence: steps, isDirty: true });\n },\n\n // Validation actions\n setDirty: (dirty) => set({ isDirty: dirty }),\n\n validateTour: () => {\n const errors: ValidationError[] = [];\n const { selectedTour, stepSequence } = get();\n\n if (!selectedTour) {\n errors.push({ field: 'tour', message: 'No tour selected' });\n set({ validationErrors: errors });\n return errors;\n }\n\n if (!selectedTour.name || selectedTour.name.trim() === '') {\n errors.push({ field: 'name', message: 'Tour name is required' });\n }\n\n if (!selectedTour.productId) {\n errors.push({ field: 'productId', message: 'Product ID is required' });\n }\n\n if (stepSequence.length === 0) {\n errors.push({ field: 'steps', message: 'At least one step is required' });\n }\n\n stepSequence.forEach((step, index) => {\n if (!step.title || step.title.trim() === '') {\n errors.push({\n field: `step[${index}].title`,\n message: `Step ${index + 1} title is required`,\n });\n }\n if (!step.content || step.content.trim() === '') {\n errors.push({\n field: `step[${index}].content`,\n message: `Step ${index + 1} content is required`,\n });\n }\n if (\n step.placement !== 'CENTER' &&\n (!step.targetSelector || step.targetSelector.trim() === '')\n ) {\n errors.push({\n field: `step[${index}].targetSelector`,\n message: `Step ${index + 1} selector is required`,\n });\n }\n });\n\n set({ validationErrors: errors });\n return errors;\n },\n\n clearValidationErrors: () => set({ validationErrors: [] }),\n\n // Media actions\n selectMedia: (media) => {\n const selected = [...get().selectedMedia];\n if (!selected.find((m) => m.id === media.id)) {\n selected.push(media);\n set({ selectedMedia: selected });\n }\n },\n\n unselectMedia: (mediaId) => {\n set({\n selectedMedia: get().selectedMedia.filter((m) => m.id !== mediaId),\n });\n },\n\n clearSelectedMedia: () => set({ selectedMedia: [] }),\n\n updateUploadProgress: (fileId, progress) => {\n set({\n uploadProgress: { ...get().uploadProgress, [fileId]: progress },\n });\n },\n\n removeUploadProgress: (fileId) => {\n const progress = { ...get().uploadProgress };\n delete progress[fileId];\n set({ uploadProgress: progress });\n },\n}));\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BurdenoffEventName, EventBus } from '@burdenoff/fe-libs/shared/events';
|
|
2
|
+
import { ToursRootProps } from './types';
|
|
3
|
+
|
|
4
|
+
export declare const TOURS_RYBBIT_ALLOWLIST: BurdenoffEventName[];
|
|
5
|
+
export type ToursApiOperation = 'tour.save' | 'step.save' | 'media.attach' | 'media.upload' | 'schedule.create' | 'template.create_from_template' | 'template.delete' | 'template.save';
|
|
6
|
+
type ToursTelemetryContext = Pick<ToursRootProps, 'productId' | 'workspaceId'>;
|
|
7
|
+
export declare function emitToursApiFailed(eventBus: EventBus, operation: ToursApiOperation, context: ToursTelemetryContext): void;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/tours/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,sBAAsB,EAAE,kBAAkB,EAKtD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,WAAW,GACX,WAAW,GACX,cAAc,GACd,cAAc,GACd,iBAAiB,GACjB,+BAA+B,GAC/B,iBAAiB,GACjB,eAAe,CAAC;AAEpB,KAAK,qBAAqB,GAAG,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,aAAa,CAAC,CAAC;AAE/E,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,qBAAqB,QAc/B"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/tours/telemetry.ts
|
|
2
|
+
var e = [
|
|
3
|
+
"tours.page.viewed",
|
|
4
|
+
"tours.tour.started",
|
|
5
|
+
"tours.tour.completed",
|
|
6
|
+
"tours.tour.skipped"
|
|
7
|
+
];
|
|
8
|
+
function t(e, t, n) {
|
|
9
|
+
e.emit("tours.api.failed", {
|
|
10
|
+
route: "/tours",
|
|
11
|
+
operation: t,
|
|
12
|
+
productId: n.productId,
|
|
13
|
+
workspaceId: n.workspaceId
|
|
14
|
+
}, { component: "microfe-tours" });
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { e as TOURS_RYBBIT_ALLOWLIST, t as emitToursApiFailed };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","names":[],"sources":["../../src/tours/telemetry.ts"],"sourcesContent":["import type { BurdenoffEventName, EventBus } from '@burdenoff/fe-libs/shared/events';\nimport type { ToursRootProps } from './types';\n\nexport const TOURS_RYBBIT_ALLOWLIST: BurdenoffEventName[] = [\n 'tours.page.viewed',\n 'tours.tour.started',\n 'tours.tour.completed',\n 'tours.tour.skipped',\n];\n\nexport type ToursApiOperation =\n | 'tour.save'\n | 'step.save'\n | 'media.attach'\n | 'media.upload'\n | 'schedule.create'\n | 'template.create_from_template'\n | 'template.delete'\n | 'template.save';\n\ntype ToursTelemetryContext = Pick<ToursRootProps, 'productId' | 'workspaceId'>;\n\nexport function emitToursApiFailed(\n eventBus: EventBus,\n operation: ToursApiOperation,\n context: ToursTelemetryContext\n) {\n eventBus.emit(\n 'tours.api.failed',\n {\n // The event registry currently allows only user-facing Tours routes.\n // App-shell event metadata still carries the exact browser pathname.\n route: '/tours',\n operation,\n productId: context.productId,\n workspaceId: context.workspaceId,\n },\n { component: 'microfe-tours' }\n );\n}\n"],"mappings":";AAGA,IAAa,IAA+C;CAC1D;CACA;CACA;CACA;CACD;AAcD,SAAgB,EACd,GACA,GACA,GACA;AACA,GAAS,KACP,oBACA;EAGE,OAAO;EACP;EACA,WAAW,EAAQ;EACnB,aAAa,EAAQ;EACtB,EACD,EAAE,WAAW,iBAAiB,CAC/B"}
|