Skip to content

Commit f550ef1

Browse files
committed
Use Bridge NPM Package
1 parent 2483d39 commit f550ef1

17 files changed

Lines changed: 398 additions & 173 deletions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { HttpTransport_$ctor_3A0BE0FB } from '@fossa-app/bridge/Services/HttpTransport';
2+
import { JsonSerializer_$ctor } from '@fossa-app/bridge/Services/JsonSerializer';
3+
import { BranchClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/BranchClient';
4+
import { CompanyClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/CompanyClient';
5+
import { CompanySettingsClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/CompanySettingsClient';
6+
import { DepartmentClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/DepartmentClient';
7+
import { EmployeeClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/EmployeeClient';
8+
import { IdentityClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/IdentityClient';
9+
import { SystemLicenseClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/SystemLicenseClient';
10+
import { CompanyLicenseClient_$ctor_Z7C557C0 } from '@fossa-app/bridge/Services/Clients/CompanyLicenseClient';
11+
12+
import { AppAccessTokenProvider, FetchHttpRequestSender } from './BridgeTransport';
13+
14+
// Initialize the shared Fable HttpTransport
15+
const sender = new FetchHttpRequestSender();
16+
const serializer = JsonSerializer_$ctor();
17+
const tokenProvider = new AppAccessTokenProvider();
18+
19+
export const httpTransport = HttpTransport_$ctor_3A0BE0FB(sender, serializer, tokenProvider);
20+
21+
// Export strongly typed Fable clients
22+
export const branchClient = BranchClient_$ctor_Z7C557C0(httpTransport);
23+
export const companyClient = CompanyClient_$ctor_Z7C557C0(httpTransport);
24+
export const companySettingsClient = CompanySettingsClient_$ctor_Z7C557C0(httpTransport);
25+
export const departmentClient = DepartmentClient_$ctor_Z7C557C0(httpTransport);
26+
export const employeeClient = EmployeeClient_$ctor_Z7C557C0(httpTransport);
27+
export const identityClient = IdentityClient_$ctor_Z7C557C0(httpTransport);
28+
export const systemLicenseClient = SystemLicenseClient_$ctor_Z7C557C0(httpTransport);
29+
export const companyLicenseClient = CompanyLicenseClient_$ctor_Z7C557C0(httpTransport);
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { IAccessTokenProvider } from '@fossa-app/bridge/Services/IAccessTokenProvider';
2+
import { IHttpRequestSender, HttpRequestMessage } from '@fossa-app/bridge/Services/IHttpRequestSender';
3+
import { unwrap } from '@fable-org/fable-library-ts/Option';
4+
import { getUserManager } from 'shared/helpers';
5+
import { MESSAGES } from 'shared/constants';
6+
import store from 'store';
7+
import { setError, removeUser } from 'store/features';
8+
import { getBackendOrigin } from '@fossa-app/bridge/Services/UrlHelpers';
9+
import { Endpoints_BasePath } from '@fossa-app/bridge/Services/Endpoints';
10+
11+
export class AppAccessTokenProvider implements IAccessTokenProvider {
12+
async GetTokenAsync(_cancellationToken: AbortSignal): Promise<string> {
13+
const userManager = getUserManager();
14+
let user = await userManager.getUser();
15+
16+
if (!user || user.expired) {
17+
try {
18+
user = await userManager.signinSilent();
19+
} catch {
20+
return '';
21+
}
22+
}
23+
24+
return user?.access_token || '';
25+
}
26+
}
27+
28+
export class FetchHttpRequestSender implements IHttpRequestSender {
29+
async SendAsync(request: HttpRequestMessage, cancellationToken: AbortSignal): Promise<string> {
30+
const methodMap: Record<number, string> = {
31+
0: 'GET',
32+
1: 'POST',
33+
2: 'PUT',
34+
3: 'PATCH',
35+
4: 'DELETE',
36+
};
37+
38+
const method = methodMap[request.Method.tag];
39+
40+
const beOrigin = getBackendOrigin(window.location.origin);
41+
const url = `${beOrigin}/${Endpoints_BasePath}/${request.Uri.replace(/^\//, '')}`;
42+
43+
const body = unwrap(request.Content);
44+
45+
const headers = new Headers();
46+
if (request.Headers) {
47+
const headersArray = Array.from(request.Headers);
48+
headersArray.forEach(([key, value]) => {
49+
headers.set(key, value);
50+
});
51+
}
52+
53+
// Default fetch config
54+
const init: RequestInit = {
55+
method,
56+
headers,
57+
signal: cancellationToken,
58+
};
59+
60+
if (body !== undefined && body !== null) {
61+
init.body = body as string;
62+
}
63+
64+
let response: Response;
65+
try {
66+
response = await fetch(url, init);
67+
} catch (_error) {
68+
// Network Error
69+
store.dispatch(setError({ title: MESSAGES.error.general.network }));
70+
throw { status: 599, title: MESSAGES.error.general.network };
71+
}
72+
73+
if (response.status === 401) {
74+
// Token is presumably dead or strictly unauthorized
75+
const userManager = getUserManager();
76+
try {
77+
await userManager.removeUser();
78+
} catch {
79+
// Ignored
80+
}
81+
82+
store.dispatch(removeUser());
83+
store.dispatch(setError({ title: MESSAGES.error.general.unAuthorized }));
84+
85+
// Let it redirect using our auth observer or via location
86+
if (typeof window !== 'undefined') {
87+
window.location.href = '/login';
88+
}
89+
90+
throw { status: 401, title: MESSAGES.error.general.unAuthorized };
91+
}
92+
93+
if (response.status >= 500) {
94+
let data = {};
95+
try {
96+
data = await response.json();
97+
} catch {
98+
// Ignored
99+
}
100+
101+
store.dispatch(setError({ title: MESSAGES.error.general.common }));
102+
throw { ...data, title: MESSAGES.error.general.common };
103+
}
104+
105+
if (!response.ok) {
106+
// 4xx errors
107+
let data = {};
108+
try {
109+
data = await response.json();
110+
} catch {
111+
// Ignored
112+
}
113+
throw data;
114+
}
115+
116+
// Attempt to return the string payload as required by IHttpRequestSender
117+
const text = await response.text();
118+
return text;
119+
}
120+
}

src/shared/constants/endpoints.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/shared/constants/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export * from './endpoints';
21
export * from './routes';
32
export * from './configs';
43
export * from './flows';

src/shared/helpers/data.helpers.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { JsonSerializer } from '@fossa-app/bridge/Services/JsonSerializer';
2+
13
export const parseResponse = <T = unknown>(response: any): T => {
24
if (response.data === '') {
35
return response as T;
@@ -8,20 +10,10 @@ export const parseResponse = <T = unknown>(response: any): T => {
810
}
911

1012
if (typeof response.data === 'string') {
11-
const isBigNumber = (num: string | number): boolean => {
12-
const n = Number(num);
13-
return !isNaN(n) && !Number.isSafeInteger(n);
14-
};
15-
16-
const enquoteBigNumber = (jsonString: string, bigNumChecker: (num: string | number) => boolean): string =>
17-
jsonString.replace(/(:\s*)(\d{15,})(\s*[,}])/g, (match, prefix, numberPart, suffix) =>
18-
bigNumChecker(numberPart) ? `${prefix}"${numberPart}"${suffix}` : match
19-
);
20-
2113
try {
2214
return {
2315
...response,
24-
data: JSON.parse(enquoteBigNumber(response.data, isBigNumber)),
16+
data: new JsonSerializer().Deserialize(response.data),
2517
} as T;
2618
} catch (error) {
2719
console.error('Error parsing response data:', error);

src/shared/helpers/url.helpers.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,3 @@
1-
export const getBackendOrigin = (frontendOrigin: string): string => {
2-
const suffixMappings = new Map([
3-
['.dev.localhost:4211', '.dev.localhost:5210'],
4-
['.test.localhost:4210', '.test.localhost:5211'],
5-
['.test.localhost:4211', '.test.localhost:5211'],
6-
['.localhost:4210', '.localhost:5210'],
7-
]);
8-
9-
for (const [frontendSuffix, backendSuffix] of suffixMappings) {
10-
if (frontendOrigin.endsWith(frontendSuffix)) {
11-
return `${frontendOrigin.slice(0, frontendOrigin.indexOf(frontendSuffix))}${backendSuffix}`;
12-
}
13-
}
14-
15-
return frontendOrigin;
16-
};
17-
181
export const prepareQueryParams = (params: Record<string, any>): string => {
192
const filtered = Object.fromEntries(Object.entries(params).filter(([, value]) => value !== null && value !== undefined && value !== ''));
203

src/shared/types/client.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/shared/types/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export * from './client';
21
export * from './route';
32
export * from './license';
43
export * from './response';

src/store/features/identitySlice.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
22
import { RootState, StateEntity } from 'store';
33
import { fetchClient } from 'store/thunks';
4-
import { Client, ErrorResponseDTO } from 'shared/types';
4+
import { ErrorResponseDTO } from 'shared/types';
5+
import { IdentityClientRetrievalModel } from '@fossa-app/bridge/Models/ApiModels/PayloadModels';
56

67
interface IdentityState {
7-
client: StateEntity<Client | undefined>;
8+
client: StateEntity<IdentityClientRetrievalModel | undefined>;
89
}
910

1011
const initialState: IdentityState = {
@@ -28,7 +29,7 @@ const identitySlice = createSlice({
2829
state.client.fetchStatus = 'failed';
2930
state.client.fetchError = action.payload;
3031
})
31-
.addCase(fetchClient.fulfilled, (state, action: PayloadAction<Client | undefined>) => {
32+
.addCase(fetchClient.fulfilled, (state, action: PayloadAction<IdentityClientRetrievalModel | undefined>) => {
3233
state.client.item = action.payload;
3334
state.client.fetchStatus = 'succeeded';
3435
});

0 commit comments

Comments
 (0)