Skip to content

Commit 0820edc

Browse files
committed
Added compliance notification badge
1 parent ab845e3 commit 0820edc

File tree

20 files changed

+424
-91
lines changed

20 files changed

+424
-91
lines changed

configs/test-utils/src/__mocks__/@monkvision/common.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const {
2222
STORAGE_KEY_AUTH_TOKEN,
2323
complianceIssueLabels,
2424
imageStatusLabels,
25+
getInspectionImages,
2526
} = jest.requireActual('@monkvision/common');
2627

2728
export = {
@@ -47,6 +48,7 @@ export = {
4748
createEmptyMonkState,
4849
complianceIssueLabels,
4950
imageStatusLabels,
51+
getInspectionImages,
5052

5153
/* Mocks */
5254
useMonkTheme: jest.fn(() => createTheme()),

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

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useState } from 'react';
2-
import { Image, ImageStatus, Sight } from '@monkvision/types';
3-
import { MonkState, useMonkState } from '@monkvision/common';
2+
import { ImageStatus, Sight } from '@monkvision/types';
3+
import { getInspectionImages, MonkState, useMonkState } from '@monkvision/common';
44
import { useInspectionPoll } from '@monkvision/network';
55
import { InspectionGalleryItem, InspectionGalleryProps } from '../types';
66

@@ -62,35 +62,12 @@ function getItems(
6262
enableCompliance: boolean,
6363
inspectionSights?: Sight[],
6464
): InspectionGalleryItem[] {
65-
const inspection = entities.inspections.find((i) => i.id === inspectionId);
66-
const items: InspectionGalleryItem[] = [];
67-
entities.images
68-
.filter((image) => inspection?.images.includes(image.id))
69-
.forEach((image) => {
70-
const item: InspectionGalleryItem = { isTaken: true, isAddDamage: false, image };
71-
const itemSightId = image.additionalData?.sight_id;
72-
if (!captureMode || !itemSightId) {
73-
items.push(item);
74-
} else {
75-
const index = items.findIndex(
76-
(i) => !i.isAddDamage && i.isTaken && i.image.additionalData?.sight_id === itemSightId,
77-
);
78-
if (index >= 0) {
79-
const itemDateISO = image.additionalData?.created_at;
80-
const alreadyExistingImageDateISO = (items[index] as { image: Image }).image
81-
.additionalData?.created_at;
82-
if (
83-
alreadyExistingImageDateISO &&
84-
itemDateISO &&
85-
new Date(itemDateISO) > new Date(alreadyExistingImageDateISO)
86-
) {
87-
items[index] = item;
88-
}
89-
} else {
90-
items.push(item);
91-
}
92-
}
93-
});
65+
const images = getInspectionImages(inspectionId, entities.images, captureMode);
66+
const items: InspectionGalleryItem[] = images.map((image) => ({
67+
isTaken: true,
68+
isAddDamage: false,
69+
image,
70+
}));
9471
inspectionSights?.forEach((sight) => {
9572
if (
9673
!items.find(
@@ -141,7 +118,11 @@ export function useInspectionGalleryItems(props: InspectionGalleryProps): Inspec
141118
id: props.inspectionId,
142119
apiConfig: props.apiConfig,
143120
compliance: props.captureMode
144-
? { enableCompliance, complianceIssues: props.complianceIssues }
121+
? {
122+
enableCompliance,
123+
complianceIssues: props.complianceIssues,
124+
useLiveCompliance: props.useLiveCompliance,
125+
}
145126
: undefined,
146127
delay: shouldFetch ? props.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS : null,
147128
onSuccess,

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

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import { renderHook } from '@testing-library/react-hooks';
22
import { sights } from '@monkvision/sights';
3-
import {
4-
ComplianceIssue,
5-
ComplianceOptions,
6-
Image,
7-
ImageStatus,
8-
Inspection,
9-
} from '@monkvision/types';
3+
import { ComplianceIssue, ComplianceOptions, Image, ImageStatus } from '@monkvision/types';
104
import { createEmptyMonkState, useMonkState } from '@monkvision/common';
115
import { useInspectionPoll } from '@monkvision/network';
126
import { act } from '@testing-library/react';
@@ -33,18 +27,16 @@ describe('useInspectionGalleryItems hook', () => {
3327
it('should initialize the gallery items using the local Monk state', () => {
3428
const initialProps = createProps();
3529
const state = createEmptyMonkState();
36-
state.inspections.push({
37-
id: initialProps.inspectionId,
38-
images: ['image-1', 'image-2'],
39-
} as unknown as Inspection);
4030
state.images.push(
4131
{
4232
id: 'image-1',
33+
inspectionId: initialProps.inspectionId,
4334
additionalData: { sight_id: 'test-sight-2' },
4435
status: ImageStatus.SUCCESS,
4536
} as unknown as Image,
4637
{
4738
id: 'image-2',
39+
inspectionId: initialProps.inspectionId,
4840
status: ImageStatus.SUCCESS,
4941
} as unknown as Image,
5042
);
@@ -65,22 +57,21 @@ describe('useInspectionGalleryItems hook', () => {
6557
it('should properly update the items after each inspection poll', () => {
6658
const initialProps = createProps();
6759
const entities = createEmptyMonkState();
68-
entities.inspections.push({
69-
id: initialProps.inspectionId,
70-
images: ['image-1', 'image-2', 'image-3'],
71-
} as unknown as Inspection);
7260
entities.images.push(
7361
{
7462
id: 'image-1',
63+
inspectionId: initialProps.inspectionId,
7564
additionalData: { sight_id: 'test-sight-1' },
7665
status: ImageStatus.SUCCESS,
7766
} as unknown as Image,
7867
{
7968
id: 'image-2',
69+
inspectionId: initialProps.inspectionId,
8070
status: ImageStatus.SUCCESS,
8171
} as unknown as Image,
8272
{
8373
id: 'image-3',
74+
inspectionId: initialProps.inspectionId,
8475
additionalData: { sight_id: 'test-sight-3' },
8576
status: ImageStatus.SUCCESS,
8677
} as unknown as Image,
@@ -112,22 +103,21 @@ describe('useInspectionGalleryItems hook', () => {
112103
it('should put items to retake first in the list', () => {
113104
const initialProps = createProps();
114105
const state = createEmptyMonkState();
115-
state.inspections.push({
116-
id: initialProps.inspectionId,
117-
images: ['image-1', 'image-2', 'image-3'],
118-
} as unknown as Inspection);
119106
state.images.push(
120107
{
121108
id: 'image-1',
109+
inspectionId: initialProps.inspectionId,
122110
additionalData: { sight_id: 'test-sight-1' },
123111
status: ImageStatus.SUCCESS,
124112
} as unknown as Image,
125113
{
126114
id: 'image-2',
115+
inspectionId: initialProps.inspectionId,
127116
status: ImageStatus.NOT_COMPLIANT,
128117
} as unknown as Image,
129118
{
130119
id: 'image-3',
120+
inspectionId: initialProps.inspectionId,
131121
additionalData: { sight_id: 'test-sight-3' },
132122
status: ImageStatus.NOT_COMPLIANT,
133123
} as unknown as Image,
@@ -150,21 +140,20 @@ describe('useInspectionGalleryItems hook', () => {
150140
const initialProps = createProps();
151141
initialProps.captureMode = false;
152142
const state = createEmptyMonkState();
153-
state.inspections.push({
154-
id: initialProps.inspectionId,
155-
images: ['image-1', 'image-2', 'image-3'],
156-
} as unknown as Inspection);
157143
state.images.push(
158144
{
159145
id: 'image-1',
146+
inspectionId: initialProps.inspectionId,
160147
additionalData: { sight_id: 'test-sight-1' },
161148
} as unknown as Image,
162149
{
163150
id: 'image-2',
151+
inspectionId: initialProps.inspectionId,
164152
additionalData: { sight_id: 'test-sight-2' },
165153
} as unknown as Image,
166154
{
167155
id: 'image-3',
156+
inspectionId: initialProps.inspectionId,
168157
additionalData: { sight_id: 'test-sight-3' },
169158
} as unknown as Image,
170159
);
@@ -194,21 +183,20 @@ describe('useInspectionGalleryItems hook', () => {
194183
const initialProps = createProps();
195184
initialProps.captureMode = true;
196185
const state = createEmptyMonkState();
197-
state.inspections.push({
198-
id: initialProps.inspectionId,
199-
images: ['image-1', 'image-2', 'image-3'],
200-
} as unknown as Inspection);
201186
state.images.push(
202187
{
203188
id: 'image-1',
189+
inspectionId: initialProps.inspectionId,
204190
additionalData: { sight_id: 'test-sight-1', created_at: '2020-01-01T01:01:01.001Z' },
205191
} as unknown as Image,
206192
{
207193
id: 'image-2',
194+
inspectionId: initialProps.inspectionId,
208195
additionalData: { sight_id: 'test-sight-1', created_at: '1999-01-01T01:01:01.001Z' },
209196
} as unknown as Image,
210197
{
211198
id: 'image-3',
199+
inspectionId: initialProps.inspectionId,
212200
additionalData: { sight_id: 'test-sight-1', created_at: '2023-01-01T01:01:01.001Z' },
213201
} as unknown as Image,
214202
);
@@ -229,17 +217,15 @@ describe('useInspectionGalleryItems hook', () => {
229217
const initialProps = createProps();
230218
initialProps.captureMode = false;
231219
const state = createEmptyMonkState();
232-
state.inspections.push({
233-
id: initialProps.inspectionId,
234-
images: ['image-1', 'image-2'],
235-
} as unknown as Inspection);
236220
state.images.push(
237221
{
238222
id: 'image-1',
223+
inspectionId: initialProps.inspectionId,
239224
additionalData: { sight_id: 'test-sight-1', created_at: '2020-01-01T01:01:01.001Z' },
240225
} as unknown as Image,
241226
{
242227
id: 'image-2',
228+
inspectionId: initialProps.inspectionId,
243229
additionalData: { sight_id: 'test-sight-1', created_at: '1999-01-01T01:01:01.001Z' },
244230
} as unknown as Image,
245231
);
@@ -290,12 +276,9 @@ describe('useInspectionGalleryItems hook', () => {
290276
const initialProps = createProps();
291277
initialProps.refreshIntervalMs = 1234;
292278
const state = createEmptyMonkState();
293-
state.inspections.push({
294-
id: initialProps.inspectionId,
295-
images: ['image-1'],
296-
} as unknown as Inspection);
297279
state.images.push({
298280
id: 'image-1',
281+
inspectionId: initialProps.inspectionId,
299282
status: ImageStatus.UPLOADING,
300283
} as unknown as Image);
301284
(useMonkState as jest.Mock).mockImplementationOnce(() => ({ state }));
@@ -314,12 +297,9 @@ describe('useInspectionGalleryItems hook', () => {
314297
const initialProps = createProps();
315298
initialProps.refreshIntervalMs = 1234;
316299
const state = createEmptyMonkState();
317-
state.inspections.push({
318-
id: initialProps.inspectionId,
319-
images: ['image-1'],
320-
} as unknown as Inspection);
321300
state.images.push({
322301
id: 'image-1',
302+
inspectionId: initialProps.inspectionId,
323303
status: ImageStatus.COMPLIANCE_RUNNING,
324304
} as unknown as Image);
325305
(useMonkState as jest.Mock).mockImplementationOnce(() => ({ state }));
@@ -338,12 +318,9 @@ describe('useInspectionGalleryItems hook', () => {
338318
const initialProps = createProps();
339319
initialProps.refreshIntervalMs = undefined;
340320
const state = createEmptyMonkState();
341-
state.inspections.push({
342-
id: initialProps.inspectionId,
343-
images: ['image-1'],
344-
} as unknown as Inspection);
345321
state.images.push({
346322
id: 'image-1',
323+
inspectionId: initialProps.inspectionId,
347324
status: ImageStatus.COMPLIANCE_RUNNING,
348325
} as unknown as Image);
349326
(useMonkState as jest.Mock).mockImplementationOnce(() => ({ state }));

packages/common/README/UTILITIES.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,19 @@ This function creates and returns a new Promise that will resolve to void after
171171

172172
---
173173

174+
# State Utils
175+
### getInspectionImages
176+
```typescript
177+
import { getInspectionImages } from '@monkvision/common';
178+
179+
console.log(getInspectionImages(inspectionId, images, filterRetakes));
180+
// Returns an array of all the images having the given inspectionId.
181+
```
182+
Utility function that extracts the images of the given inspection. Set `filterRetakes` to `false` to filter retaken
183+
pictures.
184+
185+
---
186+
174187
# String Utils
175188
### suffix
176189
```typescript

packages/common/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from './promise.utils';
66
export * from './zlib.utils';
77
export * from './browser.utils';
88
export * from './env.utils';
9+
export * from './state.utils';
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Image } from '@monkvision/types';
2+
3+
/**
4+
* Utility function that extracts the images of the given inspection.
5+
*
6+
* @param inspectionId The ID of the inspection to get the images of.
7+
* @param images Array containing every image existing in the current local state.
8+
* @param filterRetakes Boolean indicating if retaken pictures should be filtered out or not (default: false).
9+
*/
10+
export function getInspectionImages(
11+
inspectionId: string,
12+
images: Image[],
13+
filterRetakes = false,
14+
): Image[] {
15+
const inspectionImages = images.filter((image) => image.inspectionId === inspectionId);
16+
if (!filterRetakes) {
17+
return inspectionImages;
18+
}
19+
const filteredRetakes: Image[] = [];
20+
inspectionImages.forEach((image) => {
21+
if (image.additionalData?.sight_id) {
22+
const index = filteredRetakes.findIndex(
23+
(i) => i.additionalData?.sight_id === image.additionalData?.sight_id,
24+
);
25+
if (index >= 0) {
26+
const imageDateISO = image.additionalData?.created_at;
27+
const alreadyExistingImageDateISO = filteredRetakes[index].additionalData?.created_at;
28+
if (
29+
alreadyExistingImageDateISO &&
30+
imageDateISO &&
31+
new Date(imageDateISO) > new Date(alreadyExistingImageDateISO)
32+
) {
33+
filteredRetakes[index] = image;
34+
}
35+
return;
36+
}
37+
}
38+
filteredRetakes.push(image);
39+
});
40+
return filteredRetakes;
41+
}

0 commit comments

Comments
 (0)