Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface LineAppointmentSettings {
enabled: boolean;
duration: 15 | 30 | 45 | 60 | 90 | 120 | 180;
}
11 changes: 11 additions & 0 deletions packages/javascript-api/src/lib/model/line/line-color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type LineColor =
| 'VIOLET'
| 'TEAL'
| 'MINT'
| 'CORAL'
| 'YELLOW'
| 'ROSE'
| 'INDIGO'
| 'BLUE'
| 'LAVENDER'
| 'MARSHMALLOW';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface LineCreatedResponse {
id: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { LineAppointmentSettings } from './line-appointment-settings.js';
import { LineColor } from './line-color.js';
import { LineTranslation } from './line-translation.js';

export interface LineCreationRequest {
name: string;
color: LineColor;
disabled?: boolean;
translations?: LineTranslation[];
appointmentSettings?: LineAppointmentSettings;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface LineTranslation {
languageCode: string;
name?: string;
}
55 changes: 55 additions & 0 deletions packages/javascript-api/src/lib/services/line/line.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as sinon from 'sinon';
import { Line } from '../../model/line';
import { LineCreationRequest } from '../../model/line/line-creation-request';
import { ResponseValidationError } from '../../model/errors/response-validation-error';
import { Qminder } from '../../qminder';
import { LineService } from './line.service';

Expand Down Expand Up @@ -72,6 +74,59 @@ describe('Line service', function () {
});
});

describe('create()', function () {
const SUCCESSFUL_RESPONSE = { id: '12345' };

it('sends the request to the correct URL with JSON body and version headers', async function () {
requestStub.resolves(SUCCESSFUL_RESPONSE);
const request: LineCreationRequest = {
name: 'Priority Service',
color: 'TEAL',
};
const result = await LineService.create(LOCATION_ID, request);
expect(requestStub.firstCall.args).toEqual([
`locations/${LOCATION_ID}/lines`,
{
method: 'POST',
body: JSON.stringify(request),
headers: { 'X-Qminder-API-Version': '2020-09-01' },
},
]);
expect(result).toEqual(SUCCESSFUL_RESPONSE);
});

it('sends optional fields when provided', async function () {
requestStub.resolves(SUCCESSFUL_RESPONSE);
const request: LineCreationRequest = {
name: 'Priority Service',
color: 'VIOLET',
disabled: true,
translations: [{ languageCode: 'fr', name: 'Service Prioritaire' }],
appointmentSettings: { enabled: true, duration: 30 },
};
await LineService.create(LOCATION_ID, request);
expect(requestStub.firstCall.args).toEqual([
`locations/${LOCATION_ID}/lines`,
{
method: 'POST',
body: JSON.stringify(request),
headers: { 'X-Qminder-API-Version': '2020-09-01' },
},
]);
});

it('throws when response does not contain id', async function () {
requestStub.resolves({});
const request: LineCreationRequest = {
name: 'Priority Service',
color: 'TEAL',
};
await expect(LineService.create(LOCATION_ID, request)).rejects.toThrow(
new ResponseValidationError('Response does not contain "id"'),
);
});
});

describe('update()', function () {
beforeEach(function (done) {
requestStub.withArgs('v1/lines/71490').resolves({});
Expand Down
16 changes: 10 additions & 6 deletions packages/javascript-api/src/lib/services/line/line.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,24 @@ export const LineService = {
details,

/**
* Create a new Line and return its details.
* Create a new Line and return its ID.
*
* Calls the following HTTP API: `POST /locations/<ID>/lines`
*
* For example:
*
* ```javascript
* const line: Line = await Qminder.Line.create(950, { name: 'Priority Service' });
* console.log(line.id); // 1425
* const response = await Qminder.Line.create(950, {
* name: 'Priority Service',
* color: 'TEAL',
* translations: [{ languageCode: 'fr', name: 'Service Prioritaire' }],
* appointmentSettings: { enabled: true, duration: 30 },
* });
* console.log(response.id); // "1425"
* ```
* @param location the location to add the line under
* @param line the parameters of the new line - must include the line name
* @returns a Promise that resolves to a new Line object, created according
* to the parameters.
* @param line the parameters of the new line - must include name and color
* @returns a Promise that resolves to a LineCreatedResponse containing the new line's ID.
*/
create,

Expand Down
33 changes: 25 additions & 8 deletions packages/javascript-api/src/lib/services/line/line.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Line } from '../../model/line.js';
import { LineCreatedResponse } from '../../model/line/line-created-response.js';
import { LineCreationRequest } from '../../model/line/line-creation-request.js';
import { Location } from '../../model/location.js';
import { extractId, IdOrObject } from '../../util/id-or-object.js';
import { ApiBase, SuccessResponse } from '../api-base/api-base.js';
import { V2_HEADERS } from '../v2-headers.js';
import { ResponseValidationError } from '../../model/errors/response-validation-error.js';

type LineCreateParameters = Partial<Omit<Line, 'id'>> & Pick<Line, 'name'>;
type LineUpdateParameters = Pick<Line, 'id'> &
Partial<Pick<Line, 'color' | 'name'>>;

Expand All @@ -25,10 +28,10 @@ export function details(line: IdOrObject<Line>): Promise<Line> {
return ApiBase.request(`v1/lines/${lineId}/`);
}

export function create(
export async function create(
location: IdOrObject<Location>,
line: LineCreateParameters,
): Promise<Line> {
line: LineCreationRequest,
): Promise<LineCreatedResponse> {
const locationId = extractId(location);
if (!locationId || typeof locationId !== 'string') {
throw new Error('Location ID invalid or missing.');
Expand All @@ -39,10 +42,24 @@ export function create(
if (!line.name || typeof line.name !== 'string') {
throw new Error('Cannot create a line without a line name.');
}
return ApiBase.request(`v1/locations/${locationId}/lines`, {
body: line,
method: 'POST',
}) as Promise<Line>;
if (!line.color || typeof line.color !== 'string') {
throw new Error('Cannot create a line without a color.');
}

const result: LineCreatedResponse = await ApiBase.request(
`locations/${locationId}/lines`,
{
method: 'POST',
body: JSON.stringify(line),
headers: V2_HEADERS,
},
);

if (!result.id) {
throw new ResponseValidationError('Response does not contain "id"');
}

return result;
}

export function update(line: LineUpdateParameters): Promise<SuccessResponse> {
Expand Down
5 changes: 5 additions & 0 deletions packages/javascript-api/src/public-api/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ export { Desk } from '../lib/model/desk.js';
export { Device } from '../lib/model/device.js';
export { Id } from '../lib/model/id.js';
export { Line } from '../lib/model/line.js';
export { LineColor } from '../lib/model/line/line-color.js';
export { LineTranslation } from '../lib/model/line/line-translation.js';
export { LineAppointmentSettings } from '../lib/model/line/line-appointment-settings.js';
export { LineCreationRequest } from '../lib/model/line/line-creation-request.js';
export { LineCreatedResponse } from '../lib/model/line/line-created-response.js';
export { Location } from '../lib/model/location.js';
export { TicketExtra } from '../lib/model/ticket/ticket-extra.js';
export { TicketLabel } from '../lib/model/ticket/ticket-label.js';
Expand Down
Loading