Skip to content

Commit

Permalink
feat: Analytics logs for input errors caught by ErrorWrapper (#2454)
Browse files Browse the repository at this point in the history
  • Loading branch information
DafyddLlyr authored Nov 20, 2023
1 parent 14a9bf9 commit 26b6102
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 15 deletions.
4 changes: 2 additions & 2 deletions editor.planx.uk/src/@planx/components/Checklist/Public.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Checklist, Group } from "@planx/components/Checklist/model";
import ImageButton from "@planx/components/shared/Buttons/ImageButton";
import Card from "@planx/components/shared/Preview/Card";
import QuestionHeader from "@planx/components/shared/Preview/QuestionHeader";
import { useFormik } from "formik";
import { getIn, useFormik } from "formik";
import React, { useState } from "react";
import ChecklistItem from "ui/ChecklistItem";
import ErrorWrapper from "ui/ErrorWrapper";
Expand Down Expand Up @@ -139,7 +139,7 @@ const ChecklistComponent: React.FC<Props> = ({
img={img}
/>
<FullWidthWrapper>
<ErrorWrapper error={formik.errors.checked} id={id}>
<ErrorWrapper error={getIn(formik.errors, "checked")} id={id}>
<Grid container spacing={layout === ChecklistLayout.Images ? 2 : 0}>
{options ? (
options.map((option) =>
Expand Down
4 changes: 2 additions & 2 deletions editor.planx.uk/src/@planx/components/Send/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Warning from "@mui/icons-material/Warning";
import Box from "@mui/material/Box";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import { useFormik } from "formik";
import { getIn, useFormik } from "formik";
import React from "react";
import ChecklistItem from "ui/ChecklistItem";
import ErrorWrapper from "ui/ErrorWrapper";
Expand Down Expand Up @@ -89,7 +89,7 @@ const SendComponent: React.FC<Props> = (props) => {
/>
</InputRow>
<Box mt={2}>
<ErrorWrapper error={formik.errors.destinations}>
<ErrorWrapper error={getIn(formik.errors, "destinations")}>
<Grid container spacing={0}>
{options.map((option) => (
<Grid item xs={12} key={option.value}>
Expand Down
33 changes: 30 additions & 3 deletions editor.planx.uk/src/pages/FlowEditor/lib/analyticsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type AnalyticsLogDirection =

export type HelpClickMetadata = Record<string, string>;
export type SelectedUrlsMetadata = Record<"selectedUrls", string[]>;
export type BackwardsNaviagtionInitiatorType = "change" | "back";
export type BackwardsNavigationInitiatorType = "change" | "back";

type NodeMetadata = {
flagset?: FlagSet;
Expand All @@ -45,16 +45,18 @@ const analyticsContext = createContext<{
) => Promise<void>;
trackBackwardsNavigationByNodeId: (
nodeId: string,
backwardsNavigationType: BackwardsNaviagtionInitiatorType,
backwardsNavigationType: BackwardsNavigationInitiatorType,
) => Promise<void>;
node: Store.node | null;
trackInputErrors: (error: string) => Promise<void>;
}>({
createAnalytics: () => Promise.resolve(),
trackHelpClick: () => Promise.resolve(),
trackNextStepsLinkClick: () => Promise.resolve(),
trackFlowDirectionChange: () => Promise.resolve(),
trackBackwardsNavigationByNodeId: () => Promise.resolve(),
node: null,
trackInputErrors: () => Promise.resolve(),
});
const { Provider } = analyticsContext;

Expand Down Expand Up @@ -140,6 +142,7 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({
trackFlowDirectionChange,
trackBackwardsNavigationByNodeId,
node,
trackInputErrors,
}}
>
{children}
Expand Down Expand Up @@ -309,7 +312,7 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({

async function trackBackwardsNavigationByNodeId(
nodeId: string,
initiator: BackwardsNaviagtionInitiatorType,
initiator: BackwardsNavigationInitiatorType,
) {
const targetNodeMetadata = getTitleAndTypeFromFlow(nodeId);
const metadata: Record<string, NodeMetadata> = {};
Expand Down Expand Up @@ -401,6 +404,30 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({
};
return nodeMetadata;
}

/**
* Capture user input errors caught by ErrorWrapper component
*/
async function trackInputErrors(error: string) {
if (shouldTrackAnalytics && lastAnalyticsLogId) {
await publicClient.mutate({
mutation: gql`
mutation TrackInputErrors($id: bigint!, $error: jsonb) {
update_analytics_logs_by_pk(
pk_columns: { id: $id }
_append: { input_errors: $error }
) {
id
}
}
`,
variables: {
id: lastAnalyticsLogId,
error,
},
});
}
}
};

/**
Expand Down
22 changes: 14 additions & 8 deletions editor.planx.uk/src/ui/ErrorWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import Box, { BoxProps } from "@mui/material/Box";
import { styled } from "@mui/material/styles";
import Typography from "@mui/material/Typography";
import { ERROR_MESSAGE } from "@planx/components/shared/constants";
import React, { ReactElement } from "react";
import { useAnalyticsTracking } from "pages/FlowEditor/lib/analyticsProvider";
import React, { ReactElement, useEffect } from "react";
import { FONT_WEIGHT_SEMI_BOLD } from "theme";

export interface Props {
error: string | string[] | undefined;
error?: string;
children?: ReactElement;
id?: string;
}
Expand Down Expand Up @@ -34,16 +35,21 @@ const ErrorText = styled(Typography)(({ theme }) => ({
fontWeight: FONT_WEIGHT_SEMI_BOLD,
}));

export default function ErrorWrapper(props: Props): FCReturn {
const id = props.id ? `${ERROR_MESSAGE}-${props.id}` : undefined;
export default function ErrorWrapper({ id, error, children }: Props): FCReturn {
const inputId = id ? `${ERROR_MESSAGE}-${id}` : undefined;
const { trackInputErrors } = useAnalyticsTracking();

useEffect(() => {
error && trackInputErrors(error);
}, [error, trackInputErrors]);

return (
// role="status" immediately announces the error to screenreaders without interrupting focus
<Root error={props.error} role="status" data-testid="error-wrapper">
<ErrorText id={id} data-testid={id} variant="body1">
{props?.error}
<Root error={error} role="status" data-testid="error-wrapper">
<ErrorText id={inputId} data-testid={inputId} variant="body1">
{error && error}
</ErrorText>
{props.children || null}
{children || null}
</Root>
);
}
2 changes: 2 additions & 0 deletions hasura.planx.uk/metadata/tables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
- flow_direction
- has_clicked_help
- id
- input_errors
- metadata
- node_title
- node_type
Expand All @@ -57,6 +58,7 @@
columns:
- flow_direction
- has_clicked_help
- input_errors
- metadata
- next_log_created_at
- user_exit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE "public"."analytics_logs"
DROP COLUMN "input_errors"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table "public"."analytics_logs" add column "input_errors" jsonb NULL DEFAULT '[]';

0 comments on commit 26b6102

Please sign in to comment.