diff --git a/apps/demo-app/package.json b/apps/demo-app/package.json
index 74dbabafd..1a11da701 100644
--- a/apps/demo-app/package.json
+++ b/apps/demo-app/package.json
@@ -24,11 +24,13 @@
},
"dependencies": {
"@auth0/auth0-react": "^2.2.4",
+ "@monkvision/analytics": "4.0.0",
"@monkvision/common": "4.0.0",
"@monkvision/common-ui-web": "4.0.0",
"@monkvision/inspection-capture-web": "4.0.0",
"@monkvision/monitoring": "4.0.0",
"@monkvision/network": "4.0.0",
+ "@monkvision/posthog": "4.0.0",
"@monkvision/sentry": "4.0.0",
"@monkvision/sights": "4.0.0",
"@monkvision/types": "4.0.0",
diff --git a/apps/demo-app/src/index.tsx b/apps/demo-app/src/index.tsx
index 80681b31d..b29dfeb03 100644
--- a/apps/demo-app/src/index.tsx
+++ b/apps/demo-app/src/index.tsx
@@ -1,28 +1,31 @@
-import React from 'react';
import ReactDOM from 'react-dom';
import { MonitoringProvider } from '@monkvision/monitoring';
+import { AnalyticsProvider } from '@monkvision/analytics';
import { Auth0Provider } from '@auth0/auth0-react';
import { getEnvOrThrow, MonkThemeProvider } from '@monkvision/common';
import { sentryMonitoringAdapter } from './sentry';
+import { posthogAnalyticsAdapter } from './posthog';
import { AppRouter } from './components';
import './index.css';
import './i18n';
ReactDOM.render(
-
-
-
-
-
+
+
+
+
+
+
+
,
document.getElementById('root'),
);
diff --git a/apps/demo-app/src/posthog.ts b/apps/demo-app/src/posthog.ts
new file mode 100644
index 000000000..3facb2d48
--- /dev/null
+++ b/apps/demo-app/src/posthog.ts
@@ -0,0 +1,9 @@
+import { PosthogAnalyticsAdapter } from '@monkvision/posthog';
+
+export const posthogAnalyticsAdapter = new PosthogAnalyticsAdapter({
+ token: 'phc_iNzK7jyK2bLtRi9vNWnzQqy74rIPlXPdgGs0qgJrSfL',
+ api_host: 'https://eu.posthog.com',
+ environnement: 'development',
+ projectName: 'test',
+ release: '1.0.0',
+});
diff --git a/documentation/docs/packages/analytics.md b/documentation/docs/packages/analytics.md
new file mode 100644
index 000000000..37f254b14
--- /dev/null
+++ b/documentation/docs/packages/analytics.md
@@ -0,0 +1,20 @@
+---
+sidebar_position: 1
+---
+
+# analytics
+Monk analytics abstraction package.
+
+![npm latest package](https://img.shields.io/npm/v/@monkvision/analytics/latest.svg)
+
+## Overview
+This package provides an abstraction layer for the analytics features in the MonkJs ecosystem. If you plan on using any
+of these features, you can use this package to properly set up the analytics inside your application.
+
+In the MonkJs SDK, we use this "abstraction" package as a way of offering the possibility to developers to choose their
+own Analytics tools and platform if they don't want to use Posthog (the platform used internally by Monk).
+
+## Complete Documentation
+As every other package in the SDK, please refer to
+[its README file](https://github.com/monkvision/monkjs/blob/main/packages/analytics/README.md) for a complete
+documentation on how this package works.
diff --git a/documentation/docs/packages/camera-web.md b/documentation/docs/packages/camera-web.md
index 879132c72..ef7e5cefe 100644
--- a/documentation/docs/packages/camera-web.md
+++ b/documentation/docs/packages/camera-web.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 1
+sidebar_position: 2
---
# camera-web
diff --git a/documentation/docs/packages/common-ui-web.md b/documentation/docs/packages/common-ui-web.md
index b39e33bc2..2c3dd9459 100644
--- a/documentation/docs/packages/common-ui-web.md
+++ b/documentation/docs/packages/common-ui-web.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 3
+sidebar_position: 4
---
# common-ui-web
diff --git a/documentation/docs/packages/common.md b/documentation/docs/packages/common.md
index 278aa2671..c3c1512ff 100644
--- a/documentation/docs/packages/common.md
+++ b/documentation/docs/packages/common.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 2
+sidebar_position: 3
---
# common
diff --git a/documentation/docs/packages/inspection-capture-web.md b/documentation/docs/packages/inspection-capture-web.md
index 7b24830d2..c96b1e5e5 100644
--- a/documentation/docs/packages/inspection-capture-web.md
+++ b/documentation/docs/packages/inspection-capture-web.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 4
+sidebar_position: 5
---
# inspection-capture-web
diff --git a/documentation/docs/packages/inspection-report-web.md b/documentation/docs/packages/inspection-report-web.md
index 097012b0d..94d765c07 100644
--- a/documentation/docs/packages/inspection-report-web.md
+++ b/documentation/docs/packages/inspection-report-web.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 5
+sidebar_position: 6
---
# inspection-report-web
diff --git a/documentation/docs/packages/monitoring.md b/documentation/docs/packages/monitoring.md
index 74476ee70..5e19eb3d1 100644
--- a/documentation/docs/packages/monitoring.md
+++ b/documentation/docs/packages/monitoring.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 6
+sidebar_position: 7
---
# monitoring
diff --git a/documentation/docs/packages/network.md b/documentation/docs/packages/network.md
index cd7f3d3ec..ae8958eef 100644
--- a/documentation/docs/packages/network.md
+++ b/documentation/docs/packages/network.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 7
+sidebar_position: 8
---
# network
diff --git a/documentation/docs/packages/posthog.md b/documentation/docs/packages/posthog.md
new file mode 100644
index 000000000..e57e62bc1
--- /dev/null
+++ b/documentation/docs/packages/posthog.md
@@ -0,0 +1,20 @@
+---
+sidebar_position: 9
+---
+
+# posthog
+Posthog implementation used to analyze MonkJs SDK and applications.
+
+![npm latest package](https://img.shields.io/npm/v/@monkvision/posthog/latest.svg)
+
+## Overview
+This package provides an implementation of the analytics abstraction layers exposed by the
+[analytics package](docs/packages/analytics.md) using the [Posthog](https://posthog.com/) analytics platform. Posthog is
+the platform used internally by Monk to analyze the user's behaviour in our applications. Unless you already have your own analytics
+platform, and you really don't want to add Posthog as a dependency in your app, we highly recommend installing this
+analytics adapter in your app.
+
+## Complete Documentation
+As every other package in the SDK, please refer to
+[its README file](https://github.com/monkvision/monkjs/blob/main/packages/posthog/README.md) for a complete
+documentation on how this package works.
diff --git a/documentation/docs/packages/sentry.md b/documentation/docs/packages/sentry.md
index 22107467b..c6aa9cfef 100644
--- a/documentation/docs/packages/sentry.md
+++ b/documentation/docs/packages/sentry.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 8
+sidebar_position: 10
---
# sentry
diff --git a/documentation/docs/packages/sights.md b/documentation/docs/packages/sights.md
index 974ba262c..81e516e29 100644
--- a/documentation/docs/packages/sights.md
+++ b/documentation/docs/packages/sights.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 9
+sidebar_position: 11
---
# sights
diff --git a/documentation/docs/packages/types.md b/documentation/docs/packages/types.md
index b0f367d6a..aeddc81b0 100644
--- a/documentation/docs/packages/types.md
+++ b/documentation/docs/packages/types.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 10
+sidebar_position: 12
---
# types
diff --git a/packages/inspection-capture-web/package.json b/packages/inspection-capture-web/package.json
index 2245bd52a..3b13797bb 100644
--- a/packages/inspection-capture-web/package.json
+++ b/packages/inspection-capture-web/package.json
@@ -25,6 +25,7 @@
"lint:fix": "yarn run prettier:fix && yarn run eslint:fix"
},
"dependencies": {
+ "@monkvision/analytics": "4.0.0",
"@monkvision/camera-web": "4.0.0",
"@monkvision/common": "4.0.0",
"@monkvision/common-ui-web": "4.0.0",
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx b/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx
index 6ddd3b11e..d4e1fe923 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx
@@ -2,6 +2,7 @@ import { Camera, CameraHUDProps, CompressionOptions, CameraProps } from '@monkvi
import { Sight, TaskName } from '@monkvision/types';
import { useI18nSync, useLoadingState } from '@monkvision/common';
import { ComplianceOptions, MonkAPIConfig } from '@monkvision/network';
+import { useAnalytics } from '@monkvision/analytics';
import { useMonitoring } from '@monkvision/monitoring';
import { PhotoCaptureHUD, PhotoCaptureHUDProps } from './PhotoCaptureHUD';
import { styles } from './PhotoCapture.styles';
@@ -90,6 +91,7 @@ export function PhotoCapture({
}: PhotoCaptureProps) {
useI18nSync(lang);
const { handleError } = useMonitoring();
+ const analytics = useAnalytics();
const loading = useLoadingState();
const addDamageHandle = useAddDamageMode();
const startTasks = useStartTasksOnComplete({
@@ -103,6 +105,11 @@ export function PhotoCapture({
const onLastSightTaken = () => {
startTasks()
.then(() => {
+ analytics.trackEvent('inspection completed', {
+ inspectionId,
+ haveToCaptureSights: sights.length,
+ category: 'inspection_completed',
+ });
onComplete?.();
})
.catch((err) => {
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx
index df94007ca..52ef95ae6 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
import { BackdropDialog } from '@monkvision/common-ui-web';
import { CameraHUDProps, MonkPicture } from '@monkvision/camera-web';
import { LoadingState } from '@monkvision/common';
+import { useAnalytics } from '@monkvision/analytics';
import { PhotoCaptureHUDButtons } from './PhotoCaptureHUDButtons';
import { usePhotoCaptureHUDStyle } from './hooks';
import { PhotoCaptureMode } from '../hooks';
@@ -63,6 +64,10 @@ export interface PhotoCaptureHUDProps extends CameraHUDProps {
* displayed.
*/
onClose?: () => void;
+ /**
+ * Callback called when the user clicks on the gallery button.
+ */
+ onOpenGallery?: () => void;
/**
* Boolean indicating if the close button should be displayed in the HUD on top of the Camera preview.
*
@@ -88,6 +93,7 @@ export function PhotoCaptureHUD({
onCancelAddDamage,
onRetry,
onClose,
+ onOpenGallery,
showCloseButton,
loading,
handle,
@@ -96,12 +102,25 @@ export function PhotoCaptureHUD({
const { t } = useTranslation();
const [showCloseModal, setShowCloseModal] = useState(false);
const style = usePhotoCaptureHUDStyle();
+ const { trackEvent } = useAnalytics();
const handleCloseConfirm = () => {
setShowCloseModal(false);
+ trackEvent('capture closed', {
+ inspectionId,
+ category: 'capture_closed',
+ });
onClose?.();
};
+ const handleOpenGallery = () => {
+ trackEvent('gallery opened', {
+ inspectionId,
+ category: 'gallery_opened',
+ });
+ onOpenGallery?.();
+ };
+
return (
@@ -122,6 +141,7 @@ export function PhotoCaptureHUD({
setShowCloseModal(true)}
+ onOpenGallery={handleOpenGallery}
galleryPreview={lastPictureTaken ?? undefined}
closeDisabled={!!loading.error || !!handle.error}
galleryDisabled={!!loading.error || !!handle.error}
diff --git a/packages/inspection-capture-web/src/PhotoCapture/hooks/useAddDamageMode.ts b/packages/inspection-capture-web/src/PhotoCapture/hooks/useAddDamageMode.ts
index 5662fd1b8..8b953b106 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/hooks/useAddDamageMode.ts
+++ b/packages/inspection-capture-web/src/PhotoCapture/hooks/useAddDamageMode.ts
@@ -1,3 +1,4 @@
+import { useAnalytics } from '@monkvision/analytics';
import { useCallback, useMemo, useState } from 'react';
/**
@@ -45,20 +46,31 @@ export interface AddDamageHandle {
*/
export function useAddDamageMode(): AddDamageHandle {
const [mode, setMode] = useState(PhotoCaptureMode.SIGHT);
+ const { trackEvent } = useAnalytics();
- const handleAddDamage = useCallback(() => setMode(PhotoCaptureMode.ADD_DAMAGE_1ST_SHOT), []);
+ const handleAddDamage = useCallback(() => {
+ setMode(PhotoCaptureMode.ADD_DAMAGE_1ST_SHOT);
+ trackEvent('addDamage selected', {
+ mode: PhotoCaptureMode.ADD_DAMAGE_1ST_SHOT,
+ category: 'addDamage_selected',
+ });
+ }, []);
- const updatePhotoCaptureModeAfterPictureTaken = useCallback(
- () =>
- setMode((currentMode) =>
- currentMode === PhotoCaptureMode.ADD_DAMAGE_1ST_SHOT
- ? PhotoCaptureMode.ADD_DAMAGE_2ND_SHOT
- : PhotoCaptureMode.SIGHT,
- ),
- [],
- );
+ const updatePhotoCaptureModeAfterPictureTaken = useCallback(() => {
+ setMode((currentMode) =>
+ currentMode === PhotoCaptureMode.ADD_DAMAGE_1ST_SHOT
+ ? PhotoCaptureMode.ADD_DAMAGE_2ND_SHOT
+ : PhotoCaptureMode.SIGHT,
+ );
+ }, []);
- const handleCancelAddDamage = useCallback(() => setMode(PhotoCaptureMode.SIGHT), []);
+ const handleCancelAddDamage = useCallback(() => {
+ trackEvent('addDamage canceled', {
+ mode,
+ category: 'addDamage_canceled',
+ });
+ setMode(PhotoCaptureMode.SIGHT);
+ }, []);
return useMemo(
() => ({
diff --git a/packages/inspection-capture-web/src/PhotoCapture/hooks/usePhotoCaptureSightState.ts b/packages/inspection-capture-web/src/PhotoCapture/hooks/usePhotoCaptureSightState.ts
index 752aa2749..4e469eab6 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/hooks/usePhotoCaptureSightState.ts
+++ b/packages/inspection-capture-web/src/PhotoCapture/hooks/usePhotoCaptureSightState.ts
@@ -5,6 +5,7 @@ import { LoadingState, MonkGotOneInspectionAction, useAsyncEffect } from '@monkv
import { Image, Sight, TaskName } from '@monkvision/types';
import { sights } from '@monkvision/sights';
import { MonkPicture } from '@monkvision/camera-web';
+import { useAnalytics } from '@monkvision/analytics';
import { PhotoCaptureErrorName } from '../errors';
/**
@@ -162,10 +163,26 @@ export function usePhotoCaptureSightState({
const [sightsTaken, setSightsTaken] = useState([]);
const { getInspection } = useMonkApi(apiConfig);
const { handleError } = useMonitoring();
+ const analytics = useAnalytics();
+
+ const selectSight = (s: Sight) => {
+ const sightsNotTaken = captureSights.filter((sight) => !sightsTaken.includes(sight)) ?? [];
+ const nextSight = sightsNotTaken.at(sightsNotTaken.indexOf(s) + 1)?.id ?? null;
+
+ setSelectedSight(s);
+ analytics.trackEvent(`sight selected`, {
+ inspectionId,
+ sight: s.id,
+ nextSight,
+ category: 'sight_selected',
+ });
+ };
useAsyncEffect(
() => {
loading.start();
+ analytics.setUserProperties({ inspectionId });
+ analytics.setEventsProperties({ inspectionId });
return getInspection(inspectionId);
},
[inspectionId, retryCount],
@@ -174,9 +191,15 @@ export function usePhotoCaptureSightState({
try {
const alreadyTakenSights = getSightsTaken(inspectionId, response);
setSightsTaken(alreadyTakenSights);
- setSelectedSight(captureSights.filter((s) => !alreadyTakenSights.includes(s))[0]);
+ selectSight(captureSights.filter((s) => !alreadyTakenSights.includes(s))[0]);
setLastPictureTaken(getLastPictureTaken(inspectionId, response));
assertInspectionIsValid(inspectionId, response, captureSights, tasksBySight);
+ analytics.trackEvent('capture started', {
+ newInspection: !!alreadyTakenSights,
+ remainingSights: alreadyTakenSights.length,
+ haveToCaptureSights: captureSights.length,
+ category: 'capture_started',
+ });
loading.onSuccess();
} catch (err) {
handleError(err);
@@ -198,8 +221,14 @@ export function usePhotoCaptureSightState({
const updatedSightsTaken = [...sightsTaken, selectedSight];
setSightsTaken(updatedSightsTaken);
const nextSight = captureSights.filter((s) => !updatedSightsTaken.includes(s))[0];
+ analytics.trackEvent(`sight captured`, {
+ inspectionId,
+ sight: selectedSight.id,
+ nextSight: nextSight?.id ?? null,
+ category: 'take_picture',
+ });
if (nextSight) {
- setSelectedSight(nextSight);
+ selectSight(nextSight);
} else {
onLastSightTaken();
}
@@ -209,7 +238,7 @@ export function usePhotoCaptureSightState({
() => ({
selectedSight,
sightsTaken,
- selectSight: setSelectedSight,
+ selectSight,
takeSelectedSight,
lastPictureTaken,
setLastPictureTaken,
diff --git a/packages/inspection-capture-web/src/PhotoCapture/hooks/usePictureTaken.ts b/packages/inspection-capture-web/src/PhotoCapture/hooks/usePictureTaken.ts
index 56eebdffe..9a52c8bbb 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/hooks/usePictureTaken.ts
+++ b/packages/inspection-capture-web/src/PhotoCapture/hooks/usePictureTaken.ts
@@ -2,6 +2,7 @@ import { MonkPicture } from '@monkvision/camera-web';
import { TaskName } from '@monkvision/types';
import { Queue } from '@monkvision/common';
import { useCallback } from 'react';
+import { useAnalytics } from '@monkvision/analytics';
import { PictureUpload } from './useUploadQueue';
import { AddDamageHandle, PhotoCaptureMode } from './useAddDamageMode';
import { PhotoCaptureSightState } from './usePhotoCaptureSightState';
@@ -43,6 +44,7 @@ export function usePictureTaken({
uploadQueue,
tasksBySight,
}: UseTakePictureParams): HandleTakePictureFunction {
+ const { trackEvent } = useAnalytics();
return useCallback(
(picture: MonkPicture) => {
sightState.setLastPictureTaken(picture);
@@ -58,6 +60,11 @@ export function usePictureTaken({
uploadQueue.push(upload);
if (addDamageHandle.mode === PhotoCaptureMode.SIGHT) {
sightState.takeSelectedSight();
+ } else {
+ trackEvent('damage captured', {
+ mode: addDamageHandle.mode,
+ category: 'damage_captured',
+ });
}
addDamageHandle.updatePhotoCaptureModeAfterPictureTaken();
},