Skip to content

Commit b771311

Browse files
Fix Refresh in PhotoCapture (#738)
* Fix compliance status on refresh and allow retake of compliant pictures * Added sightId and createdAt in image object
1 parent cf6a6c3 commit b771311

File tree

30 files changed

+460
-243
lines changed

30 files changed

+460
-243
lines changed

packages/common-ui-web/src/components/ImageDetailedView/ImageDetailedViewOverlay/ImageDetailedViewOverlay.tsx

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { useTranslation } from 'react-i18next';
22
import { useObjectTranslation } from '@monkvision/common';
33
import {
44
ImageDetailedViewOverlayProps,
5-
isComplianceContainerDisplayed,
6-
useComplianceLabels,
5+
useRetakeOverlay,
76
useImageDetailedViewOverlayStyles,
87
useImageLabelIcon,
98
} from './hooks';
@@ -14,7 +13,7 @@ export function ImageDetailedViewOverlay(props: ImageDetailedViewOverlayProps) {
1413
const { t } = useTranslation();
1514
const { tObj } = useObjectTranslation();
1615
const labelIcon = useImageLabelIcon(props);
17-
const complianceLabels = useComplianceLabels(props);
16+
const retakeOverlay = useRetakeOverlay(props);
1817
const {
1918
mainContainerStyle,
2019
overlayDisplayStyle,
@@ -32,25 +31,27 @@ export function ImageDetailedViewOverlay(props: ImageDetailedViewOverlayProps) {
3231
return (
3332
<div style={mainContainerStyle}>
3433
<div style={overlayDisplayStyle}>
35-
{isComplianceContainerDisplayed(props) && (
36-
<div style={complianceContainerStyle}>
37-
<div style={complianceMessageContainerStyle}>
38-
<Icon icon='error' primaryColor='alert' size={complianceIcon.size} />
39-
<div style={complianceMessageStyle}>
40-
<div style={complianceTitleStyle}>{complianceLabels?.title}</div>
41-
<div style={complianceDescriptionStyle}>{complianceLabels?.description}</div>
42-
</div>
34+
<div style={complianceContainerStyle}>
35+
<div style={complianceMessageContainerStyle}>
36+
<Icon
37+
icon={retakeOverlay.icon}
38+
primaryColor={retakeOverlay.iconColor}
39+
size={complianceIcon.size}
40+
/>
41+
<div style={complianceMessageStyle}>
42+
<div style={complianceTitleStyle}>{retakeOverlay.title}</div>
43+
<div style={complianceDescriptionStyle}>{retakeOverlay.description}</div>
4344
</div>
44-
<Button
45-
style={complianceRetakeButton.style}
46-
size={complianceRetakeButton.size}
47-
primaryColor='alert'
48-
onClick={props.onRetake}
49-
>
50-
{t('retake')}
51-
</Button>
5245
</div>
53-
)}
46+
<Button
47+
style={complianceRetakeButton.style}
48+
size={complianceRetakeButton.size}
49+
primaryColor={retakeOverlay.buttonColor}
50+
onClick={props.onRetake}
51+
>
52+
{t('retake')}
53+
</Button>
54+
</div>
5455
{props.image.label && (
5556
<div style={imageLabelStyle}>
5657
{labelIcon && (

packages/common-ui-web/src/components/ImageDetailedView/ImageDetailedViewOverlay/hooks.ts

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,51 @@ export interface ImageLabelIcon {
2525
primaryColor: ColorProp;
2626
}
2727

28-
export function isComplianceContainerDisplayed(props: ImageDetailedViewOverlayProps): boolean {
28+
export function isImageValid(props: ImageDetailedViewOverlayProps): boolean {
2929
return (
30-
props.captureMode &&
31-
[ImageStatus.UPLOAD_FAILED, ImageStatus.NOT_COMPLIANT].includes(props.image.status)
30+
!props.captureMode ||
31+
![ImageStatus.UPLOAD_FAILED, ImageStatus.NOT_COMPLIANT].includes(props.image.status)
3232
);
3333
}
3434

35-
export function useComplianceLabels(
36-
props: ImageDetailedViewOverlayProps,
37-
): { title: string; description: string } | null {
35+
export function useRetakeOverlay(props: ImageDetailedViewOverlayProps): {
36+
title: string;
37+
description: string;
38+
icon: IconName;
39+
iconColor: ColorProp;
40+
buttonColor: ColorProp;
41+
} {
3842
const { tObj } = useObjectTranslation();
3943

40-
if (!isComplianceContainerDisplayed(props)) {
41-
return null;
44+
const success = {
45+
title: tObj(imageStatusLabels[ImageStatus.SUCCESS].title),
46+
description: tObj(imageStatusLabels[ImageStatus.SUCCESS].description),
47+
iconColor: 'text-secondary',
48+
icon: 'check-circle' as IconName,
49+
buttonColor: 'primary',
50+
};
51+
52+
if (isImageValid(props)) {
53+
return success;
4254
}
4355
if (props.image.status === ImageStatus.UPLOAD_FAILED) {
4456
return {
4557
title: tObj(imageStatusLabels[ImageStatus.UPLOAD_FAILED].title),
4658
description: tObj(imageStatusLabels[ImageStatus.UPLOAD_FAILED].description),
59+
iconColor: 'alert',
60+
icon: 'error',
61+
buttonColor: 'alert',
4762
};
4863
}
4964
if (!props.image.complianceIssues || props.image.complianceIssues.length === 0) {
50-
return null;
65+
return success;
5166
}
5267
return {
5368
title: tObj(complianceIssueLabels[props.image.complianceIssues[0]].title),
5469
description: tObj(complianceIssueLabels[props.image.complianceIssues[0]].description),
70+
iconColor: 'alert',
71+
icon: 'error',
72+
buttonColor: 'alert',
5573
};
5674
}
5775

@@ -88,25 +106,17 @@ export function useImageDetailedViewOverlayStyles(props: ImageDetailedViewOverla
88106
const { responsive } = useResponsiveStyle();
89107
const { palette } = useMonkTheme();
90108

91-
let overlayDisplayJustifyContent = 'space-between';
92-
if (!isComplianceContainerDisplayed(props)) {
93-
overlayDisplayJustifyContent = 'end';
94-
}
95-
if (!props.image.label) {
96-
overlayDisplayJustifyContent = 'start';
97-
}
98-
99109
return {
100110
mainContainerStyle: {
101111
...styles['mainContainer'],
102112
...responsive(styles['mainContainerSmall']),
103-
background: isComplianceContainerDisplayed(props)
113+
background: isImageValid(props)
104114
? 'linear-gradient(rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0) 50%)'
105115
: 'transparent',
106116
},
107117
overlayDisplayStyle: {
108118
...styles['overlayDisplay'],
109-
justifyContent: overlayDisplayJustifyContent,
119+
justifyContent: props.image.label ? 'space-between' : 'start',
110120
},
111121
complianceContainerStyle: {
112122
...styles['complianceContainer'],

packages/common-ui-web/src/components/InspectionGallery/InspectionGallery.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ export const InspectionGallery = i18nWrap((props: InspectionGalleryProps) => {
5959
};
6060

6161
const handleRetakeImage = (image: Image | null) => {
62-
if (props.captureMode && image?.additionalData?.sight_id) {
62+
if (props.captureMode && image?.sightId) {
6363
props.onNavigateToCapture?.({
6464
reason: NavigateToCaptureReason.RETAKE_PICTURE,
65-
sightId: image?.additionalData.sight_id,
65+
sightId: image.sightId,
6666
});
6767
} else if (props.captureMode && image?.type === ImageType.CLOSE_UP) {
6868
props.onNavigateToCapture?.({

packages/common-ui-web/src/components/InspectionGallery/hooks/useInspectionGalleryItems.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function getSightSortIndex(item: InspectionGalleryItem, inspectionSights?: Sight
1111
if (item.isAddDamage) {
1212
return defaultIndex + 1;
1313
}
14-
const sightId = item.isTaken ? item.image.additionalData?.sight_id : item.sightId;
14+
const sightId = item.isTaken ? item.image.sightId : item.sightId;
1515
if (!sightId) {
1616
return defaultIndex;
1717
}
@@ -66,10 +66,7 @@ function getItems(
6666
inspectionSights?.forEach((sight) => {
6767
if (
6868
captureMode &&
69-
!items.find(
70-
(item) =>
71-
!item.isAddDamage && item.isTaken && item.image.additionalData?.sight_id === sight.id,
72-
)
69+
!items.find((item) => !item.isAddDamage && item.isTaken && item.image.sightId === sight.id)
7370
) {
7471
items.push({ isTaken: false, isAddDamage: false, sightId: sight.id });
7572
}

packages/common-ui-web/test/components/ImageDetailedView/ImageDetailedViewOverlay/ImageDetailedViewOverlay.test.tsx

Lines changed: 35 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { useTranslation } from 'react-i18next';
2-
31
jest.mock('../../../../src/components/Button', () => ({
42
Button: jest.fn(() => <></>),
53
}));
@@ -11,17 +9,24 @@ jest.mock('../../../../src/components/ImageDetailedView/ImageDetailedViewOverlay
119
'../../../../src/components/ImageDetailedView/ImageDetailedViewOverlay/hooks',
1210
),
1311
useImageLabelIcon: jest.fn(() => null),
14-
useComplianceLabels: jest.fn(() => null),
15-
isComplianceContainerDisplayed: jest.fn(() => false),
12+
useRetakeOverlay: jest.fn(() => ({
13+
title: '',
14+
description: '',
15+
iconColor: '',
16+
icon: '',
17+
buttonColor: '',
18+
})),
19+
isImageValid: jest.fn(() => true),
1620
}));
1721

22+
import { useTranslation } from 'react-i18next';
1823
import { expectPropsOnChildMock } from '@monkvision/test-utils';
1924
import { render, screen } from '@testing-library/react';
2025
import { ImageDetailedViewOverlay } from '../../../../src/components/ImageDetailedView/ImageDetailedViewOverlay';
2126
import {
2227
ImageDetailedViewOverlayProps,
23-
isComplianceContainerDisplayed,
24-
useComplianceLabels,
28+
isImageValid,
29+
useRetakeOverlay,
2530
useImageLabelIcon,
2631
} from '../../../../src/components/ImageDetailedView/ImageDetailedViewOverlay/hooks';
2732
import { Image, ImageStatus } from '@monkvision/types';
@@ -41,46 +46,35 @@ describe('ImageDetailedViewOverlay component', () => {
4146
jest.clearAllMocks();
4247
});
4348

44-
it('should display a retake button if the compliance container is displayed', () => {
45-
(isComplianceContainerDisplayed as jest.Mock).mockImplementationOnce(() => true);
46-
const props = createProps();
47-
const { unmount } = render(<ImageDetailedViewOverlay {...props} />);
48-
49-
expect(useTranslation).toHaveBeenCalled();
50-
const { t } = (useTranslation as jest.Mock).mock.results[0].value;
51-
expect(t).toHaveBeenCalledWith('retake');
52-
expectPropsOnChildMock(Button, {
53-
children: 'retake',
54-
onClick: expect.any(Function),
49+
[true, false].forEach((isValid) => {
50+
it(`should display a retake button if isImageValid is ${isValid}`, () => {
51+
(isImageValid as jest.Mock).mockImplementationOnce(() => isValid);
52+
const props = createProps();
53+
const { unmount } = render(<ImageDetailedViewOverlay {...props} />);
54+
55+
expect(useTranslation).toHaveBeenCalled();
56+
const { t } = (useTranslation as jest.Mock).mock.results[0].value;
57+
expect(t).toHaveBeenCalledWith('retake');
58+
expectPropsOnChildMock(Button, {
59+
children: 'retake',
60+
onClick: expect.any(Function),
61+
});
62+
const { onClick } = (Button as unknown as jest.Mock).mock.calls.find(
63+
(args) => args[0].children === 'retake',
64+
)[0];
65+
expect(props.onRetake).not.toHaveBeenCalled();
66+
onClick();
67+
expect(props.onRetake).toHaveBeenCalled();
68+
69+
unmount();
5570
});
56-
const { onClick } = (Button as unknown as jest.Mock).mock.calls.find(
57-
(args) => args[0].children === 'retake',
58-
)[0];
59-
expect(props.onRetake).not.toHaveBeenCalled();
60-
onClick();
61-
expect(props.onRetake).toHaveBeenCalled();
62-
63-
unmount();
64-
});
65-
66-
it('should not display a retake button if the compliance container is not displayed', () => {
67-
(isComplianceContainerDisplayed as jest.Mock).mockImplementationOnce(() => false);
68-
const props = createProps();
69-
const { unmount } = render(<ImageDetailedViewOverlay {...props} />);
70-
71-
expect(Button).not.toHaveBeenCalledWith(
72-
expect.objectContaining({ children: 'retake' }),
73-
expect.anything(),
74-
);
75-
76-
unmount();
7771
});
7872

79-
it('should contain the compliance labels if the compliance container is displayed', () => {
73+
it('should contain the retake labels', () => {
8074
const title = 'test-title-test';
8175
const description = 'test-description-test';
82-
(isComplianceContainerDisplayed as jest.Mock).mockImplementationOnce(() => true);
83-
(useComplianceLabels as jest.Mock).mockImplementationOnce(() => ({ title, description }));
76+
(isImageValid as jest.Mock).mockImplementationOnce(() => true);
77+
(useRetakeOverlay as jest.Mock).mockImplementationOnce(() => ({ title, description }));
8478
const props = createProps();
8579
const { unmount } = render(<ImageDetailedViewOverlay {...props} />);
8680

@@ -90,20 +84,6 @@ describe('ImageDetailedViewOverlay component', () => {
9084
unmount();
9185
});
9286

93-
it('should not contain the compliance labels if the compliance container is not displayed', () => {
94-
const title = 'test-title-test';
95-
const description = 'test-description-test';
96-
(isComplianceContainerDisplayed as jest.Mock).mockImplementationOnce(() => false);
97-
(useComplianceLabels as jest.Mock).mockImplementationOnce(() => ({ title, description }));
98-
const props = createProps();
99-
const { unmount } = render(<ImageDetailedViewOverlay {...props} />);
100-
101-
expect(screen.queryByText(title)).toBeNull();
102-
expect(screen.queryByText(description)).toBeNull();
103-
104-
unmount();
105-
});
106-
10787
it('should display the image label with the proper icon', () => {
10888
const props = createProps();
10989
props.image.label = { en: 'test', fr: 'fr', de: 'test-de', nl: 'test-nl' };

0 commit comments

Comments
 (0)