Skip to content

Commit

Permalink
RHOAIENG-9232 Create useTrackUser (#3024)
Browse files Browse the repository at this point in the history
  • Loading branch information
pilhuhn authored Aug 12, 2024
1 parent b9e2a52 commit e42fdcd
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 17 deletions.
16 changes: 14 additions & 2 deletions frontend/src/concepts/analyticsTracking/segmentIOUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ export const firePageEvent = (): void => {
}
};

// Stuff that gets send over as traits on an identify call. Must not include (anonymous) user Id.
type IdentifyTraits = {
isAdmin: boolean;
canCreateProjects: boolean;
clusterID: string;
};

/*
* This fires a call to associate further processing with the passed (anonymous) userId
* in the properties.
Expand All @@ -94,8 +101,13 @@ export const fireIdentifyEvent = (properties: IdentifyEventProperties): void =>
const clusterID = window.clusterID ?? '';
if (DEV_MODE) {
/* eslint-disable-next-line no-console */
console.log(`Identify event triggered`);
console.log(`Identify event triggered: ${JSON.stringify(properties)}`);
} else if (window.analytics) {
window.analytics.identify(properties.anonymousID, { clusterID });
const traits: IdentifyTraits = {
clusterID,
isAdmin: properties.isAdmin,
canCreateProjects: properties.canCreateProjects,
};
window.analytics.identify(properties.anonymousID, traits);
}
};
3 changes: 3 additions & 0 deletions frontend/src/concepts/analyticsTracking/trackingProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ export type ODHSegmentKey = {
};

export type IdentifyEventProperties = {
isAdmin: boolean;
anonymousID?: string;
userId?: string;
canCreateProjects: boolean;
};

export const enum TrackingOutcome {
Expand Down
30 changes: 15 additions & 15 deletions frontend/src/concepts/analyticsTracking/useSegmentTracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { useAppContext } from '~/app/AppContext';
import { useAppSelector } from '~/redux/hooks';
import { fireIdentifyEvent, firePageEvent } from '~/concepts/analyticsTracking/segmentIOUtils';
import { useTrackUser } from '~/concepts/analyticsTracking/useTrackUser';
import { useWatchSegmentKey } from './useWatchSegmentKey';
import { initSegment } from './initSegment';

Expand All @@ -10,28 +11,27 @@ export const useSegmentTracking = (): void => {
const { dashboardConfig } = useAppContext();
const username = useAppSelector((state) => state.user);
const clusterID = useAppSelector((state) => state.clusterID);
const [userProps, uPropsLoaded] = useTrackUser(username);

React.useEffect(() => {
if (segmentKey && loaded && !loadError && username && clusterID) {
const computeUserId = async () => {
const anonymousIDBuffer = await crypto.subtle.digest(
'SHA-1',
new TextEncoder().encode(username),
);
const anonymousIDArray = Array.from(new Uint8Array(anonymousIDBuffer));
return anonymousIDArray.map((b) => b.toString(16).padStart(2, '0')).join('');
};

if (segmentKey && loaded && !loadError && username && clusterID && uPropsLoaded) {
window.clusterID = clusterID;
initSegment({
segmentKey,
enabled: !dashboardConfig.spec.dashboardConfig.disableTracking,
}).then(() => {
computeUserId().then((userId) => {
fireIdentifyEvent({ anonymousID: userId });
firePageEvent();
});
fireIdentifyEvent(userProps);
firePageEvent();
});
}
}, [clusterID, loadError, loaded, segmentKey, username, dashboardConfig]);
}, [
clusterID,
loadError,
loaded,
segmentKey,
username,
dashboardConfig,
userProps,
uPropsLoaded,
]);
};
50 changes: 50 additions & 0 deletions frontend/src/concepts/analyticsTracking/useTrackUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { useUser } from '~/redux/selectors';
import { useAccessReview } from '~/api';
import { AccessReviewResourceAttributes } from '~/k8sTypes';
import { IdentifyEventProperties } from '~/concepts/analyticsTracking/trackingProperties';

export const useTrackUser = (username?: string): [IdentifyEventProperties, boolean] => {
const { isAdmin } = useUser();
const [anonymousId, setAnonymousId] = React.useState<string | undefined>(undefined);

const [loaded, setLoaded] = React.useState(false);
const createReviewResource: AccessReviewResourceAttributes = {
group: 'project.openshift.io',
resource: 'projectrequests',
verb: 'create',
};
const [allowCreate, acLoaded] = useAccessReview(createReviewResource);

React.useEffect(() => {
const computeAnonymousUserId = async () => {
const anonymousIDBuffer = await crypto.subtle.digest(
'SHA-1',
new TextEncoder().encode(username),
);
const anonymousIDArray = Array.from(new Uint8Array(anonymousIDBuffer));
const aId = anonymousIDArray.map((b) => b.toString(16).padStart(2, '0')).join('');
return aId;
};

if (!anonymousId) {
computeAnonymousUserId().then((val) => {
setAnonymousId(val);
});
}
if (acLoaded && anonymousId) {
setLoaded(true);
}
}, [username, anonymousId, acLoaded]);

const props: IdentifyEventProperties = React.useMemo(
() => ({
isAdmin,
canCreateProjects: allowCreate,
anonymousID: anonymousId,
}),
[isAdmin, allowCreate, anonymousId],
);

return [props, loaded];
};

0 comments on commit e42fdcd

Please sign in to comment.