@vtex/faststore-plugin-buyer-portal 1.3.27 → 1.3.28
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/CHANGELOG.md +8 -2
- package/package.json +1 -1
- package/src/features/addresses/components/AddRecipientsDrawer/AddRecipientsDrawer.tsx +20 -2
- package/src/features/addresses/components/CreateAddressDrawer/CreateAddressDrawer.tsx +50 -4
- package/src/features/addresses/components/DeleteAddressDrawer/DeleteAddressDrawer.tsx +26 -2
- package/src/features/addresses/components/DeleteAddressLocationDrawer/DeleteAddressLocationDrawer.tsx +29 -3
- package/src/features/addresses/components/DeleteRecipientAddressDrawer/DeleteRecipientAddressDrawer.tsx +24 -2
- package/src/features/addresses/components/EditAddressDrawer/EditAddressDrawer.tsx +28 -2
- package/src/features/addresses/components/EditAddressLocationDrawer/EditAddressLocationDrawer.tsx +30 -4
- package/src/features/addresses/components/EditRecipientAddressDrawer/EditRecipientAddressDrawer.tsx +30 -2
- package/src/features/addresses/components/LocationsDrawer/LocationsDrawer.tsx +29 -2
- package/src/features/budgets/components/BudgetDeleteDrawer/BudgetDeleteDrawer.tsx +32 -4
- package/src/features/budgets/components/CreateBudgetDrawer/CreateBudgetDrawer.tsx +59 -4
- package/src/features/budgets/components/EditBudgetDrawer/EditBudgetDrawer.tsx +28 -1
- package/src/features/buying-policies/components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer.tsx +48 -5
- package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/DeleteBuyingPolicyDrawer.tsx +28 -2
- package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/UpdateBuyingPolicyDrawer.tsx +49 -5
- package/src/features/custom-fields/components/CreateCustomFieldValueDrawer/CreateCustomFieldValueDrawer.tsx +60 -5
- package/src/features/custom-fields/components/DeleteCustomFieldValueDrawer/DeleteCustomFieldValueDrawer.tsx +61 -5
- package/src/features/custom-fields/components/UpdateCustomFieldValueDrawer/UpdateCustomFieldValueDrawer.tsx +32 -3
- package/src/features/org-units/components/CreateOrgUnitDrawer/CreateOrgUnitDrawer.tsx +18 -0
- package/src/features/org-units/components/DeleteOrgUnitDrawer/DeleteOrgUnitDrawer.tsx +28 -0
- package/src/features/org-units/components/UpdateOrgUnitDrawer/UpdateOrgUnitDrawer.tsx +28 -0
- package/src/features/shared/hooks/analytics/types.ts +14 -0
- package/src/features/shared/hooks/analytics/useAnalytics.ts +249 -0
- package/src/features/shared/hooks/index.ts +1 -0
- package/src/features/shared/services/logger/analytics/analytics.ts +101 -0
- package/src/features/shared/services/logger/analytics/constants.ts +83 -0
- package/src/features/shared/services/logger/analytics/types.ts +108 -0
- package/src/features/shared/services/logger/index.ts +1 -0
- package/src/features/shared/utils/constants.ts +1 -1
- package/src/features/users/components/CreateUserDrawer/CreateUserDrawer.tsx +24 -0
- package/src/features/users/components/DeleteUserDrawer/DeleteUserDrawer.tsx +23 -2
- package/src/features/users/components/UpdateUserDrawer/UpdateUserDrawer.tsx +45 -4
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics event categories
|
|
3
|
+
*/
|
|
4
|
+
export type EventCategory =
|
|
5
|
+
| "click"
|
|
6
|
+
| "view"
|
|
7
|
+
| "apiAnswer"
|
|
8
|
+
| "webVitals"
|
|
9
|
+
| "creation"
|
|
10
|
+
| "edition"
|
|
11
|
+
| "error"
|
|
12
|
+
| "timing"
|
|
13
|
+
| "interaction";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Analytics event fields
|
|
17
|
+
*/
|
|
18
|
+
export interface DataIngestionApiFields {
|
|
19
|
+
/** The type of the event */
|
|
20
|
+
event_category?: EventCategory;
|
|
21
|
+
/** The name of the event. Has to be unique through the app. */
|
|
22
|
+
event_name: string;
|
|
23
|
+
/** Additional informations */
|
|
24
|
+
/** Time spent on page */
|
|
25
|
+
time_on_page?: number;
|
|
26
|
+
/** Additional metadata about the event */
|
|
27
|
+
metadata?: Record<string, unknown>;
|
|
28
|
+
/** Entity type (e.g., 'budget', 'buying_policy') */
|
|
29
|
+
entity_type?: string;
|
|
30
|
+
/** Entity ID */
|
|
31
|
+
entity_id?: string;
|
|
32
|
+
/** Is this a new entity? */
|
|
33
|
+
is_new?: boolean;
|
|
34
|
+
/** Duration in milliseconds */
|
|
35
|
+
duration_ms?: number;
|
|
36
|
+
/** Step name for multi-step flows */
|
|
37
|
+
step_name?: string;
|
|
38
|
+
/** Flow name for multi-step flows */
|
|
39
|
+
flow_name?: string;
|
|
40
|
+
/** Component type for interactions */
|
|
41
|
+
component_type?: string;
|
|
42
|
+
/** Action performed */
|
|
43
|
+
action?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Internal params for data ingestion API
|
|
48
|
+
*/
|
|
49
|
+
export interface DataIngestionApiParams {
|
|
50
|
+
[key: string]: string | number | boolean | object | undefined;
|
|
51
|
+
workspace?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Step timing properties
|
|
56
|
+
*/
|
|
57
|
+
export interface StepTimingProperties {
|
|
58
|
+
flow_name: string;
|
|
59
|
+
step_name: string;
|
|
60
|
+
from_step?: string;
|
|
61
|
+
to_step?: string;
|
|
62
|
+
duration_ms: number;
|
|
63
|
+
step_index?: number;
|
|
64
|
+
total_steps?: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Error tracking properties
|
|
69
|
+
*/
|
|
70
|
+
export interface ErrorEventProperties {
|
|
71
|
+
error_message: string;
|
|
72
|
+
error_type?: string;
|
|
73
|
+
error_stack?: string;
|
|
74
|
+
entity_type?: string;
|
|
75
|
+
entity_id?: string;
|
|
76
|
+
is_new_entity: boolean;
|
|
77
|
+
operation?: string; // create, update, delete
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Interaction properties
|
|
82
|
+
*/
|
|
83
|
+
export interface InteractionEventProperties {
|
|
84
|
+
component_type: string;
|
|
85
|
+
component_id?: string;
|
|
86
|
+
action: string;
|
|
87
|
+
selected_option?: string;
|
|
88
|
+
metadata?: Record<string, unknown>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Generic entity creation properties
|
|
93
|
+
*/
|
|
94
|
+
export interface EntityCreatedProperties {
|
|
95
|
+
entity_type: string;
|
|
96
|
+
entity_id?: string;
|
|
97
|
+
properties: Record<string, unknown>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Generic entity edition properties
|
|
102
|
+
*/
|
|
103
|
+
export interface EntityEditedProperties {
|
|
104
|
+
entity_type: string;
|
|
105
|
+
entity_id: string;
|
|
106
|
+
changed_fields?: string[];
|
|
107
|
+
properties: Record<string, unknown>;
|
|
108
|
+
}
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
Icon,
|
|
13
13
|
InputText,
|
|
14
14
|
} from "../../../shared/components";
|
|
15
|
+
import { useAnalytics } from "../../../shared/hooks";
|
|
16
|
+
import { ANALYTICS_EVENTS } from "../../../shared/services/logger/analytics/constants";
|
|
15
17
|
import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
16
18
|
import { maskPhoneNumber } from "../../../shared/utils/phoneNumber";
|
|
17
19
|
import { useAddUserToOrgUnit } from "../../hooks";
|
|
@@ -31,6 +33,11 @@ export const CreateUserDrawer = ({
|
|
|
31
33
|
}: CreateUserDrawerProps) => {
|
|
32
34
|
const { pushToast } = useUI();
|
|
33
35
|
const router = useRouter();
|
|
36
|
+
const { trackEntityCreated, trackEntityCreateError } = useAnalytics({
|
|
37
|
+
entityType: "user",
|
|
38
|
+
defaultTimerName: "user_creation",
|
|
39
|
+
shouldTrackDefaultTimer: true,
|
|
40
|
+
});
|
|
34
41
|
const [drawerState, setDrawerState] = useState<
|
|
35
42
|
"CREATE_USER" | "USER_ALREADY_EXISTS"
|
|
36
43
|
>("CREATE_USER");
|
|
@@ -74,6 +81,15 @@ export const CreateUserDrawer = ({
|
|
|
74
81
|
};
|
|
75
82
|
|
|
76
83
|
const handleAddUserSuccess = ({ user }: { user: { id: string } }) => {
|
|
84
|
+
trackEntityCreated(ANALYTICS_EVENTS.USER_CREATED, "user", {
|
|
85
|
+
user_name: name,
|
|
86
|
+
user_email: email,
|
|
87
|
+
user_phone: phone,
|
|
88
|
+
roles_count: roles.length,
|
|
89
|
+
role_ids: roles,
|
|
90
|
+
org_unit_id: orgUnitId,
|
|
91
|
+
});
|
|
92
|
+
|
|
77
93
|
pushToast({
|
|
78
94
|
message: "User successfully added",
|
|
79
95
|
status: "INFO",
|
|
@@ -112,6 +128,14 @@ export const CreateUserDrawer = ({
|
|
|
112
128
|
};
|
|
113
129
|
};
|
|
114
130
|
|
|
131
|
+
trackEntityCreateError(ANALYTICS_EVENTS.USER_CREATE_ERROR, err, {
|
|
132
|
+
org_unit_id: orgUnitId,
|
|
133
|
+
error_type:
|
|
134
|
+
error.code === "USER_ALREADY_EXISTS"
|
|
135
|
+
? "user_already_exists"
|
|
136
|
+
: "unknown",
|
|
137
|
+
});
|
|
138
|
+
|
|
115
139
|
setUserAlreadyInUse({
|
|
116
140
|
...error.user,
|
|
117
141
|
orgUnit: error.orgUnit,
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
InputText,
|
|
9
9
|
type BasicDrawerProps,
|
|
10
10
|
} from "../../../shared/components";
|
|
11
|
+
import { useAnalytics } from "../../../shared/hooks";
|
|
12
|
+
import { ANALYTICS_EVENTS } from "../../../shared/services/logger/analytics/constants";
|
|
11
13
|
import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
12
14
|
import { useRemoveUserFromOrgUnit } from "../../hooks";
|
|
13
15
|
|
|
@@ -26,10 +28,22 @@ export const DeleteUserDrawer = ({
|
|
|
26
28
|
const [userNameConfirmation, setUserNameConfirmation] = useState("");
|
|
27
29
|
|
|
28
30
|
const { pushToast } = useUI();
|
|
29
|
-
|
|
30
31
|
const { orgUnit } = useOrgUnitByUser(user.id);
|
|
32
|
+
const { trackEvent } = useAnalytics({
|
|
33
|
+
entityType: "user",
|
|
34
|
+
entityId: user.id,
|
|
35
|
+
defaultTimerName: "user_delete",
|
|
36
|
+
shouldTrackDefaultTimer: true,
|
|
37
|
+
});
|
|
31
38
|
|
|
32
39
|
const handleRemoveSuccess = () => {
|
|
40
|
+
trackEvent(ANALYTICS_EVENTS.USER_DELETED, {
|
|
41
|
+
user_id: user.id,
|
|
42
|
+
user_name: user.name,
|
|
43
|
+
org_unit_id: orgUnit?.id,
|
|
44
|
+
entity_type: "user",
|
|
45
|
+
});
|
|
46
|
+
|
|
33
47
|
pushToast({
|
|
34
48
|
message: "User successfully deleted",
|
|
35
49
|
status: "INFO",
|
|
@@ -52,7 +66,14 @@ export const DeleteUserDrawer = ({
|
|
|
52
66
|
const { removeUserFromOrgUnit, isRemoveUserFromOrgUnitLoading } =
|
|
53
67
|
useRemoveUserFromOrgUnit({
|
|
54
68
|
onSuccess: handleRemoveSuccess,
|
|
55
|
-
onError: () => {
|
|
69
|
+
onError: (error) => {
|
|
70
|
+
trackEvent(ANALYTICS_EVENTS.USER_DELETE_ERROR, {
|
|
71
|
+
entity_id: user.id,
|
|
72
|
+
user_name: user.name,
|
|
73
|
+
error_message: error instanceof Error ? error.message : String(error),
|
|
74
|
+
org_unit_id: orgUnit?.id,
|
|
75
|
+
});
|
|
76
|
+
|
|
56
77
|
pushToast({
|
|
57
78
|
message: "An error occurred while deleting the user",
|
|
58
79
|
status: "ERROR",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { Skeleton, useUI } from "@faststore/ui";
|
|
4
4
|
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
ErrorMessage,
|
|
11
11
|
InputText,
|
|
12
12
|
} from "../../../shared/components";
|
|
13
|
+
import { useAnalytics } from "../../../shared/hooks";
|
|
14
|
+
import { ANALYTICS_EVENTS } from "../../../shared/services/logger/analytics/constants";
|
|
13
15
|
import { maskPhoneNumber } from "../../../shared/utils/phoneNumber";
|
|
14
16
|
import { useGetUserById, useUpdateUser } from "../../hooks";
|
|
15
17
|
|
|
@@ -29,16 +31,25 @@ export const UpdateUserDrawer = ({
|
|
|
29
31
|
...props
|
|
30
32
|
}: UpdateUserDrawerProps) => {
|
|
31
33
|
const { pushToast } = useUI();
|
|
34
|
+
const { trackEntityEdited, trackEntityEditError } = useAnalytics({
|
|
35
|
+
entityType: "user",
|
|
36
|
+
entityId: userId,
|
|
37
|
+
defaultTimerName: "user_edit",
|
|
38
|
+
shouldTrackDefaultTimer: true,
|
|
39
|
+
});
|
|
40
|
+
const initialRolesRef = useRef<string[]>([]);
|
|
32
41
|
|
|
33
42
|
const { isUserLoading } = useGetUserById(
|
|
34
43
|
{ orgUnitId, userId },
|
|
35
44
|
{
|
|
36
45
|
onSuccess: (data) => {
|
|
46
|
+
const userRoles = data?.roles ? data.roles : [];
|
|
47
|
+
initialRolesRef.current = userRoles;
|
|
37
48
|
setForm({
|
|
38
49
|
name: data?.name ?? "",
|
|
39
50
|
email: data?.email ?? "",
|
|
40
51
|
phone: data?.phone ?? "",
|
|
41
|
-
roles:
|
|
52
|
+
roles: userRoles,
|
|
42
53
|
});
|
|
43
54
|
},
|
|
44
55
|
onError: () => {
|
|
@@ -74,6 +85,16 @@ export const UpdateUserDrawer = ({
|
|
|
74
85
|
};
|
|
75
86
|
|
|
76
87
|
const handleUpdateUserSuccess = () => {
|
|
88
|
+
trackEntityEdited(ANALYTICS_EVENTS.USER_EDITED, {
|
|
89
|
+
user_id: userId,
|
|
90
|
+
user_name: name,
|
|
91
|
+
user_phone: phone,
|
|
92
|
+
old_roles: initialRolesRef.current,
|
|
93
|
+
new_roles: roles,
|
|
94
|
+
roles_count: roles.length,
|
|
95
|
+
org_unit_id: orgUnitId,
|
|
96
|
+
});
|
|
97
|
+
|
|
77
98
|
pushToast({
|
|
78
99
|
message: "User successfully updated",
|
|
79
100
|
status: "INFO",
|
|
@@ -84,7 +105,17 @@ export const UpdateUserDrawer = ({
|
|
|
84
105
|
|
|
85
106
|
const { updateUser, isUpdateUserLoading } = useUpdateUser({
|
|
86
107
|
onSuccess: handleUpdateUserSuccess,
|
|
87
|
-
onError: () => {
|
|
108
|
+
onError: (error) => {
|
|
109
|
+
trackEntityEditError(
|
|
110
|
+
ANALYTICS_EVENTS.USER_EDIT_ERROR,
|
|
111
|
+
"user",
|
|
112
|
+
userId,
|
|
113
|
+
error,
|
|
114
|
+
{
|
|
115
|
+
org_unit_id: orgUnitId,
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
88
119
|
pushToast({
|
|
89
120
|
message: "Failed to update user",
|
|
90
121
|
status: "ERROR",
|
|
@@ -94,7 +125,17 @@ export const UpdateUserDrawer = ({
|
|
|
94
125
|
|
|
95
126
|
const { updateRoles, isUpdateRolesLoading } = useUpdateRoles({
|
|
96
127
|
onSuccess: handleUpdateUserSuccess,
|
|
97
|
-
onError: () => {
|
|
128
|
+
onError: (error) => {
|
|
129
|
+
trackEntityEditError(
|
|
130
|
+
ANALYTICS_EVENTS.USER_EDIT_ERROR,
|
|
131
|
+
"user",
|
|
132
|
+
userId,
|
|
133
|
+
error,
|
|
134
|
+
{
|
|
135
|
+
org_unit_id: orgUnitId,
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
|
|
98
139
|
pushToast({
|
|
99
140
|
message: "Failed to update user",
|
|
100
141
|
status: "ERROR",
|