({
+ [`& .${classes.option}`]: {
+ display: "flex",
+ width: "100%",
+ },
+
+ [`& .${classes.left}`]: {
+ flexGrow: 1,
+ display: "flex",
+ flexDirection: "column",
+ }
+}));
+
export enum V4SamplingLevel {
Default = "DEFAULT",
SMALL = "SMALL",
@@ -44,34 +68,22 @@ export enum CohortSize {
const removeDeprecatedColumns = (column: ColumnT): true | false =>
column.attributes?.status !== "DEPRECATED"
-const useColumnStyles = makeStyles(() => ({
- option: {
- display: "flex",
- width: "100%",
- },
- left: {
- flexGrow: 1,
- display: "flex",
- flexDirection: "column",
- },
-}))
const Column: React.FC<{ column: ColumnT }> = ({ column }) => {
- const classes = useColumnStyles()
return (
-
-
-
- {column.attributes!.uiName}
-
-
- {column.id}
+
+
+
+ {column.attributes!.uiName}
+
+
+ {column.id}
+
+
+
+ {column.attributes!.group}
-
- {column.attributes!.group}
-
-
)
}
@@ -98,12 +110,16 @@ export const DimensionPicker: React.FC<{
options={
successful(request)?.dimensions.filter(removeDeprecatedColumns) || []
}
- getOptionLabel={dimension => dimension.id!}
+ getOptionLabel={(dimension) => typeof dimension === "string" ? dimension : dimension.id!}
value={selectedDimension || null}
onChange={(_event, value) =>
setDimensionID(value === null ? undefined : (value as ColumnT).id)
}
- renderOption={column =>
}
+ renderOption={(props, column) => (
+
+
+
+ )}
renderInput={params => (
dimension.id!}
+ getOptionLabel={(dimension) => typeof dimension === "string" ? dimension : dimension.id!}
value={selectedDimensions || []}
onChange={(_event, value) =>
setDimensionIDs((value as ColumnT[])?.map(c => c.id!))
}
- renderOption={column => }
+ renderOption={(props, column) => (
+
+
+
+ )}
renderInput={params => (
true) || []
}
- getOptionLabel={metric => metric.id!}
+ getOptionLabel={(metric) => typeof metric === "string" ? metric : metric.id!}
value={selectedMetric || null}
onChange={(_event, value) =>
setMetricID(value === null ? undefined : (value as ColumnT).id)
}
- renderOption={column => }
+ renderOption={(props, column) => (
+
+
+
+ )}
renderInput={params => (
metric.id!}
+ getOptionLabel={(metric) => typeof metric === "string" ? metric : metric.id!}
value={selectedMetrics || []}
onChange={(_event, value) =>
setMetricIDs((value as ColumnT[])?.map(c => c.id!))
}
- renderOption={column => }
+ renderOption={(props, column) => (
+
+
+
+ )}
renderInput={params => (
= ({ segment, showSegmentDefinition }) => {
- const classes = useColumnStyles()
const subtitleText = showSegmentDefinition
? segment.definition || `${segment.name} has no segment definition.`
: segment.segmentId || ""
@@ -279,23 +306,25 @@ const Segment: React.FC<{
? subtitleText.substring(0, 40) + "..."
: subtitleText
return (
-
-
-
- {segment.name}
-
-
- {abbreviatedText}
+
+
+
+
+ {segment.name}
+
+
+ {abbreviatedText}
+
+
+
+ {segment.type === "CUSTOM"
+ ? "Custom Segment"
+ : segment.type === "DYNAMIC"
+ ? "Dynamic Segment"
+ : "Built In Segment"}
-
- {segment.type === "CUSTOM"
- ? "Custom Segment"
- : segment.type === "DYNAMIC"
- ? "Dynamic Segment"
- : "Built In Segment"}
-
-
+
)
}
@@ -318,10 +347,10 @@ export const SegmentPicker: React.FC<{
const request = React.useContext(UASegmentsRequestCtx)
const getOptionLabel = React.useCallback(
- (segment: SegmentT) =>
- (showSegmentDefinition
+ (segment: SegmentT | string) =>
+ typeof segment === "string" ? segment : (showSegmentDefinition
? segment.definition ||
- (segment.name && `${segment.name} has no segment definiton.`)
+ (segment.name && `${segment.name} has no segment definition.`)
: segment.segmentId!) || "",
[showSegmentDefinition]
)
@@ -334,7 +363,7 @@ export const SegmentPicker: React.FC<{
freeSolo
loading={request.status === RequestStatus.InProgress}
options={successful(request)?.segments || []}
- getOptionSelected={(a, b) =>
+ isOptionEqualToValue={(a, b) =>
a.id === b.id || a.definition === b.definition
}
getOptionLabel={getOptionLabel}
@@ -357,11 +386,13 @@ export const SegmentPicker: React.FC<{
onChange={(_event, value) => {
setSegmentID(value === null ? undefined : (value as SegmentT).id)
}}
- renderOption={column => (
-
+ renderOption={(props, column) => (
+
+
+
)}
renderInput={params => (
setSelected(value === null ? undefined : (value as V4SamplingLevel))
}
- renderOption={column => column}
+ renderOption={(props, column) => (
+
+ {column}
+
+ )}
renderInput={params => (
column}
+ renderOption={(props, column) => (
+
+ {column}
+
+ )}
renderInput={params => (
setSelected(value === null ? undefined : (value as CohortSize))
}
- renderOption={column => column}
+ renderOption={(props, column) => (
+
+ {column}
+
+ )}
renderInput={params => (
(theme => ({
- root: props => ({
+const PREFIX = 'ViewSelector';
+
+const classes = {
+ root: `${PREFIX}-root`,
+ formControl: `${PREFIX}-formControl`
+};
+
+const Root = styled('div')((
+ {
+ theme
+ }
+) => ({
+ [`&.${classes.root}`]: {
display: "flex",
- flexDirection: props.vertical ? "column" : "unset",
- ...(props.vertical ? { marginBottom: theme.spacing(1) } : {}),
+ flexDirection: "unset",
width: "100%",
- }),
- formControl: {
+ },
+
+ [`& .${classes.formControl}`]: {
width: "100%",
margin: theme.spacing(1),
marginLeft: "unset",
- },
-}))
+ }
+}));
interface CommonProps {
account?: AccountSummary
@@ -76,7 +87,7 @@ const ViewSelector: React.FC = props => {
size = "medium",
variant = "standard",
} = props
- const classes = useStyles(props)
+
const request = useAccountSummaries(account, property)
@@ -96,7 +107,7 @@ const ViewSelector: React.FC = props => {
}
return (
-
+
data-testid={TestID.AccountAutocomplete}
blurOnSelect
@@ -120,7 +131,7 @@ const ViewSelector: React.FC = props => {
!props.onlyProperty && props.setViewID(firstView?.id || undefined)
}
}}
- getOptionSelected={(a, b) => a.id === b.id}
+ isOptionEqualToValue={(a, b) => a.id === b.id}
getOptionLabel={account => account.name || ""}
renderInput={params => (
= props => {
!props.onlyProperty && props.setViewID(firstView?.id || undefined)
}
}}
- getOptionSelected={(a, b) => a.id === b.id}
+ isOptionEqualToValue={(a, b) => a.id === b.id}
getOptionLabel={property => property.name || ""}
renderInput={params => (
= props => {
: "You don't have any views for this property."
}
value={props.view || null}
- getOptionSelected={(a, b) => a.id === b.id}
+ isOptionEqualToValue={(a, b) => a.id === b.id}
onChange={(_, v: ProfileSummary | null) => {
props.setViewID(v?.id || undefined)
}}
@@ -197,8 +208,8 @@ const ViewSelector: React.FC = props => {
)}
/>
)}
-
- )
+
+ );
}
export default ViewSelector
diff --git a/src/components/Warning.tsx b/src/components/Warning.tsx
index 32e29f29..18ad014a 100644
--- a/src/components/Warning.tsx
+++ b/src/components/Warning.tsx
@@ -1,15 +1,24 @@
import * as React from "react"
-import { Paper, makeStyles } from "@material-ui/core"
+import { styled } from '@mui/material/styles';
+import { Paper } from "@mui/material"
import classnames from "classnames"
-import { Warning as WarningIcon } from "@material-ui/icons"
-import red from "@material-ui/core/colors/red"
+import { Warning as WarningIcon } from "@mui/icons-material"
+import { red } from "@mui/material/colors"
+import {PropsWithChildren} from 'react';
-interface WarningProps {
- className?: string
-}
+const PREFIX = 'Warning';
-const useStyles = makeStyles(theme => ({
- warning: {
+const classes = {
+ warning: `${PREFIX}-warning`,
+ warningIcon: `${PREFIX}-warningIcon`
+};
+
+const StyledPaper = styled(Paper)((
+ {
+ theme
+ }
+) => ({
+ [`&.${classes.warning}`]: {
margin: theme.spacing(2, 0),
marginRight: theme.spacing(1),
padding: theme.spacing(1),
@@ -19,20 +28,25 @@ const useStyles = makeStyles(theme => ({
alignItems: "center",
backgroundColor: red[100],
},
- warningIcon: {
+
+ [`& .${classes.warningIcon}`]: {
margin: theme.spacing(0, 2),
- },
-}))
+ }
+}));
+
+interface WarningProps {
+ className?: string
+}
+
+const Warning: React.FC> = ({ children, className }) => {
-const Warning: React.FC = ({ children, className }) => {
- const classes = useStyles()
return (
-
+
-
- )
+
+ );
}
export default Warning
diff --git a/src/components/WithHelpText.tsx b/src/components/WithHelpText.tsx
index aa8e28f9..a99dd6e6 100644
--- a/src/components/WithHelpText.tsx
+++ b/src/components/WithHelpText.tsx
@@ -1,29 +1,36 @@
import * as React from "react"
-import { makeStyles } from "@material-ui/core"
+import { styled } from '@mui/material/styles';
import clsx from "classnames"
-import Typography from "@material-ui/core/Typography"
-import useFormStyles from "@/hooks/useFormStyles"
+import Typography from "@mui/material/Typography"
+import {PropsWithChildren} from 'react';
-interface WithHelpTextProps {
- label?: string | JSX.Element | undefined
- helpText?: string | JSX.Element
- afterHelp?: JSX.Element
- className?: string
- notched?: boolean
- shrink?: boolean
- hrGroup?: boolean
-}
+const PREFIX = 'WithHelpText';
-interface Props {
- notched?: boolean
- shrink?: boolean
-}
-const useStyles = makeStyles(theme => ({
- withHelpText: ({ notched, shrink }: Props) => ({
- marginTop: notched ? theme.spacing(1.5) : "unset",
- ...(shrink ? { display: "flex" } : {}),
- }),
- helpText: {
+const classes = {
+ withHelpText: `${PREFIX}-withHelpText`,
+ helpText: `${PREFIX}-helpText`,
+ shrunk: `${PREFIX}-shrunk`,
+ notchedContainer: `${PREFIX}-notchedContainer`,
+ label: `${PREFIX}-label`,
+ legend: `${PREFIX}-legend`,
+ fieldset: `${PREFIX}-fieldset`,
+ notchedChild: `${PREFIX}-notchedChild`,
+ hr: `${PREFIX}-hr`,
+ hrChildren: `${PREFIX}-hrChildren`,
+ verticalHr: `${PREFIX}-verticalHr`
+};
+
+const Root = styled('div')((
+ {
+ theme
+ }
+) => ({
+ [`& .${classes.withHelpText}`]: {
+ marginTop: theme.spacing(1.5),
+ display: "flex",
+ },
+
+ [`& .${classes.helpText}`]: {
...theme.typography.caption,
marginTop: theme.spacing(0.5),
paddingBottom: theme.spacing(2),
@@ -31,23 +38,27 @@ const useStyles = makeStyles(theme => ({
marginLeft: theme.spacing(2),
padding: "unset",
},
- shrunk: {
+
+ [`& .${classes.shrunk}`]: {
flexShrink: 1,
},
- notchedContainer: ({ shrink }: Props) => ({
+
+ [`& .${classes.notchedContainer}`]: {
position: "relative",
- ...(shrink ? {} : { width: "100%" }),
- }),
- label: {
+ width: "100%",
+ },
+ [`& .${classes.label}`]: {
color: "rgba(0, 0, 0, 0.54)",
...theme.typography.caption,
marginBottom: theme.spacing(1),
},
- legend: {
+
+ [`& .${classes.legend}`]: {
color: "rgba(0, 0, 0, 0.54)",
...theme.typography.caption,
},
- fieldset: {
+
+ [`& .${classes.fieldset}`]: {
position: "absolute",
top: theme.spacing(-1.5),
left: 0,
@@ -65,20 +76,39 @@ const useStyles = makeStyles(theme => ({
...theme.typography.caption,
},
},
- notchedChild: {
+
+ [`& .${classes.notchedChild}`]: {
padding: theme.spacing(1),
},
- hr: ({ shrink }: Props) => ({
- ...(shrink ? {} : { width: "100%" }),
- }),
- hrChildren: {
+ [`& .${classes.verticalHr}`]: {
+ display: "flex",
+ "&> hr": {
+ marginRight: theme.spacing(1),
+ },
+ "&> :not(:first-child)": {
+ flexGrow: 1,
+ },
+ },
+ [`&.${classes.hr}`]: {
+ width: "100%",
+ },
+ [`& .${classes.hrChildren}`]: {
"&> :last-child": {
paddingBottom: theme.spacing(2),
},
- },
-}))
+ }
+}));
-const WithHelpText: React.FC = ({
+interface WithHelpTextProps {
+ label?: string | JSX.Element | undefined
+ helpText?: string | JSX.Element
+ afterHelp?: JSX.Element
+ className?: string
+ notched?: boolean
+ shrink?: boolean
+ hrGroup?: boolean
+}
+const WithHelpText: React.FC> = ({
label,
children,
helpText,
@@ -88,12 +118,11 @@ const WithHelpText: React.FC = ({
className,
hrGroup,
}) => {
- const classes = useStyles({ notched, shrink })
- const formClasses = useFormStyles()
+
if (hrGroup) {
return (
-
-
+
+
@@ -110,11 +139,11 @@ const WithHelpText: React.FC = ({
-
- )
+
+ );
}
return (
-
+
)
}
diff --git a/src/components/ga4/DimensionsMetricsExplorer/Compatible.tsx b/src/components/ga4/DimensionsMetricsExplorer/Compatible.tsx
index 112ffd31..8116b345 100644
--- a/src/components/ga4/DimensionsMetricsExplorer/Compatible.tsx
+++ b/src/components/ga4/DimensionsMetricsExplorer/Compatible.tsx
@@ -1,42 +1,60 @@
import { PropertySummary } from "@/types/ga4/StreamPicker"
+import { styled } from '@mui/material/styles';
import {
Chip,
IconButton,
- makeStyles,
Paper,
Typography,
-} from "@material-ui/core"
-import { Replay } from "@material-ui/icons"
+} from "@mui/material"
+import { Replay } from "@mui/icons-material"
import { navigate } from "gatsby"
import * as React from "react"
import QueryExplorerLink from "../QueryExplorer/BasicReport/QueryExplorerLink"
import { CompatibleHook } from "./useCompatibility"
-const useStyles = makeStyles(theme => ({
- compatible: {
+const PREFIX = 'Compatible';
+
+const classes = {
+ compatible: `${PREFIX}-compatible`,
+ chipGrid: `${PREFIX}-chipGrid`,
+ chipLabel: `${PREFIX}-chipLabel`,
+ chips: `${PREFIX}-chips`,
+ removeButton: `${PREFIX}-removeButton`
+};
+
+const StyledPaper = styled(Paper)((
+ {
+ theme
+ }
+) => ({
+ [`&.${classes.compatible}`]: {
padding: theme.spacing(2),
marginTop: theme.spacing(2),
marginBottom: theme.spacing(1),
},
- chipGrid: {
+
+ [`& .${classes.chipGrid}`]: {
display: "grid",
gridTemplateColumns: "min-content 1fr",
alignItems: "baseline",
},
- chipLabel: {
+
+ [`& .${classes.chipLabel}`]: {
justifySelf: "end",
marginRight: theme.spacing(1),
},
- chips: {
+
+ [`& .${classes.chips}`]: {
"&> :not(:first-child)": {
marginLeft: theme.spacing(1),
},
},
- removeButton: {
+
+ [`& .${classes.removeButton}`]: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
- },
-}))
+ }
+}));
const WithProperty: React.FC<
CompatibleHook & { property: PropertySummary | undefined }
@@ -48,7 +66,7 @@ const WithProperty: React.FC<
property,
hasFieldSelected,
}) => {
- const classes = useStyles()
+
if (property === undefined) {
return null
@@ -103,11 +121,11 @@ const WithProperty: React.FC<
const Compatible: React.FC<
CompatibleHook & { property: PropertySummary | undefined }
> = props => {
- const classes = useStyles()
+
const { reset, property, hasFieldSelected } = props
return (
-
+
Compatible Fields
@@ -120,8 +138,8 @@ const Compatible: React.FC<
Pick a property above to enable this functionality.
)}
-
- )
+
+ );
}
export default Compatible
diff --git a/src/components/ga4/DimensionsMetricsExplorer/Field.tsx b/src/components/ga4/DimensionsMetricsExplorer/Field.tsx
index d6695bfe..513144bc 100644
--- a/src/components/ga4/DimensionsMetricsExplorer/Field.tsx
+++ b/src/components/ga4/DimensionsMetricsExplorer/Field.tsx
@@ -1,8 +1,9 @@
import * as React from "react"
-import IconLink from "@material-ui/icons/Link"
-import makeStyles from "@material-ui/core/styles/makeStyles"
-import Typography from "@material-ui/core/Typography"
+import { styled } from '@mui/material/styles';
+
+import IconLink from "@mui/icons-material/Link"
+import Typography from "@mui/material/Typography"
import InlineCode from "@/components/InlineCode"
import { CopyIconButton } from "@/components/CopyButton"
@@ -13,6 +14,48 @@ import { AccountSummary, PropertySummary } from "@/types/ga4/StreamPicker"
import LabeledCheckbox from "@/components/LabeledCheckbox"
import { CompatibleHook } from "./useCompatibility"
+const PREFIX = 'Field';
+
+const classes = {
+ headingUIName: `${PREFIX}-headingUIName`,
+ heading: `${PREFIX}-heading`,
+ apiName: `${PREFIX}-apiName`
+};
+
+const Root = styled('div')((
+ {
+ theme
+ }
+) => ({
+ [`& .${classes.headingUIName}`]: {
+ marginRight: theme.spacing(1),
+ "& > span": {
+ fontSize: "inherit",
+ },
+ },
+
+ [`& .${classes.heading}`]: {
+ display: "flex",
+ flexWrap: "wrap",
+ alignItems: "center",
+ marginBottom: theme.spacing(1),
+ "&> button": {
+ display: "none",
+ },
+ "&:hover": {
+ "&> button": {
+ display: "unset",
+ padding: "unset",
+ },
+ },
+ },
+
+ [`& .${classes.apiName}`]: {
+ margin: theme.spacing(0, 1),
+ fontSize: "0.75em",
+ }
+}));
+
const knownLinks: [string, JSX.Element][] = [
[
"",
@@ -75,34 +118,6 @@ const linkifyText = (
}
}
-const useStyles = makeStyles(theme => ({
- headingUIName: {
- marginRight: theme.spacing(1),
- "& > span": {
- fontSize: "inherit",
- },
- },
- heading: {
- display: "flex",
- flexWrap: "wrap",
- alignItems: "center",
- marginBottom: theme.spacing(1),
- "&> button": {
- display: "none",
- },
- "&:hover": {
- "&> button": {
- display: "unset",
- padding: "unset",
- },
- },
- },
- apiName: {
- margin: theme.spacing(0, 1),
- fontSize: "0.75em",
- },
-}))
-
interface FieldProps extends CompatibleHook {
field:
| { type: "dimension"; value: Dimension }
@@ -112,7 +127,7 @@ interface FieldProps extends CompatibleHook {
}
const Field: React.FC = props => {
- const classes = useStyles()
+
const {
field,
@@ -193,7 +208,7 @@ const Field: React.FC = props => {
}, [checked, addDimension, addMetric, removeDimension, removeMetric, field])
return (
-
+
{property === undefined ? (
uiName
@@ -215,8 +230,8 @@ const Field: React.FC = props => {
/>
{withLinks}
-
- )
+
+ );
}
export default Field
diff --git a/src/components/ga4/DimensionsMetricsExplorer/index.tsx b/src/components/ga4/DimensionsMetricsExplorer/index.tsx
index 6ce407ff..1cbeef95 100644
--- a/src/components/ga4/DimensionsMetricsExplorer/index.tsx
+++ b/src/components/ga4/DimensionsMetricsExplorer/index.tsx
@@ -1,11 +1,12 @@
import * as React from "react"
+import { styled } from '@mui/material/styles';
import { useMemo } from "react"
import ExternalLink from "@/components/ExternalLink"
-import Typography from "@material-ui/core/Typography"
-import TextField from "@material-ui/core/TextField"
-import IconButton from "@material-ui/core/IconButton"
-import Clear from "@material-ui/icons/Clear"
+import Typography from "@mui/material/Typography"
+import TextField from "@mui/material/TextField"
+import IconButton from "@mui/material/IconButton"
+import Clear from "@mui/icons-material/Clear"
import { Url, StorageKey } from "@/constants"
import { useScrollTo } from "@/hooks"
@@ -19,44 +20,54 @@ import {
Dimension,
Metric,
} from "./useDimensionsAndMetrics"
-import useFormStyles from "@/hooks/useFormStyles"
import StreamPicker from "../StreamPicker"
import useAccountProperty, {
AccountProperty,
} from "../StreamPicker/useAccountProperty"
import { Link } from "gatsby"
-import { makeStyles } from "@material-ui/core"
import useCompatibility from "./useCompatibility"
import Compatible from "./Compatible"
import ScrollToTop from "@/components/ScrollToTop"
-const dataAPI = (
-
- GA4 Data API's getMetadata method
-
-)
+const PREFIX = 'DimensionsMetricsExplorer';
-// TODO - add back in once this api is public.
-// const checkCompatibility = (
-// checkCompatibility
-// )
+const classes = {
+ headingLinks: `${PREFIX}-headingLinks`,
+ form: `${PREFIX}-form`,
+ search: `${PREFIX}-search`
+};
-const useStyles = makeStyles(theme => ({
- headingLinks: {
+const Root = styled('div')((
+ {
+ theme
+ }
+) => ({
+ [`& .${classes.headingLinks}`]: {
"& > a": {
color: theme.palette.text.primary,
},
},
- search: {
+
+ [`& .${classes.search}`]: {
marginTop: theme.spacing(1),
},
-}))
+
+ [`& .${classes.form}`]: {
+ maxWidth: "80ch",
+ }
+}));
+
+const dataAPI = (
+
+ GA4 Data API's getMetadata method
+
+)
const RenderSuccessful: React.FC = ({
categories,
aps,
}) => {
- const classes = useStyles()
+
const { search, setSearch } = useInputs()
const searchRegex = useMemo(
() =>
@@ -106,7 +117,7 @@ const RenderSuccessful: React.FC = ({
useScrollTo()
return (
- <>
+ (
= ({
)
})}
- >
- )
+ )
+ );
}
export enum QueryParam {
@@ -191,7 +202,6 @@ export enum QueryParam {
}
const DimensionsMetricsExplorer: React.FC = () => {
- const formClasses = useFormStyles()
const aps = useAccountProperty(
StorageKey.ga4DimensionsMetricsExplorerAPS,
QueryParam,
@@ -219,7 +229,7 @@ const DimensionsMetricsExplorer: React.FC = () => {
This demo is a catalog of all dimensions and metrics available for a
given property with linkable descriptions for all fields.
-
+
diff --git a/src/components/ga4/DimensionsMetricsExplorer/useCompatibility.tsx b/src/components/ga4/DimensionsMetricsExplorer/useCompatibility.tsx
index 7c700795..ffe3a45e 100644
--- a/src/components/ga4/DimensionsMetricsExplorer/useCompatibility.tsx
+++ b/src/components/ga4/DimensionsMetricsExplorer/useCompatibility.tsx
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"
import { useSelector } from "react-redux"
import { AccountProperty } from "../StreamPicker/useAccountProperty"
import { Dimension, Metric } from "./useDimensionsAndMetrics"
+type CheckCompatibilityResponse = gapi.client.analyticsdata.CheckCompatibilityResponse
export interface CompatibleHook {
dimensions: Dimension[] | undefined
@@ -56,6 +57,7 @@ const useCompatibility = (ap: AccountProperty): CompatibleHook => {
setIncompatibleDimensions(undefined)
return
}
+
gapi.client
.request({
path: `https://content-analyticsdata.googleapis.com/v1beta/${ap.property?.property}:checkCompatibility`,
@@ -66,17 +68,17 @@ const useCompatibility = (ap: AccountProperty): CompatibleHook => {
metrics: metrics?.map(m => ({ name: m.apiName })),
}),
})
- .then(response => {
+ .then((response) => {
const {
dimensionCompatibilities,
metricCompatibilities,
- } = response.result
- const d = dimensionCompatibilities
+ } = (response.result as CheckCompatibilityResponse)
+ const d = dimensionCompatibilities!
.filter(d => d.compatibility === "INCOMPATIBLE")
- .map(d => d.dimensionMetadata)
- const m = metricCompatibilities
+ .map(d => d.dimensionMetadata!)
+ const m = metricCompatibilities!
.filter(m => m.compatibility === "INCOMPATIBLE")
- .map(m => m.metricMetadata)
+ .map(m => m.metricMetadata!)
setIncompatibleMetrics(m)
setIncompatibleDimensions(d)
})
@@ -85,8 +87,8 @@ const useCompatibility = (ap: AccountProperty): CompatibleHook => {
const hasFieldSelected = useMemo(
() =>
- (dimensions !== undefined && dimensions.length) > 0 ||
- (metrics !== undefined && metrics.length > 0),
+ (dimensions !== undefined && dimensions!.length > 0) ||
+ (metrics !== undefined && metrics!.length > 0),
[dimensions, metrics]
)
diff --git a/src/components/ga4/EnhancedEcommerce/add-to-cart.module.css b/src/components/ga4/EnhancedEcommerce/add-to-cart.module.css
new file mode 100644
index 00000000..03f2531a
--- /dev/null
+++ b/src/components/ga4/EnhancedEcommerce/add-to-cart.module.css
@@ -0,0 +1,18 @@
+.addToCart {
+ display: flex;
+ flex-direction: row;
+ color: var(--text-color-inverted);
+ background-color: var(--primary);
+ align-self: flex-end;
+ padding: var(--space-sm) var(--space-xl);
+ border-radius: var(--radius-md);
+ font-weight: var(--bold);
+ align-items: center;
+ height: var(--size-input);
+ justify-content: center;
+ transition: var(--transition);
+}
+
+.addToCart:hover {
+ box-shadow: var(--shadow);
+}
\ No newline at end of file
diff --git a/src/components/ga4/EnhancedEcommerce/add-to-cart.tsx b/src/components/ga4/EnhancedEcommerce/add-to-cart.tsx
new file mode 100644
index 00000000..2f244ca2
--- /dev/null
+++ b/src/components/ga4/EnhancedEcommerce/add-to-cart.tsx
@@ -0,0 +1,42 @@
+import * as React from "react"
+import {addToCart as addToCartStyle} from "./add-to-cart.module.css"
+import {Product, StoreContext} from "./store-context"
+
+interface Props {
+ variantId: string,
+ quantity: number,
+ product: Product
+}
+
+export function AddToCart(props: Props) {
+ const {addVariantToCart, addEvent} = React.useContext(StoreContext)
+
+ function addToCart(e: React.MouseEvent) {
+ e.preventDefault()
+ const snippet = `gtag("event", "add_to_cart", {
+ "currency": "USD",
+ "value": ${parseInt(props.product.price) * props.quantity},
+ "items": [{
+ "item_id": "${props.product.id}",
+ "item_name": "${props.product.title}",
+ "price": "${props.product.price}",
+ "item_brand": "${props.product.brand}",
+ "item_category": "${props.product.category}",
+ "index": 0,
+ "size": "M"
+ }]
+});`
+ addEvent('add_to_cart', 'Item(s) added to cart.', snippet)
+ addVariantToCart(props.product, props.variantId, props.quantity)
+ }
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/ga4/EnhancedEcommerce/cart-button.tsx b/src/components/ga4/EnhancedEcommerce/cart-button.tsx
index f7292a0f..4cb3729b 100644
--- a/src/components/ga4/EnhancedEcommerce/cart-button.tsx
+++ b/src/components/ga4/EnhancedEcommerce/cart-button.tsx
@@ -2,19 +2,23 @@ import * as React from "react"
import {Link} from "gatsby"
import {badge, cartButton} from "./cart-button.module.css"
import {MdShoppingCart} from 'react-icons/md';
-import IconButton from "@material-ui/core/IconButton"
+import IconButton from "@mui/material/IconButton"
-export function CartButton({quantity}) {
+interface Props
+{
+ quantity:number
+}
+export function CartButton(props:Props) {
return (
- {quantity > 0 && {quantity}
}
+ {props.quantity > 0 && {props.quantity}
}
)
}
diff --git a/src/components/ga4/EnhancedEcommerce/ga-console.tsx b/src/components/ga4/EnhancedEcommerce/ga-console.tsx
index d6c8a0e0..0396f02f 100644
--- a/src/components/ga4/EnhancedEcommerce/ga-console.tsx
+++ b/src/components/ga4/EnhancedEcommerce/ga-console.tsx
@@ -1,27 +1,32 @@
import * as React from "react"
import {StoreContext} from "./store-context"
import {emptyEvents, eventDescription, eventLine, eventName, eventSnippet, eventTimestamp, gaConsoleStyle} from "@/components/ga4/EnhancedEcommerce/ga-console.module.css";
-import Dialog from '@material-ui/core/Dialog';
-import Tabs from '@material-ui/core/Tabs';
-import Tab from '@material-ui/core/Tab';
-import DialogActions from '@material-ui/core/DialogActions';
-import DialogContent from '@material-ui/core/DialogContent';
-import DialogContentText from '@material-ui/core/DialogContentText';
-import DialogTitle from '@material-ui/core/DialogTitle';
-import Button from '@material-ui/core/Button';
-import TextField from '@material-ui/core/TextField';
+import Dialog from '@mui/material/Dialog';
+import Tabs from '@mui/material/Tabs';
+import Tab from '@mui/material/Tab';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogContentText from '@mui/material/DialogContentText';
+import DialogTitle from '@mui/material/DialogTitle';
+import Button from '@mui/material/Button';
+import TextField from '@mui/material/TextField';
import {Link} from "gatsby";
-import {Box, Typography} from "@material-ui/core";
+import {Box, Typography} from "@mui/material";
+import {ReactNode, SyntheticEvent} from 'react';
-function TabPanel(props) {
- const {children, value, index, ...other} = props;
+type Props = {
+ children: ReactNode,
+ value?: number,
+ index: number
+}
+function TabPanel(props: Props) {
+ const {children, value, index} = props;
return (
{value === index && (
@@ -32,7 +37,7 @@ function TabPanel(props) {
);
}
-export function GaConsole({className}) {
+export function GaConsole({className = ''}) {
const {events} = React.useContext(StoreContext)
const [open, setOpen] = React.useState(false);
@@ -46,14 +51,14 @@ export function GaConsole({className}) {
const [value, setValue] = React.useState(0);
- const handleClickOpen = (eventKey) => () => {
+ const handleClickOpen = (eventKey: number) => () => {
setSelectedEvent(events[events.length - eventKey - 1])
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
- const handleChange = (event, newValue) => {
+ const handleChange = (event: SyntheticEvent, newValue: any) => {
setValue(newValue);
};
diff --git a/src/components/ga4/EnhancedEcommerce/navigation.tsx b/src/components/ga4/EnhancedEcommerce/navigation.tsx
index 66bc6e2a..defbfe48 100644
--- a/src/components/ga4/EnhancedEcommerce/navigation.tsx
+++ b/src/components/ga4/EnhancedEcommerce/navigation.tsx
@@ -2,7 +2,7 @@ import {Link} from "gatsby"
import * as React from "react"
import {navStyle, navLink, activeLink} from "./navigation.module.css"
-export function Navigation({className}) {
+export function Navigation({className=''}) {
return (