@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.
- package/README.md +342 -0
- package/dist/__tests__/setup.d.ts +2 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/constants/featureFlags.d.ts +25 -0
- package/dist/constants/featureFlags.d.ts.map +1 -0
- package/dist/constants/featureFlags.js +9 -0
- package/dist/constants/featureFlags.js.map +1 -0
- package/dist/constants/permissions.d.ts +49 -0
- package/dist/constants/permissions.d.ts.map +1 -0
- package/dist/constants/permissions.js +38 -0
- package/dist/constants/permissions.js.map +1 -0
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +1270 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-operations.js +650 -0
- package/dist/generated/global-operations.js.map +1 -0
- package/dist/generated/global-types.d.ts +20448 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +53398 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/tours/ToursAdminRoot.d.ts +16 -0
- package/dist/tours/ToursAdminRoot.d.ts.map +1 -0
- package/dist/tours/ToursAdminRoot.js +42 -0
- package/dist/tours/ToursAdminRoot.js.map +1 -0
- package/dist/tours/ToursAdminRoutes.d.ts +12 -0
- package/dist/tours/ToursAdminRoutes.d.ts.map +1 -0
- package/dist/tours/ToursAdminRoutes.js +109 -0
- package/dist/tours/ToursAdminRoutes.js.map +1 -0
- package/dist/tours/ToursRoot.d.ts +10 -0
- package/dist/tours/ToursRoot.d.ts.map +1 -0
- package/dist/tours/ToursRoot.js +1 -0
- package/dist/tours/ToursRoutes.d.ts +8 -0
- package/dist/tours/ToursRoutes.d.ts.map +1 -0
- package/dist/tours/ToursUserRoot.d.ts +15 -0
- package/dist/tours/ToursUserRoot.d.ts.map +1 -0
- package/dist/tours/ToursUserRoot.js +48 -0
- package/dist/tours/ToursUserRoot.js.map +1 -0
- package/dist/tours/ToursUserRoutes.d.ts +15 -0
- package/dist/tours/ToursUserRoutes.d.ts.map +1 -0
- package/dist/tours/ToursUserRoutes.js +66 -0
- package/dist/tours/ToursUserRoutes.js.map +1 -0
- package/dist/tours/components/RouteHelpers.d.ts +33 -0
- package/dist/tours/components/RouteHelpers.d.ts.map +1 -0
- package/dist/tours/components/RouteHelpers.js +75 -0
- package/dist/tours/components/RouteHelpers.js.map +1 -0
- package/dist/tours/components/ToursAdminNavRegistrar.d.ts +25 -0
- package/dist/tours/components/ToursAdminNavRegistrar.d.ts.map +1 -0
- package/dist/tours/components/ToursAdminNavRegistrar.js +60 -0
- package/dist/tours/components/ToursAdminNavRegistrar.js.map +1 -0
- package/dist/tours/components/ui.d.ts +2 -0
- package/dist/tours/components/ui.d.ts.map +1 -0
- package/dist/tours/hooks/useMediaLibrary.d.ts +22 -0
- package/dist/tours/hooks/useMediaLibrary.d.ts.map +1 -0
- package/dist/tours/hooks/useMediaLibrary.js +82 -0
- package/dist/tours/hooks/useMediaLibrary.js.map +1 -0
- package/dist/tours/hooks/useStepSequencer.d.ts +20 -0
- package/dist/tours/hooks/useStepSequencer.d.ts.map +1 -0
- package/dist/tours/hooks/useStepSequencer.js +53 -0
- package/dist/tours/hooks/useStepSequencer.js.map +1 -0
- package/dist/tours/hooks/useTourAnalytics.d.ts +32 -0
- package/dist/tours/hooks/useTourAnalytics.d.ts.map +1 -0
- package/dist/tours/hooks/useTourAnalytics.js +70 -0
- package/dist/tours/hooks/useTourAnalytics.js.map +1 -0
- package/dist/tours/hooks/useTourBuilder.d.ts +61 -0
- package/dist/tours/hooks/useTourBuilder.d.ts.map +1 -0
- package/dist/tours/hooks/useTourBuilder.js +192 -0
- package/dist/tours/hooks/useTourBuilder.js.map +1 -0
- package/dist/tours/hooks/useTourLifecycle.d.ts +22 -0
- package/dist/tours/hooks/useTourLifecycle.d.ts.map +1 -0
- package/dist/tours/hooks/useTourLifecycle.js +28 -0
- package/dist/tours/hooks/useTourLifecycle.js.map +1 -0
- package/dist/tours/hooks/useTourPreview.d.ts +33 -0
- package/dist/tours/hooks/useTourPreview.d.ts.map +1 -0
- package/dist/tours/hooks/useTourPreview.js +70 -0
- package/dist/tours/hooks/useTourPreview.js.map +1 -0
- package/dist/tours/hooks/useToursList.d.ts +30 -0
- package/dist/tours/hooks/useToursList.d.ts.map +1 -0
- package/dist/tours/hooks/useToursList.js +49 -0
- package/dist/tours/hooks/useToursList.js.map +1 -0
- package/dist/tours/hooks/useToursPermissionAccess.d.ts +16 -0
- package/dist/tours/hooks/useToursPermissionAccess.d.ts.map +1 -0
- package/dist/tours/hooks/useToursPermissionAccess.js +9 -0
- package/dist/tours/hooks/useToursPermissionAccess.js.map +1 -0
- package/dist/tours/i18n.d.ts +172 -0
- package/dist/tours/i18n.d.ts.map +1 -0
- package/dist/tours/i18n.js +175 -0
- package/dist/tours/i18n.js.map +1 -0
- package/dist/tours/index.d.ts +21 -0
- package/dist/tours/index.d.ts.map +1 -0
- package/dist/tours/index.js +5 -0
- package/dist/tours/pages/AnalyticsDashboardPage.d.ts +6 -0
- package/dist/tours/pages/AnalyticsDashboardPage.d.ts.map +1 -0
- package/dist/tours/pages/AnalyticsDashboardPage.js +230 -0
- package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -0
- package/dist/tours/pages/MediaLibraryPage.d.ts +6 -0
- package/dist/tours/pages/MediaLibraryPage.d.ts.map +1 -0
- package/dist/tours/pages/MediaLibraryPage.js +195 -0
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -0
- package/dist/tours/pages/MyToursPage.d.ts +11 -0
- package/dist/tours/pages/MyToursPage.d.ts.map +1 -0
- package/dist/tours/pages/MyToursPage.js +103 -0
- package/dist/tours/pages/MyToursPage.js.map +1 -0
- package/dist/tours/pages/MyToursProgressPage.d.ts +6 -0
- package/dist/tours/pages/MyToursProgressPage.d.ts.map +1 -0
- package/dist/tours/pages/MyToursProgressPage.js +142 -0
- package/dist/tours/pages/MyToursProgressPage.js.map +1 -0
- package/dist/tours/pages/SchedulerPage.d.ts +6 -0
- package/dist/tours/pages/SchedulerPage.d.ts.map +1 -0
- package/dist/tours/pages/SchedulerPage.js +231 -0
- package/dist/tours/pages/SchedulerPage.js.map +1 -0
- package/dist/tours/pages/StepEditorPage.d.ts +7 -0
- package/dist/tours/pages/StepEditorPage.d.ts.map +1 -0
- package/dist/tours/pages/StepEditorPage.js +586 -0
- package/dist/tours/pages/StepEditorPage.js.map +1 -0
- package/dist/tours/pages/SystemAnalyticsPage.d.ts +6 -0
- package/dist/tours/pages/SystemAnalyticsPage.d.ts.map +1 -0
- package/dist/tours/pages/SystemAnalyticsPage.js +155 -0
- package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -0
- package/dist/tours/pages/TemplateLibraryPage.d.ts +6 -0
- package/dist/tours/pages/TemplateLibraryPage.d.ts.map +1 -0
- package/dist/tours/pages/TemplateLibraryPage.js +207 -0
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -0
- package/dist/tours/pages/TourBuilderPage.d.ts +6 -0
- package/dist/tours/pages/TourBuilderPage.d.ts.map +1 -0
- package/dist/tours/pages/TourBuilderPage.js +363 -0
- package/dist/tours/pages/TourBuilderPage.js.map +1 -0
- package/dist/tours/pages/TourPreviewPage.d.ts +6 -0
- package/dist/tours/pages/TourPreviewPage.d.ts.map +1 -0
- package/dist/tours/pages/TourPreviewPage.js +239 -0
- package/dist/tours/pages/TourPreviewPage.js.map +1 -0
- package/dist/tours/pages/ToursListPage.d.ts +6 -0
- package/dist/tours/pages/ToursListPage.d.ts.map +1 -0
- package/dist/tours/pages/ToursListPage.js +310 -0
- package/dist/tours/pages/ToursListPage.js.map +1 -0
- package/dist/tours/providers/ToursProvider.d.ts +27 -0
- package/dist/tours/providers/ToursProvider.d.ts.map +1 -0
- package/dist/tours/providers/ToursProvider.js +28 -0
- package/dist/tours/providers/ToursProvider.js.map +1 -0
- package/dist/tours/store/toursStore.d.ts +39 -0
- package/dist/tours/store/toursStore.d.ts.map +1 -0
- package/dist/tours/store/toursStore.js +143 -0
- package/dist/tours/store/toursStore.js.map +1 -0
- package/dist/tours/types/index.d.ts +350 -0
- package/dist/tours/types/index.d.ts.map +1 -0
- package/dist/tours/utils/cn.d.ts +8 -0
- package/dist/tours/utils/cn.d.ts.map +1 -0
- package/dist/tours/utils/index.d.ts +102 -0
- package/dist/tours/utils/index.d.ts.map +1 -0
- package/dist/tours/utils/index.js +28 -0
- package/dist/tours/utils/index.js.map +1 -0
- package/dist/tours/utils/joinPath.d.ts +9 -0
- package/dist/tours/utils/joinPath.d.ts.map +1 -0
- package/dist/tours/utils/joinPath.js +8 -0
- package/dist/tours/utils/joinPath.js.map +1 -0
- package/dist/utils/nativeBridge.d.ts +3 -0
- package/dist/utils/nativeBridge.d.ts.map +1 -0
- package/dist/utils/nativeBridge.js +2 -0
- 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 @@
|
|
|
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"}
|