@burdenoff/microfe-tours 2026.601.1 → 2026.624.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/tours/ToursUserRoutes.js +3 -3
- package/dist/tours/ToursUserRoutes.js.map +1 -1
- package/dist/tours/components/RouteHelpers.js +6 -6
- package/dist/tours/components/RouteHelpers.js.map +1 -1
- package/dist/tours/pages/AnalyticsDashboardPage.js +21 -21
- package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.js +18 -18
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/MyToursPage.js +10 -10
- package/dist/tours/pages/MyToursPage.js.map +1 -1
- package/dist/tours/pages/MyToursProgressPage.js +11 -11
- package/dist/tours/pages/MyToursProgressPage.js.map +1 -1
- package/dist/tours/pages/SchedulerPage.js +15 -15
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.js +47 -47
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/SystemAnalyticsPage.js +17 -17
- package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.js +19 -19
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
- package/dist/tours/pages/TourBuilderPage.js +39 -39
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.js +26 -26
- package/dist/tours/pages/TourPreviewPage.js.map +1 -1
- package/dist/tours/pages/ToursListPage.js +24 -24
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -17,10 +17,10 @@ function m() {
|
|
|
17
17
|
children: /* @__PURE__ */ f("div", {
|
|
18
18
|
className: "text-center",
|
|
19
19
|
children: [/* @__PURE__ */ d("h2", {
|
|
20
|
-
className: "text-lg font-semibold text-
|
|
20
|
+
className: "text-lg font-semibold text-text-primary mb-2",
|
|
21
21
|
children: h("systemAnalytics.accessDenied", "Access Denied")
|
|
22
22
|
}), /* @__PURE__ */ d("p", {
|
|
23
|
-
className: "text-sm text-
|
|
23
|
+
className: "text-sm text-text-secondary",
|
|
24
24
|
children: h("systemAnalytics.noPermission", "You do not have permission to view system analytics.")
|
|
25
25
|
})]
|
|
26
26
|
})
|
|
@@ -28,7 +28,7 @@ function m() {
|
|
|
28
28
|
if (b) return /* @__PURE__ */ d("div", {
|
|
29
29
|
className: "flex items-center justify-center h-full",
|
|
30
30
|
children: /* @__PURE__ */ d("p", {
|
|
31
|
-
className: "text-
|
|
31
|
+
className: "text-text-secondary",
|
|
32
32
|
children: h("systemAnalytics.loading", "Loading analytics...")
|
|
33
33
|
})
|
|
34
34
|
});
|
|
@@ -39,23 +39,23 @@ function m() {
|
|
|
39
39
|
className: "text-xl sm:text-2xl font-bold",
|
|
40
40
|
children: h("systemAnalytics.title", "System Analytics")
|
|
41
41
|
}), /* @__PURE__ */ d("p", {
|
|
42
|
-
className: "text-sm text-
|
|
42
|
+
className: "text-sm text-text-secondary",
|
|
43
43
|
children: h("systemAnalytics.subtitle", "Workspace-wide tour performance overview")
|
|
44
44
|
})] }), /* @__PURE__ */ f("div", {
|
|
45
45
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4",
|
|
46
46
|
children: [
|
|
47
47
|
/* @__PURE__ */ f("div", {
|
|
48
|
-
className: "border border-border rounded-md p-4 bg-
|
|
48
|
+
className: "border border-border-subtle rounded-md p-4 bg-bg-surface",
|
|
49
49
|
children: [/* @__PURE__ */ f("div", {
|
|
50
50
|
className: "flex items-center gap-3 mb-2",
|
|
51
51
|
children: [/* @__PURE__ */ d("div", {
|
|
52
|
-
className: "p-2 bg-primary/10 rounded-md",
|
|
52
|
+
className: "p-2 bg-action-primary-bg/10 rounded-md",
|
|
53
53
|
children: /* @__PURE__ */ d(s, {
|
|
54
54
|
className: "text-primary",
|
|
55
55
|
size: 20
|
|
56
56
|
})
|
|
57
57
|
}), /* @__PURE__ */ d("span", {
|
|
58
|
-
className: "text-sm text-
|
|
58
|
+
className: "text-sm text-text-secondary",
|
|
59
59
|
children: h("systemAnalytics.totalTours", "Total Tours")
|
|
60
60
|
})]
|
|
61
61
|
}), /* @__PURE__ */ d("div", {
|
|
@@ -64,7 +64,7 @@ function m() {
|
|
|
64
64
|
})]
|
|
65
65
|
}),
|
|
66
66
|
/* @__PURE__ */ f("div", {
|
|
67
|
-
className: "border border-border rounded-md p-4 bg-
|
|
67
|
+
className: "border border-border-subtle rounded-md p-4 bg-bg-surface",
|
|
68
68
|
children: [/* @__PURE__ */ f("div", {
|
|
69
69
|
className: "flex items-center gap-3 mb-2",
|
|
70
70
|
children: [/* @__PURE__ */ d("div", {
|
|
@@ -74,7 +74,7 @@ function m() {
|
|
|
74
74
|
size: 20
|
|
75
75
|
})
|
|
76
76
|
}), /* @__PURE__ */ d("span", {
|
|
77
|
-
className: "text-sm text-
|
|
77
|
+
className: "text-sm text-text-secondary",
|
|
78
78
|
children: h("systemAnalytics.publishedTours", "Published Tours")
|
|
79
79
|
})]
|
|
80
80
|
}), /* @__PURE__ */ d("div", {
|
|
@@ -83,7 +83,7 @@ function m() {
|
|
|
83
83
|
})]
|
|
84
84
|
}),
|
|
85
85
|
/* @__PURE__ */ f("div", {
|
|
86
|
-
className: "border border-border rounded-md p-4 bg-
|
|
86
|
+
className: "border border-border-subtle rounded-md p-4 bg-bg-surface",
|
|
87
87
|
children: [/* @__PURE__ */ f("div", {
|
|
88
88
|
className: "flex items-center gap-3 mb-2",
|
|
89
89
|
children: [/* @__PURE__ */ d("div", {
|
|
@@ -93,7 +93,7 @@ function m() {
|
|
|
93
93
|
size: 20
|
|
94
94
|
})
|
|
95
95
|
}), /* @__PURE__ */ d("span", {
|
|
96
|
-
className: "text-sm text-
|
|
96
|
+
className: "text-sm text-text-secondary",
|
|
97
97
|
children: h("systemAnalytics.totalViews", "Total Views")
|
|
98
98
|
})]
|
|
99
99
|
}), /* @__PURE__ */ d("div", {
|
|
@@ -102,7 +102,7 @@ function m() {
|
|
|
102
102
|
})]
|
|
103
103
|
}),
|
|
104
104
|
/* @__PURE__ */ f("div", {
|
|
105
|
-
className: "border border-border rounded-md p-4 bg-
|
|
105
|
+
className: "border border-border-subtle rounded-md p-4 bg-bg-surface",
|
|
106
106
|
children: [/* @__PURE__ */ f("div", {
|
|
107
107
|
className: "flex items-center gap-3 mb-2",
|
|
108
108
|
children: [/* @__PURE__ */ d("div", {
|
|
@@ -112,7 +112,7 @@ function m() {
|
|
|
112
112
|
size: 20
|
|
113
113
|
})
|
|
114
114
|
}), /* @__PURE__ */ d("span", {
|
|
115
|
-
className: "text-sm text-
|
|
115
|
+
className: "text-sm text-text-secondary",
|
|
116
116
|
children: h("systemAnalytics.totalCompletions", "Total Completions")
|
|
117
117
|
})]
|
|
118
118
|
}), /* @__PURE__ */ d("div", {
|
|
@@ -121,17 +121,17 @@ function m() {
|
|
|
121
121
|
})]
|
|
122
122
|
}),
|
|
123
123
|
/* @__PURE__ */ f("div", {
|
|
124
|
-
className: "border border-border rounded-md p-4 bg-
|
|
124
|
+
className: "border border-border-subtle rounded-md p-4 bg-bg-surface",
|
|
125
125
|
children: [/* @__PURE__ */ f("div", {
|
|
126
126
|
className: "flex items-center gap-3 mb-2",
|
|
127
127
|
children: [/* @__PURE__ */ d("div", {
|
|
128
|
-
className: "p-2 bg-primary/10 rounded-md",
|
|
128
|
+
className: "p-2 bg-action-primary-bg/10 rounded-md",
|
|
129
129
|
children: /* @__PURE__ */ d(o, {
|
|
130
130
|
className: "text-primary",
|
|
131
131
|
size: 20
|
|
132
132
|
})
|
|
133
133
|
}), /* @__PURE__ */ d("span", {
|
|
134
|
-
className: "text-sm text-
|
|
134
|
+
className: "text-sm text-text-secondary",
|
|
135
135
|
children: h("systemAnalytics.completionRate", "Completion Rate")
|
|
136
136
|
})]
|
|
137
137
|
}), /* @__PURE__ */ d("div", {
|
|
@@ -144,7 +144,7 @@ function m() {
|
|
|
144
144
|
}) : /* @__PURE__ */ d("div", {
|
|
145
145
|
className: "flex items-center justify-center h-full",
|
|
146
146
|
children: /* @__PURE__ */ d("p", {
|
|
147
|
-
className: "text-
|
|
147
|
+
className: "text-text-secondary",
|
|
148
148
|
children: h("systemAnalytics.noData", "No analytics data available")
|
|
149
149
|
})
|
|
150
150
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SystemAnalyticsPage.js","names":[],"sources":["../../../src/tours/pages/SystemAnalyticsPage.tsx"],"sourcesContent":["import { useCallback } from 'react';\nimport { Compass, Globe, Eye, TrendingUp, BarChart3 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useGetWorkspaceAnalyticsSummaryQuery } from '../../generated/global-operations';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { formatNumber, formatPercentage } from '../utils';\n\n/**\n * System-wide analytics page\n * Displays workspace-level tour analytics summary (no tourId needed)\n */\nexport function SystemAnalyticsPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canViewAnalytics = hasPermission(TOUR_PERMISSIONS.TOUR_ANALYTICS_READ);\n\n const { data, loading } = useGetWorkspaceAnalyticsSummaryQuery({\n skip: permissionsLoading || !canViewAnalytics,\n });\n\n if (!permissionsLoading && !canViewAnalytics) {\n return (\n <div className=\"flex items-center justify-center h-full p-3 sm:p-6\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-
|
|
1
|
+
{"version":3,"file":"SystemAnalyticsPage.js","names":[],"sources":["../../../src/tours/pages/SystemAnalyticsPage.tsx"],"sourcesContent":["import { useCallback } from 'react';\nimport { Compass, Globe, Eye, TrendingUp, BarChart3 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useGetWorkspaceAnalyticsSummaryQuery } from '../../generated/global-operations';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { formatNumber, formatPercentage } from '../utils';\n\n/**\n * System-wide analytics page\n * Displays workspace-level tour analytics summary (no tourId needed)\n */\nexport function SystemAnalyticsPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canViewAnalytics = hasPermission(TOUR_PERMISSIONS.TOUR_ANALYTICS_READ);\n\n const { data, loading } = useGetWorkspaceAnalyticsSummaryQuery({\n skip: permissionsLoading || !canViewAnalytics,\n });\n\n if (!permissionsLoading && !canViewAnalytics) {\n return (\n <div className=\"flex items-center justify-center h-full p-3 sm:p-6\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('systemAnalytics.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'systemAnalytics.noPermission',\n 'You do not have permission to view system analytics.'\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <p className=\"text-text-secondary\">\n {tr('systemAnalytics.loading', 'Loading analytics...')}\n </p>\n </div>\n );\n }\n\n const summary = data?.workspaceAnalyticsSummary;\n\n if (!summary) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <p className=\"text-text-secondary\">\n {tr('systemAnalytics.noData', 'No analytics data available')}\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('systemAnalytics.title', 'System Analytics')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr('systemAnalytics.subtitle', 'Workspace-wide tour performance overview')}\n </p>\n </div>\n\n {/* Summary Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4\">\n <div className=\"border border-border-subtle rounded-md p-4 bg-bg-surface\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-md\">\n <Compass className=\"text-primary\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('systemAnalytics.totalTours', 'Total Tours')}\n </span>\n </div>\n <div className=\"text-2xl font-bold\">{formatNumber(summary.totalTours)}</div>\n </div>\n\n <div className=\"border border-border-subtle rounded-md p-4 bg-bg-surface\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-success/10 rounded-md\">\n <Globe className=\"text-success\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('systemAnalytics.publishedTours', 'Published Tours')}\n </span>\n </div>\n <div className=\"text-2xl font-bold\">{formatNumber(summary.publishedTours)}</div>\n </div>\n\n <div className=\"border border-border-subtle rounded-md p-4 bg-bg-surface\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-info/10 rounded-md\">\n <Eye className=\"text-info\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('systemAnalytics.totalViews', 'Total Views')}\n </span>\n </div>\n <div className=\"text-2xl font-bold\">{formatNumber(summary.totalViews)}</div>\n </div>\n\n <div className=\"border border-border-subtle rounded-md p-4 bg-bg-surface\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-warning/10 rounded-md\">\n <TrendingUp className=\"text-warning\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('systemAnalytics.totalCompletions', 'Total Completions')}\n </span>\n </div>\n <div className=\"text-2xl font-bold\">{formatNumber(summary.totalCompletions)}</div>\n </div>\n\n <div className=\"border border-border-subtle rounded-md p-4 bg-bg-surface\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-md\">\n <BarChart3 className=\"text-primary\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('systemAnalytics.completionRate', 'Completion Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold\">\n {formatPercentage(summary.overallCompletionRate)}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -50,7 +50,7 @@ function S() {
|
|
|
50
50
|
className: "text-xl sm:text-2xl font-bold",
|
|
51
51
|
children: S("templateLibrary.title")
|
|
52
52
|
}), /* @__PURE__ */ v("p", {
|
|
53
|
-
className: "text-sm text-
|
|
53
|
+
className: "text-sm text-text-secondary",
|
|
54
54
|
children: S("templateLibrary.subtitle")
|
|
55
55
|
})] }),
|
|
56
56
|
/* @__PURE__ */ y("div", {
|
|
@@ -59,21 +59,21 @@ function S() {
|
|
|
59
59
|
/* @__PURE__ */ y("div", {
|
|
60
60
|
className: "flex-1 relative",
|
|
61
61
|
children: [/* @__PURE__ */ v(h, {
|
|
62
|
-
className: "absolute left-3 top-1/2 -translate-y-1/2 text-
|
|
62
|
+
className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary",
|
|
63
63
|
size: 20
|
|
64
64
|
}), /* @__PURE__ */ v("input", {
|
|
65
65
|
type: "text",
|
|
66
66
|
placeholder: S("templateLibrary.searchPlaceholder"),
|
|
67
67
|
value: j,
|
|
68
68
|
onChange: (e) => M(e.target.value),
|
|
69
|
-
className: "w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border rounded-md bg-
|
|
69
|
+
className: "w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface",
|
|
70
70
|
"aria-label": S("templateLibrary.searchPlaceholder")
|
|
71
71
|
})]
|
|
72
72
|
}),
|
|
73
73
|
/* @__PURE__ */ y("select", {
|
|
74
74
|
value: N,
|
|
75
75
|
onChange: (e) => P(e.target.value),
|
|
76
|
-
className: "px-4 py-2 min-h-[44px] border border-border rounded-md bg-
|
|
76
|
+
className: "px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface",
|
|
77
77
|
"aria-label": S("templateLibrary.allCategories"),
|
|
78
78
|
children: [
|
|
79
79
|
/* @__PURE__ */ v("option", {
|
|
@@ -99,7 +99,7 @@ function S() {
|
|
|
99
99
|
]
|
|
100
100
|
}),
|
|
101
101
|
/* @__PURE__ */ y("label", {
|
|
102
|
-
className: "flex items-center gap-2 px-4 py-2 min-h-[44px] border border-border rounded-md bg-
|
|
102
|
+
className: "flex items-center gap-2 px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface cursor-pointer",
|
|
103
103
|
children: [/* @__PURE__ */ v("input", {
|
|
104
104
|
type: "checkbox",
|
|
105
105
|
checked: F,
|
|
@@ -116,21 +116,21 @@ function S() {
|
|
|
116
116
|
R ? /* @__PURE__ */ v("div", {
|
|
117
117
|
className: "text-center py-12",
|
|
118
118
|
children: /* @__PURE__ */ v("p", {
|
|
119
|
-
className: "text-
|
|
119
|
+
className: "text-text-secondary",
|
|
120
120
|
children: S("templateLibrary.loading")
|
|
121
121
|
})
|
|
122
122
|
}) : z.length > 0 ? /* @__PURE__ */ v("div", {
|
|
123
123
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
124
124
|
children: z.map((e) => /* @__PURE__ */ y("div", {
|
|
125
|
-
className: "border border-border rounded-md overflow-hidden hover:shadow-md transition-shadow",
|
|
125
|
+
className: "border border-border-subtle rounded-md overflow-hidden hover:shadow-md transition-shadow",
|
|
126
126
|
children: [/* @__PURE__ */ v("div", {
|
|
127
|
-
className: "aspect-video bg-
|
|
127
|
+
className: "aspect-video bg-bg-sunken flex items-center justify-center",
|
|
128
128
|
children: e.thumbnail ? /* @__PURE__ */ v("img", {
|
|
129
129
|
src: e.thumbnail,
|
|
130
130
|
alt: e.name,
|
|
131
131
|
className: "w-full h-full object-cover"
|
|
132
132
|
}) : /* @__PURE__ */ v(p, {
|
|
133
|
-
className: "text-
|
|
133
|
+
className: "text-text-secondary",
|
|
134
134
|
size: 48
|
|
135
135
|
})
|
|
136
136
|
}), /* @__PURE__ */ y("div", {
|
|
@@ -147,22 +147,22 @@ function S() {
|
|
|
147
147
|
className: "text-warning",
|
|
148
148
|
size: 16
|
|
149
149
|
}), e.isPublic ? /* @__PURE__ */ v(f, {
|
|
150
|
-
className: "text-
|
|
150
|
+
className: "text-text-secondary",
|
|
151
151
|
size: 16
|
|
152
152
|
}) : /* @__PURE__ */ v(m, {
|
|
153
|
-
className: "text-
|
|
153
|
+
className: "text-text-secondary",
|
|
154
154
|
size: 16
|
|
155
155
|
})]
|
|
156
156
|
})]
|
|
157
157
|
}),
|
|
158
158
|
e.description && /* @__PURE__ */ v("p", {
|
|
159
|
-
className: "text-sm text-
|
|
159
|
+
className: "text-sm text-text-secondary mb-3 line-clamp-2",
|
|
160
160
|
children: e.description
|
|
161
161
|
}),
|
|
162
162
|
/* @__PURE__ */ y("div", {
|
|
163
163
|
className: "flex items-center justify-between",
|
|
164
164
|
children: [/* @__PURE__ */ y("span", {
|
|
165
|
-
className: "text-xs text-
|
|
165
|
+
className: "text-xs text-text-secondary",
|
|
166
166
|
children: [
|
|
167
167
|
S("templateLibrary.usedTimes"),
|
|
168
168
|
" ",
|
|
@@ -175,13 +175,13 @@ function S() {
|
|
|
175
175
|
children: [A && /* @__PURE__ */ v("button", {
|
|
176
176
|
type: "button",
|
|
177
177
|
onClick: () => void W(e.id),
|
|
178
|
-
className: "p-2 min-h-[44px] min-w-[44px] text-
|
|
178
|
+
className: "p-2 min-h-[44px] min-w-[44px] text-text-secondary hover:text-status-error-text rounded-md",
|
|
179
179
|
"aria-label": S("templateLibrary.deleteTemplate"),
|
|
180
180
|
children: /* @__PURE__ */ v(_, { size: 16 })
|
|
181
181
|
}), k && /* @__PURE__ */ v("button", {
|
|
182
182
|
type: "button",
|
|
183
183
|
onClick: () => V(e.id),
|
|
184
|
-
className: "px-3 py-2 min-h-[44px] bg-primary text-primary-
|
|
184
|
+
className: "px-3 py-2 min-h-[44px] bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 text-sm",
|
|
185
185
|
children: S("templateLibrary.useTemplate")
|
|
186
186
|
})]
|
|
187
187
|
})]
|
|
@@ -190,18 +190,18 @@ function S() {
|
|
|
190
190
|
})]
|
|
191
191
|
}, e.id))
|
|
192
192
|
}) : /* @__PURE__ */ y("div", {
|
|
193
|
-
className: "text-center py-12 border border-dashed border-border rounded-md",
|
|
193
|
+
className: "text-center py-12 border border-dashed border-border-subtle rounded-md",
|
|
194
194
|
children: [
|
|
195
195
|
/* @__PURE__ */ v(p, {
|
|
196
|
-
className: "mx-auto mb-4 text-
|
|
196
|
+
className: "mx-auto mb-4 text-text-secondary",
|
|
197
197
|
size: 48
|
|
198
198
|
}),
|
|
199
199
|
/* @__PURE__ */ v("p", {
|
|
200
|
-
className: "text-
|
|
200
|
+
className: "text-text-secondary mb-2",
|
|
201
201
|
children: S("templateLibrary.noTemplatesFound")
|
|
202
202
|
}),
|
|
203
203
|
/* @__PURE__ */ v("p", {
|
|
204
|
-
className: "text-sm text-
|
|
204
|
+
className: "text-sm text-text-secondary",
|
|
205
205
|
children: S("templateLibrary.adjustFilters")
|
|
206
206
|
})
|
|
207
207
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateLibraryPage.js","names":[],"sources":["../../../src/tours/pages/TemplateLibraryPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Search, LayoutTemplate, Star, Globe, Lock, Trash2 } from 'lucide-react';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport {\n useGetTourTemplatesQuery,\n useCreateTourFromTemplateMutation,\n useDeleteTourTemplateMutation,\n} from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TemplateCategory } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\n\n/**\n * Template library page\n * Browse and use tour templates\n */\nexport function TemplateLibraryPage() {\n const { tr } = useToursI18n();\n\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canListTemplates = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_LIST);\n const canUseTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_USE);\n const canDeleteTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_DELETE);\n\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategory | 'all'>('all');\n const [publicOnly, setPublicOnly] = useState(false);\n\n const { data, loading } = useGetTourTemplatesQuery({\n skip: !canListTemplates,\n variables: {\n isPublic: publicOnly || undefined,\n category: categoryFilter === 'all' ? undefined : categoryFilter,\n },\n });\n const templates = data?.tourTemplates ?? [];\n\n const filteredTemplates = templates.filter(\n (t: (typeof templates)[number]) =>\n !searchQuery || t.name.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const [createFromTemplate] = useCreateTourFromTemplateMutation();\n\n const handleUseTemplate = async (templateId: string) => {\n nativeImpact('light');\n try {\n const { data } = await createFromTemplate({\n variables: { templateId },\n });\n if (data?.createTourFromTemplate) {\n void nativeNotify('success');\n navigate(`${basePath}/${data.createTourFromTemplate.id}/edit`);\n }\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.create_from_template', toursContext);\n }\n };\n\n const [deleteTemplate] = useDeleteTourTemplateMutation();\n\n const handleDeleteTemplate = async (templateId: string) => {\n try {\n await deleteTemplate({\n variables: { id: templateId },\n refetchQueries: ['GetTourTemplates'],\n });\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.delete', toursContext);\n }\n };\n\n const handleDeleteTemplateClick = async (templateId: string) => {\n nativeImpact('medium');\n const message = tr('templateLibrary.deleteConfirm');\n const nativeResult = await nativeConfirm({\n title: tr('templateLibrary.deleteConfirm'),\n message,\n });\n const confirmed = nativeResult === null ? window.confirm(message) : nativeResult;\n if (confirmed) await handleDeleteTemplate(templateId);\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">{tr('templateLibrary.title')}</h1>\n <p className=\"text-sm text-muted-foreground\">{tr('templateLibrary.subtitle')}</p>\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <div className=\"flex-1 relative\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('templateLibrary.searchPlaceholder')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n aria-label={tr('templateLibrary.searchPlaceholder')}\n />\n </div>\n <select\n value={categoryFilter}\n onChange={(e) => setCategoryFilter(e.target.value as TemplateCategory | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n aria-label={tr('templateLibrary.allCategories')}\n >\n <option value=\"all\">{tr('templateLibrary.allCategories')}</option>\n <option value=\"ONBOARDING\">{tr('templateLibrary.categoryOnboarding')}</option>\n <option value=\"FEATURE_ANNOUNCEMENT\">\n {tr('templateLibrary.categoryFeatureAnnouncement')}\n </option>\n <option value=\"HELP\">{tr('templateLibrary.categoryHelp')}</option>\n <option value=\"CUSTOM\">{tr('templateLibrary.categoryCustom')}</option>\n </select>\n <label className=\"flex items-center gap-2 px-4 py-2 min-h-[44px] border border-border rounded-md bg-background cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={publicOnly}\n onChange={(e) => setPublicOnly(e.target.checked)}\n className=\"rounded\"\n aria-label={tr('templateLibrary.publicOnly')}\n />\n <span className=\"text-sm\">{tr('templateLibrary.publicOnly')}</span>\n </label>\n </div>\n\n {/* Templates Grid */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-muted-foreground\">{tr('templateLibrary.loading')}</p>\n </div>\n ) : filteredTemplates.length > 0 ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredTemplates.map((template: (typeof filteredTemplates)[number]) => (\n <div\n key={template.id}\n className=\"border border-border rounded-md overflow-hidden hover:shadow-md transition-shadow\"\n >\n {/* Thumbnail */}\n <div className=\"aspect-video bg-muted flex items-center justify-center\">\n {template.thumbnail ? (\n <img\n src={template.thumbnail}\n alt={template.name}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <LayoutTemplate className=\"text-muted-foreground\" size={48} />\n )}\n </div>\n\n {/* Content */}\n <div className=\"p-4\">\n <div className=\"flex items-start justify-between mb-2\">\n <h3 className=\"font-semibold\">{template.name}</h3>\n <div className=\"flex gap-1\">\n {template.isPremium && <Star className=\"text-warning\" size={16} />}\n {template.isPublic ? (\n <Globe className=\"text-muted-foreground\" size={16} />\n ) : (\n <Lock className=\"text-muted-foreground\" size={16} />\n )}\n </div>\n </div>\n\n {template.description && (\n <p className=\"text-sm text-muted-foreground mb-3 line-clamp-2\">\n {template.description}\n </p>\n )}\n\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">\n {tr('templateLibrary.usedTimes')} {template.useCount}{' '}\n {tr('templateLibrary.times')}\n </span>\n <div className=\"flex items-center gap-2\">\n {canDeleteTemplate && (\n <button\n type=\"button\"\n onClick={() => void handleDeleteTemplateClick(template.id)}\n className=\"p-2 min-h-[44px] min-w-[44px] text-muted-foreground hover:text-destructive rounded-md\"\n aria-label={tr('templateLibrary.deleteTemplate')}\n >\n <Trash2 size={16} />\n </button>\n )}\n {canUseTemplate && (\n <button\n type=\"button\"\n onClick={() => handleUseTemplate(template.id)}\n className=\"px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 text-sm\"\n >\n {tr('templateLibrary.useTemplate')}\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-12 border border-dashed border-border rounded-md\">\n <LayoutTemplate className=\"mx-auto mb-4 text-muted-foreground\" size={48} />\n <p className=\"text-muted-foreground mb-2\">{tr('templateLibrary.noTemplatesFound')}</p>\n <p className=\"text-sm text-muted-foreground\">{tr('templateLibrary.adjustFilters')}</p>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TemplateLibraryPage.js","names":[],"sources":["../../../src/tours/pages/TemplateLibraryPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Search, LayoutTemplate, Star, Globe, Lock, Trash2 } from 'lucide-react';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport {\n useGetTourTemplatesQuery,\n useCreateTourFromTemplateMutation,\n useDeleteTourTemplateMutation,\n} from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TemplateCategory } from '../types';\nimport { useToursI18n } from '../i18n';\nimport { emitToursApiFailed } from '../telemetry';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\n\n/**\n * Template library page\n * Browse and use tour templates\n */\nexport function TemplateLibraryPage() {\n const { tr } = useToursI18n();\n\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canListTemplates = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_LIST);\n const canUseTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_USE);\n const canDeleteTemplate = hasPermission(TOUR_PERMISSIONS.TOUR_TEMPLATE_DELETE);\n\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategory | 'all'>('all');\n const [publicOnly, setPublicOnly] = useState(false);\n\n const { data, loading } = useGetTourTemplatesQuery({\n skip: !canListTemplates,\n variables: {\n isPublic: publicOnly || undefined,\n category: categoryFilter === 'all' ? undefined : categoryFilter,\n },\n });\n const templates = data?.tourTemplates ?? [];\n\n const filteredTemplates = templates.filter(\n (t: (typeof templates)[number]) =>\n !searchQuery || t.name.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const [createFromTemplate] = useCreateTourFromTemplateMutation();\n\n const handleUseTemplate = async (templateId: string) => {\n nativeImpact('light');\n try {\n const { data } = await createFromTemplate({\n variables: { templateId },\n });\n if (data?.createTourFromTemplate) {\n void nativeNotify('success');\n navigate(`${basePath}/${data.createTourFromTemplate.id}/edit`);\n }\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.create_from_template', toursContext);\n }\n };\n\n const [deleteTemplate] = useDeleteTourTemplateMutation();\n\n const handleDeleteTemplate = async (templateId: string) => {\n try {\n await deleteTemplate({\n variables: { id: templateId },\n refetchQueries: ['GetTourTemplates'],\n });\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n emitToursApiFailed(eventBus, 'template.delete', toursContext);\n }\n };\n\n const handleDeleteTemplateClick = async (templateId: string) => {\n nativeImpact('medium');\n const message = tr('templateLibrary.deleteConfirm');\n const nativeResult = await nativeConfirm({\n title: tr('templateLibrary.deleteConfirm'),\n message,\n });\n const confirmed = nativeResult === null ? window.confirm(message) : nativeResult;\n if (confirmed) await handleDeleteTemplate(templateId);\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">{tr('templateLibrary.title')}</h1>\n <p className=\"text-sm text-text-secondary\">{tr('templateLibrary.subtitle')}</p>\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <div className=\"flex-1 relative\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('templateLibrary.searchPlaceholder')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface\"\n aria-label={tr('templateLibrary.searchPlaceholder')}\n />\n </div>\n <select\n value={categoryFilter}\n onChange={(e) => setCategoryFilter(e.target.value as TemplateCategory | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface\"\n aria-label={tr('templateLibrary.allCategories')}\n >\n <option value=\"all\">{tr('templateLibrary.allCategories')}</option>\n <option value=\"ONBOARDING\">{tr('templateLibrary.categoryOnboarding')}</option>\n <option value=\"FEATURE_ANNOUNCEMENT\">\n {tr('templateLibrary.categoryFeatureAnnouncement')}\n </option>\n <option value=\"HELP\">{tr('templateLibrary.categoryHelp')}</option>\n <option value=\"CUSTOM\">{tr('templateLibrary.categoryCustom')}</option>\n </select>\n <label className=\"flex items-center gap-2 px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={publicOnly}\n onChange={(e) => setPublicOnly(e.target.checked)}\n className=\"rounded\"\n aria-label={tr('templateLibrary.publicOnly')}\n />\n <span className=\"text-sm\">{tr('templateLibrary.publicOnly')}</span>\n </label>\n </div>\n\n {/* Templates Grid */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-text-secondary\">{tr('templateLibrary.loading')}</p>\n </div>\n ) : filteredTemplates.length > 0 ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredTemplates.map((template: (typeof filteredTemplates)[number]) => (\n <div\n key={template.id}\n className=\"border border-border-subtle rounded-md overflow-hidden hover:shadow-md transition-shadow\"\n >\n {/* Thumbnail */}\n <div className=\"aspect-video bg-bg-sunken flex items-center justify-center\">\n {template.thumbnail ? (\n <img\n src={template.thumbnail}\n alt={template.name}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <LayoutTemplate className=\"text-text-secondary\" size={48} />\n )}\n </div>\n\n {/* Content */}\n <div className=\"p-4\">\n <div className=\"flex items-start justify-between mb-2\">\n <h3 className=\"font-semibold\">{template.name}</h3>\n <div className=\"flex gap-1\">\n {template.isPremium && <Star className=\"text-warning\" size={16} />}\n {template.isPublic ? (\n <Globe className=\"text-text-secondary\" size={16} />\n ) : (\n <Lock className=\"text-text-secondary\" size={16} />\n )}\n </div>\n </div>\n\n {template.description && (\n <p className=\"text-sm text-text-secondary mb-3 line-clamp-2\">\n {template.description}\n </p>\n )}\n\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">\n {tr('templateLibrary.usedTimes')} {template.useCount}{' '}\n {tr('templateLibrary.times')}\n </span>\n <div className=\"flex items-center gap-2\">\n {canDeleteTemplate && (\n <button\n type=\"button\"\n onClick={() => void handleDeleteTemplateClick(template.id)}\n className=\"p-2 min-h-[44px] min-w-[44px] text-text-secondary hover:text-status-error-text rounded-md\"\n aria-label={tr('templateLibrary.deleteTemplate')}\n >\n <Trash2 size={16} />\n </button>\n )}\n {canUseTemplate && (\n <button\n type=\"button\"\n onClick={() => handleUseTemplate(template.id)}\n className=\"px-3 py-2 min-h-[44px] bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 text-sm\"\n >\n {tr('templateLibrary.useTemplate')}\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-12 border border-dashed border-border-subtle rounded-md\">\n <LayoutTemplate className=\"mx-auto mb-4 text-text-secondary\" size={48} />\n <p className=\"text-text-secondary mb-2\">{tr('templateLibrary.noTemplatesFound')}</p>\n <p className=\"text-sm text-text-secondary\">{tr('templateLibrary.adjustFilters')}</p>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|