Skip to content

Commit

Permalink
Added local damage / pricing state before api request
Browse files Browse the repository at this point in the history
  • Loading branch information
dlymonkai committed Oct 24, 2024
1 parent 0f60c8e commit 73674a8
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 12 deletions.
125 changes: 124 additions & 1 deletion packages/common/README/STATE_MANAGEMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const action: Monk = {
```

## CreatedOneImage Action
This action can be dispatched after an image has beencreated and uploaded to the API. The payload of this action should
This action can be dispatched after an image has been created and uploaded to the API. The payload of this action should
contain the details about the image that has been created, as well as the ID of the inspection. You can also start by
creating a local image (with a custom local ID), and then update this image when the API has returned the actual ID of
the image. To do so, re-dispatch another time the same action, but with the new Id and the property `localId` in the
Expand Down Expand Up @@ -122,4 +122,127 @@ const action: Monk = {
{ id: '4097bc0e-02d0-4ed8-9411-b18f0cb922f2', status: ProgressStatus.IN_PROGRESS },
]
}

```
## CreatedOnePricing Action
This action can be dispatched after pricing has been created and uploaded to the API. Similar to the image, you can
first create a local pricing entry with a custom local ID and then update it once the API returns the actual ID.

```typescript
import { MonkResetStateAction, MonkActionType } from '@monkvision/common';
import { PricingV2RelatedItemType} from '@monkvision/types';

const action: Monk = {
type: MonkActionType.CREATED_ONE_PRICING,
payload: {
pricing: {
entityType: MonkEntityType.PRICING,
id: '2b2ac131-c613-41a9-ac04-d00b942e2290',
inspectionId: 'e1cb2852-77f3-4fb5-a851-e700cf31a7d1',
relatedItemType: PricingV2RelatedItemType.PART,
pricing: 500,
},
}
};
```

## UpdatedOnePricing Action
This action can be dispatched after a pricing entry has been updated. The payload should contain the details of the
pricing that has been updated along with the inspection ID.

```typescript
import { MonkResetStateAction, MonkActionType } from '@monkvision/common';

const action: Monk = {
type: MonkActionType.UPDATED_ONE_PRICING,
payload: {
inspectionId: 'e1cb2852-77f3-4fb5-a851-e700cf31a7d1',
pricing: {
id: 'pricing-id',
...updatedPricingDetails,
},
}
};

```

## DeletedOnePricing Action
This action can be dispatched after a pricing entry has been deleted from the API. The payload contains the ID of the
inspection and the ID of the pricing that was deleted.

```typescript
import { MonkResetStateAction, MonkActionType } from '@monkvision/common';

const action: Monk = {
type: MonkActionType.DELETED_ONE_PRICING,
payload: {
inspectionId: 'e1cb2852-77f3-4fb5-a851-e700cf31a7d1',
pricingId: 'pricing-id-to-be-deleted',
}
};

```

## CreatedOneDamage Action
This action can be dispatched after a damage has been created and uploaded to the API. You can start with a locally
created damage and update it later once the API returns the actual ID.

```typescript
import { MonkResetStateAction, MonkActionType } from '@monkvision/common';

const action: Monk = {
type: MonkActionType.CREATED_ONE_DAMAGE,
payload: {
inspectionId: 'e1cb2852-77f3-4fb5-a851-e700cf31a7d1',
damage: {
entityType: MonkEntityType.DAMAGE,
id: '2b2ac131-c613-41a9-ac04-d00b942e2290',
inspectionId: 'e1cb2852-77f3-4fb5-a851-e700cf31a7d1',
parts: [VehiclePart.BUMPER_BACK],
relatedImages: [],
type: DamageType.BODY_CRACK,
},
}
};
```

## DeletedOneDamage Action
This action can be dispatched after a damage entry has been deleted from the API. The payload contains the ID of the
inspection and the ID of the damage that was deleted.

```typescript
import { MonkResetStateAction, MonkActionType } from '@monkvision/common';

const action: Monk = {
type: MonkActionType.DELETED_ONE_DAMAGE,
payload: {
pricing: {
entityType: MonkEntityType.PRICING,
id: '2b2ac131-c613-41a9-ac04-d00b942e2290',
inspectionId: 'e1cb2852-77f3-4fb5-a851-e700cf31a7d1',
relatedItemType: PricingV2RelatedItemType.PART,
pricing: 800,
},
}
};
```

## UpdatedOneInspectionAdditionalData Action
This action can be dispatched after the additional data of an inspection has been updated in the API. The payload
contains the ID of the inspection and any additional data used for the update.

```typescript
import { MonkResetStateAction, MonkActionType } from '@monkvision/common';
import { AdditionalData } from '@monkvision/types';

const action: Monk = {
type: MonkActionType.UPDATED_ONE_INSPECTION_ADDITIONAL_DATA,
payload: {
inspectionId: 'e1cb2852-77f3-4fb5-a851-e700cf31a7d1',
additionalData: {
someKey: 'someValue',
...otherData,
},
},
};
```
18 changes: 15 additions & 3 deletions packages/common/src/state/actions/createdOneDamage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export interface MonkCreatedOneDamagePayload {
* The damage created.
*/
damage: Damage;
/**
* This ID is used when you first want to create the entity locally while you wait for the API to give you the true
* ID of the damage. You first create the damage with a custom local ID, then you dispatch the action a second time
* and specify this custom ID in the `localId` param. The damage will then be updated instead of added.
*/
localId?: string;
}

/**
Expand Down Expand Up @@ -43,8 +49,14 @@ export function createdOneDamage(state: MonkState, action: MonkCreatedOneDamageA

const inspection = inspections.find((value) => value.id === payload.damage.inspectionId);
if (inspection) {
inspection.damages.push(action.payload.damage.id);
inspection.damages = inspection.damages.filter(
(damageId) => ![payload.damage.id, payload.localId].includes(damageId),
);
inspection.damages.push(payload.damage.id);
}
const newDamages = damages.filter(
(damage) => ![payload.damage.id, payload.localId].includes(damage.id),
);
const partsRelated = action.payload.damage.parts
.map((part) => parts.find((value) => value.type === part)?.id)
.filter((v) => v !== undefined) as string[];
Expand All @@ -54,11 +66,11 @@ export function createdOneDamage(state: MonkState, action: MonkCreatedOneDamageA
}
return part;
});
damages.push({ ...payload.damage, parts: partsRelated });
newDamages.push({ ...payload.damage, parts: partsRelated });
return {
...state,
parts: newParts,
damages: [...damages],
damages: newDamages,
inspections: [...inspections],
};
}
18 changes: 15 additions & 3 deletions packages/common/src/state/actions/createdOnePricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export interface MonkCreatedOnePricingPayload {
* The pricing created.
*/
pricing: PricingV2;
/**
* This ID is used when you first want to create the entity locally while you wait for the API to give you the true
* ID of the damage. You first create the damage with a custom local ID, then you dispatch the action a second time
* and specify this custom ID in the `localId` param. The damage will then be updated instead of added.
*/
localId?: string;
}

/**
Expand Down Expand Up @@ -48,12 +54,18 @@ export function createdOnePricing(

const inspection = inspections.find((value) => value.id === payload.pricing.inspectionId);
if (inspection) {
inspection.pricings?.push(action.payload.pricing.id);
inspection.pricings = inspection.pricings?.filter(
(pricingId) => ![payload.pricing.id, payload.localId].includes(pricingId),
);
inspection.pricings?.push(payload.pricing.id);
}
pricings.push(action.payload.pricing);
const newPricings = pricings.filter(
(pricing) => ![payload.pricing.id, payload.localId].includes(pricing.id),
);
newPricings.push(action.payload.pricing);
return {
...state,
pricings: [...pricings],
pricings: newPricings,
inspections: [...inspections],
};
}
16 changes: 16 additions & 0 deletions packages/network/src/api/damage/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '@monkvision/common';
import { DamageType, MonkEntityType, VehiclePart } from '@monkvision/types';
import ky from 'ky';
import { v4 } from 'uuid';
import { Dispatch } from 'react';
import { getDefaultOptions, MonkApiConfig } from '../config';
import { ApiIdColumn } from '../models';
Expand Down Expand Up @@ -44,6 +45,20 @@ export async function createDamage(
config: MonkApiConfig,
dispatch?: Dispatch<MonkCreatedOneDamageAction>,
): Promise<MonkApiResponse> {
const localId = v4();
dispatch?.({
type: MonkActionType.CREATED_ONE_DAMAGE,
payload: {
damage: {
entityType: MonkEntityType.DAMAGE,
id: localId,
inspectionId: options.id,
parts: [options.vehiclePart],
relatedImages: [],
type: options.damageType,
},
},
});
const kyOptions = getDefaultOptions(config);
const response = await ky.post(`inspections/${options.id}/damages`, {
...kyOptions,
Expand All @@ -61,6 +76,7 @@ export async function createDamage(
relatedImages: [],
type: options.damageType,
},
localId,
},
});
return {
Expand Down
22 changes: 21 additions & 1 deletion packages/network/src/api/pricing/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
MonkUpdatedOnePricingAction,
} from '@monkvision/common';
import ky from 'ky';
import { v4 } from 'uuid';
import { MonkEntityType, PricingV2RelatedItemType } from '@monkvision/types';
import { getDefaultOptions, MonkApiConfig } from '../config';
import { MonkApiResponse } from '../types';
import { ApiIdColumn, ApiPricingV2Details } from '../models';
Expand Down Expand Up @@ -41,6 +43,24 @@ export async function createPricing(
config: MonkApiConfig,
dispatch?: Dispatch<MonkCreatedOnePricingAction>,
): Promise<MonkApiResponse> {
const localId = v4();
const localPricing = {
entityType: MonkEntityType.PRICING,
id: localId,
inspectionId: options.id,
relatedItemType: options.pricing.type,
pricing: options.pricing.pricing,
relatedItemId:
options.pricing.type === PricingV2RelatedItemType.PART
? options.pricing.vehiclePart
: undefined,
};
dispatch?.({
type: MonkActionType.CREATED_ONE_PRICING,
payload: {
pricing: localPricing,
},
});
const kyOptions = getDefaultOptions(config);
const response = await ky.post(`inspections/${options.id}/pricing`, {
...kyOptions,
Expand All @@ -50,7 +70,7 @@ export async function createPricing(
const pricing = mapApiPricingPost(options.id, body);
dispatch?.({
type: MonkActionType.CREATED_ONE_PRICING,
payload: { pricing },
payload: { pricing, localId },
});
return {
id: body.id,
Expand Down
16 changes: 15 additions & 1 deletion packages/network/test/api/damage/requests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,20 @@ describe('Damage requests', () => {
...kyOptions,
json: apiDamage,
});
expect(dispatch).toHaveBeenCalledWith({
expect(dispatch.mock.calls[0][0]).toEqual({
type: MonkActionType.CREATED_ONE_DAMAGE,
payload: {
damage: {
entityType: MonkEntityType.DAMAGE,
id: expect.any(String),
inspectionId: damage.id,
parts: [damage.vehiclePart],
relatedImages: [],
type: damage.damageType,
},
},
});
expect(dispatch.mock.calls[1][0]).toEqual({
type: MonkActionType.CREATED_ONE_DAMAGE,
payload: {
damage: {
Expand All @@ -72,6 +85,7 @@ describe('Damage requests', () => {
relatedImages: [],
type: damage.damageType,
},
localId: expect.any(String),
},
});
expect(result).toEqual({
Expand Down
20 changes: 17 additions & 3 deletions packages/network/test/api/pricing/requests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jest.mock('ky', () => ({
),
}));

import { PricingV2RelatedItemType, VehiclePart } from '@monkvision/types';
import { MonkEntityType, PricingV2RelatedItemType, VehiclePart } from '@monkvision/types';
import {
createPricing,
deletePricing,
Expand Down Expand Up @@ -65,9 +65,23 @@ describe('Pricing requests', () => {
...kyOptions,
json: apiPricingPost,
});
expect(dispatch).toHaveBeenCalledWith({
expect(dispatch.mock.calls[0][0]).toEqual({
type: MonkActionType.CREATED_ONE_PRICING,
payload: { pricing: apiPricing },
payload: {
pricing: {
entityType: MonkEntityType.PRICING,
id: expect.any(String),
inspectionId: id,
relatedItemType: pricing.type,
pricing: pricing.pricing,
relatedItemId:
pricing.type === PricingV2RelatedItemType.PART ? pricing.vehiclePart : undefined,
},
},
});
expect(dispatch.mock.calls[1][0]).toEqual({
type: MonkActionType.CREATED_ONE_PRICING,
payload: { pricing: apiPricing, localId: expect.any(String) },
});
expect(result).toEqual({
id: body.id,
Expand Down

0 comments on commit 73674a8

Please sign in to comment.