Skip to content

Commit

Permalink
feat: track a user restarting their application
Browse files Browse the repository at this point in the history
- Add analytics endoint to handle tracking application restarts
- Updates the flow_direction of the restart node to "reset"
  • Loading branch information
Mike-Heneghan committed Oct 13, 2023
1 parent f2ec92f commit f5cc5fd
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 2 deletions.
8 changes: 7 additions & 1 deletion api.planx.uk/modules/analytics/controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from "zod";
import { trackAnalyticsLogExit } from "./service";
import { trackAnalyticsLogExit, trackUserReset } from "./service";
import { ValidatedRequestHandler } from "../../shared/middleware/validate";

export const logAnalyticsSchema = z.object({
Expand All @@ -24,3 +24,9 @@ export const logUserResumeController: LogAnalytics = async (req, res) => {
trackAnalyticsLogExit({ id: Number(analyticsLogId), isUserExit: false });
res.status(204).send();
};

export const logUserResetController: LogAnalytics = async (req, res) => {
const { analyticsLogId } = req.query;
trackUserReset({ id: Number(analyticsLogId), flow_direction: "reset" });
res.status(204).send();
};
6 changes: 6 additions & 0 deletions api.planx.uk/modules/analytics/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
logAnalyticsSchema,
logUserExitController,
logUserResumeController,
logUserResetController,
} from "./controller";

const router = Router();
Expand All @@ -18,5 +19,10 @@ router.post(
validate(logAnalyticsSchema),
logUserResumeController,
);
router.post(
"/log-user-reset",
validate(logAnalyticsSchema),
logUserResetController,
);

export default router;
37 changes: 37 additions & 0 deletions api.planx.uk/modules/analytics/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,40 @@ export const trackAnalyticsLogExit = async ({

return;
};

export const trackUserReset = async ({
id,
flow_direction,
}: {
id: number;
flow_direction: string;
}) => {
try {
await adminClient.request(
gql`
mutation UpdateAnalyticsLogUserReset(
$id: bigint!
$flow_direction: String
) {
update_analytics_logs_by_pk(
pk_columns: { id: $id }
_set: { flow_direction: $flow_direction }
) {
id
}
}
`,
{
id,
flow_direction: flow_direction,
},
);
} catch (e) {
// We need to catch this exception here otherwise the exception would become an unhandled rejection which brings down the whole node.js process
console.error(
"There's been an error while recording metrics for analytics but because this thread is non-blocking we didn't reject the request",
(e as Error).stack,
);
}
return;
};
2 changes: 2 additions & 0 deletions editor.planx.uk/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ const PublicToolbar: React.FC<{
state.id,
state.teamTheme,
]);
const { trackUserResetConfirmation } = useAnalyticsTracking();

// Center the service title on desktop layouts, or drop it to second line on mobile
// ref https://design-system.service.gov.uk/styles/page-template/
Expand All @@ -322,6 +323,7 @@ const PublicToolbar: React.FC<{
"Are you sure you want to restart? This will delete your previous answers",
)
) {
trackUserResetConfirmation();
if (path === ApplicationPath.SingleSession) {
clearLocalFlow(id);
window.location.reload();
Expand Down
15 changes: 14 additions & 1 deletion editor.planx.uk/src/pages/FlowEditor/lib/analyticsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, { createContext, useContext, useEffect, useState } from "react";

import { Store, useStore } from "./store";

export type AnalyticsType = "init" | "resume";
export type AnalyticsType = "init" | "resume" | "reset"
type AnalyticsLogDirection = AnalyticsType | "forwards" | "backwards";

export type HelpClickMetadata = Record<string, string>;
Expand All @@ -18,11 +18,13 @@ const analyticsContext = createContext<{
createAnalytics: (type: AnalyticsType) => Promise<void>;
trackHelpClick: (metadata?: HelpClickMetadata) => Promise<void>;
trackNextStepsLinkClick: (metadata?: SelectedUrlsMetadata) => Promise<void>;
trackUserResetConfirmation: () => Promise<void>;
node: Store.node | null;
}>({
createAnalytics: () => Promise.resolve(),
trackHelpClick: () => Promise.resolve(),
trackNextStepsLinkClick: () => Promise.resolve(),
trackUserResetConfirmation: () => Promise.resolve(),
node: null,
});
const { Provider } = analyticsContext;
Expand Down Expand Up @@ -104,6 +106,7 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({
createAnalytics,
trackHelpClick,
trackNextStepsLinkClick,
trackUserResetConfirmation,
node,
}}
>
Expand Down Expand Up @@ -199,6 +202,16 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({
}
}

async function trackUserResetConfirmation(){
if (lastAnalyticsLogId && shouldTrackAnalytics) {
send(
`${
process.env.REACT_APP_API_URL
}/analytics/log-user-reset?analyticsLogId=${lastAnalyticsLogId.toString()}`,
);
}
};

async function createAnalytics(type: AnalyticsType) {
if (shouldTrackAnalytics) {
const response = await publicClient.mutate({
Expand Down

0 comments on commit f5cc5fd

Please sign in to comment.