From 1e6819881025d089fe022369df2f43730991b6d9 Mon Sep 17 00:00:00 2001 From: Ian Krieger <48930920+IanKrieger@users.noreply.github.com> Date: Wed, 2 Aug 2023 11:26:47 -0400 Subject: [PATCH] feat: persist metric filter preference (#849) * feat: persist metric filter preference * fix: display even if 0 conversions --- src/graphql/analytics-overview.generated.tsx | 13 +++++ src/graphql/analytics-overview.graphql | 5 ++ src/graphql/types.ts | 5 ++ .../hooks/usePersistMetricFilter.ts | 50 +++++++++++++++++++ .../reports/campaign/EngagementsOverview.tsx | 35 ++++--------- 5 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 src/user/analytics/analyticsOverview/hooks/usePersistMetricFilter.ts diff --git a/src/graphql/analytics-overview.generated.tsx b/src/graphql/analytics-overview.generated.tsx index d686482c..4fc01ff7 100644 --- a/src/graphql/analytics-overview.generated.tsx +++ b/src/graphql/analytics-overview.generated.tsx @@ -39,6 +39,10 @@ export type CampaignWithEngagementsFragment = { endAt: any; pacingIndex?: number | null; format: Types.CampaignFormat; + adSets: Array<{ + __typename?: "AdSet"; + conversions?: Array<{ __typename?: "Conversion"; type: string }> | null; + }>; engagements?: Array<{ __typename?: "Engagement"; creativeinstanceid: string; @@ -82,6 +86,10 @@ export type AnalyticOverviewQuery = { endAt: any; pacingIndex?: number | null; format: Types.CampaignFormat; + adSets: Array<{ + __typename?: "AdSet"; + conversions?: Array<{ __typename?: "Conversion"; type: string }> | null; + }>; engagements?: Array<{ __typename?: "Engagement"; creativeinstanceid: string; @@ -161,6 +169,11 @@ export const CampaignWithEngagementsFragmentDoc = gql` currency pacingIndex format + adSets { + conversions { + type + } + } engagements { ...Engagement } diff --git a/src/graphql/analytics-overview.graphql b/src/graphql/analytics-overview.graphql index ea8ac9ba..45df71b0 100644 --- a/src/graphql/analytics-overview.graphql +++ b/src/graphql/analytics-overview.graphql @@ -33,6 +33,11 @@ fragment CampaignWithEngagements on Campaign { currency pacingIndex format + adSets { + conversions { + type + } + } engagements { ...Engagement } diff --git a/src/graphql/types.ts b/src/graphql/types.ts index 7edde713..8ed21fc1 100644 --- a/src/graphql/types.ts +++ b/src/graphql/types.ts @@ -31,6 +31,11 @@ export type AdvertiserCampaignFilter = { includeCreativeSets?: InputMaybe; }; +export enum AdvertiserSource { + Managed = "MANAGED", + SelfServe = "SELF_SERVE", +} + export type ApproveCampaignInput = { campaignId: Scalars["String"]; }; diff --git a/src/user/analytics/analyticsOverview/hooks/usePersistMetricFilter.ts b/src/user/analytics/analyticsOverview/hooks/usePersistMetricFilter.ts new file mode 100644 index 00000000..65969a80 --- /dev/null +++ b/src/user/analytics/analyticsOverview/hooks/usePersistMetricFilter.ts @@ -0,0 +1,50 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import { Metrics, StatsMetric } from "user/analytics/analyticsOverview/types"; +import _ from "lodash"; + +export function usePersistMetricFilter( + opts: { campaignId?: string; hasConversions?: boolean } = {}, +) { + const baseFilter: Metrics = { + metric1: { key: "views", active: true }, + metric2: { key: "clicks", active: false }, + metric3: { + key: opts.hasConversions ? "conversions" : "dismissals", + active: false, + }, + metric4: { key: "landings", active: false }, + }; + + const [metrics, setMetrics] = useState(); + + useEffect(() => { + const rawFilter = window.localStorage.getItem("metricFilter"); + if (rawFilter) { + setMetrics(JSON.parse(rawFilter)); + } else { + setMetrics(baseFilter); + } + }, [opts.hasConversions]); + + const setMetric = useCallback( + (metric: keyof Metrics, value: keyof StatsMetric, active: boolean) => { + if (!metrics) { + return; + } + + const metricsCopy = _.cloneDeep(metrics); + const selectedMetric = metricsCopy[metric]; + + if (selectedMetric) { + selectedMetric.key = value; + selectedMetric.active = active; + } + + setMetrics({ ...metricsCopy }); + window.localStorage.setItem("metricFilter", JSON.stringify(metricsCopy)); + }, + [metrics], + ); + + return { metrics: metrics!, setMetric }; +} diff --git a/src/user/analytics/analyticsOverview/reports/campaign/EngagementsOverview.tsx b/src/user/analytics/analyticsOverview/reports/campaign/EngagementsOverview.tsx index 6d7d41b7..0b0ab506 100644 --- a/src/user/analytics/analyticsOverview/reports/campaign/EngagementsOverview.tsx +++ b/src/user/analytics/analyticsOverview/reports/campaign/EngagementsOverview.tsx @@ -19,6 +19,7 @@ import { CampaignFormat } from "graphql/types"; import { ErrorDetail } from "components/Error/ErrorDetail"; import { ApolloError } from "@apollo/client"; import _ from "lodash"; +import { usePersistMetricFilter } from "user/analytics/analyticsOverview/hooks/usePersistMetricFilter"; interface Props { loading: boolean; @@ -33,6 +34,14 @@ export function EngagementsOverview({ error, loading, }: Props) { + const [grouping, setGrouping] = useState("daily"); + const { metrics, setMetric } = usePersistMetricFilter({ + campaignId: campaign?.id, + hasConversions: campaign?.adSets.some( + (a) => a.conversions && a.conversions.length, + ), + }); + if (error) { return ( ({ - metric1: { key: "views", active: true }, - metric2: { key: "clicks", active: false }, - metric3: { key: "dismissals", active: false }, - metric4: { key: "landings", active: false }, - }); - - const setActiveMetric = ( - metric: keyof Metrics, - value: keyof StatsMetric, - active: boolean, - ) => { - const metricsCopy = _.cloneDeep(metrics); - const selectedMetric = metricsCopy[metric]; - - if (selectedMetric) { - selectedMetric.key = value; - selectedMetric.active = active; - } - setMetrics({ ...metricsCopy }); - }; - const processedData = processData(engagements, metrics, grouping); const processedStats = processStats(engagements); const options = prepareChart(metrics, processedData); @@ -103,7 +88,7 @@ export function EngagementsOverview({