diff --git a/apps/demo-app/src/local-config.json b/apps/demo-app/src/local-config.json
index 62cde5f45..fec061484 100644
--- a/apps/demo-app/src/local-config.json
+++ b/apps/demo-app/src/local-config.json
@@ -1,4 +1,6 @@
{
+ "id": "demo-app-dev",
+ "description": "Config for the dev Demo App.",
"allowSkipRetake": true,
"enableAddDamage": true,
"enableSightGuidelines": true,
@@ -11,6 +13,9 @@
},
"apiDomain": "api.preview.monk.ai/v1",
"thumbnailDomain": "europe-west1-monk-preview-321715.cloudfunctions.net/image_resize",
+ "enableTutorial": "enabled",
+ "allowSkipTutorial": true,
+ "enableSightTutorial": false,
"startTasksOnComplete": true,
"showCloseButton": false,
"enforceOrientation": "landscape",
diff --git a/apps/drive-app/src/local-config.json b/apps/drive-app/src/local-config.json
index e2706b5ac..1bb9ec8a3 100644
--- a/apps/drive-app/src/local-config.json
+++ b/apps/drive-app/src/local-config.json
@@ -12,6 +12,9 @@
},
"apiDomain": "api.preview.monk.ai/v1",
"thumbnailDomain": "europe-west1-monk-preview-321715.cloudfunctions.net/image_resize",
+ "enableTutorial": "first_time_only",
+ "allowSkipTutorial": false,
+ "enableSightTutorial": false,
"startTasksOnComplete": true,
"showCloseButton": false,
"enforceOrientation": "landscape",
diff --git a/apps/lux-demo-app/src/local-config.json b/apps/lux-demo-app/src/local-config.json
index b087d72f0..81d766ec3 100644
--- a/apps/lux-demo-app/src/local-config.json
+++ b/apps/lux-demo-app/src/local-config.json
@@ -10,6 +10,9 @@
},
"apiDomain": "api.preview.monk.ai/v1",
"thumbnailDomain": "europe-west1-monk-preview-321715.cloudfunctions.net/image_resize",
+ "enableTutorial": "enabled",
+ "allowSkipTutorial": true,
+ "enableSightTutorial": false,
"startTasksOnComplete": true,
"showCloseButton": false,
"enforceOrientation": "landscape",
diff --git a/apps/renault-demo-app/src/local-config.json b/apps/renault-demo-app/src/local-config.json
index dd77163a1..7585c2641 100644
--- a/apps/renault-demo-app/src/local-config.json
+++ b/apps/renault-demo-app/src/local-config.json
@@ -10,6 +10,9 @@
},
"apiDomain": "api.preview.monk.ai/v1",
"thumbnailDomain": "europe-west1-monk-preview-321715.cloudfunctions.net/image_resize",
+ "enableTutorial": "enabled",
+ "allowSkipTutorial": true,
+ "enableSightTutorial": false,
"startTasksOnComplete": true,
"showCloseButton": false,
"enforceOrientation": "landscape",
diff --git a/documentation/src/utils/schemas.ts b/documentation/src/utils/schemas.ts
index 2cbef4590..b64eda6f6 100644
--- a/documentation/src/utils/schemas.ts
+++ b/documentation/src/utils/schemas.ts
@@ -5,6 +5,7 @@ import {
CompressionFormat,
DeviceOrientation,
MonkApiPermission,
+ PhotoCaptureTutorialOption,
SteeringWheelPosition,
TaskName,
VehicleType,
@@ -272,6 +273,9 @@ export const LiveConfigSchema = z
enableAddDamage: z.boolean().optional(),
enableSightGuidelines: z.boolean().optional(),
sightGuidelines: z.array(SightGuidelineSchema).optional(),
+ enableTutorial: z.nativeEnum(PhotoCaptureTutorialOption).optional(),
+ allowSkipTutorial: z.boolean().optional(),
+ enableSightTutorial: z.boolean().optional(),
defaultVehicleType: z.nativeEnum(VehicleType),
allowManualLogin: z.boolean(),
allowVehicleTypeSelection: z.boolean(),
diff --git a/packages/inspection-capture-web/README.md b/packages/inspection-capture-web/README.md
index 3cd110e52..44e50cd83 100644
--- a/packages/inspection-capture-web/README.md
+++ b/packages/inspection-capture-web/README.md
@@ -60,33 +60,38 @@ export function MonkPhotoCapturePage({ authToken }) {
}
```
-| Prop | Type | Description | Required | Default Value |
-|------------------------------------|----------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-----------------------------|
-| sights | Sight[] | The list of Sights to take pictures of. The values in this array should be retreived from the `@monkvision/sights` package. | ✔️ | |
-| inspectionId | string | The ID of the inspection to add images to. Make sure that the user that created the inspection if the same one as the one described in the auth token in the `apiConfig` prop. | ✔️ | |
-| apiConfig | ApiConfig | The api config used to communicate with the API. Make sure that the user described in the auth token is the same one as the one that created the inspection provided in the `inspectionId` prop. | ✔️ | |
-| onClose | `() => void` | Callback called when the user clicks on the Close button. If this callback is not provided, the button will not be displayed on the screen. | | |
-| onComplete | `() => void` | Callback called when inspection capture is complete. | | |
-| lang | string | null | The language to be used by this component. | | `'en'` |
-| enforceOrientation | `DeviceOrientation` | Use this prop to enforce a specific device orientation for the Camera screen. | | |
-| maxUploadDurationWarning | `number` | Max upload duration in milliseconds before showing a bad connection warning to the user. Use `-1` to never display the warning. | | `15000` |
-| useAdaptiveImageQuality | `boolean` | Boolean indicating if the image quality should be downgraded automatically in case of low connection. | | `true` |
-| showCloseButton | `boolean` | Indicates if the close button should be displayed in the HUD on top of the Camera preview. | | `false` |
-| startTasksOnComplete | `boolean | TaskName[]` | Value indicating if tasks should be started at the end of the inspection. See the `inspection-capture-web` package doc for more info. | | `true` |
-| additionalTasks | `TaskName[]` | An optional list of additional tasks to run on every Sight of the inspection. | | |
-| tasksBySight | `Record` | Record associating each sight with a list of tasks to execute for it. If not provided, the default tasks of the sight will be used. | | |
-| format | `CompressionFormat` | The output format of the compression. | | `CompressionFormat.JPEG` |
-| quality | `number` | Value indicating image quality for the compression output. | | `0.6` |
-| resolution | `CameraResolution` | Indicates the resolution of the pictures taken by the Camera. | | `CameraResolution.UHD_4K` |
-| allowImageUpscaling | `boolean` | Allow images to be scaled up if the device does not support the specified resolution in the `resolution` prop. | | `false` |
-| allowSkipRetake | `boolean` | If compliance is enabled, this prop indicate if the user is allowed to skip the retaking process if some pictures are not compliant. | | `false` |
-| enableCompliance | `boolean` | Indicates if compliance checks should be enabled or not. | | `true` |
-| enableCompliancePerSight | `string[]` | Array of Sight IDs that indicates for which sight IDs the compliance should be enabled. | | |
-| complianceIssues | `ComplianceIssue[]` | If compliance checks are enabled, this property can be used to select a list of compliance issues to check. | | `DEFAULT_COMPLIANCE_ISSUES` |
-| complianceIssuesPerSight | `Record` | A map associating Sight IDs to a list of compliance issues to check. | | |
-| useLiveCompliance | `boolean` | Indicates if live compliance should be enabled or not. | | `false` |
-| customComplianceThresholds | `CustomComplianceThresholds` | Custom thresholds that can be used to modify the strictness of the compliance for certain compliance issues. | | |
-| customComplianceThresholdsPerSight | `Record` | A map associating Sight IDs to custom compliance thresholds. | | |
-| validateButtonLabel | `string` | Custom label for validate button in gallery view. | | |
-| enableSightGuideline | `boolean` | Boolean indicating whether the sight guideline feature is enabled. If disabled, the guideline text will be hidden. | | `true` |
-| sightGuidelines | `sightGuideline[]` | A collection of sight guidelines in different language with a list of sightIds associate to it. | | |
+| Prop | Type | Description | Required | Default Value |
+|------------------------------------|----------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|----------------------------------------------|
+| sights | Sight[] | The list of Sights to take pictures of. The values in this array should be retreived from the `@monkvision/sights` package. | ✔️ | |
+| inspectionId | string | The ID of the inspection to add images to. Make sure that the user that created the inspection if the same one as the one described in the auth token in the `apiConfig` prop. | ✔️ | |
+| apiConfig | ApiConfig | The api config used to communicate with the API. Make sure that the user described in the auth token is the same one as the one that created the inspection provided in the `inspectionId` prop. | ✔️ | |
+| onClose | `() => void` | Callback called when the user clicks on the Close button. If this callback is not provided, the button will not be displayed on the screen. | | |
+| onComplete | `() => void` | Callback called when inspection capture is complete. | | |
+| lang | string | null | The language to be used by this component. | | `'en'` |
+| enforceOrientation | `DeviceOrientation` | Use this prop to enforce a specific device orientation for the Camera screen. | | |
+| maxUploadDurationWarning | `number` | Max upload duration in milliseconds before showing a bad connection warning to the user. Use `-1` to never display the warning. | | `15000` |
+| useAdaptiveImageQuality | `boolean` | Boolean indicating if the image quality should be downgraded automatically in case of low connection. | | `true` |
+| showCloseButton | `boolean` | Indicates if the close button should be displayed in the HUD on top of the Camera preview. | | `false` |
+| startTasksOnComplete | `boolean | TaskName[]` | Value indicating if tasks should be started at the end of the inspection. See the `inspection-capture-web` package doc for more info. | | `true` |
+| additionalTasks | `TaskName[]` | An optional list of additional tasks to run on every Sight of the inspection. | | |
+| tasksBySight | `Record` | Record associating each sight with a list of tasks to execute for it. If not provided, the default tasks of the sight will be used. | | |
+| format | `CompressionFormat` | The output format of the compression. | | `CompressionFormat.JPEG` |
+| quality | `number` | Value indicating image quality for the compression output. | | `0.6` |
+| resolution | `CameraResolution` | Indicates the resolution of the pictures taken by the Camera. | | `CameraResolution.UHD_4K` |
+| allowImageUpscaling | `boolean` | Allow images to be scaled up if the device does not support the specified resolution in the `resolution` prop. | | `false` |
+| allowSkipRetake | `boolean` | If compliance is enabled, this prop indicate if the user is allowed to skip the retaking process if some pictures are not compliant. | | `false` |
+| enableCompliance | `boolean` | Indicates if compliance checks should be enabled or not. | | `true` |
+| enableCompliancePerSight | `string[]` | Array of Sight IDs that indicates for which sight IDs the compliance should be enabled. | | |
+| complianceIssues | `ComplianceIssue[]` | If compliance checks are enabled, this property can be used to select a list of compliance issues to check. | | `DEFAULT_COMPLIANCE_ISSUES` |
+| complianceIssuesPerSight | `Record` | A map associating Sight IDs to a list of compliance issues to check. | | |
+| useLiveCompliance | `boolean` | Indicates if live compliance should be enabled or not. | | `false` |
+| customComplianceThresholds | `CustomComplianceThresholds` | Custom thresholds that can be used to modify the strictness of the compliance for certain compliance issues. | | |
+| customComplianceThresholdsPerSight | `Record` | A map associating Sight IDs to custom compliance thresholds. | | |
+| validateButtonLabel | `string` | Custom label for validate button in gallery view. | | |
+| enableSightGuideline | `boolean` | Boolean indicating whether the sight guideline feature is enabled. If disabled, the guideline text will be hidden. | | `true` |
+| sightGuidelines | `sightGuideline[]` | A collection of sight guidelines in different language with a list of sightIds associate to it. | | |
+| enableTutorial | `PhotoCaptureTutorialOption` | Options for displaying the photo capture tutorial. | | `PhotoCaptureTutorialOption.FIRST_TIME_ONLY` |
+| allowSkipTutorial | `boolean` | Boolean indicating if the user can skip the PhotoCapture tutorial. | | `true` |
+| thumbnailDomain | `string` | The API domain used to communicate with the resize micro service. | ✔️ | |
+
+
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx b/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx
index 5be0aca1a..0b49612b7 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCapture.tsx
@@ -22,6 +22,7 @@ import {
ComplianceOptions,
CompressionOptions,
DeviceOrientation,
+ PhotoCaptureTutorialOption,
Sight,
} from '@monkvision/types';
import { useState } from 'react';
@@ -35,6 +36,7 @@ import {
useComplianceAnalytics,
usePhotoCaptureImages,
usePhotoCaptureSightState,
+ usePhotoCaptureTutorial,
usePictureTaken,
useStartTasksOnComplete,
useTracking,
@@ -60,6 +62,9 @@ export interface PhotoCaptureProps
| 'enableAddDamage'
| 'sightGuidelines'
| 'enableSightGuidelines'
+ | 'enableTutorial'
+ | 'allowSkipTutorial'
+ | 'enableSightTutorial'
>,
Partial,
Partial {
@@ -126,6 +131,9 @@ export function PhotoCapture({
allowSkipRetake = false,
enableAddDamage = true,
sightGuidelines,
+ enableTutorial = PhotoCaptureTutorialOption.FIRST_TIME_ONLY,
+ allowSkipTutorial = true,
+ enableSightTutorial = true,
enableSightGuidelines = true,
useAdaptiveImageQuality = true,
lang,
@@ -179,6 +187,11 @@ export function PhotoCapture({
complianceOptions,
setIsInitialInspectionFetched,
});
+ const { currentTutorialStep, goToNextTutorialStep, closeTutorial } = usePhotoCaptureTutorial({
+ enableTutorial,
+ enableSightGuidelines,
+ enableSightTutorial,
+ });
const {
isBadConnectionWarningDialogDisplayed,
closeBadConnectionWarningDialog,
@@ -257,6 +270,10 @@ export function PhotoCapture({
enableAddDamage,
sightGuidelines,
enableSightGuidelines,
+ currentTutorialStep,
+ onNextTutorialStep: goToNextTutorialStep,
+ onCloseTutorial: closeTutorial,
+ allowSkipTutorial,
};
return (
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx
index 20ab2e12f..1cd9638bc 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUD.tsx
@@ -7,16 +7,24 @@ import { LoadingState } from '@monkvision/common';
import { useAnalytics } from '@monkvision/analytics';
import { PhotoCaptureHUDButtons } from './PhotoCaptureHUDButtons';
import { usePhotoCaptureHUDStyle } from './hooks';
-import { PhotoCaptureMode } from '../hooks';
+import { PhotoCaptureMode, TutorialSteps } from '../hooks';
import { PhotoCaptureHUDOverlay } from './PhotoCaptureHUDOverlay';
import { PhotoCaptureHUDElements } from './PhotoCaptureHUDElements';
+import { PhotoCaptureHUDTutorial } from './PhotoCaptureHUDTutorial';
/**
* Props of the PhotoCaptureHUD component.
*/
export interface PhotoCaptureHUDProps
extends CameraHUDProps,
- Pick {
+ Pick<
+ CaptureAppConfig,
+ | 'enableSightGuidelines'
+ | 'sightGuidelines'
+ | 'enableAddDamage'
+ | 'showCloseButton'
+ | 'allowSkipTutorial'
+ > {
/**
* The inspection ID.
*/
@@ -45,6 +53,18 @@ export interface PhotoCaptureHUDProps
* Global loading state of the PhotoCapture component.
*/
loading: LoadingState;
+ /**
+ * The current tutorial step in PhotoCapture component.
+ */
+ currentTutorialStep: TutorialSteps | null;
+ /**
+ * Callback called when the user clicks on "Next" button in PhotoCapture tutorial.
+ */
+ onNextTutorialStep: () => void;
+ /**
+ * Callback called when the user clicks on "Close" button in PhotoCapture tutorial.
+ */
+ onCloseTutorial: () => void;
/**
* Callback called when the user manually select a new sight.
*/
@@ -74,12 +94,6 @@ export interface PhotoCaptureHUDProps
* displayed.
*/
onClose?: () => void;
- /**
- * Boolean indicating if the close button should be displayed in the HUD on top of the Camera preview.
- *
- * @default false
- */
- showCloseButton?: boolean;
/**
* The current images taken by the user (ignoring retaken pictures etc.).
*/
@@ -113,6 +127,10 @@ export function PhotoCaptureHUD({
enableAddDamage,
sightGuidelines,
enableSightGuidelines,
+ currentTutorialStep,
+ allowSkipTutorial,
+ onNextTutorialStep,
+ onCloseTutorial,
}: PhotoCaptureHUDProps) {
const { t } = useTranslation();
const [showCloseModal, setShowCloseModal] = useState(false);
@@ -154,6 +172,7 @@ export function PhotoCaptureHUD({
enableAddDamage={enableAddDamage}
sightGuidelines={sightGuidelines}
enableSightGuidelines={enableSightGuidelines}
+ tutorialStep={currentTutorialStep}
/>
setShowCloseModal(false)}
onConfirm={handleCloseConfirm}
/>
+
);
}
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElements/PhotoCaptureHUDElements.tsx b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElements/PhotoCaptureHUDElements.tsx
index 6da4ea3f2..7d68858db 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElements/PhotoCaptureHUDElements.tsx
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElements/PhotoCaptureHUDElements.tsx
@@ -1,5 +1,5 @@
import { CaptureAppConfig, Image, PixelDimensions, Sight } from '@monkvision/types';
-import { PhotoCaptureMode } from '../../hooks';
+import { PhotoCaptureMode, TutorialSteps } from '../../hooks';
import { PhotoCaptureHUDElementsSight } from '../PhotoCaptureHUDElementsSight';
import { PhotoCaptureHUDElementsAddDamage1stShot } from '../PhotoCaptureHUDElementsAddDamage1stShot';
import { PhotoCaptureHUDElementsAddDamage2ndShot } from '../PhotoCaptureHUDElementsAddDamage2ndShot';
@@ -25,6 +25,10 @@ export interface PhotoCaptureHUDElementsProps
* The current mode of the component.
*/
mode: PhotoCaptureMode;
+ /**
+ * The current tutorial step in PhotoCapture component.
+ */
+ tutorialStep: TutorialSteps | null;
/**
* Callback called when the user presses the Add Damage button.
*/
@@ -80,6 +84,7 @@ export function PhotoCaptureHUDElements(params: PhotoCaptureHUDElementsProps) {
enableAddDamage={params.enableAddDamage}
sightGuidelines={params.sightGuidelines}
enableSightGuidelines={params.enableSightGuidelines}
+ tutorialStep={params.tutorialStep}
/>
);
}
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.styles.ts b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.styles.ts
index b4981f61d..43b79cf66 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.styles.ts
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.styles.ts
@@ -15,7 +15,6 @@ export const styles: Styles = {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
- zIndex: 9,
},
elementsContainerPortrait: {
__media: { portrait: true },
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.tsx b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.tsx
index ff6e6cbb4..eca17bf92 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.tsx
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/PhotoCaptureHUDElementsSight.tsx
@@ -4,7 +4,7 @@ import { styles } from './PhotoCaptureHUDElementsSight.styles';
import { AddDamageButton } from './AddDamageButton';
import { PhotoCaptureHUDElementsSightProps, usePhotoCaptureHUDSightPreviewStyle } from './hooks';
import { PhotoCaptureHUDCounter } from '../PhotoCaptureHUDCounter';
-import { PhotoCaptureMode } from '../../hooks';
+import { PhotoCaptureMode, TutorialSteps } from '../../hooks';
import { SightGuideline } from './SightGuideline';
/**
@@ -23,38 +23,43 @@ export function PhotoCaptureHUDElementsSight({
enableAddDamage,
sightGuidelines,
enableSightGuidelines,
+ tutorialStep,
}: PhotoCaptureHUDElementsSightProps) {
const style = usePhotoCaptureHUDSightPreviewStyle({ previewDimensions });
+ const showSight = previewDimensions && (!tutorialStep || tutorialStep === TutorialSteps.SIGHT);
+
return (
- {previewDimensions && }
-
-
-
-
-
-
-
-
+ {showSight && }
+ {!tutorialStep && (
+
+
+
+
+
+
+
+
+
-
+ )}
);
}
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/hooks.ts b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/hooks.ts
index f2d94d72a..99513078e 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/hooks.ts
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/hooks.ts
@@ -2,6 +2,7 @@ import { CaptureAppConfig, Image, PixelDimensions, Sight } from '@monkvision/typ
import { useResponsiveStyle } from '@monkvision/common';
import { CSSProperties } from 'react';
import { styles } from './PhotoCaptureHUDElementsSight.styles';
+import { TutorialSteps } from '../../hooks';
/**
* Props of the PhotoCaptureHUDElementsSight component.
@@ -16,6 +17,10 @@ export interface PhotoCaptureHUDElementsSightProps
* The currently selected sight in the PhotoCapture component : the sight that the user needs to capture.
*/
selectedSight: Sight;
+ /**
+ * The current tutorial step in PhotoCapture component.
+ */
+ tutorialStep: TutorialSteps | null;
/**
* Callback called when the user manually select a new sight.
*/
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/index.ts b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/index.ts
index df19a58a6..60061b684 100644
--- a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/index.ts
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDElementsSight/index.ts
@@ -1,4 +1,5 @@
export * from './SightSlider';
export * from './AddDamageButton';
+export * from './SightGuideline';
export { PhotoCaptureHUDElementsSight } from './PhotoCaptureHUDElementsSight';
export { type PhotoCaptureHUDElementsSightProps } from './hooks';
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDTutorial/PhotoCaptureHUDTutorial.styles.ts b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDTutorial/PhotoCaptureHUDTutorial.styles.ts
new file mode 100644
index 000000000..97c1cf202
--- /dev/null
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDTutorial/PhotoCaptureHUDTutorial.styles.ts
@@ -0,0 +1,66 @@
+import { Styles } from '@monkvision/types';
+import { PHOTO_CAPTURE_HUD_BUTTONS_BAR_WIDTH } from '../PhotoCaptureHUDButtons/PhotoCaptureHUDButtons.styles';
+
+export const styles: Styles = {
+ backdropContainer: {
+ position: 'fixed',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ zIndex: 10,
+ transition: 'opacity 0.5s ease-out',
+ backgroundColor: `rgba(0, 0, 0, 0.5)`,
+ },
+ elementsContainer: {
+ display: 'flex',
+ flexDirection: 'column',
+ position: 'fixed',
+ width: `calc(98% - (${PHOTO_CAPTURE_HUD_BUTTONS_BAR_WIDTH * 4}px))`,
+ top: '10px',
+ bottom: '40px',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+ topContainer: {
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ gap: '3px',
+ },
+ buttonsContainer: {
+ display: 'flex',
+ width: '100%',
+ justifyContent: 'space-between',
+ gap: '3px',
+ },
+ closeButtonTwin: {
+ padding: '22px',
+ },
+ closeButton: {
+ width: '44px',
+ height: '44px',
+ },
+ text: {
+ display: 'flex',
+ flexDirection: 'column',
+ textAlign: 'center',
+ },
+ title: {
+ fontWeight: 'bold',
+ fontSize: '20px',
+ paddingBottom: '5px',
+ },
+ arrowGuideline: {
+ height: '40px',
+ },
+ arrowSightTutorial: {
+ position: 'fixed',
+ bottom: '60px',
+ left: `calc((${PHOTO_CAPTURE_HUD_BUTTONS_BAR_WIDTH * 2}px))`,
+ width: '40px',
+ },
+};
diff --git a/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDTutorial/PhotoCaptureHUDTutorial.tsx b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDTutorial/PhotoCaptureHUDTutorial.tsx
new file mode 100644
index 000000000..44a842864
--- /dev/null
+++ b/packages/inspection-capture-web/src/PhotoCapture/PhotoCaptureHUD/PhotoCaptureHUDTutorial/PhotoCaptureHUDTutorial.tsx
@@ -0,0 +1,81 @@
+import { CSSProperties } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Button } from '@monkvision/common-ui-web';
+import { CaptureAppConfig } from '@monkvision/types';
+import { styles } from './PhotoCaptureHUDTutorial.styles';
+import { TutorialSteps } from '../../hooks';
+import { usePhotoCaptureHUDButtonBackground } from '../hooks';
+import { SightGuideline } from '../PhotoCaptureHUDElementsSight';
+import { ArrowIcon, DisplayText } from './TutorialElements';
+
+/**
+ * Props of the PhotoCaptureHUDTutorial component.
+ */
+export interface PhotoCaptureHUDTutorialProps
+ extends Pick {
+ /**
+ * The id of the sight.
+ */
+ sightId: string;
+ /**
+ * The current tutorial step in PhotoCapture component.
+ */
+ tutorialStep: TutorialSteps | null;
+ /**
+ * Callback called when the user clicks on "Next" button in PhotoCapture tutorial.
+ */
+ onNextTutorialStep: () => void;
+ /**
+ * Callback called when the user clicks on "Close" button in PhotoCapture tutorial.
+ */
+ onCloseTutorial: () => void;
+}
+
+function getButtonStyle(enableAddDamage?: boolean): CSSProperties {
+ return { visibility: enableAddDamage ? 'visible' : 'hidden' };
+}
+
+/**
+ * Component that displays an tutorial overlay on top of the PhotoCapture component.
+ */
+export function PhotoCaptureHUDTutorial({
+ tutorialStep,
+ allowSkipTutorial,
+ sightGuidelines,
+ sightId,
+ onNextTutorialStep,
+ onCloseTutorial,
+}: PhotoCaptureHUDTutorialProps) {
+ const { t } = useTranslation();
+ const primaryColor = usePhotoCaptureHUDButtonBackground();
+
+ return tutorialStep ? (
+