Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 0 additions & 113 deletions src/hooks/useSections.ts

This file was deleted.

76 changes: 76 additions & 0 deletions src/hooks/useSections/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* eslint-disable max-params */
import { RefObject, createRef, useEffect, useMemo, useRef, useState } from 'react';
import ConstructorIO from '@constructor-io/constructorio-client-javascript';
import { Nullable } from '@constructor-io/constructorio-client-javascript/lib/types';
import { AdvancedParameters, PodData, UserDefinedSection } from '../../types';
import useActiveSections from './useActiveSections';
import useSectionsResults from './useSectionsResults';
import useActiveSectionsWithData from './useActiveSectionsWithData';
import useRemoveSections from './useRemoveSections';

export default function useSections(
query: string,
cioClient: Nullable<ConstructorIO>,
sections: UserDefinedSection[],
zeroStateSections?: UserDefinedSection[],
advancedParameters?: AdvancedParameters
) {
const [podsData, setPodsData] = useState<Record<string, PodData>>({});

// Get Active Sections defined by configuration object
const { activeSections, showZeroStateSections, setActiveSections } = useActiveSections(
query,
sections,
podsData,
zeroStateSections
);

// create refs for active sections
const sectionsRefs = useRef<RefObject<HTMLLIElement>[]>(activeSections.map(() => createRef()));

// Get API results for each active section
const { recommendations, autocomplete } = useSectionsResults(
query,
cioClient,
activeSections,
advancedParameters
);

// Access the Pods Data from the Recommendations response to update Active Sections configuration
useEffect(() => {
if (!recommendations.podsData) {
setPodsData(recommendations.podsData);
}
}, [recommendations.podsData]);

useRemoveSections(
sections,
podsData,
setActiveSections,
showZeroStateSections,
zeroStateSections
);

// Combine recommendations and autocomplete results in sectionsResults
const sectionsResults = useMemo(
() => ({ ...autocomplete.results, ...recommendations.results }),
[autocomplete.results, recommendations.results]
);

// Return current active sections populated with data from the API response sectionsResults
const activeSectionsWithData = useActiveSectionsWithData(
sectionsResults,
activeSections,
sectionsRefs,
query
);

return {
fetchRecommendationResults: recommendations.fetchRecommendationResults,
activeSections,
activeSectionsWithData,
zeroStateActiveSections: showZeroStateSections,
request: autocomplete.request,
totalNumResultsPerSection: autocomplete.totalNumResultsPerSection,
};
}
41 changes: 41 additions & 0 deletions src/hooks/useSections/useActiveSections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useMemo, useState } from 'react';
import { PodData, UserDefinedSection } from '../../types';
import { isRecommendationsSection } from '../../typeGuards';

export default function useActiveSections(
query: string,
sections: UserDefinedSection[],
podsData?: Record<string, PodData>,
zeroStateSections?: UserDefinedSection[]
) {
const showZeroStateSections = !query.length && !!zeroStateSections?.length;

const [activeSections, setActiveSections] = useState<UserDefinedSection[]>(
showZeroStateSections ? zeroStateSections : sections
);

// Merge Recommendation Pods Display Name from Dashboard
const activeSectionsTransformed = useMemo(
() =>
activeSections.map((config: UserDefinedSection) => {
const mergedConfig = config;

if (isRecommendationsSection(config)) {
const podData = podsData?.[config.podId];
const libraryDisplayName = config.displayName;
const dashboardDisplayName = podData?.displayName;

mergedConfig.displayName = libraryDisplayName || dashboardDisplayName;
}

return mergedConfig;
}),
[activeSections, podsData]
);

return {
activeSections: activeSectionsTransformed,
showZeroStateSections,
setActiveSections,
};
}
27 changes: 27 additions & 0 deletions src/hooks/useSections/useActiveSectionsWithData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { RefObject, useEffect, useState } from 'react';
import { UserDefinedSection, Section, SectionsData } from '../../types';
import { getActiveSectionsWithData } from '../../utils';

export default function useActiveSectionsWithData(
sectionsResults: SectionsData,
activeSections: UserDefinedSection[],
sectionsRefs: React.MutableRefObject<RefObject<HTMLLIElement>[]>,
query: string
) {
const [activeSectionsWithData, setActiveSectionsWithData] = useState<Section[]>([]);

// Add to active sections the results data and refs when autocomplete results or recommendation results fetched
useEffect(() => {
const activeSectionsWithDataValue = getActiveSectionsWithData(
activeSections,
sectionsResults,
sectionsRefs
);

if (activeSectionsWithDataValue.length || !query) {
setActiveSectionsWithData(activeSectionsWithDataValue);
}
}, [activeSections, sectionsResults, sectionsRefs, query]);

return activeSectionsWithData;
}
27 changes: 27 additions & 0 deletions src/hooks/useSections/useRemoveSections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* eslint-disable max-params */
import { useEffect } from 'react';
import { PodData, UserDefinedSection } from '../../types';
import { getFeatures } from '../../utils';

export default function useRemoveSections(
sections: UserDefinedSection[],
podsData: Record<string, PodData>,
setActiveSections: any,
showZeroStateSections: boolean,
zeroStateSections?: UserDefinedSection[]
) {
// Remove sections if necessary
useEffect(() => {
const features = getFeatures(Object.values(podsData || {})?.[0]?.request);

if (showZeroStateSections) {
if (!features.featureDisplayZeroStateRecommendations) {
setActiveSections([]);
} else {
setActiveSections(zeroStateSections);
}
} else {
setActiveSections(sections);
}
}, [zeroStateSections, showZeroStateSections, sections, podsData, setActiveSections]);
}
64 changes: 64 additions & 0 deletions src/hooks/useSections/useSectionsResults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* eslint-disable max-params */
import ConstructorIO from '@constructor-io/constructorio-client-javascript';
import { Nullable } from '@constructor-io/constructorio-client-javascript/lib/types';
import { useMemo } from 'react';
import {
AdvancedParameters,
AutocompleteSectionConfiguration,
RecommendationsSectionConfiguration,
UserDefinedSection,
} from '../../types';
import useDebouncedFetchSection from '../useDebouncedFetchSections';
import useFetchRecommendationPod from '../useFetchRecommendationPod';
import { isAutocompleteSection, isRecommendationsSection } from '../../typeGuards';

export default function useSectionsResults(
query: string,
cioClient: Nullable<ConstructorIO>,
activeSections: UserDefinedSection[],
advancedParameters?: AdvancedParameters
) {
// Fetch Autocomplete Results
const activeAutocompleteSections = useMemo(
() =>
activeSections?.filter((config: UserDefinedSection) =>
isAutocompleteSection(config)
) as AutocompleteSectionConfiguration[],
[activeSections]
);

const {
sectionsData: autocompleteResults,
request,
totalNumResultsPerSection,
} = useDebouncedFetchSection(query, cioClient, activeAutocompleteSections, advancedParameters);

// Fetch Recommendations Results
const activeRecommendationsSections = useMemo(
() =>
activeSections?.filter((config: UserDefinedSection) =>
isRecommendationsSection(config)
) as RecommendationsSectionConfiguration[],
[activeSections]
);

const { fetchRecommendationResults, recommendationsResults, podsData } =
useFetchRecommendationPod(
cioClient,
activeRecommendationsSections,
advancedParameters?.fetchZeroStateOnFocus
);

return {
recommendations: {
results: recommendationsResults,
fetchRecommendationResults,
podsData,
},
autocomplete: {
results: autocompleteResults,
request,
totalNumResultsPerSection,
},
};
}
14 changes: 10 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,18 +173,18 @@ export const getCioClient = (apiKey?: string, cioJsClientOptions?: ConstructorCl

export const getActiveSectionsWithData = (
activeSections: UserDefinedSection[],
sectionResults: SectionsData,
sectionsResults: SectionsData,
sectionsRefs: React.MutableRefObject<React.RefObject<HTMLLIElement>[]>
) => {
const activeSectionsWithData: Section[] = [];

activeSections?.forEach((sectionConfig, index) => {
const getSectionData = (sectionConfig) => {
const { type } = sectionConfig;
let sectionData: Item[];

switch (type) {
case 'recommendations':
sectionData = sectionResults[sectionConfig.podId];
sectionData = sectionsResults[sectionConfig.podId];
break;
case 'custom':
// Copy id from data to the top level
Expand All @@ -195,9 +195,15 @@ export const getActiveSectionsWithData = (
break;
default:
// Autocomplete
sectionData = sectionResults[sectionConfig.indexSectionName];
sectionData = sectionsResults[sectionConfig.indexSectionName];
}

return sectionData;
};

activeSections?.forEach((sectionConfig, index) => {
const sectionData = getSectionData(sectionConfig);

if (Array.isArray(sectionData)) {
const section = {
...sectionConfig,
Expand Down
Loading