Skip to content

Commit 55c168e

Browse files
committed
Address comments
1 parent 80aab62 commit 55c168e

File tree

6 files changed

+54
-52
lines changed

6 files changed

+54
-52
lines changed

src/hooks/useCioAutocomplete.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { useMemo, useState } from 'react';
22
import useCioClient from './useCioClient';
33
import useDownShift from './useDownShift';
4-
import { CioAutocompleteProps, CioClientConfig, Section, UserDefinedSection } from '../types';
4+
import {
5+
CioAutocompleteProps,
6+
CioClientConfig,
7+
Section,
8+
UserDefinedSection,
9+
HTMLPropsWithCioDataAttributes,
10+
} from '../types';
511
import usePrevious from './usePrevious';
612
import {
713
getItemPosition,
@@ -165,23 +171,17 @@ const useCioAutocomplete = (options: UseCioAutocompleteOptions) => {
165171
}),
166172
getSectionProps: (section: Section) => {
167173
const sectionName = section?.displayName || section?.identifier;
168-
let attributes: React.DetailedHTMLProps<React.HTMLAttributes<any>, any> = {
174+
const attributes: HTMLPropsWithCioDataAttributes = {
169175
className: `${sectionName} cio-section`,
170176
ref: section.ref,
171177
role: 'none',
172-
};
173-
174-
const cnstrcDataAttributes = {
175-
'data-cnstrc-recommendations': true,
176178
'data-cnstrc-section': section.data[0]?.section,
177-
'data-cnstrc-recommendations-pod-id': section.identifier,
178179
};
179180

181+
// Add data attributes for recommendations
180182
if (section.type === 'recommendations') {
181-
attributes = {
182-
...attributes,
183-
...cnstrcDataAttributes,
184-
};
183+
attributes['data-cnstrc-recommendations'] = true;
184+
attributes['data-cnstrc-recommendations-pod-id'] = section.identifier;
185185
}
186186
return attributes;
187187
},

src/hooks/useDownShift.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ const useDownShift: UseDownShift = ({ setQuery, items, onSubmit, cioClient, prev
4646
section: selectedItem.section,
4747
resultId: selectedItem.result_id,
4848
});
49-
// Other Select tracking
50-
} else {
49+
// Select tracking for all other Constructor sections:
50+
// (ie: Search Suggestions, Products, Custom Cio sections, etc)
51+
// This does not apply to custom user defined sections that aren't part of Constructor index
52+
} else if (selectedItem.result_id) {
5153
cioClient?.tracker.trackAutocompleteSelect(selectedItem.value, {
5254
originalQuery: previousQuery,
5355
section: selectedItem.section,

src/hooks/useRecommendationsObserver.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,23 @@ import { Nullable } from '@constructor-io/constructorio-client-javascript/lib/ty
33
import ConstructorIO from '@constructor-io/constructorio-client-javascript';
44
import { Section } from '../types';
55

6+
/**
7+
* Custom hook that observes the visibility of recommendation sections and calls trackRecommendationView event.
8+
* This is done by using the IntersectionObserver API to observe the visibility of each recommendation section.
9+
* That is done by passing the ref of each recommendation section to the IntersectionObserver.
10+
* The refs are either passed by the user in section config or generated by the library by default.
11+
* Either way the refs are stored in the sections array.
12+
*
13+
* @param menuIsOpen - A boolean indicating whether the menu is open.
14+
* @param sections - An array of sections to observe.
15+
* @param constructorIO - An instance of the ConstructorIO client.
16+
* @param trackRecommendationView - A callback function to track the recommendation view event.
17+
*/
618
function useRecommendationsObserver(
719
menuIsOpen: boolean,
820
sections: Section[],
921
constructorIO: Nullable<ConstructorIO>,
10-
callback: (
22+
trackRecommendationView: (
1123
target: HTMLElement,
1224
sections: Section[],
1325
constructorIO: Nullable<ConstructorIO>
@@ -19,21 +31,20 @@ function useRecommendationsObserver(
1931
.map((section) => section.ref);
2032

2133
useEffect(() => {
22-
const observer = new IntersectionObserver(
23-
(entries) => {
24-
// For each section, check if it's intersecting
25-
entries.forEach((entry) => {
26-
if (entry.isIntersecting) {
27-
// Call the callback, which will be trackRecommendationView in our case
28-
callback(entry.target as HTMLElement, sections, constructorIO);
29-
}
30-
});
31-
},
32-
{
33-
root: null,
34-
threshold: 0.1,
35-
}
36-
);
34+
const intersectionObserverOptions = {
35+
// Root element is the bounding target for the observer to observe. If null, then the document viewport is used.
36+
root: null,
37+
// 0.1 indicate the callback should be called when that proportion of the target is visible (e.g., 10% visible).
38+
threshold: 0.1,
39+
};
40+
const observer = new IntersectionObserver((entries) => {
41+
// For each section, check if it's intersecting
42+
entries.forEach((entry) => {
43+
if (entry.isIntersecting) {
44+
trackRecommendationView(entry.target as HTMLElement, sections, constructorIO);
45+
}
46+
});
47+
}, intersectionObserverOptions);
3748

3849
// Observe each section
3950
refs.forEach((ref) => {

src/hooks/useSections.ts

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,7 @@ export default function useSections(
1717
const zeroStateActiveSections = !query.length && zeroStateSections;
1818

1919
// Define All Sections
20-
const [activeSections, setActiveSections] = useState<UserDefinedSection[]>(
21-
zeroStateActiveSections ? zeroStateSections : sections
22-
);
23-
24-
useEffect(() => {
25-
setActiveSections(zeroStateActiveSections ? zeroStateSections : sections);
26-
// eslint-disable-next-line react-hooks/exhaustive-deps
27-
}, [zeroStateActiveSections]);
28-
20+
const activeSections = zeroStateActiveSections ? zeroStateSections : sections;
2921
const sectionsRefs = useRef<RefObject<HTMLLIElement>[]>(activeSections.map(() => createRef()));
3022
const [activeSectionsWithData, setActiveSectionsWithData] = useState<Section[]>([]);
3123
const autocompleteSections = useMemo(
@@ -62,16 +54,6 @@ export default function useSections(
6254
);
6355
}, [autocompleteResults, recommendationsResults, activeSections]);
6456

65-
// Reset sections
66-
useEffect(() => {
67-
if (
68-
(sections && !Array.isArray(sections)) ||
69-
(zeroStateSections && !Array.isArray(zeroStateSections))
70-
) {
71-
setActiveSections([]);
72-
}
73-
}, [sections, zeroStateSections]);
74-
7557
return {
7658
activeSections,
7759
activeSectionsWithData,

src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,10 @@ export type InGroupSuggestion = SearchSuggestion & {
117117
groupId: string;
118118
groupName: string;
119119
};
120+
121+
export type HTMLPropsWithCioDataAttributes<T = any> = React.DetailedHTMLProps<
122+
React.HTMLAttributes<T>,
123+
T
124+
> & {
125+
[key: `data-cnstrc-${string}`]: any;
126+
};

src/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ export const getActiveSectionsWithData = (
170170
data: sectionData,
171171
};
172172

173-
if (sectionConfig.type === 'recommendations') {
174-
// If user provided a ref in config, use it. Otherwise, use the ref from our refs array
175-
section.ref = sectionConfig.ref || sectionsRefs.current[index];
176-
}
173+
// If user provided a ref in `sectionConfig`, use it. Otherwise, use the ref from our library generated refs array
174+
const userDefinedSectionRef = sectionConfig.ref;
175+
const libraryGeneratedSectionRef = sectionsRefs.current[index];
176+
section.ref = userDefinedSectionRef || libraryGeneratedSectionRef;
177177

178178
activeSectionsWithData.push(section);
179179
}

0 commit comments

Comments
 (0)