@burdenoff/microfe-tours 2026.510.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +342 -0
  2. package/dist/__tests__/setup.d.ts +2 -0
  3. package/dist/__tests__/setup.d.ts.map +1 -0
  4. package/dist/constants/featureFlags.d.ts +25 -0
  5. package/dist/constants/featureFlags.d.ts.map +1 -0
  6. package/dist/constants/featureFlags.js +9 -0
  7. package/dist/constants/featureFlags.js.map +1 -0
  8. package/dist/constants/permissions.d.ts +49 -0
  9. package/dist/constants/permissions.d.ts.map +1 -0
  10. package/dist/constants/permissions.js +38 -0
  11. package/dist/constants/permissions.js.map +1 -0
  12. package/dist/dev/main.d.ts +2 -0
  13. package/dist/dev/main.d.ts.map +1 -0
  14. package/dist/generated/global-operations.d.ts +1270 -0
  15. package/dist/generated/global-operations.d.ts.map +1 -0
  16. package/dist/generated/global-operations.js +650 -0
  17. package/dist/generated/global-operations.js.map +1 -0
  18. package/dist/generated/global-types.d.ts +20448 -0
  19. package/dist/generated/global-types.d.ts.map +1 -0
  20. package/dist/generated/wspace-operations.d.ts +2 -0
  21. package/dist/generated/wspace-operations.d.ts.map +1 -0
  22. package/dist/generated/wspace-types.d.ts +53398 -0
  23. package/dist/generated/wspace-types.d.ts.map +1 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +6 -0
  27. package/dist/tours/ToursAdminRoot.d.ts +16 -0
  28. package/dist/tours/ToursAdminRoot.d.ts.map +1 -0
  29. package/dist/tours/ToursAdminRoot.js +42 -0
  30. package/dist/tours/ToursAdminRoot.js.map +1 -0
  31. package/dist/tours/ToursAdminRoutes.d.ts +12 -0
  32. package/dist/tours/ToursAdminRoutes.d.ts.map +1 -0
  33. package/dist/tours/ToursAdminRoutes.js +109 -0
  34. package/dist/tours/ToursAdminRoutes.js.map +1 -0
  35. package/dist/tours/ToursRoot.d.ts +10 -0
  36. package/dist/tours/ToursRoot.d.ts.map +1 -0
  37. package/dist/tours/ToursRoot.js +1 -0
  38. package/dist/tours/ToursRoutes.d.ts +8 -0
  39. package/dist/tours/ToursRoutes.d.ts.map +1 -0
  40. package/dist/tours/ToursUserRoot.d.ts +15 -0
  41. package/dist/tours/ToursUserRoot.d.ts.map +1 -0
  42. package/dist/tours/ToursUserRoot.js +48 -0
  43. package/dist/tours/ToursUserRoot.js.map +1 -0
  44. package/dist/tours/ToursUserRoutes.d.ts +15 -0
  45. package/dist/tours/ToursUserRoutes.d.ts.map +1 -0
  46. package/dist/tours/ToursUserRoutes.js +66 -0
  47. package/dist/tours/ToursUserRoutes.js.map +1 -0
  48. package/dist/tours/components/RouteHelpers.d.ts +33 -0
  49. package/dist/tours/components/RouteHelpers.d.ts.map +1 -0
  50. package/dist/tours/components/RouteHelpers.js +75 -0
  51. package/dist/tours/components/RouteHelpers.js.map +1 -0
  52. package/dist/tours/components/ToursAdminNavRegistrar.d.ts +25 -0
  53. package/dist/tours/components/ToursAdminNavRegistrar.d.ts.map +1 -0
  54. package/dist/tours/components/ToursAdminNavRegistrar.js +60 -0
  55. package/dist/tours/components/ToursAdminNavRegistrar.js.map +1 -0
  56. package/dist/tours/components/ui.d.ts +2 -0
  57. package/dist/tours/components/ui.d.ts.map +1 -0
  58. package/dist/tours/hooks/useMediaLibrary.d.ts +22 -0
  59. package/dist/tours/hooks/useMediaLibrary.d.ts.map +1 -0
  60. package/dist/tours/hooks/useMediaLibrary.js +82 -0
  61. package/dist/tours/hooks/useMediaLibrary.js.map +1 -0
  62. package/dist/tours/hooks/useStepSequencer.d.ts +20 -0
  63. package/dist/tours/hooks/useStepSequencer.d.ts.map +1 -0
  64. package/dist/tours/hooks/useStepSequencer.js +53 -0
  65. package/dist/tours/hooks/useStepSequencer.js.map +1 -0
  66. package/dist/tours/hooks/useTourAnalytics.d.ts +32 -0
  67. package/dist/tours/hooks/useTourAnalytics.d.ts.map +1 -0
  68. package/dist/tours/hooks/useTourAnalytics.js +70 -0
  69. package/dist/tours/hooks/useTourAnalytics.js.map +1 -0
  70. package/dist/tours/hooks/useTourBuilder.d.ts +61 -0
  71. package/dist/tours/hooks/useTourBuilder.d.ts.map +1 -0
  72. package/dist/tours/hooks/useTourBuilder.js +192 -0
  73. package/dist/tours/hooks/useTourBuilder.js.map +1 -0
  74. package/dist/tours/hooks/useTourLifecycle.d.ts +22 -0
  75. package/dist/tours/hooks/useTourLifecycle.d.ts.map +1 -0
  76. package/dist/tours/hooks/useTourLifecycle.js +28 -0
  77. package/dist/tours/hooks/useTourLifecycle.js.map +1 -0
  78. package/dist/tours/hooks/useTourPreview.d.ts +33 -0
  79. package/dist/tours/hooks/useTourPreview.d.ts.map +1 -0
  80. package/dist/tours/hooks/useTourPreview.js +70 -0
  81. package/dist/tours/hooks/useTourPreview.js.map +1 -0
  82. package/dist/tours/hooks/useToursList.d.ts +30 -0
  83. package/dist/tours/hooks/useToursList.d.ts.map +1 -0
  84. package/dist/tours/hooks/useToursList.js +49 -0
  85. package/dist/tours/hooks/useToursList.js.map +1 -0
  86. package/dist/tours/hooks/useToursPermissionAccess.d.ts +16 -0
  87. package/dist/tours/hooks/useToursPermissionAccess.d.ts.map +1 -0
  88. package/dist/tours/hooks/useToursPermissionAccess.js +9 -0
  89. package/dist/tours/hooks/useToursPermissionAccess.js.map +1 -0
  90. package/dist/tours/i18n.d.ts +172 -0
  91. package/dist/tours/i18n.d.ts.map +1 -0
  92. package/dist/tours/i18n.js +175 -0
  93. package/dist/tours/i18n.js.map +1 -0
  94. package/dist/tours/index.d.ts +21 -0
  95. package/dist/tours/index.d.ts.map +1 -0
  96. package/dist/tours/index.js +5 -0
  97. package/dist/tours/pages/AnalyticsDashboardPage.d.ts +6 -0
  98. package/dist/tours/pages/AnalyticsDashboardPage.d.ts.map +1 -0
  99. package/dist/tours/pages/AnalyticsDashboardPage.js +230 -0
  100. package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -0
  101. package/dist/tours/pages/MediaLibraryPage.d.ts +6 -0
  102. package/dist/tours/pages/MediaLibraryPage.d.ts.map +1 -0
  103. package/dist/tours/pages/MediaLibraryPage.js +195 -0
  104. package/dist/tours/pages/MediaLibraryPage.js.map +1 -0
  105. package/dist/tours/pages/MyToursPage.d.ts +11 -0
  106. package/dist/tours/pages/MyToursPage.d.ts.map +1 -0
  107. package/dist/tours/pages/MyToursPage.js +103 -0
  108. package/dist/tours/pages/MyToursPage.js.map +1 -0
  109. package/dist/tours/pages/MyToursProgressPage.d.ts +6 -0
  110. package/dist/tours/pages/MyToursProgressPage.d.ts.map +1 -0
  111. package/dist/tours/pages/MyToursProgressPage.js +142 -0
  112. package/dist/tours/pages/MyToursProgressPage.js.map +1 -0
  113. package/dist/tours/pages/SchedulerPage.d.ts +6 -0
  114. package/dist/tours/pages/SchedulerPage.d.ts.map +1 -0
  115. package/dist/tours/pages/SchedulerPage.js +231 -0
  116. package/dist/tours/pages/SchedulerPage.js.map +1 -0
  117. package/dist/tours/pages/StepEditorPage.d.ts +7 -0
  118. package/dist/tours/pages/StepEditorPage.d.ts.map +1 -0
  119. package/dist/tours/pages/StepEditorPage.js +586 -0
  120. package/dist/tours/pages/StepEditorPage.js.map +1 -0
  121. package/dist/tours/pages/SystemAnalyticsPage.d.ts +6 -0
  122. package/dist/tours/pages/SystemAnalyticsPage.d.ts.map +1 -0
  123. package/dist/tours/pages/SystemAnalyticsPage.js +155 -0
  124. package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -0
  125. package/dist/tours/pages/TemplateLibraryPage.d.ts +6 -0
  126. package/dist/tours/pages/TemplateLibraryPage.d.ts.map +1 -0
  127. package/dist/tours/pages/TemplateLibraryPage.js +207 -0
  128. package/dist/tours/pages/TemplateLibraryPage.js.map +1 -0
  129. package/dist/tours/pages/TourBuilderPage.d.ts +6 -0
  130. package/dist/tours/pages/TourBuilderPage.d.ts.map +1 -0
  131. package/dist/tours/pages/TourBuilderPage.js +363 -0
  132. package/dist/tours/pages/TourBuilderPage.js.map +1 -0
  133. package/dist/tours/pages/TourPreviewPage.d.ts +6 -0
  134. package/dist/tours/pages/TourPreviewPage.d.ts.map +1 -0
  135. package/dist/tours/pages/TourPreviewPage.js +239 -0
  136. package/dist/tours/pages/TourPreviewPage.js.map +1 -0
  137. package/dist/tours/pages/ToursListPage.d.ts +6 -0
  138. package/dist/tours/pages/ToursListPage.d.ts.map +1 -0
  139. package/dist/tours/pages/ToursListPage.js +310 -0
  140. package/dist/tours/pages/ToursListPage.js.map +1 -0
  141. package/dist/tours/providers/ToursProvider.d.ts +27 -0
  142. package/dist/tours/providers/ToursProvider.d.ts.map +1 -0
  143. package/dist/tours/providers/ToursProvider.js +28 -0
  144. package/dist/tours/providers/ToursProvider.js.map +1 -0
  145. package/dist/tours/store/toursStore.d.ts +39 -0
  146. package/dist/tours/store/toursStore.d.ts.map +1 -0
  147. package/dist/tours/store/toursStore.js +143 -0
  148. package/dist/tours/store/toursStore.js.map +1 -0
  149. package/dist/tours/types/index.d.ts +350 -0
  150. package/dist/tours/types/index.d.ts.map +1 -0
  151. package/dist/tours/utils/cn.d.ts +8 -0
  152. package/dist/tours/utils/cn.d.ts.map +1 -0
  153. package/dist/tours/utils/index.d.ts +102 -0
  154. package/dist/tours/utils/index.d.ts.map +1 -0
  155. package/dist/tours/utils/index.js +28 -0
  156. package/dist/tours/utils/index.js.map +1 -0
  157. package/dist/tours/utils/joinPath.d.ts +9 -0
  158. package/dist/tours/utils/joinPath.d.ts.map +1 -0
  159. package/dist/tours/utils/joinPath.js +8 -0
  160. package/dist/tours/utils/joinPath.js.map +1 -0
  161. package/dist/utils/nativeBridge.d.ts +3 -0
  162. package/dist/utils/nativeBridge.d.ts.map +1 -0
  163. package/dist/utils/nativeBridge.js +2 -0
  164. package/package.json +114 -0
@@ -0,0 +1,60 @@
1
+ import { TOURS_FEATURES as e } from "../../constants/featureFlags.js";
2
+ import { joinPath as t } from "../utils/joinPath.js";
3
+ import { useEffect as n, useMemo as r, useRef as i } from "react";
4
+ import { useFeatureFlag as a } from "@burdenoff/fe-libs/shared/feature-flags";
5
+ import { BarChart3 as o, Image as s, LayoutTemplate as c, List as l, Plus as u } from "lucide-react";
6
+ import { jsx as d } from "react/jsx-runtime";
7
+ //#region src/tours/components/ToursAdminNavRegistrar.tsx
8
+ function f({ basePath: f, registerNavItems: p }) {
9
+ let m = a(e.MEDIA, !1), h = i(p);
10
+ h.current = p;
11
+ let g = r(() => {
12
+ let e = [
13
+ {
14
+ id: "tours-list",
15
+ label: "All Tours",
16
+ path: t(f, "list"),
17
+ icon: /* @__PURE__ */ d(l, { size: 20 }),
18
+ order: 10,
19
+ group: "tours"
20
+ },
21
+ {
22
+ id: "tours-new",
23
+ label: "Create Tour",
24
+ path: t(f, "new"),
25
+ icon: /* @__PURE__ */ d(u, { size: 20 }),
26
+ order: 20,
27
+ group: "tours"
28
+ },
29
+ {
30
+ id: "tours-templates",
31
+ label: "Templates",
32
+ path: t(f, "templates"),
33
+ icon: /* @__PURE__ */ d(c, { size: 20 }),
34
+ order: 30,
35
+ group: "tours"
36
+ },
37
+ {
38
+ id: "tours-analytics",
39
+ label: "Analytics",
40
+ path: t(f, "analytics"),
41
+ icon: /* @__PURE__ */ d(o, { size: 20 }),
42
+ order: 50,
43
+ group: "tours"
44
+ }
45
+ ];
46
+ return m && e.push({
47
+ id: "tours-media",
48
+ label: "Media Library",
49
+ path: t(f, "media"),
50
+ icon: /* @__PURE__ */ d(s, { size: 20 }),
51
+ order: 40,
52
+ group: "tours"
53
+ }), e;
54
+ }, [f, m]);
55
+ return n(() => h.current(g), [g]), null;
56
+ }
57
+ //#endregion
58
+ export { f as ToursAdminNavRegistrar };
59
+
60
+ //# sourceMappingURL=ToursAdminNavRegistrar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToursAdminNavRegistrar.js","names":[],"sources":["../../../src/tours/components/ToursAdminNavRegistrar.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef } from 'react';\nimport { useFeatureFlag } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { List, Plus, LayoutTemplate, Image, BarChart3 } from 'lucide-react';\n\nimport { TOURS_FEATURES } from '../../constants/featureFlags';\nimport type { NavItem } from '../types';\nimport { joinPath } from '../utils/joinPath';\n\ninterface ToursAdminNavRegistrarProps {\n basePath: string;\n registerNavItems: (items: NavItem | NavItem[]) => () => void;\n}\n\n/**\n * Registers the admin tours nav items with the host shell.\n *\n * Rendered inside `<FeatureFlagProvider>` so it can consult `useFeatureFlag`\n * to conditionally include flag-gated items. Re-registers whenever flag state\n * changes so the host shell's nav reflects the current evaluation in real time.\n *\n * Baseline items (always registered): All Tours, Create Tour, Templates,\n * Analytics. Media Library is gated on `tours.media` because the upload\n * pipeline is still incomplete — the nav item appears only when the flag is\n * enabled for the workspace or the user has opted in via Feature Previews.\n *\n * `registerNavItems` is captured in a ref so a host shell that hands over a\n * fresh closure on every render can't trigger an unregister → re-register\n * storm. Only flag-state / `basePath` changes cause re-registration.\n */\nexport function ToursAdminNavRegistrar({\n basePath,\n registerNavItems,\n}: ToursAdminNavRegistrarProps) {\n const mediaEnabled = useFeatureFlag(TOURS_FEATURES.MEDIA, false);\n\n const registerNavItemsRef = useRef(registerNavItems);\n registerNavItemsRef.current = registerNavItems;\n\n const navItems = useMemo<NavItem[]>(() => {\n const items: NavItem[] = [\n {\n id: 'tours-list',\n label: 'All Tours',\n path: joinPath(basePath, 'list'),\n icon: <List size={20} />,\n order: 10,\n group: 'tours',\n },\n {\n id: 'tours-new',\n label: 'Create Tour',\n path: joinPath(basePath, 'new'),\n icon: <Plus size={20} />,\n order: 20,\n group: 'tours',\n },\n {\n id: 'tours-templates',\n label: 'Templates',\n path: joinPath(basePath, 'templates'),\n icon: <LayoutTemplate size={20} />,\n order: 30,\n group: 'tours',\n },\n {\n id: 'tours-analytics',\n label: 'Analytics',\n path: joinPath(basePath, 'analytics'),\n icon: <BarChart3 size={20} />,\n order: 50,\n group: 'tours',\n },\n ];\n\n if (mediaEnabled) {\n items.push({\n id: 'tours-media',\n label: 'Media Library',\n path: joinPath(basePath, 'media'),\n icon: <Image size={20} />,\n order: 40,\n group: 'tours',\n });\n }\n\n return items;\n }, [basePath, mediaEnabled]);\n\n useEffect(() => {\n const unregister = registerNavItemsRef.current(navItems);\n return unregister;\n }, [navItems]);\n\n return null;\n}\n"],"mappings":";;;;;;;AA6BA,SAAgB,EAAuB,EACrC,aACA,uBAC8B;CAC9B,IAAM,IAAe,EAAe,EAAe,OAAO,GAAM,EAE1D,IAAsB,EAAO,EAAiB;AACpD,GAAoB,UAAU;CAE9B,IAAM,IAAW,QAAyB;EACxC,IAAM,IAAmB;GACvB;IACE,IAAI;IACJ,OAAO;IACP,MAAM,EAAS,GAAU,OAAO;IAChC,MAAM,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IACxB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO;IACP,MAAM,EAAS,GAAU,MAAM;IAC/B,MAAM,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IACxB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO;IACP,MAAM,EAAS,GAAU,YAAY;IACrC,MAAM,kBAAC,GAAD,EAAgB,MAAM,IAAM,CAAA;IAClC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO;IACP,MAAM,EAAS,GAAU,YAAY;IACrC,MAAM,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;IAC7B,OAAO;IACP,OAAO;IACR;GACF;AAaD,SAXI,KACF,EAAM,KAAK;GACT,IAAI;GACJ,OAAO;GACP,MAAM,EAAS,GAAU,QAAQ;GACjC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;GACzB,OAAO;GACP,OAAO;GACR,CAAC,EAGG;IACN,CAAC,GAAU,EAAa,CAAC;AAO5B,QALA,QACqB,EAAoB,QAAQ,EAAS,EAEvD,CAAC,EAAS,CAAC,EAEP"}
@@ -0,0 +1,2 @@
1
+ export { Badge, Button, Card, CardContent, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Skeleton, Tabs, TabsContent, TabsList, TabsTrigger, } from '@burdenoff/fe-libs/ui';
2
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/tours/components/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,MAAM,EACN,IAAI,EACJ,WAAW,EACX,KAAK,EACL,MAAM,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACb,WAAW,EACX,SAAS,EACT,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,WAAW,GACZ,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { TourMedia, TourMediaType, MediaPosition } from '../types';
2
+
3
+ /**
4
+ * Hook for media library functionality
5
+ * Manages media upload, browsing, and attachment
6
+ * All media is now global (no workspace scoping)
7
+ */
8
+ export declare function useMediaLibrary(): {
9
+ media: TourMedia[];
10
+ selectedMedia: TourMedia[];
11
+ uploadProgress: Record<string, number>;
12
+ loading: boolean;
13
+ error: Error | null;
14
+ fetchMedia: (_type?: TourMediaType, _search?: string) => Promise<void>;
15
+ uploadMedia: (file: File, metadata?: Partial<TourMedia>) => Promise<any>;
16
+ deleteMedia: (mediaId: string) => Promise<void>;
17
+ selectMedia: (media: TourMedia) => void;
18
+ unselectMedia: (mediaId: string) => void;
19
+ clearSelectedMedia: () => void;
20
+ attachToStep: (stepId: string, mediaId: string, position: MediaPosition, displayOrder: number) => Promise<any>;
21
+ };
22
+ //# sourceMappingURL=useMediaLibrary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaLibrary.d.ts","sourceRoot":"","sources":["../../../src/tours/hooks/useMediaLibrary.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,eAAe;;;;;;yBAoDZ,aAAa,YAAY,MAAM;wBAYjC,IAAI,aAAa,OAAO,CAAC,SAAS,CAAC;2BAuChC,MAAM;;;;2BAcP,MAAM,WAAW,MAAM,YAAY,aAAa,gBAAgB,MAAM;EAiCxF"}
@@ -0,0 +1,82 @@
1
+ import { useAttachMediaToStepMutation as e, useDeleteTourMediaMutation as t, useGetTourMediaQuery as n, useUploadTourMediaMutation as r } from "../../generated/global-operations.js";
2
+ import { useToursStore as i } from "../store/toursStore.js";
3
+ import { useCallback as a, useMemo as o } from "react";
4
+ //#region src/tours/hooks/useMediaLibrary.ts
5
+ function s() {
6
+ let { selectedMedia: s, uploadProgress: l, selectMedia: u, unselectMedia: d, clearSelectedMedia: f, updateUploadProgress: p, removeUploadProgress: m } = i(), { data: h, loading: g, error: _, refetch: v } = n(), [y] = r(), [b] = t(), [x] = e();
7
+ return {
8
+ media: o(() => h?.tourMedia ? h.tourMedia.map((e) => ({
9
+ id: e.id,
10
+ name: e.name,
11
+ type: e.type,
12
+ cdnUrl: e.cdnUrl || e.storageUrl,
13
+ mimeType: e.mimeType,
14
+ size: e.size,
15
+ duration: e.duration ?? void 0,
16
+ width: e.width ?? void 0,
17
+ height: e.height ?? void 0,
18
+ altText: e.altText ?? void 0,
19
+ caption: e.caption ?? void 0,
20
+ transcript: e.transcript ?? void 0,
21
+ metadata: e.metadata ?? void 0,
22
+ createdBy: e.uploadedBy || "",
23
+ createdAt: e.createdAt,
24
+ updatedAt: e.updatedAt
25
+ })) : [], [h]),
26
+ selectedMedia: s,
27
+ uploadProgress: l,
28
+ loading: g,
29
+ error: _ ? Error(_.message) : null,
30
+ fetchMedia: a(async (e, t) => {
31
+ await v();
32
+ }, [v]),
33
+ uploadMedia: a(async (e, t) => {
34
+ let n = `upload_${Date.now()}`;
35
+ p(n, 0);
36
+ try {
37
+ p(n, 50);
38
+ let r = await y({ variables: { input: {
39
+ name: t?.name || e.name,
40
+ type: c(e.type),
41
+ storageUrl: `/uploads/tours/${Date.now()}-${e.name}`,
42
+ storagePath: `tours/${Date.now()}-${e.name}`,
43
+ mimeType: e.type,
44
+ size: e.size,
45
+ altText: t?.altText,
46
+ caption: t?.caption
47
+ } } });
48
+ return p(n, 100), m(n), await v(), r.data?.uploadTourMedia ?? null;
49
+ } catch (e) {
50
+ throw m(n), e;
51
+ }
52
+ }, [
53
+ y,
54
+ p,
55
+ m,
56
+ v
57
+ ]),
58
+ deleteMedia: a(async (e) => {
59
+ await b({ variables: { id: e } }), d(e), await v();
60
+ }, [
61
+ b,
62
+ d,
63
+ v
64
+ ]),
65
+ selectMedia: u,
66
+ unselectMedia: d,
67
+ clearSelectedMedia: f,
68
+ attachToStep: a(async (e, t, n, r) => (await x({ variables: { input: {
69
+ stepId: e,
70
+ mediaId: t,
71
+ position: n === "body" ? "INLINE" : n.toUpperCase(),
72
+ metadata: r > 0 ? { displayOrder: r } : void 0
73
+ } } })).data?.attachMediaToStep ?? null, [x])
74
+ };
75
+ }
76
+ function c(e) {
77
+ return e.startsWith("image/") ? "IMAGE" : e.startsWith("video/") ? "VIDEO" : e.startsWith("audio/") ? "AUDIO" : "DOCUMENT";
78
+ }
79
+ //#endregion
80
+ export { s as useMediaLibrary };
81
+
82
+ //# sourceMappingURL=useMediaLibrary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaLibrary.js","names":[],"sources":["../../../src/tours/hooks/useMediaLibrary.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { useToursStore } from '../store/toursStore';\nimport {\n useGetTourMediaQuery,\n useUploadTourMediaMutation,\n useDeleteTourMediaMutation,\n useAttachMediaToStepMutation,\n} from '../../generated/global-operations';\nimport type { TourMedia as ApiTourMedia } from '../../generated/global-types';\nimport type { TourMedia, TourMediaType, MediaPosition } from '../types';\n\n/**\n * Hook for media library functionality\n * Manages media upload, browsing, and attachment\n * All media is now global (no workspace scoping)\n */\nexport function useMediaLibrary() {\n const {\n selectedMedia,\n uploadProgress,\n selectMedia,\n unselectMedia,\n clearSelectedMedia,\n updateUploadProgress,\n removeUploadProgress,\n } = useToursStore();\n\n // Fetch media from API\n const { data, loading, error: queryError, refetch } = useGetTourMediaQuery();\n\n // Upload media mutation\n const [uploadTourMediaMutation] = useUploadTourMediaMutation();\n\n // Delete media mutation\n const [deleteTourMediaMutation] = useDeleteTourMediaMutation();\n\n // Attach media to step mutation\n const [attachMediaToStepMutation] = useAttachMediaToStepMutation();\n\n // Transform API response to match our TourMedia type\n const media: TourMedia[] = useMemo(() => {\n if (!data?.tourMedia) return [];\n return data.tourMedia.map((m: ApiTourMedia) => ({\n id: m.id,\n name: m.name,\n type: m.type as TourMediaType,\n cdnUrl: m.cdnUrl || m.storageUrl,\n mimeType: m.mimeType,\n size: m.size,\n duration: m.duration ?? undefined,\n width: m.width ?? undefined,\n height: m.height ?? undefined,\n altText: m.altText ?? undefined,\n caption: m.caption ?? undefined,\n transcript: m.transcript ?? undefined,\n metadata: m.metadata ?? undefined,\n createdBy: m.uploadedBy || '',\n createdAt: m.createdAt,\n updatedAt: m.updatedAt,\n }));\n }, [data]);\n\n const error = queryError ? new Error(queryError.message) : null;\n\n /**\n * Fetch/refetch media library\n */\n const fetchMedia = useCallback(\n async (_type?: TourMediaType, _search?: string) => {\n // Note: type and search filtering will be done client-side\n // since the API doesn't support these filters yet\n await refetch();\n },\n [refetch]\n );\n\n /**\n * Upload media file\n */\n const uploadMedia = useCallback(\n async (file: File, metadata?: Partial<TourMedia>) => {\n const fileId = `upload_${Date.now()}`;\n updateUploadProgress(fileId, 0);\n\n try {\n updateUploadProgress(fileId, 50);\n\n const result = await uploadTourMediaMutation({\n variables: {\n input: {\n name: metadata?.name || file.name,\n type: getMediaType(file.type),\n storageUrl: `/uploads/tours/${Date.now()}-${file.name}`,\n storagePath: `tours/${Date.now()}-${file.name}`,\n mimeType: file.type,\n size: file.size,\n altText: metadata?.altText,\n caption: metadata?.caption,\n },\n },\n });\n\n updateUploadProgress(fileId, 100);\n removeUploadProgress(fileId);\n await refetch();\n\n return result.data?.uploadTourMedia ?? null;\n } catch (err) {\n removeUploadProgress(fileId);\n throw err;\n }\n },\n [uploadTourMediaMutation, updateUploadProgress, removeUploadProgress, refetch]\n );\n\n /**\n * Delete media\n */\n const deleteMedia = useCallback(\n async (mediaId: string) => {\n await deleteTourMediaMutation({\n variables: { id: mediaId },\n });\n unselectMedia(mediaId);\n await refetch();\n },\n [deleteTourMediaMutation, unselectMedia, refetch]\n );\n\n /**\n * Attach media to step\n */\n const attachToStep = useCallback(\n async (stepId: string, mediaId: string, position: MediaPosition, displayOrder: number) => {\n const result = await attachMediaToStepMutation({\n variables: {\n input: {\n stepId,\n mediaId,\n position:\n position === 'body'\n ? 'INLINE'\n : (position.toUpperCase() as 'HEADER' | 'INLINE' | 'FOOTER'),\n metadata: displayOrder > 0 ? { displayOrder } : undefined,\n },\n },\n });\n return result.data?.attachMediaToStep ?? null;\n },\n [attachMediaToStepMutation]\n );\n\n return {\n media,\n selectedMedia,\n uploadProgress,\n loading,\n error,\n fetchMedia,\n uploadMedia,\n deleteMedia,\n selectMedia,\n unselectMedia,\n clearSelectedMedia,\n attachToStep,\n };\n}\n\n/**\n * Helper to determine media type from MIME type\n */\nfunction getMediaType(mimeType: string): 'IMAGE' | 'VIDEO' | 'AUDIO' | 'DOCUMENT' {\n if (mimeType.startsWith('image/')) return 'IMAGE';\n if (mimeType.startsWith('video/')) return 'VIDEO';\n if (mimeType.startsWith('audio/')) return 'AUDIO';\n return 'DOCUMENT';\n}\n"],"mappings":";;;;AAgBA,SAAgB,IAAkB;CAChC,IAAM,EACJ,kBACA,mBACA,gBACA,kBACA,uBACA,yBACA,4BACE,GAAe,EAGb,EAAE,SAAM,YAAS,OAAO,GAAY,eAAY,GAAsB,EAGtE,CAAC,KAA2B,GAA4B,EAGxD,CAAC,KAA2B,GAA4B,EAGxD,CAAC,KAA6B,GAA8B;AAmHlE,QAAO;EACL,OAjHyB,QACpB,GAAM,YACJ,EAAK,UAAU,KAAK,OAAqB;GAC9C,IAAI,EAAE;GACN,MAAM,EAAE;GACR,MAAM,EAAE;GACR,QAAQ,EAAE,UAAU,EAAE;GACtB,UAAU,EAAE;GACZ,MAAM,EAAE;GACR,UAAU,EAAE,YAAY,KAAA;GACxB,OAAO,EAAE,SAAS,KAAA;GAClB,QAAQ,EAAE,UAAU,KAAA;GACpB,SAAS,EAAE,WAAW,KAAA;GACtB,SAAS,EAAE,WAAW,KAAA;GACtB,YAAY,EAAE,cAAc,KAAA;GAC5B,UAAU,EAAE,YAAY,KAAA;GACxB,WAAW,EAAE,cAAc;GAC3B,WAAW,EAAE;GACb,WAAW,EAAE;GACd,EAAE,GAlB0B,EAAE,EAmB9B,CAAC,EAAK,CAAC;EA8FR;EACA;EACA;EACA,OA/FY,IAAiB,MAAM,EAAW,QAAQ,GAAG;EAgGzD,YA3FiB,EACjB,OAAO,GAAuB,MAAqB;AAGjD,SAAM,GAAS;KAEjB,CAAC,EAAQ,CACV;EAqFC,aAhFkB,EAClB,OAAO,GAAY,MAAkC;GACnD,IAAM,IAAS,UAAU,KAAK,KAAK;AACnC,KAAqB,GAAQ,EAAE;AAE/B,OAAI;AACF,MAAqB,GAAQ,GAAG;IAEhC,IAAM,IAAS,MAAM,EAAwB,EAC3C,WAAW,EACT,OAAO;KACL,MAAM,GAAU,QAAQ,EAAK;KAC7B,MAAM,EAAa,EAAK,KAAK;KAC7B,YAAY,kBAAkB,KAAK,KAAK,CAAC,GAAG,EAAK;KACjD,aAAa,SAAS,KAAK,KAAK,CAAC,GAAG,EAAK;KACzC,UAAU,EAAK;KACf,MAAM,EAAK;KACX,SAAS,GAAU;KACnB,SAAS,GAAU;KACpB,EACF,EACF,CAAC;AAMF,WAJA,EAAqB,GAAQ,IAAI,EACjC,EAAqB,EAAO,EAC5B,MAAM,GAAS,EAER,EAAO,MAAM,mBAAmB;YAChC,GAAK;AAEZ,UADA,EAAqB,EAAO,EACtB;;KAGV;GAAC;GAAyB;GAAsB;GAAsB;GAAQ,CAC/E;EA+CC,aA1CkB,EAClB,OAAO,MAAoB;AAKzB,GAJA,MAAM,EAAwB,EAC5B,WAAW,EAAE,IAAI,GAAS,EAC3B,CAAC,EACF,EAAc,EAAQ,EACtB,MAAM,GAAS;KAEjB;GAAC;GAAyB;GAAe;GAAQ,CAClD;EAkCC;EACA;EACA;EACA,cAhCmB,EACnB,OAAO,GAAgB,GAAiB,GAAyB,OAChD,MAAM,EAA0B,EAC7C,WAAW,EACT,OAAO;GACL;GACA;GACA,UACE,MAAa,SACT,WACC,EAAS,aAAa;GAC7B,UAAU,IAAe,IAAI,EAAE,iBAAc,GAAG,KAAA;GACjD,EACF,EACF,CAAC,EACY,MAAM,qBAAqB,MAE3C,CAAC,EAA0B,CAC5B;EAeA;;AAMH,SAAS,EAAa,GAA4D;AAIhF,QAHI,EAAS,WAAW,SAAS,GAAS,UACtC,EAAS,WAAW,SAAS,GAAS,UACtC,EAAS,WAAW,SAAS,GAAS,UACnC"}
@@ -0,0 +1,20 @@
1
+ import { TourStep, StepPlacement } from '../types';
2
+
3
+ /**
4
+ * Hook for step sequencer functionality
5
+ * Manages step creation, reordering, and editing locally.
6
+ * Steps are persisted to backend via useTourBuilder.syncSteps()
7
+ */
8
+ export declare function useStepSequencer(): {
9
+ steps: TourStep[];
10
+ selectedStep: TourStep | null;
11
+ selectStep: (step: TourStep | null) => void;
12
+ createStep: (stepData?: Partial<TourStep>) => void;
13
+ deleteStep: (stepId: string) => void;
14
+ updateStepField: (stepId: string, field: keyof TourStep, value: unknown) => void;
15
+ setStepSelector: (stepId: string, selector: string, deviceType?: "mobile" | "tablet" | "desktop") => void;
16
+ setStepPlacement: (stepId: string, placement: StepPlacement) => void;
17
+ moveStep: (fromIndex: number, toIndex: number) => void;
18
+ duplicateStep: (stepId: string) => void;
19
+ };
20
+ //# sourceMappingURL=useStepSequencer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStepSequencer.d.ts","sourceRoot":"","sources":["../../../src/tours/hooks/useStepSequencer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,gBAAgB;;;;4BAehB,OAAO,CAAC,QAAQ,CAAC;yBAkBpB,MAAM;8BAaN,MAAM,SAAS,MAAM,QAAQ,SAAS,OAAO;8BAU7C,MAAM,YAAY,MAAM,eAAe,QAAQ,GAAG,QAAQ,GAAG,SAAS;+BAkBtE,MAAM,aAAa,aAAa;0BAU7B,MAAM,WAAW,MAAM;4BAU1B,MAAM;EA2BlB"}
@@ -0,0 +1,53 @@
1
+ import { useToursStore as e } from "../store/toursStore.js";
2
+ import { useCallback as t } from "react";
3
+ //#region src/tours/hooks/useStepSequencer.ts
4
+ function n() {
5
+ let { stepSequence: n, selectedStep: r, setSelectedStep: i, addStep: a, removeStep: o, updateStep: s, reorderSteps: c } = e();
6
+ return {
7
+ steps: n,
8
+ selectedStep: r,
9
+ selectStep: i,
10
+ createStep: t((e) => {
11
+ a({
12
+ title: e?.title || "New Step",
13
+ content: e?.content || "",
14
+ targetSelector: e?.targetSelector || "",
15
+ placement: e?.placement || "AUTO",
16
+ stepOrder: n.length + 1,
17
+ ...e
18
+ });
19
+ }, [a, n.length]),
20
+ deleteStep: t((e) => {
21
+ o(e), r?.id === e && i(null);
22
+ }, [
23
+ o,
24
+ r,
25
+ i
26
+ ]),
27
+ updateStepField: t((e, t, n) => {
28
+ s(e, { [t]: n });
29
+ }, [s]),
30
+ setStepSelector: t((e, t, n) => {
31
+ n === "mobile" ? s(e, { targetSelectorMobile: t }) : n === "tablet" ? s(e, { targetSelectorTablet: t }) : n === "desktop" ? s(e, { targetSelectorDesktop: t }) : s(e, { targetSelector: t });
32
+ }, [s]),
33
+ setStepPlacement: t((e, t) => {
34
+ s(e, { placement: t });
35
+ }, [s]),
36
+ moveStep: t((e, t) => {
37
+ c(e, t);
38
+ }, [c]),
39
+ duplicateStep: t((e) => {
40
+ let t = n.find((t) => t.id === e);
41
+ t && a({
42
+ ...t,
43
+ id: void 0,
44
+ title: `${t.title} (Copy)`,
45
+ stepOrder: n.length
46
+ });
47
+ }, [n, a])
48
+ };
49
+ }
50
+ //#endregion
51
+ export { n as useStepSequencer };
52
+
53
+ //# sourceMappingURL=useStepSequencer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStepSequencer.js","names":[],"sources":["../../../src/tours/hooks/useStepSequencer.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useToursStore } from '../store/toursStore';\nimport type { TourStep, StepPlacement } from '../types';\n\n/**\n * Hook for step sequencer functionality\n * Manages step creation, reordering, and editing locally.\n * Steps are persisted to backend via useTourBuilder.syncSteps()\n */\nexport function useStepSequencer() {\n const {\n stepSequence,\n selectedStep,\n setSelectedStep,\n addStep,\n removeStep,\n updateStep,\n reorderSteps,\n } = useToursStore();\n\n /**\n * Create new step\n */\n const createStep = useCallback(\n (stepData?: Partial<TourStep>) => {\n const newStep: Partial<TourStep> = {\n title: stepData?.title || 'New Step',\n content: stepData?.content || '',\n targetSelector: stepData?.targetSelector || '',\n placement: stepData?.placement || 'AUTO',\n stepOrder: stepSequence.length + 1,\n ...stepData,\n };\n addStep(newStep);\n },\n [addStep, stepSequence.length]\n );\n\n /**\n * Delete step\n */\n const deleteStep = useCallback(\n (stepId: string) => {\n removeStep(stepId);\n if (selectedStep?.id === stepId) {\n setSelectedStep(null);\n }\n },\n [removeStep, selectedStep, setSelectedStep]\n );\n\n /**\n * Update step field\n */\n const updateStepField = useCallback(\n (stepId: string, field: keyof TourStep, value: unknown) => {\n updateStep(stepId, { [field]: value });\n },\n [updateStep]\n );\n\n /**\n * Set step target selector\n */\n const setStepSelector = useCallback(\n (stepId: string, selector: string, deviceType?: 'mobile' | 'tablet' | 'desktop') => {\n if (deviceType === 'mobile') {\n updateStep(stepId, { targetSelectorMobile: selector });\n } else if (deviceType === 'tablet') {\n updateStep(stepId, { targetSelectorTablet: selector });\n } else if (deviceType === 'desktop') {\n updateStep(stepId, { targetSelectorDesktop: selector });\n } else {\n updateStep(stepId, { targetSelector: selector });\n }\n },\n [updateStep]\n );\n\n /**\n * Set step placement\n */\n const setStepPlacement = useCallback(\n (stepId: string, placement: StepPlacement) => {\n updateStep(stepId, { placement });\n },\n [updateStep]\n );\n\n /**\n * Move step\n */\n const moveStep = useCallback(\n (fromIndex: number, toIndex: number) => {\n reorderSteps(fromIndex, toIndex);\n },\n [reorderSteps]\n );\n\n /**\n * Duplicate step\n */\n const duplicateStep = useCallback(\n (stepId: string) => {\n const step = stepSequence.find((s) => s.id === stepId);\n if (step) {\n const duplicatedStep: Partial<TourStep> = {\n ...step,\n id: undefined,\n title: `${step.title} (Copy)`,\n stepOrder: stepSequence.length,\n };\n addStep(duplicatedStep);\n }\n },\n [stepSequence, addStep]\n );\n\n return {\n steps: stepSequence,\n selectedStep,\n selectStep: setSelectedStep,\n createStep,\n deleteStep,\n updateStepField,\n setStepSelector,\n setStepPlacement,\n moveStep,\n duplicateStep,\n };\n}\n"],"mappings":";;;AASA,SAAgB,IAAmB;CACjC,IAAM,EACJ,iBACA,iBACA,oBACA,YACA,eACA,eACA,oBACE,GAAe;AAoGnB,QAAO;EACL,OAAO;EACP;EACA,YAAY;EACZ,YAnGiB,GAChB,MAAiC;AAShC,KARmC;IACjC,OAAO,GAAU,SAAS;IAC1B,SAAS,GAAU,WAAW;IAC9B,gBAAgB,GAAU,kBAAkB;IAC5C,WAAW,GAAU,aAAa;IAClC,WAAW,EAAa,SAAS;IACjC,GAAG;IACJ,CACe;KAElB,CAAC,GAAS,EAAa,OAAO,CAC/B;EAuFC,YAlFiB,GAChB,MAAmB;AAElB,GADA,EAAW,EAAO,EACd,GAAc,OAAO,KACvB,EAAgB,KAAK;KAGzB;GAAC;GAAY;GAAc;GAAgB,CAC5C;EA2EC,iBAtEsB,GACrB,GAAgB,GAAuB,MAAmB;AACzD,KAAW,GAAQ,GAAG,IAAQ,GAAO,CAAC;KAExC,CAAC,EAAW,CACb;EAkEC,iBA7DsB,GACrB,GAAgB,GAAkB,MAAiD;AAClF,GAAI,MAAe,WACjB,EAAW,GAAQ,EAAE,sBAAsB,GAAU,CAAC,GAC7C,MAAe,WACxB,EAAW,GAAQ,EAAE,sBAAsB,GAAU,CAAC,GAC7C,MAAe,YACxB,EAAW,GAAQ,EAAE,uBAAuB,GAAU,CAAC,GAEvD,EAAW,GAAQ,EAAE,gBAAgB,GAAU,CAAC;KAGpD,CAAC,EAAW,CACb;EAiDC,kBA5CuB,GACtB,GAAgB,MAA6B;AAC5C,KAAW,GAAQ,EAAE,cAAW,CAAC;KAEnC,CAAC,EAAW,CACb;EAwCC,UAnCe,GACd,GAAmB,MAAoB;AACtC,KAAa,GAAW,EAAQ;KAElC,CAAC,EAAa,CACf;EA+BC,eA1BoB,GACnB,MAAmB;GAClB,IAAM,IAAO,EAAa,MAAM,MAAM,EAAE,OAAO,EAAO;AACtD,GAAI,KAOF,EAN0C;IACxC,GAAG;IACH,IAAI,KAAA;IACJ,OAAO,GAAG,EAAK,MAAM;IACrB,WAAW,EAAa;IACzB,CACsB;KAG3B,CAAC,GAAc,EAAQ,CACxB;EAaA"}
@@ -0,0 +1,32 @@
1
+ import { TourAnalytics } from '../types';
2
+
3
+ /**
4
+ * Hook for tour analytics functionality
5
+ * Fetches and processes tour performance data
6
+ */
7
+ export declare function useTourAnalytics(tourId?: string): {
8
+ analytics: TourAnalytics | null;
9
+ loading: boolean;
10
+ error: import('@apollo/client').ApolloError | undefined;
11
+ fetchAnalytics: (_dateRange?: {
12
+ start: string;
13
+ end: string;
14
+ }) => Promise<void>;
15
+ getCompletionRate: () => number;
16
+ getSkipRate: () => number;
17
+ getBestDevice: () => {
18
+ deviceType: import('../types').DeviceType;
19
+ count: number;
20
+ completionRate: number;
21
+ } | null;
22
+ getHighestDropOffStep: () => {
23
+ stepId: string;
24
+ stepOrder: number;
25
+ views: number;
26
+ completions: number;
27
+ dropOffRate: number;
28
+ averageDuration: number;
29
+ } | null;
30
+ exportAnalytics: (format: "csv" | "pdf" | "json") => Promise<void>;
31
+ };
32
+ //# sourceMappingURL=useTourAnalytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTourAnalytics.d.ts","sourceRoot":"","sources":["../../../src/tours/hooks/useTourAnalytics.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM;;;;kCA2CxB;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;8BAiDnC,KAAK,GAAG,KAAK,GAAG,MAAM;EAiDxC"}
@@ -0,0 +1,70 @@
1
+ import { useGetTourAnalyticsQuery as e } from "../../generated/global-operations.js";
2
+ import { useCallback as t, useMemo as n } from "react";
3
+ //#region src/tours/hooks/useTourAnalytics.ts
4
+ function r(r) {
5
+ let { data: i, loading: a, error: o, refetch: s } = e({
6
+ variables: { tourId: r },
7
+ skip: !r
8
+ }), c = n(() => {
9
+ if (!i?.tourAnalytics || !r) return null;
10
+ let { tourAnalytics: e, tourStepAnalytics: t } = i;
11
+ return {
12
+ tourId: r,
13
+ totalViews: e.totalViews,
14
+ totalCompletions: e.totalCompletions,
15
+ totalSkips: e.totalSkips,
16
+ averageCompletionRate: e.averageCompletionRate,
17
+ averageDuration: e.averageDuration,
18
+ byDeviceType: e.byDeviceType.map((e) => ({
19
+ deviceType: e.deviceType.toLowerCase(),
20
+ count: e.count,
21
+ completionRate: e.completionRate
22
+ })),
23
+ byEventType: e.byEventType.map((e) => ({
24
+ eventType: e.eventType,
25
+ count: e.count
26
+ })),
27
+ stepAnalytics: t.map((e, t) => ({
28
+ stepId: e.stepId,
29
+ stepOrder: t + 1,
30
+ views: e.viewCount,
31
+ completions: e.completionCount,
32
+ dropOffRate: e.viewCount > 0 ? (e.viewCount - e.completionCount) / e.viewCount * 100 : 0,
33
+ averageDuration: e.averageDuration
34
+ }))
35
+ };
36
+ }, [i, r]);
37
+ return {
38
+ analytics: c,
39
+ loading: a,
40
+ error: o,
41
+ fetchAnalytics: t(async (e) => {
42
+ r && await s();
43
+ }, [r, s]),
44
+ getCompletionRate: t(() => !c || c.totalViews === 0 ? 0 : c.totalCompletions / c.totalViews * 100, [c]),
45
+ getSkipRate: t(() => !c || c.totalViews === 0 ? 0 : c.totalSkips / c.totalViews * 100, [c]),
46
+ getBestDevice: t(() => !c || c.byDeviceType.length === 0 ? null : c.byDeviceType.reduce((e, t) => t.completionRate > e.completionRate ? t : e), [c]),
47
+ getHighestDropOffStep: t(() => !c || !c.stepAnalytics || c.stepAnalytics.length === 0 ? null : c.stepAnalytics.reduce((e, t) => t.dropOffRate > e.dropOffRate ? t : e), [c]),
48
+ exportAnalytics: t(async (e) => {
49
+ if (!c) return;
50
+ let t, n, r;
51
+ if (e === "json") t = JSON.stringify(c, null, 2), n = "application/json", r = "json";
52
+ else if (e === "csv") {
53
+ let e = ["Metric", "Value"], i = [
54
+ ["Total Views", String(c.totalViews)],
55
+ ["Total Completions", String(c.totalCompletions)],
56
+ ["Total Skips", String(c.totalSkips)],
57
+ ["Completion Rate", `${c.averageCompletionRate.toFixed(2)}%`],
58
+ ["Average Duration (s)", String(c.averageDuration)]
59
+ ];
60
+ t = [e.join(","), ...i.map((e) => e.join(","))].join("\n"), n = "text/csv", r = "csv";
61
+ } else return;
62
+ let i = new Blob([t], { type: n }), a = URL.createObjectURL(i), o = document.createElement("a");
63
+ o.href = a, o.download = `tour-analytics-${c.tourId}.${r}`, o.click(), setTimeout(() => URL.revokeObjectURL(a), 100);
64
+ }, [c])
65
+ };
66
+ }
67
+ //#endregion
68
+ export { r as useTourAnalytics };
69
+
70
+ //# sourceMappingURL=useTourAnalytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTourAnalytics.js","names":[],"sources":["../../../src/tours/hooks/useTourAnalytics.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { useGetTourAnalyticsQuery } from '../../generated/global-operations';\nimport type {\n DeviceTypeStats,\n TourEventTypeStats,\n TourStepAnalytics,\n} from '../../generated/global-types';\nimport type { TourAnalytics } from '../types';\n\n/**\n * Hook for tour analytics functionality\n * Fetches and processes tour performance data\n */\nexport function useTourAnalytics(tourId?: string) {\n const { data, loading, error, refetch } = useGetTourAnalyticsQuery({\n variables: { tourId: tourId! },\n skip: !tourId,\n });\n\n // Transform API response to match our TourAnalytics type\n const analytics: TourAnalytics | null = useMemo(() => {\n if (!data?.tourAnalytics || !tourId) return null;\n\n const { tourAnalytics, tourStepAnalytics } = data;\n\n return {\n tourId,\n totalViews: tourAnalytics.totalViews,\n totalCompletions: tourAnalytics.totalCompletions,\n totalSkips: tourAnalytics.totalSkips,\n averageCompletionRate: tourAnalytics.averageCompletionRate,\n averageDuration: tourAnalytics.averageDuration,\n byDeviceType: tourAnalytics.byDeviceType.map((d: DeviceTypeStats) => ({\n deviceType: d.deviceType.toLowerCase() as 'mobile' | 'tablet' | 'desktop',\n count: d.count,\n completionRate: d.completionRate,\n })),\n byEventType: tourAnalytics.byEventType.map((e: TourEventTypeStats) => ({\n eventType: e.eventType,\n count: e.count,\n })),\n stepAnalytics: tourStepAnalytics.map((s: TourStepAnalytics, index: number) => ({\n stepId: s.stepId,\n stepOrder: index + 1,\n views: s.viewCount,\n completions: s.completionCount,\n dropOffRate: s.viewCount > 0 ? ((s.viewCount - s.completionCount) / s.viewCount) * 100 : 0,\n averageDuration: s.averageDuration,\n })),\n };\n }, [data, tourId]);\n\n /**\n * Fetch/refetch tour analytics\n */\n const fetchAnalytics = useCallback(\n async (_dateRange?: { start: string; end: string }) => {\n if (!tourId) return;\n await refetch();\n },\n [tourId, refetch]\n );\n\n /**\n * Calculate completion rate percentage\n */\n const getCompletionRate = useCallback(() => {\n if (!analytics || analytics.totalViews === 0) return 0;\n return (analytics.totalCompletions / analytics.totalViews) * 100;\n }, [analytics]);\n\n /**\n * Calculate skip rate percentage\n */\n const getSkipRate = useCallback(() => {\n if (!analytics || analytics.totalViews === 0) return 0;\n return (analytics.totalSkips / analytics.totalViews) * 100;\n }, [analytics]);\n\n /**\n * Get device with highest completion rate\n */\n const getBestDevice = useCallback(() => {\n if (!analytics || analytics.byDeviceType.length === 0) return null;\n return analytics.byDeviceType.reduce((best, current) =>\n current.completionRate > best.completionRate ? current : best\n );\n }, [analytics]);\n\n /**\n * Get step with highest drop-off rate\n */\n const getHighestDropOffStep = useCallback(() => {\n if (!analytics || !analytics.stepAnalytics || analytics.stepAnalytics.length === 0) {\n return null;\n }\n return analytics.stepAnalytics.reduce((worst, current) =>\n current.dropOffRate > worst.dropOffRate ? current : worst\n );\n }, [analytics]);\n\n /**\n * Export analytics data\n */\n const exportAnalytics = useCallback(\n async (format: 'csv' | 'pdf' | 'json') => {\n if (!analytics) return;\n\n let content: string;\n let mimeType: string;\n let extension: string;\n\n if (format === 'json') {\n content = JSON.stringify(analytics, null, 2);\n mimeType = 'application/json';\n extension = 'json';\n } else if (format === 'csv') {\n const headers = ['Metric', 'Value'];\n const rows = [\n ['Total Views', String(analytics.totalViews)],\n ['Total Completions', String(analytics.totalCompletions)],\n ['Total Skips', String(analytics.totalSkips)],\n ['Completion Rate', `${analytics.averageCompletionRate.toFixed(2)}%`],\n ['Average Duration (s)', String(analytics.averageDuration)],\n ];\n content = [headers.join(','), ...rows.map((r) => r.join(','))].join('\\n');\n mimeType = 'text/csv';\n extension = 'csv';\n } else {\n return; // PDF not supported client-side\n }\n\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `tour-analytics-${analytics.tourId}.${extension}`;\n a.click();\n setTimeout(() => URL.revokeObjectURL(url), 100);\n },\n [analytics]\n );\n\n return {\n analytics,\n loading,\n error,\n fetchAnalytics,\n getCompletionRate,\n getSkipRate,\n getBestDevice,\n getHighestDropOffStep,\n exportAnalytics,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { Tour, TourStep } from '../types';
2
+ import { TourStatus, TourStepPlacement } from '../../generated/global-types';
3
+
4
+ /**
5
+ * Hook for tour builder functionality
6
+ * Manages tour creation, editing, and step synchronization
7
+ * Uses the gateway client from fe-libs
8
+ */
9
+ export declare function useTourBuilder(tourId?: string): {
10
+ tour: Tour | null;
11
+ steps: TourStep[];
12
+ isDirty: boolean;
13
+ validationErrors: import('../types').ValidationError[];
14
+ saving: boolean;
15
+ loading: boolean;
16
+ deleting: boolean;
17
+ error: Error | null;
18
+ loadTour: (id: string) => Promise<void>;
19
+ createTour: (input: Partial<Tour>) => Promise<{
20
+ __typename?: "Tour";
21
+ id: string;
22
+ name: string;
23
+ slug: string;
24
+ productId: string;
25
+ status: TourStatus;
26
+ createdAt: string;
27
+ } | null>;
28
+ updateTour: (id: string, input: Partial<Tour>) => Promise<{
29
+ __typename?: "Tour";
30
+ id: string;
31
+ name: string;
32
+ slug: string;
33
+ status: TourStatus;
34
+ updatedAt: string;
35
+ } | null>;
36
+ deleteTour: (id: string) => Promise<boolean>;
37
+ syncSteps: (tourIdParam: string, steps: TourStep[]) => Promise<{
38
+ __typename?: "TourStep";
39
+ id: string;
40
+ tourId: string;
41
+ title: string;
42
+ content: string;
43
+ stepOrder: number;
44
+ targetSelector?: string | null;
45
+ placement: TourStepPlacement;
46
+ targetSelectorMobile?: string | null;
47
+ targetSelectorTablet?: string | null;
48
+ targetSelectorDesktop?: string | null;
49
+ customData?: Record<string, unknown> | null;
50
+ actions?: Record<string, unknown> | null;
51
+ requireInteraction: boolean;
52
+ waitForSelector?: string | null;
53
+ waitForEvent?: string | null;
54
+ waitForTimeout?: number | null;
55
+ skipConditions?: Record<string, unknown> | null;
56
+ createdAt: string;
57
+ updatedAt: string;
58
+ }[] | null>;
59
+ saveTour: () => Promise<void>;
60
+ };
61
+ //# sourceMappingURL=useTourBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTourBuilder.d.ts","sourceRoot":"","sources":["../../../src/tours/hooks/useTourBuilder.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAmB,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAqBnG;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM;;;;;;;;;mBAyB/B,MAAM;wBAkCH,OAAO,CAAC,IAAI,CAAC;;;;;;;;;qBAiEhB,MAAM,SAAS,OAAO,CAAC,IAAI,CAAC;;;;;;;;qBAmD5B,MAAM;6BA2BG,MAAM,SAAS,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;EAiGhD"}