Skip to content

Commit 8605e98

Browse files
SIV-450 Associations service created
1 parent 821b635 commit 8605e98

File tree

5 files changed

+1430
-0
lines changed

5 files changed

+1430
-0
lines changed

src/services/associations/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./types";
2+
export * from "./service";
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
import IHttpClient, { Headers, HttpResponse } from "http/http-client";
2+
import Resource from "../../services/resource";
3+
import {
4+
Association,
5+
AssociationList,
6+
AssociationsResponse,
7+
AssociationStatus,
8+
Errors,
9+
InvitationList,
10+
NewAssociationResponse,
11+
PreviousStateList,
12+
QueryParameters
13+
} from "./types";
14+
import Mapping from "../../mapping/mapping";
15+
16+
/**
17+
* A service class for managing communications with the associations API.
18+
*/
19+
export default class AssociationsService {
20+
private static readonly STATUS = "status";
21+
22+
/**
23+
* Constructs an AssociationsService instance.
24+
* @param client - The HTTP client for making requests.
25+
*/
26+
constructor (private readonly client: IHttpClient) { }
27+
28+
/**
29+
* Initiates an HTTP GET request to retrieve the associations for a company.
30+
* @param companyNumber - a company number of the company for which the associations should be retrieved.
31+
* @param includeRemoved - a flag to get a list of companies where status is "removed". Default value: false.
32+
* @param pageIndex - a page number to be returned. Default value: 0.
33+
* @param itemsPerPage - a number of items to be returned per page. Default value: 15.
34+
* @param userEmail - an email address of a user to check if associated with the company.
35+
* @param userId - a unique identifier of a user to check if associated with the company.
36+
* @returns a promise that resolves to the HTTP response from the server that includes the associations or errors object.
37+
*/
38+
public async getCompanyAssociations (
39+
companyNumber: string,
40+
includeRemoved?: boolean,
41+
pageIndex?: number,
42+
itemsPerPage?: number,
43+
userEmail?: string,
44+
userId?: string
45+
): Promise<Resource<AssociationList | Errors>> {
46+
let queryString: string = "";
47+
if (includeRemoved || pageIndex || itemsPerPage || userId) {
48+
const queryParameters: QueryParameters = {
49+
include_removed: includeRemoved || undefined,
50+
page_index: pageIndex || undefined,
51+
items_per_page: itemsPerPage || undefined,
52+
user_id: userId || undefined
53+
};
54+
queryString = this.getQueryString(queryParameters);
55+
}
56+
57+
let headers: Headers;
58+
if (userEmail) {
59+
headers = { user_email: userEmail };
60+
}
61+
62+
const url = `/associations/companies/${companyNumber}${queryString}`;
63+
const response = await this.client.httpGet(url, headers);
64+
65+
return this.getResource(response) as Resource<AssociationList | Errors>;
66+
}
67+
68+
/**
69+
* Initiates an HTTP GET request to retrieve the associations searched based on association status.
70+
* @param associationStatus - an association status used to filter associations. This parameter is required. Available values: confirmed, awaiting-approval, removed. Default value: confirmed.
71+
* @param pageIndex - a page to be returned. Default value: 0.
72+
* @param itemsPerPage - a number of items returned per page. Default value: 15.
73+
* @param companyNumber - a filter based on company number.
74+
* @returns a promise that resolves to the HTTP response from the server that includes the associations or errors object.
75+
*/
76+
public async searchAssociations (
77+
associationStatus: AssociationStatus[],
78+
pageIndex?: number,
79+
itemsPerPage?: number,
80+
companyNumber?: string
81+
): Promise<Resource<AssociationList | Errors>> {
82+
const queryParameters: QueryParameters = {
83+
page_index: pageIndex || undefined,
84+
items_per_page: itemsPerPage || undefined,
85+
company_number: companyNumber || undefined,
86+
status: associationStatus
87+
};
88+
const queryString = this.getQueryString(queryParameters);
89+
90+
const url = `/associations${queryString}`;
91+
const response = await this.client.httpGet(url);
92+
93+
return this.getResource(response) as Resource<AssociationList | Errors>;
94+
}
95+
96+
/**
97+
* Creates a new association for a user in session.
98+
* @param companyNumber - a company number of the company with which a new association for the user will be created.
99+
* @param inviteeEmailAddress - an email address of the user invited to have an association with a company.
100+
* @returns a promise that resolves to the HTTP response from the server that includes the new association's link (it contains the association identifier) or errors object.
101+
*/
102+
public async createAssociation (
103+
companyNumber: string,
104+
inviteeEmailAddress?: string
105+
): Promise<Resource<NewAssociationResponse | Errors>> {
106+
const url = inviteeEmailAddress ? "/associations/invitations" : "/associations";
107+
const body = inviteeEmailAddress
108+
? { company_number: companyNumber, invitee_email_id: inviteeEmailAddress }
109+
: { company_number: companyNumber };
110+
const response = await this.client.httpPost(url, body);
111+
112+
return this.getResource(response) as Resource<NewAssociationResponse | Errors>;
113+
}
114+
115+
/**
116+
* Returns an association data for the association with the provided association identifier.
117+
* @param associationId - an identifier of the association for which data has to be returned.
118+
* @returns a promise that resolves to the HTTP response from the server that includes the association data or errors object.
119+
*/
120+
public async getAssociation (
121+
associationId: string
122+
): Promise<Resource<Association | Errors>> {
123+
const url = `/associations/${associationId}`;
124+
const response = await this.client.httpGet(url);
125+
126+
return this.getResource(response) as Resource<Association | Errors>;
127+
}
128+
129+
/**
130+
* Changes the status of an association with the provided identifier to the provided status.
131+
* @param associationId - an identifier of the association to modify.
132+
* @param status - a new status for the association.
133+
* @returns a promise that resolves to the HTTP response from the server that has no resource data or includes errors object.
134+
*/
135+
public async updateAssociationStatus (
136+
associationId: string,
137+
status: AssociationStatus
138+
): Promise<Resource<undefined | Errors>> {
139+
const url = `/associations/${associationId}`;
140+
const body = { status: status };
141+
const response = await this.client.httpPatch(url, body);
142+
143+
return this.getResource(response) as Resource<undefined | Errors>;
144+
}
145+
146+
/**
147+
* Initiates an HTTP GET fetch active invitations for a user in session from all associations.
148+
* This request return only the invitations which are active (status = awaiting_approval)
149+
* and not expired.
150+
* @param pageIndex - page number to be returned, default value: 0.
151+
* @param itemsPerPage - a number of items to be returned per page. Default value: 15.
152+
* @returns a promise that resolves to the invitations list for this user or errors object.
153+
*/
154+
public async getInvitations (
155+
pageIndex?: number,
156+
itemsPerPage?: number
157+
): Promise<Resource<InvitationList | Errors>> {
158+
const queryParameters: QueryParameters = {
159+
page_index: pageIndex || undefined,
160+
items_per_page: itemsPerPage || undefined
161+
};
162+
const queryString = this.getQueryString(queryParameters);
163+
164+
const url = `/associations/invitations${queryString}`;
165+
const response = await this.client.httpGet(url);
166+
167+
return this.getResource(response) as Resource<InvitationList | Errors>;
168+
}
169+
170+
/**
171+
* Creates a new invitation (association) for the supplied email and company number.
172+
* @param companyNumber - the company number.
173+
* @param inviteeEmailAddress - email address of the user invited to have an association.
174+
* @returns a promise that resolves to the HTTP response from the server that includes the new association's identifier or errors object.
175+
*/
176+
public async postInvitation (
177+
companyNumber: string,
178+
inviteeEmailAddress: string
179+
): Promise<Resource<NewAssociationResponse | Errors>> {
180+
const body = {
181+
company_number: companyNumber,
182+
invitee_email_id: inviteeEmailAddress
183+
};
184+
const url = `/associations/invitations`;
185+
186+
const response = await this.client.httpPost(url, body);
187+
188+
return this.getResource(response) as Resource<NewAssociationResponse | Errors>;
189+
}
190+
191+
/**
192+
* Initiates an HTTP GET request to return all previous states for an association. This will not return the active state.
193+
* @param associationID - an identifier of the association for which the previous states are being returned.
194+
* @param pageIndex - a page number to be returned. Default value: 0.
195+
* @param itemsPerPage - a number of items to be returned per page. Default value: 15.
196+
* @returns a promise that resolves to the HTTP response from the server that includes the PreviousStateList or an Errors object.
197+
*/
198+
public async getPreviousStates (
199+
associationID: string,
200+
pageIndex?: number,
201+
itemsPerPage?: number
202+
): Promise<Resource<PreviousStateList | Errors>> {
203+
let queryString: string = "";
204+
if (pageIndex || itemsPerPage) {
205+
const queryParameters: QueryParameters = {
206+
page_index: pageIndex || undefined,
207+
items_per_page: itemsPerPage || undefined
208+
};
209+
queryString = this.getQueryString(queryParameters);
210+
}
211+
212+
const url = `/associations/${associationID}/previous-states${queryString}`;
213+
const response = await this.client.httpGet(url);
214+
215+
return this.getResource(response) as Resource<PreviousStateList | Errors>;
216+
}
217+
218+
/**
219+
* Creates a query string based on the properties provided in queryParameters object.
220+
* @param queryParameters - an object of which properties are used as key-value entries to a query string to be added to URL.
221+
* @returns - a query string or an empty string if no parameters provided.
222+
*/
223+
private getQueryString (queryParameters: QueryParameters): string {
224+
let queryString: string = "";
225+
if (queryParameters && Object.keys(queryParameters).length > 0) {
226+
let counter = Object.keys(queryParameters).length;
227+
queryString = "?";
228+
for (const [key, value] of Object.entries(queryParameters)) {
229+
counter--;
230+
if (!value) {
231+
continue;
232+
}
233+
234+
const keyValuePair =
235+
key === AssociationsService.STATUS
236+
? this.getExplodableArray<AssociationStatus>(key, value)
237+
: `${key}=${value}`;
238+
const separator = counter > 0 ? "&" : "";
239+
queryString = `${queryString}${keyValuePair}${separator}`;
240+
}
241+
}
242+
return queryString;
243+
}
244+
245+
/**
246+
* Creates a string containing key-value pairs connected with an ampersand & to include in a query string.
247+
* @param keyName - a key name common for all values.
248+
* @param values - an array of values to include in the string.
249+
* @returns a string containing key-value pairs connected with an ampersand.
250+
*/
251+
private getExplodableArray<T> (keyName: string, values: T[]): string {
252+
let queryString: string = "";
253+
let counter = values.length;
254+
for (const value of values) {
255+
counter--;
256+
const separator = counter > 0 ? "&" : "";
257+
queryString = `${queryString}${keyName}=${value}${separator}`;
258+
}
259+
return queryString;
260+
}
261+
262+
/**
263+
* Maps the resource data structures from snake case to camel keys.
264+
* @param response - a HTTP response object with resource data.
265+
* @returns a resource data with camel case keys.
266+
*/
267+
private getResource (response: HttpResponse): Resource<AssociationsResponse> {
268+
const resource: Resource<AssociationsResponse> = {
269+
httpStatusCode: response.status
270+
};
271+
272+
resource.resource = Mapping.camelCaseKeys<AssociationsResponse>(response.body);
273+
274+
return resource;
275+
}
276+
}

0 commit comments

Comments
 (0)