From eba01f09dce118ceb5da80aae716c1524e84bb3b Mon Sep 17 00:00:00 2001 From: farmerpaul Date: Fri, 23 Feb 2024 10:30:47 -0400 Subject: [PATCH 1/5] M2-5202: add missing `.env.example` --- .env.example | 8 ++++++++ .gitignore | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..b73cd1d5a --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +NODE_ENV=development +VITE_ENV=dev +VITE_API_HOST=http://localhost:8000/ +VITE_ADMIN_PANEL_HOST=http://localhost:3000/ +VITE_SECURE_LOCAL_STORAGE_HASH_KEY=ML_SECURE +VITE_SECURE_LOCAL_STORAGE_PREFIX=ML_SECURE +VITE_IV_LENGTH=16 +VITE_BUILD_VERSION=dev-build diff --git a/.gitignore b/.gitignore index ec97d4476..1be8c838a 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ coverage *.sw? .env .env* - +!.env.example From 60b037ce3518215dd7384608bf89d4c2ea6164fa Mon Sep 17 00:00:00 2001 From: Victor Ryabkov <45964820+moiskillnadne@users.noreply.github.com> Date: Wed, 28 Feb 2024 03:31:09 +0800 Subject: [PATCH 2/5] Track activity restart and activity resume events (#393) Co-authored-by: Viktor Riabkov --- src/widgets/ActivityGroups/ui/ActivityCard/index.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx b/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx index fa65a734b..f7260df65 100644 --- a/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx +++ b/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx @@ -19,7 +19,7 @@ import { ActivityListItem } from '~/abstract/lib/GroupBuilder'; import { useActivityByIdMutation } from '~/entities/activity'; import { appletModel } from '~/entities/applet'; import Loader from '~/shared/ui/Loader'; -import { useAppSelector, useCustomMediaQuery } from '~/shared/utils'; +import { Mixpanel, useAppSelector, useCustomMediaQuery } from '~/shared/utils'; type Props = { activityListItem: ActivityListItem; @@ -112,8 +112,14 @@ export const ActivityCard = ({ activityListItem }: Props) => { ); } - const restartActivity = () => onStartActivity(true); - const resumeActivity = () => onStartActivity(false); + const restartActivity = () => { + onStartActivity(true); + Mixpanel.track('[Web] Activity Restart Button Pressed'); + }; + const resumeActivity = () => { + onStartActivity(false); + Mixpanel.track('[Web] Activity Resume Button Pressed'); + }; if (isLoading) { return ( From 980b766ba9b168cb616adaf41fd2bf5a0e78450f Mon Sep 17 00:00:00 2001 From: Victor Ryabkov <45964820+moiskillnadne@users.noreply.github.com> Date: Wed, 28 Feb 2024 18:23:59 +0800 Subject: [PATCH 3/5] M2-5077 [WEB] Mixpanel Tracking: Applet ID in event properties (#394) * Create MixEvents and MixProperties for analytics * Add appletId property for Transfer Ownership Accepted event * Add appletId props for AssessmentCompleted event * Add appletId props for AssessmentStarted event * Add appletId props for InvitationAccepted event * Add appletId props for Activity restarted and Activity resumed events --------- Co-authored-by: Viktor Riabkov --- src/entities/applet/ui/AppletCard.tsx | 4 ++-- .../ui/PrivateJoinAcceptButton.tsx | 10 +++++++--- .../ui/TransferOwnershipAccept.tsx | 4 ++-- src/shared/api/types/invitation.ts | 2 +- src/shared/utils/analytics/analyticsService.ts | 13 +++++++++++++ src/shared/utils/analytics/index.ts | 2 ++ src/shared/utils/{ => analytics}/mixpanel.ts | 0 src/shared/utils/index.ts | 2 +- .../model/hooks/useSubmitAnswersMutation.ts | 14 +++++++++----- .../ActivityGroups/model/hooks/useStartEntity.ts | 4 ++-- .../ActivityGroups/ui/ActivityCard/index.tsx | 12 +++++++++--- .../FetchInvitation/ui/FetchPrivateInvitation.tsx | 6 ++++-- 12 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 src/shared/utils/analytics/analyticsService.ts create mode 100644 src/shared/utils/analytics/index.ts rename src/shared/utils/{ => analytics}/mixpanel.ts (100%) diff --git a/src/entities/applet/ui/AppletCard.tsx b/src/entities/applet/ui/AppletCard.tsx index e08c204d0..12c3a9022 100644 --- a/src/entities/applet/ui/AppletCard.tsx +++ b/src/entities/applet/ui/AppletCard.tsx @@ -4,7 +4,7 @@ import { AppletListItem } from '../lib'; import { ROUTES } from '~/shared/constants'; import { CustomCard } from '~/shared/ui'; -import { Mixpanel, useCustomNavigation } from '~/shared/utils'; +import { MixEvents, MixProperties, Mixpanel, useCustomNavigation } from '~/shared/utils'; type Props = { applet: AppletListItem; @@ -14,7 +14,7 @@ export const AppletCard = ({ applet }: Props) => { const navigator = useCustomNavigation(); const onAppletCardClick = () => { - Mixpanel.track('Applet click'); + Mixpanel.track(MixEvents.AppletClick, { [MixProperties.AppletId]: applet.id }); return navigator.navigate(ROUTES.appletDetails.navigateTo(applet.id)); }; diff --git a/src/features/PrivateJoinAccept/ui/PrivateJoinAcceptButton.tsx b/src/features/PrivateJoinAccept/ui/PrivateJoinAcceptButton.tsx index d4a63c8ff..50f5500eb 100644 --- a/src/features/PrivateJoinAccept/ui/PrivateJoinAcceptButton.tsx +++ b/src/features/PrivateJoinAccept/ui/PrivateJoinAcceptButton.tsx @@ -4,13 +4,17 @@ import { useNavigate } from 'react-router-dom'; import { useAcceptPrivateInviteMutation, useInvitationTranslation } from '~/entities/invitation'; import { ROUTES } from '~/shared/constants'; import { BaseButton, useNotification } from '~/shared/ui'; -import { Mixpanel } from '~/shared/utils'; +import { MixEvents, MixProperties, Mixpanel } from '~/shared/utils'; interface PrivateJoinAcceptButtonProps { invitationKey: string; + appletId: string; } -export const PrivateJoinAcceptButton = ({ invitationKey }: PrivateJoinAcceptButtonProps) => { +export const PrivateJoinAcceptButton = ({ + invitationKey, + appletId, +}: PrivateJoinAcceptButtonProps) => { const { t } = useInvitationTranslation(); const navigate = useNavigate(); const { showSuccessNotification } = useNotification(); @@ -18,7 +22,7 @@ export const PrivateJoinAcceptButton = ({ invitationKey }: PrivateJoinAcceptButt const { mutate: acceptPrivateInvite, isLoading } = useAcceptPrivateInviteMutation({ onSuccess() { showSuccessNotification(t('invitationAccepted')); - Mixpanel.track('Invitation Accepted'); + Mixpanel.track(MixEvents.InvitationAccepted, { [MixProperties.AppletId]: appletId }); return navigate(ROUTES.appletList.path); }, }); diff --git a/src/features/TransferOwnershipAccept/ui/TransferOwnershipAccept.tsx b/src/features/TransferOwnershipAccept/ui/TransferOwnershipAccept.tsx index 51e5c67ab..fb9da62b0 100644 --- a/src/features/TransferOwnershipAccept/ui/TransferOwnershipAccept.tsx +++ b/src/features/TransferOwnershipAccept/ui/TransferOwnershipAccept.tsx @@ -5,7 +5,7 @@ import { useAcceptTransferOwnershipQuery } from '../api'; import { PageMessage } from '~/shared/ui'; import Loader from '~/shared/ui/Loader'; -import { Mixpanel, useCustomTranslation } from '~/shared/utils'; +import { MixEvents, MixProperties, Mixpanel, useCustomTranslation } from '~/shared/utils'; type TransferOwnershipProps = { appletId: string; @@ -21,7 +21,7 @@ export const TransferOwnershipAccept = ({ appletId, keyParam }: TransferOwnershi { appletId, key: keyParam }, { onSuccess() { - Mixpanel.track('Transfer Ownership Accepted'); + Mixpanel.track(MixEvents.TransferOwnershipAccepted, { [MixProperties.AppletId]: appletId }); }, }, ); diff --git a/src/shared/api/types/invitation.ts b/src/shared/api/types/invitation.ts index e82b6cc8b..2ad7b39e4 100644 --- a/src/shared/api/types/invitation.ts +++ b/src/shared/api/types/invitation.ts @@ -29,5 +29,5 @@ export type GetInvitationSuccessResponse = BaseSuccessResponse<{ body: string | null; appletName: string; - appletId: string | number; + appletId: string; }>; diff --git a/src/shared/utils/analytics/analyticsService.ts b/src/shared/utils/analytics/analyticsService.ts new file mode 100644 index 000000000..dcc0cf550 --- /dev/null +++ b/src/shared/utils/analytics/analyticsService.ts @@ -0,0 +1,13 @@ +export const MixProperties = { + AppletId: 'Applet ID', +}; + +export const MixEvents = { + AppletClick: 'Applet click', + TransferOwnershipAccepted: 'Transfer Ownership Accepted', + AssessmentCompleted: 'Assessment completed', + AssessmentStarted: 'Assessment Started', + InvitationAccepted: 'Invitation Accepted', + ActivityRestarted: '[Web] Activity Restart Button Pressed', + ActivityResumed: '[Web] Activity Resume Button Pressed', +}; diff --git a/src/shared/utils/analytics/index.ts b/src/shared/utils/analytics/index.ts new file mode 100644 index 000000000..685bcc4ff --- /dev/null +++ b/src/shared/utils/analytics/index.ts @@ -0,0 +1,2 @@ +export * from './mixpanel'; +export * from './analyticsService'; diff --git a/src/shared/utils/mixpanel.ts b/src/shared/utils/analytics/mixpanel.ts similarity index 100% rename from src/shared/utils/mixpanel.ts rename to src/shared/utils/analytics/mixpanel.ts diff --git a/src/shared/utils/index.ts b/src/shared/utils/index.ts index 317eba5a7..0023b79e2 100644 --- a/src/shared/utils/index.ts +++ b/src/shared/utils/index.ts @@ -12,6 +12,6 @@ export * from './helpers'; // Common export * from './eventEmitter'; export * from './dictionary.map'; -export * from './mixpanel'; +export * from './analytics'; export * from './useTimer'; export * from './matchPaths'; diff --git a/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts b/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts index bcfef8f7d..455dcc9fe 100644 --- a/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts +++ b/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts @@ -1,5 +1,5 @@ import { usePublicSaveAnswerMutation, useSaveAnswerMutation } from '~/entities/activity'; -import { Mixpanel } from '~/shared/utils'; +import { MixEvents, MixProperties, Mixpanel } from '~/shared/utils'; type Props = { isPublic: boolean; @@ -9,8 +9,10 @@ type Props = { export const useSubmitAnswersMutations = (props: Props) => { const { mutate: submitAnswers, isLoading: submitLoading } = useSaveAnswerMutation({ - onSuccess() { - Mixpanel.track('Assessment completed'); + onSuccess(_, variables) { + Mixpanel.track(MixEvents.AssessmentCompleted, { + [MixProperties.AppletId]: variables.appletId, + }); return props.onSubmitSuccess(); }, @@ -18,8 +20,10 @@ export const useSubmitAnswersMutations = (props: Props) => { const { mutate: submitPublicAnswers, isLoading: publicSubmitLoading } = usePublicSaveAnswerMutation({ - onSuccess() { - Mixpanel.track('Assessment completed'); + onSuccess(_, variables) { + Mixpanel.track(MixEvents.AssessmentCompleted, { + [MixProperties.AppletId]: variables.appletId, + }); return props.onSubmitSuccess(); }, diff --git a/src/widgets/ActivityGroups/model/hooks/useStartEntity.ts b/src/widgets/ActivityGroups/model/hooks/useStartEntity.ts index 40943529b..2ebe70702 100644 --- a/src/widgets/ActivityGroups/model/hooks/useStartEntity.ts +++ b/src/widgets/ActivityGroups/model/hooks/useStartEntity.ts @@ -4,7 +4,7 @@ import { ActivityStatus, EntityType } from '~/abstract/lib/GroupBuilder'; import { appletModel } from '~/entities/applet'; import { AppletDetailsBaseInfoDTO } from '~/shared/api'; import { ROUTES } from '~/shared/constants'; -import { Mixpanel, useCustomNavigation } from '~/shared/utils'; +import { MixEvents, MixProperties, Mixpanel, useCustomNavigation } from '~/shared/utils'; type NavigateToEntityProps = { flowId: string | null; @@ -57,7 +57,7 @@ export const useStartEntity = (props: Props) => { } function startActivityOrFlow(params: OnActivityCardClickProps) { - Mixpanel.track('Assessment Started'); + Mixpanel.track(MixEvents.AssessmentStarted, { [MixProperties.AppletId]: props.applet.id }); const { flowId, eventId, activity, status, shouldRestart } = params; diff --git a/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx b/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx index f7260df65..c10236000 100644 --- a/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx +++ b/src/widgets/ActivityGroups/ui/ActivityCard/index.tsx @@ -19,7 +19,13 @@ import { ActivityListItem } from '~/abstract/lib/GroupBuilder'; import { useActivityByIdMutation } from '~/entities/activity'; import { appletModel } from '~/entities/applet'; import Loader from '~/shared/ui/Loader'; -import { Mixpanel, useAppSelector, useCustomMediaQuery } from '~/shared/utils'; +import { + MixEvents, + MixProperties, + Mixpanel, + useAppSelector, + useCustomMediaQuery, +} from '~/shared/utils'; type Props = { activityListItem: ActivityListItem; @@ -114,11 +120,11 @@ export const ActivityCard = ({ activityListItem }: Props) => { const restartActivity = () => { onStartActivity(true); - Mixpanel.track('[Web] Activity Restart Button Pressed'); + Mixpanel.track(MixEvents.ActivityRestarted, { [MixProperties.AppletId]: context.applet.id }); }; const resumeActivity = () => { onStartActivity(false); - Mixpanel.track('[Web] Activity Resume Button Pressed'); + Mixpanel.track(MixEvents.ActivityResumed, { [MixProperties.AppletId]: context.applet.id }); }; if (isLoading) { diff --git a/src/widgets/FetchInvitation/ui/FetchPrivateInvitation.tsx b/src/widgets/FetchInvitation/ui/FetchPrivateInvitation.tsx index 6d65e5311..729f78757 100644 --- a/src/widgets/FetchInvitation/ui/FetchPrivateInvitation.tsx +++ b/src/widgets/FetchInvitation/ui/FetchPrivateInvitation.tsx @@ -50,9 +50,11 @@ export const FetchPrivateInvitation = ({ ); } + const invitation = data?.data?.result; + return ( @@ -65,7 +67,7 @@ export const FetchPrivateInvitation = ({ margin="16px 0px" flexDirection={lessThanSM ? 'column' : 'row'} > - + ) : ( From cb4ca1e137dc9bc0fc72d22f4a59aed312993eef Mon Sep 17 00:00:00 2001 From: Victor Ryabkov <45964820+moiskillnadne@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:01:19 +0800 Subject: [PATCH 4/5] Add SubmitId prop for AssessmentCompleted event (#395) Co-authored-by: Viktor Riabkov --- src/shared/utils/analytics/analyticsService.ts | 1 + .../ActivityDetails/model/hooks/useSubmitAnswersMutation.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/shared/utils/analytics/analyticsService.ts b/src/shared/utils/analytics/analyticsService.ts index dcc0cf550..b1103ddbe 100644 --- a/src/shared/utils/analytics/analyticsService.ts +++ b/src/shared/utils/analytics/analyticsService.ts @@ -1,5 +1,6 @@ export const MixProperties = { AppletId: 'Applet ID', + SubmitId: 'Submit ID', }; export const MixEvents = { diff --git a/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts b/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts index 455dcc9fe..122a1fd2f 100644 --- a/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts +++ b/src/widgets/ActivityDetails/model/hooks/useSubmitAnswersMutation.ts @@ -12,6 +12,7 @@ export const useSubmitAnswersMutations = (props: Props) => { onSuccess(_, variables) { Mixpanel.track(MixEvents.AssessmentCompleted, { [MixProperties.AppletId]: variables.appletId, + [MixProperties.SubmitId]: variables.submitId, }); return props.onSubmitSuccess(); @@ -23,6 +24,7 @@ export const useSubmitAnswersMutations = (props: Props) => { onSuccess(_, variables) { Mixpanel.track(MixEvents.AssessmentCompleted, { [MixProperties.AppletId]: variables.appletId, + [MixProperties.SubmitId]: variables.submitId, }); return props.onSubmitSuccess(); From 67855007ae3c607102ccab0c2d432f8d68f576d5 Mon Sep 17 00:00:00 2001 From: Victor Ryabkov <45964820+moiskillnadne@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:26:26 +0800 Subject: [PATCH 5/5] Update jenkins job (#396) Co-authored-by: Viktor Riabkov --- Jenkinsfile.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile.groovy b/Jenkinsfile.groovy index 839b2ecd2..52fe6edd1 100644 --- a/Jenkinsfile.groovy +++ b/Jenkinsfile.groovy @@ -1 +1 @@ -build( job: env.MindloggerWebRefactorNewBuilder ) +build( job: env.MindloggerWebRefactorBuilder )