Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added upload PDF #890

Merged
merged 2 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions packages/common/src/state/actions/gotOneInspectionPdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { MonkAction, MonkActionType } from './monkAction';
import { MonkState } from '../state';

/**
* The payload of a MonkGotOneInspectionPdfPayload.
*/
export interface MonkGotOneInspectionPdfPayload {
/**
* The ID of the inspection to which the PDF was fetched.
*/
inspectionId: string;
/**
* The URL of the PDF.
*/
pdfUrl: string;
}

/**
* Action dispatched when a inspection PDF has been fetched.
*/
export interface MonkGotOneInspectionPdfAction extends MonkAction {
/**
* The type of the action : `MonkActionType.GOT_ONE_INSPECTION_PDF`.
*/
type: MonkActionType.GOT_ONE_INSPECTION_PDF;
/**
* The payload of the action containing the fetched entities.
*/
payload: MonkGotOneInspectionPdfPayload;
}

/**
* Matcher function that matches a GotOneInspection while also inferring its type using TypeScript's type predicate
* feature.
*/
export function isGotOneInspectionPdfAction(
action: MonkAction,
): action is MonkGotOneInspectionPdfAction {
return action.type === MonkActionType.GOT_ONE_INSPECTION_PDF;
}

/**
* Reducer function for a GotOneInspection action.
*/
export function gotOneInspectionPdf(
state: MonkState,
action: MonkGotOneInspectionPdfAction,
): MonkState {
const { inspections } = state;
const { payload } = action;

const inspection = inspections.find((value) => value.id === payload.inspectionId);
if (inspection) {
inspection.pdfUrl = payload.pdfUrl;
}
return {
...state,
inspections: [...inspections],
};
}
1 change: 1 addition & 0 deletions packages/common/src/state/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './updatedOnePricing';
export * from './updatedOneInspectionAdditionalData';
export * from './createdOneDamage';
export * from './deletedOneDamage';
export * from './gotOneInspectionPdf';
4 changes: 4 additions & 0 deletions packages/common/src/state/actions/monkAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export enum MonkActionType {
* Clear and reset the state.
*/
RESET_STATE = 'reset_state',
/**
* An inspection PDF has been fetched from the API.
*/
GOT_ONE_INSPECTION_PDF = 'got_one_inspection_pdf',
}

/**
Expand Down
5 changes: 5 additions & 0 deletions packages/common/src/state/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
isCreatedOneDamageAction,
deletedOneDamage,
isDeletedOneDamageAction,
isGotOneInspectionPdfAction,
gotOneInspectionPdf,
} from './actions';
import { MonkState } from './state';

Expand Down Expand Up @@ -62,5 +64,8 @@ export function monkReducer(state: MonkState, action: MonkAction): MonkState {
if (isDeletedOneDamageAction(action)) {
return deletedOneDamage(state, action);
}
if (isGotOneInspectionPdfAction(action)) {
return gotOneInspectionPdf(state, action);
}
return state;
}
49 changes: 49 additions & 0 deletions packages/common/test/state/actions/gotOneInspectionPdf.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
createEmptyMonkState,
MonkActionType,
isGotOneInspectionPdfAction,
gotOneInspectionPdf,
MonkGotOneInspectionPdfAction,
} from '../../../src';
import { Inspection } from '@monkvision/types';

const action: MonkGotOneInspectionPdfAction = {
type: MonkActionType.GOT_ONE_INSPECTION_PDF,
payload: {
inspectionId: 'inspections-test-111111',
pdfUrl: 'pdf-url-test',
},
};

describe('gotOneInspectionPdf action handlers', () => {
describe('Action matcher', () => {
it('should return true if the action has the proper type', () => {
expect(isGotOneInspectionPdfAction({ type: MonkActionType.GOT_ONE_INSPECTION_PDF })).toBe(
true,
);
});

it('should return false if the action does not have the proper type', () => {
expect(isGotOneInspectionPdfAction({ type: MonkActionType.RESET_STATE })).toBe(false);
});
});

describe('Action handler', () => {
it('should return a new state', () => {
const state = createEmptyMonkState();
expect(Object.is(gotOneInspectionPdf(state, action), state)).toBe(false);
});

it('should update inspection in the state', () => {
const state = createEmptyMonkState();
state.inspections.push({
id: 'inspections-test-111111',
} as Inspection);
const newState = gotOneInspectionPdf(state, action);
expect(newState.inspections).toContainEqual({
id: action.payload.inspectionId,
pdfUrl: action.payload.pdfUrl,
});
});
});
});
5 changes: 5 additions & 0 deletions packages/common/test/state/reducer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jest.mock('../../src/state/actions', () => ({
isDeletedOneDamageAction: jest.fn(() => false),
isUpdatedOneInspectionAdditionalDataAction: jest.fn(() => false),
isUpdatedVehicleAction: jest.fn(() => false),
isGotOneInspectionPdfAction: jest.fn(() => false),
createdOneImage: jest.fn(() => null),
gotOneInspection: jest.fn(() => null),
resetState: jest.fn(() => null),
Expand All @@ -21,6 +22,7 @@ jest.mock('../../src/state/actions', () => ({
deletedOneDamage: jest.fn(() => null),
updatedOneInspectionAdditionalData: jest.fn(() => null),
updatedVehicle: jest.fn(() => null),
gotOneInspectionPdf: jest.fn(() => null),
}));

import {
Expand All @@ -33,6 +35,7 @@ import {
deletedOneDamage,
updatedOneInspectionAdditionalData,
updatedVehicle,
gotOneInspectionPdf,
isCreatedOneImageAction,
isGotOneInspectionAction,
isResetStateAction,
Expand All @@ -44,6 +47,7 @@ import {
isDeletedOneDamageAction,
isUpdatedOneInspectionAdditionalDataAction,
isUpdatedVehicleAction,
isGotOneInspectionPdfAction,
MonkAction,
monkReducer,
MonkState,
Expand All @@ -66,6 +70,7 @@ const actions = [
handler: updatedOneInspectionAdditionalData,
},
{ matcher: isUpdatedVehicleAction, handler: updatedVehicle },
{ matcher: isGotOneInspectionPdfAction, handler: gotOneInspectionPdf },
] as unknown as { matcher: jest.Mock; handler: jest.Mock; noParams?: boolean }[];

describe('Monk state reducer', () => {
Expand Down
26 changes: 26 additions & 0 deletions packages/network/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,32 @@ Gets the count of inspections that match the given filters.
|-----------|--------------------------|-----------------------------|----------|
| options | GetAllInspectionsOptions | The options of the request. | ✔️ |

### getPdf
```typescript
import { MonkApi } from '@monkvision/network';

MonkApi.getPdf(options, apiConfig, dispatch);
```

Gets the PDF url of an inspection.

| Parameter | Type | Description | Required |
|-----------|---------------|-----------------------------|----------|
| options | GetPdfOptions | The options of the request. | ✔️ |

### uploadPdf
```typescript
import { MonkApi } from '@monkvision/network';

MonkApi.uploadPdf(options, apiConfig, dispatch);
```

Upload a new PDF to an inspection.

| Parameter | Type | Description | Required |
|-----------|------------------|-----------------------------|----------|
| options | UploadPdfOptions | The options of the request. | ✔️ |

# React Tools
In order to simply integrate the Monk Api requests into your React app, you can make use of the `useMonkApi` hook. This
custom hook returns a custom version of the `MonkApi` object described in the section above, in which the requests do
Expand Down
3 changes: 3 additions & 0 deletions packages/network/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getLiveConfig } from './liveConfigs';
import { updateInspectionVehicle } from './vehicle';
import { createPricing, deletePricing, updatePricing } from './pricing';
import { createDamage, deleteDamage } from './damage';
import { getPdf, uploadPdf } from './pdf';

/**
* Object regrouping the different API requests available to communicate with the API using the `@monkvision/network`
Expand All @@ -32,4 +33,6 @@ export const MonkApi = {
updatePricing,
createDamage,
deleteDamage,
uploadPdf,
getPdf,
};
4 changes: 2 additions & 2 deletions packages/network/src/api/damage/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export interface CreateDamageOptions {
/**
* Create a new damage with the given options. See the `CreateDamageOptions` interface for more details.
*
* @param options The options of the inspection.
* @param options The options of the request.
* @param config The API config.
* @param [dispatch] Optional MonkState dispatch function that you can pass if you want this request to handle React
* state management for you.
Expand Down Expand Up @@ -103,7 +103,7 @@ export interface DeleteDamageOptions {
/**
* Delete a damage with the given options. See the `DeleteDamageOptions` interface for more details.
*
* @param options The options of the inspection.
* @param options The options of the request.
* @param config The API config.
* @param [dispatch] Optional MonkState dispatch function that you can pass if you want this request to handle React
* state management for you.
Expand Down
9 changes: 9 additions & 0 deletions packages/network/src/api/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export enum MonkNetworkError {
* authorization to perform the request.
*/
INSUFFICIENT_AUTHORIZATION = 'InsufficientAuthorization',
/**
* The PDF requested is not available.
*/
UNAVAILABLE_PDF = 'UnavailablePdf',
}

function getErrorMessage(name: string): string | null {
Expand All @@ -35,6 +39,8 @@ function getErrorMessage(name: string): string | null {
return 'Authentication token is expired.';
case MonkNetworkError.INSUFFICIENT_AUTHORIZATION:
return 'User does not have the proper authorization grants to perform this request.';
case MonkNetworkError.UNAVAILABLE_PDF:
return 'The PDF requested is not available.';
default:
return null;
}
Expand All @@ -60,6 +66,9 @@ function getErrorName(status: number, message: string): MonkNetworkError | null
if (status === 401 && message.includes('Token is expired')) {
return MonkNetworkError.EXPIRED_TOKEN;
}
if (status === 422 && message.includes('PDF has not been required to be generated')) {
return MonkNetworkError.UNAVAILABLE_PDF;
}
// TODO : Also check conditions for MonkNetworkError.INSUFFICIENT_AUTHORIZATION.
return null;
}
Expand Down
1 change: 1 addition & 0 deletions packages/network/src/api/inspection/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ function mapInspection(
wheelAnalysis: mapWheelAnalysis(response),
severityResults: ids.severityResultIds,
pricings: ids.pricingIds,
pdfUrl: 'pdf_url' in response ? response.pdf_url : undefined,
additionalData: response.additional_data,
};
}
Expand Down
8 changes: 8 additions & 0 deletions packages/network/src/api/models/pdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface ApiPdfPost {
pdf_post_strategy?: string;
}

export interface ApiPdf {
id: string;
pdf_url: string;
}
1 change: 1 addition & 0 deletions packages/network/src/api/pdf/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './requests';
Loading