@reservamos/browser-analytics 1.0.7 → 1.0.10-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-analytics.cjs +3 -3
- package/dist/browser-analytics.cjs.map +1 -1
- package/dist/browser-analytics.d.ts +137 -6
- package/dist/browser-analytics.esm.js +871 -2850
- package/dist/browser-analytics.esm.js.map +1 -1
- package/dist/browser-analytics.iife.js +3 -3
- package/dist/browser-analytics.iife.js.map +1 -1
- package/package.json +2 -2
- package/src/events/customEvent/trackCustomEvent.ts +1 -1
- package/src/events/identify/identify.ts +14 -14
- package/src/index.ts +17 -2
- package/src/init.ts +4 -22
- package/src/profiles/createAnonymousProfile/createAnonymousProfile.ts +10 -33
- package/src/recommendations/createRecommendedSeats/createRecommendedSeats.ts +40 -0
- package/src/recommendations/createRecommendedSeats/createRecommendedSeatsSchema.ts +25 -0
- package/src/recommendations/createRecommendedSeats/index.ts +5 -0
- package/src/recommendations/getRecommendedPlaces/getRecommendedPlaces.ts +63 -0
- package/src/recommendations/getRecommendedPlaces/index.ts +3 -0
- package/src/recommendations/getRecommendedSeats/getRecommendedSeats.ts +37 -0
- package/src/recommendations/getRecommendedSeats/getRecommendedSeatsSchema.ts +24 -0
- package/src/recommendations/getRecommendedSeats/index.ts +5 -0
- package/src/recommendations/getRecommendedTrips/getRecommendedTrips.ts +36 -0
- package/src/recommendations/getRecommendedTrips/getRecommendedTripsSchema.ts +10 -0
- package/src/recommendations/getRecommendedTrips/index.ts +5 -0
- package/src/services/config.ts +33 -10
- package/src/services/mixpanel.ts +2 -2
- package/src/track.ts +16 -31
- package/src/js-api-client.d.ts +0 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reservamos/browser-analytics",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10-alpha.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/reservamos/reservamos-browser-analytics.git"
|
|
@@ -88,6 +88,6 @@
|
|
|
88
88
|
"upgradeps": "^2.0.6",
|
|
89
89
|
"vite": "^5.0.12",
|
|
90
90
|
"vitest": "^1.2.1",
|
|
91
|
-
"@reservamos/js-api-client": "
|
|
91
|
+
"@reservamos/js-api-client": "6.0.0-alpha.5"
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getApiConfig } from '@/init';
|
|
2
1
|
import createAnonymousProfile from '@/profiles/createAnonymousProfile';
|
|
2
|
+
import configService from '@/services/config';
|
|
3
3
|
import geolocationService from '@/services/geolocation';
|
|
4
4
|
import validatorService from '@/services/validator';
|
|
5
5
|
import { trackEventError, tryTrackEvent } from '@/track';
|
|
@@ -53,7 +53,6 @@ const identifyWithLocation = async (
|
|
|
53
53
|
properties: UserProperties,
|
|
54
54
|
) => {
|
|
55
55
|
try {
|
|
56
|
-
const apiConfig = getApiConfig();
|
|
57
56
|
const coordinates = geolocationService.getCoordinates();
|
|
58
57
|
|
|
59
58
|
if (!coordinates) {
|
|
@@ -69,12 +68,13 @@ const identifyWithLocation = async (
|
|
|
69
68
|
delete properties.firstName;
|
|
70
69
|
delete properties.lastName;
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
const coreApiConfig = configService.getCoreAPIConfig();
|
|
72
|
+
fetch(`${coreApiConfig.baseUrl}/v1/datalake/identify`, {
|
|
73
73
|
method: 'POST',
|
|
74
74
|
headers: {
|
|
75
75
|
'Content-Type': 'application/json',
|
|
76
|
-
'Authorization':
|
|
77
|
-
|
|
76
|
+
'Authorization': coreApiConfig.defaultHeaders?.Authorization || '',
|
|
77
|
+
'Origin': coreApiConfig.defaultHeaders?.Origin || '',
|
|
78
78
|
},
|
|
79
79
|
body: JSON.stringify({
|
|
80
80
|
profile_params: {
|
|
@@ -99,8 +99,8 @@ async function identify(
|
|
|
99
99
|
userId: string,
|
|
100
100
|
properties: UserProperties = {},
|
|
101
101
|
): Promise<void> {
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
tryTrackEvent(async () => {
|
|
103
|
+
try {
|
|
104
104
|
validatorService.parseIdentifyProps(properties);
|
|
105
105
|
|
|
106
106
|
if (!userId) {
|
|
@@ -118,13 +118,13 @@ async function identify(
|
|
|
118
118
|
if (fingerprint) {
|
|
119
119
|
mixpanelService.attachProperty(FINGERPRINT_PROPERTY, fingerprint);
|
|
120
120
|
}
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Error identifying user', error);
|
|
123
|
+
trackEventError('Identify', error, { userId, properties });
|
|
124
|
+
} finally {
|
|
125
|
+
identifyWithLocation(userId, properties);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
export default identify;
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,10 @@ import type { SearchProps } from '@/events/search';
|
|
|
10
10
|
import type { SeatChangeProps } from '@/events/seatChange';
|
|
11
11
|
import type { ViewResultsProps } from '@/events/viewResults';
|
|
12
12
|
import type { CreateAnonymousProfileProps } from '@/profiles/createAnonymousProfile';
|
|
13
|
+
import type { CreateRecommendedSeatsSchemaProps } from '@/recommendations/createRecommendedSeats';
|
|
14
|
+
import type { GetRecommendedSeatsSchemaProps } from '@/recommendations/getRecommendedSeats';
|
|
13
15
|
import type { EventData, EventMetadata } from '@/types/eventData';
|
|
16
|
+
import type { GetRecommendedTripsProps } from '@/recommendations/getRecommendedTrips';
|
|
14
17
|
import trackCustomEvent from '@/events/customEvent';
|
|
15
18
|
import identify from '@/events/identify';
|
|
16
19
|
import trackInterestInHome from '@/events/interestInHome';
|
|
@@ -19,15 +22,18 @@ import trackPassengersCreated from '@/events/passengersCreated';
|
|
|
19
22
|
import trackPaymentAttempt from '@/events/paymentAttempt';
|
|
20
23
|
import trackPickedDeparture from '@/events/pickedDeparture';
|
|
21
24
|
import trackPurchaseAttempt from '@/events/purchaseAttempt';
|
|
25
|
+
import trackPurchaseCanceled from '@/events/purchaseCanceled';
|
|
22
26
|
import trackSearch from '@/events/search';
|
|
23
27
|
import trackSeatChange from '@/events/seatChange';
|
|
24
28
|
import trackViewResults from '@/events/viewResults';
|
|
25
29
|
import init, { isTrackerReady } from '@/init';
|
|
26
30
|
import createAnonymousProfile from '@/profiles/createAnonymousProfile';
|
|
31
|
+
import createRecommendedSeats from '@/recommendations/createRecommendedSeats';
|
|
32
|
+
import getRecommendedPlaces from '@/recommendations/getRecommendedPlaces';
|
|
33
|
+
import getRecommendedSeats from '@/recommendations/getRecommendedSeats';
|
|
34
|
+
import getRecommendedTrips from '@/recommendations/getRecommendedTrips';
|
|
27
35
|
import fingerprintService from '@/services/fingerprint';
|
|
28
36
|
import mixpanelService from '@/services/mixpanel';
|
|
29
|
-
import './js-api-client.d.ts';
|
|
30
|
-
import trackPurchaseCanceled from './events/purchaseCanceled/trackPurchaseCanceled.js';
|
|
31
37
|
|
|
32
38
|
const analytics = {
|
|
33
39
|
init,
|
|
@@ -40,6 +46,12 @@ const analytics = {
|
|
|
40
46
|
profiles: {
|
|
41
47
|
createAnonymousProfile,
|
|
42
48
|
},
|
|
49
|
+
recommendations: {
|
|
50
|
+
getRecommendedPlaces,
|
|
51
|
+
createRecommendedSeats,
|
|
52
|
+
getRecommendedSeats,
|
|
53
|
+
getRecommendedTrips,
|
|
54
|
+
},
|
|
43
55
|
track: {
|
|
44
56
|
search: trackSearch,
|
|
45
57
|
seatChange: trackSeatChange,
|
|
@@ -70,6 +82,9 @@ export type {
|
|
|
70
82
|
EventMetadata,
|
|
71
83
|
EventData,
|
|
72
84
|
PurchaseCanceledProps,
|
|
85
|
+
GetRecommendedSeatsSchemaProps,
|
|
86
|
+
CreateRecommendedSeatsSchemaProps,
|
|
87
|
+
GetRecommendedTripsProps,
|
|
73
88
|
};
|
|
74
89
|
|
|
75
90
|
export default analytics;
|
package/src/init.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import coreApi from '@reservamos/js-api-client/core';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import configService from '@/services/config';
|
|
4
4
|
import fingerprintService from '@/services/fingerprint';
|
|
@@ -21,15 +21,6 @@ function onLoaded() {
|
|
|
21
21
|
window.dispatchEvent(new CustomEvent('Tracker Ready'));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
interface ApiConfig {
|
|
25
|
-
coreUrl: string;
|
|
26
|
-
coreVersion: string;
|
|
27
|
-
headers: { Origin: string };
|
|
28
|
-
coreApiKey: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let apiConfig: ApiConfig | null = null;
|
|
32
|
-
|
|
33
24
|
/**
|
|
34
25
|
* Initializes the tracking library with the provided configuration.
|
|
35
26
|
* @param {InitConfig} config - The configuration object for initialization.
|
|
@@ -60,10 +51,8 @@ async function init(config: InitConfig) {
|
|
|
60
51
|
console.error('Error initializing identification service:', error);
|
|
61
52
|
}
|
|
62
53
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
setApiConfig(apiConfig);
|
|
54
|
+
configService.setEnvironment(isSandbox ? 'sandbox' : 'prod');
|
|
55
|
+
coreApi.setConfig(configService.getCoreAPIConfig());
|
|
67
56
|
|
|
68
57
|
// Dispatch the 'Tracker Ready' event
|
|
69
58
|
onLoaded();
|
|
@@ -79,12 +68,5 @@ function isTrackerReady(): boolean {
|
|
|
79
68
|
return mixpanelService.isReady();
|
|
80
69
|
}
|
|
81
70
|
|
|
82
|
-
|
|
83
|
-
* Returns the current API configuration.
|
|
84
|
-
* @returns {ApiConfig | null} The current API configuration or null if not initialized.
|
|
85
|
-
*/
|
|
86
|
-
function getApiConfig(): ApiConfig | null {
|
|
87
|
-
return apiConfig;
|
|
88
|
-
}
|
|
89
|
-
export { isTrackerReady, getApiConfig };
|
|
71
|
+
export { isTrackerReady };
|
|
90
72
|
export default init;
|
|
@@ -1,31 +1,20 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnonymousIdentifier,
|
|
3
|
+
AnonymousProfile,
|
|
4
|
+
CreateAnonymousProfilePayload,
|
|
5
|
+
IdentifierKey,
|
|
6
|
+
} from '@reservamos/js-api-client/core';
|
|
1
7
|
import type { CreateAnonymousProfileProps } from './createAnonymousProfileSchema';
|
|
2
|
-
import
|
|
8
|
+
import coreApi from '@reservamos/js-api-client/core';
|
|
3
9
|
import fingerprintService from '@/services/fingerprint';
|
|
4
10
|
import mixpanelService from '@/services/mixpanel';
|
|
5
11
|
import validatorService from '@/services/validator';
|
|
6
12
|
import CreateAnonymousProfileSchema from './createAnonymousProfileSchema';
|
|
7
13
|
|
|
8
|
-
type IdentifierKey = 'phone' | 'email';
|
|
9
|
-
|
|
10
|
-
interface AnonymousProfilePayload {
|
|
11
|
-
identifier_key: IdentifierKey;
|
|
12
|
-
identifier_value: string;
|
|
13
|
-
identifiers: AnonymousIdentifier[];
|
|
14
|
-
details: Record<string, string>;
|
|
15
|
-
}
|
|
16
|
-
interface AnonymousProfileResponse {
|
|
17
|
-
id: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Transforms the identifier object based on the provided values.
|
|
21
|
-
* @param {CreateAnonymousProfileProps} values - The values to transform.
|
|
22
|
-
* @param {AnonymousIdentifier[]} identifiersProps - Additional identifiers to include.
|
|
23
|
-
* @returns {AnonymousProfilePayload} The transformed identifier object.
|
|
24
|
-
*/
|
|
25
14
|
function getAnonymousProfilePayload(
|
|
26
15
|
values: CreateAnonymousProfileProps,
|
|
27
16
|
identifiersProps: AnonymousIdentifier[],
|
|
28
|
-
):
|
|
17
|
+
): CreateAnonymousProfilePayload {
|
|
29
18
|
let identifier_key: IdentifierKey = 'phone';
|
|
30
19
|
let identifier_value: string = values.phone || '';
|
|
31
20
|
const identifiers: AnonymousIdentifier[] = [];
|
|
@@ -65,19 +54,9 @@ function getAnonymousProfilePayload(
|
|
|
65
54
|
};
|
|
66
55
|
}
|
|
67
56
|
|
|
68
|
-
interface AnonymousIdentifier {
|
|
69
|
-
key: string;
|
|
70
|
-
value: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Creates an anonymous profile using the provided payload.
|
|
75
|
-
* @param {CreateAnonymousProfileProps} payload - The payload to create the anonymous profile.
|
|
76
|
-
* @returns {Promise<void>} - A promise that resolves when the anonymous profile is created.
|
|
77
|
-
*/
|
|
78
57
|
async function createAnonymousProfile(
|
|
79
58
|
payload: CreateAnonymousProfileProps,
|
|
80
|
-
): Promise<
|
|
59
|
+
): Promise<AnonymousProfile | undefined> {
|
|
81
60
|
try {
|
|
82
61
|
validatorService.validateProps(payload, CreateAnonymousProfileSchema);
|
|
83
62
|
|
|
@@ -90,9 +69,7 @@ async function createAnonymousProfile(
|
|
|
90
69
|
if (distinctId) identifiers.push({ key: 'distinct_id', value: distinctId });
|
|
91
70
|
|
|
92
71
|
const dataPayload = getAnonymousProfilePayload(payload, identifiers);
|
|
93
|
-
|
|
94
|
-
const result = await coreApi.createAnonymousProfile(dataPayload);
|
|
95
|
-
return result.data;
|
|
72
|
+
return await coreApi.profiles.createAnonymousProfile(dataPayload);
|
|
96
73
|
} catch (error) {
|
|
97
74
|
console.error('Could not create anonymous profile:', error);
|
|
98
75
|
return undefined;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RecommendedSeatsPayload,
|
|
3
|
+
RecommendedSeatsResponse,
|
|
4
|
+
} from '@reservamos/js-api-client/core';
|
|
5
|
+
import coreApi from '@reservamos/js-api-client/core';
|
|
6
|
+
import fingerprintService from '@/services/fingerprint';
|
|
7
|
+
import mixpanelService from '@/services/mixpanel';
|
|
8
|
+
import validatorService from '@/services/validator';
|
|
9
|
+
import CreateRecommendedSeatsSchema from './createRecommendedSeatsSchema';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates recommended seats by combining the provided payload with user identification data
|
|
13
|
+
* from Mixpanel and Fingerprint services.
|
|
14
|
+
* @throws {Error} When no distinct ID is found
|
|
15
|
+
* @throws {Error} When payload validation fails
|
|
16
|
+
* @throws {Error} When the API request fails
|
|
17
|
+
*/
|
|
18
|
+
async function createRecommendedSeats(
|
|
19
|
+
payload: RecommendedSeatsPayload,
|
|
20
|
+
): Promise<RecommendedSeatsResponse> {
|
|
21
|
+
try {
|
|
22
|
+
validatorService.validateProps(payload, CreateRecommendedSeatsSchema);
|
|
23
|
+
const distinctId = mixpanelService.getMixpanelDistinctId();
|
|
24
|
+
const userFingerprintId = fingerprintService.getCachedFingerprint();
|
|
25
|
+
if (!distinctId) {
|
|
26
|
+
throw new Error('No distinct ID found');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return await coreApi.recommendations.createRecommendedSeats({
|
|
30
|
+
...payload,
|
|
31
|
+
distinct_id: distinctId,
|
|
32
|
+
device_fingerprint: userFingerprintId || '',
|
|
33
|
+
});
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error('Could not create recommended seats:', error);
|
|
36
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default createRecommendedSeats;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
const SeatSchema = z.object({
|
|
4
|
+
category: z.string(),
|
|
5
|
+
number: z.string().optional(),
|
|
6
|
+
occupied: z.boolean().optional(),
|
|
7
|
+
adjacent_seats: z.null().optional(),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const BusSchemeSchema = z.object({
|
|
11
|
+
bus: z.array(z.array(z.array(SeatSchema))),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const CreateRecommendedSeatsSchema = z.object({
|
|
15
|
+
bus_type: z.string(),
|
|
16
|
+
selected_seats: z.string(),
|
|
17
|
+
bus_scheme: BusSchemeSchema,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
type CreateRecommendedSeatsSchemaProps = z.infer<
|
|
21
|
+
typeof CreateRecommendedSeatsSchema
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
export type { CreateRecommendedSeatsSchemaProps };
|
|
25
|
+
export default CreateRecommendedSeatsSchema;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { RecommendedPlacesResponse } from '@reservamos/js-api-client/core';
|
|
2
|
+
import coreApi from '@reservamos/js-api-client/core';
|
|
3
|
+
import mixpanelService from '@/services/mixpanel';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Polls the recommended places API until a final state is reached
|
|
7
|
+
* @throws Will reject the promise if the polling status returns 'failed'
|
|
8
|
+
* @private
|
|
9
|
+
*/
|
|
10
|
+
const pollingRecommendedPlaces = async (
|
|
11
|
+
response: RecommendedPlacesResponse,
|
|
12
|
+
) => {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const { state, polling_id } = response;
|
|
15
|
+
if (state === 'finished') {
|
|
16
|
+
resolve(response);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
coreApi.recommendations.pollRecommendedPlaces(polling_id, {
|
|
20
|
+
start: true,
|
|
21
|
+
watch: 'state',
|
|
22
|
+
expect: 'finished',
|
|
23
|
+
onEachResponse: (profile) => {
|
|
24
|
+
if (profile.status === 'finished') {
|
|
25
|
+
resolve(profile);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (profile.status === 'failed') {
|
|
29
|
+
reject(profile);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Fetches personalized place recommendations for a user
|
|
39
|
+
* This function retrieves recommended places based on the user's Mixpanel distinct ID.
|
|
40
|
+
* It initiates the recommendation process and polls until the results are ready.
|
|
41
|
+
* @returns {Promise<RecommendedPlacesResponse>} A promise that resolves with the recommended places
|
|
42
|
+
* @throws {Error} When no Mixpanel distinct ID is found
|
|
43
|
+
* @throws {Error} When no response is received from the recommendations API
|
|
44
|
+
*/
|
|
45
|
+
async function getRecommendedPlaces(): Promise<RecommendedPlacesResponse> {
|
|
46
|
+
const distinctId = mixpanelService.getMixpanelDistinctId();
|
|
47
|
+
if (!distinctId) {
|
|
48
|
+
throw new Error('No distinct ID found');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const response = await coreApi.recommendations.createRecommendedPlaces({
|
|
52
|
+
distinct_id: distinctId,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (!response) {
|
|
56
|
+
throw new Error('No response received');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const profile = await pollingRecommendedPlaces(response);
|
|
60
|
+
return profile as RecommendedPlacesResponse;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default getRecommendedPlaces;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GetRecommendedSeatsPayload,
|
|
3
|
+
GetRecommendedSeatsResponse,
|
|
4
|
+
} from '@reservamos/js-api-client/core';
|
|
5
|
+
import coreApi from '@reservamos/js-api-client/core';
|
|
6
|
+
import mixpanelService from '@/services/mixpanel';
|
|
7
|
+
import validatorService from '@/services/validator';
|
|
8
|
+
import GetRecommendedSeatsSchema from './getRecommendedSeatsSchema';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create recommended seats by combining the provided payload with data from
|
|
12
|
+
* user identification from Mixpanel and Fingerprint services.
|
|
13
|
+
* @throws {Error} When the payload fails schema validation
|
|
14
|
+
* @throws {Error} When no Mixpanel distinct ID is found
|
|
15
|
+
* @throws {Error} When the API request fails
|
|
16
|
+
*/
|
|
17
|
+
async function createRecommendedSeats(
|
|
18
|
+
payload: GetRecommendedSeatsPayload,
|
|
19
|
+
): Promise<GetRecommendedSeatsResponse> {
|
|
20
|
+
try {
|
|
21
|
+
validatorService.validateProps(payload, GetRecommendedSeatsSchema);
|
|
22
|
+
const distinctId = mixpanelService.getMixpanelDistinctId();
|
|
23
|
+
if (!distinctId) {
|
|
24
|
+
throw new Error('No distinct ID found');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return await coreApi.recommendations.getRecommendedSeats({
|
|
28
|
+
...payload,
|
|
29
|
+
distinct_id: distinctId,
|
|
30
|
+
});
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error('Could not create recommended seats:', error);
|
|
33
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default createRecommendedSeats;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
const SeatSchema = z.object({
|
|
4
|
+
category: z.string(),
|
|
5
|
+
number: z.string().optional(),
|
|
6
|
+
occupied: z.boolean().optional(),
|
|
7
|
+
adjacent_seats: z.null().optional(),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const BusSchemeSchema = z.object({
|
|
11
|
+
bus: z.array(z.array(z.array(SeatSchema))),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const GetRecommendedSeatsSchema = z.object({
|
|
15
|
+
bus_scheme: BusSchemeSchema,
|
|
16
|
+
total_seats: z.number()
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
type GetRecommendedSeatsSchemaProps = z.infer<
|
|
20
|
+
typeof GetRecommendedSeatsSchema
|
|
21
|
+
>;
|
|
22
|
+
|
|
23
|
+
export type { GetRecommendedSeatsSchemaProps };
|
|
24
|
+
export default GetRecommendedSeatsSchema;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RecommendedTripsResponse,
|
|
3
|
+
GetRecommendedTripsPayload
|
|
4
|
+
} from '@reservamos/js-api-client/core';
|
|
5
|
+
import coreApi from '@reservamos/js-api-client/core';
|
|
6
|
+
import fingerprintService from '@/services/fingerprint';
|
|
7
|
+
import mixpanelService from '@/services/mixpanel';
|
|
8
|
+
import validatorService from '@/services/validator';
|
|
9
|
+
import GetRecommendedTripsSchema from './getRecommendedTripsSchema';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fetches recommended trips based on the provided search ID.
|
|
13
|
+
* @throws Error if user identifier is not loaded correctly or if the api request fails
|
|
14
|
+
*/
|
|
15
|
+
async function getRecommendedTrips({
|
|
16
|
+
searchId,
|
|
17
|
+
}: GetRecommendedTripsPayload): Promise<RecommendedTripsResponse> {
|
|
18
|
+
try {
|
|
19
|
+
validatorService.validateProps({ searchId }, GetRecommendedTripsSchema);
|
|
20
|
+
const identifier =
|
|
21
|
+
fingerprintService.getCachedFingerprint() ||
|
|
22
|
+
mixpanelService.getMixpanelDistinctId();
|
|
23
|
+
if (!identifier) throw new Error('No identifier id');
|
|
24
|
+
|
|
25
|
+
const response = await coreApi.recommendations.getRecommendedTrips({
|
|
26
|
+
searchId,
|
|
27
|
+
userIdentifier: String(identifier),
|
|
28
|
+
});
|
|
29
|
+
return response;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('Could not get recommended trips:', error);
|
|
32
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default getRecommendedTrips;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
const GetRecommendedTripsSchema = z.object({
|
|
4
|
+
searchId: z.number().min(1, 'SearchId is required'),
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
type GetRecommendedTripsProps = z.infer<typeof GetRecommendedTripsSchema>;
|
|
8
|
+
|
|
9
|
+
export type { GetRecommendedTripsProps };
|
|
10
|
+
export default GetRecommendedTripsSchema;
|
package/src/services/config.ts
CHANGED
|
@@ -1,26 +1,49 @@
|
|
|
1
|
+
import type { ApiConfig } from '@reservamos/js-api-client/core';
|
|
2
|
+
|
|
3
|
+
type AvailableEnvironments = 'sandbox' | 'prod';
|
|
4
|
+
|
|
5
|
+
let environment: AvailableEnvironments | undefined;
|
|
1
6
|
const origin = window.location.origin;
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
type CoreAPIConfig = Record<AvailableEnvironments, ApiConfig>;
|
|
9
|
+
|
|
10
|
+
const coreAPIConfig: CoreAPIConfig = {
|
|
4
11
|
sandbox: {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
headers: {
|
|
12
|
+
baseUrl: 'https://datalake-api-dev.reservamossaas.com/api',
|
|
13
|
+
defaultHeaders: {
|
|
8
14
|
Origin: origin,
|
|
15
|
+
Authorization: 'Bearer 753bf0710dc920a84236d42241d4f487',
|
|
9
16
|
},
|
|
10
|
-
coreApiKey: 'Bearer 753bf0710dc920a84236d42241d4f487'
|
|
11
17
|
},
|
|
12
18
|
prod: {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
headers: {
|
|
19
|
+
baseUrl: 'https://data-lake.reservamossaas.com/api',
|
|
20
|
+
defaultHeaders: {
|
|
16
21
|
Origin: origin,
|
|
22
|
+
Authorization: 'Bearer 753bf0710dc920a84236d42241d4f487',
|
|
17
23
|
},
|
|
18
|
-
coreApiKey:'Bearer 753bf0710dc920a84236d42241d4f487'
|
|
19
24
|
},
|
|
20
25
|
};
|
|
21
26
|
|
|
27
|
+
function setEnvironment(env: AvailableEnvironments) {
|
|
28
|
+
environment = env;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the core API config for the current environment.
|
|
33
|
+
* @throws {Error} Throws an error if the environment is not set.
|
|
34
|
+
*/
|
|
35
|
+
function getCoreAPIConfig(): ApiConfig {
|
|
36
|
+
if (!environment) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
'Unable to get core API config, environment not set. Use configService.setEnvironment(environment) to set the environment.',
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return coreAPIConfig[environment];
|
|
42
|
+
}
|
|
43
|
+
|
|
22
44
|
const configService = {
|
|
23
|
-
|
|
45
|
+
setEnvironment,
|
|
46
|
+
getCoreAPIConfig,
|
|
24
47
|
};
|
|
25
48
|
|
|
26
49
|
export default configService;
|
package/src/services/mixpanel.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import mixpanel from 'mixpanel-browser';
|
|
2
|
+
import { version } from '../../package.json';
|
|
2
3
|
|
|
3
4
|
declare global {
|
|
4
5
|
interface Window {
|
|
@@ -79,8 +80,7 @@ function track(eventName: string, properties: Record<string, unknown>): void {
|
|
|
79
80
|
if (!isReady()) {
|
|
80
81
|
return;
|
|
81
82
|
}
|
|
82
|
-
|
|
83
|
-
mixpanel.track(eventName, properties);
|
|
83
|
+
mixpanel.track(eventName, { ...properties, 'Reservamos Version': version });
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|