Skip to content

Commit

Permalink
feature: add category names
Browse files Browse the repository at this point in the history
  • Loading branch information
kathleentynan committed Nov 1, 2023
1 parent 8f4beb4 commit cda8e18
Show file tree
Hide file tree
Showing 17 changed files with 131 additions and 44 deletions.
9 changes: 6 additions & 3 deletions src/api/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ const Facet = `
attribute
buckets {
title
__typename
... on CategoryView {
name
count
path
}
... on ScalarBucket {
__typename
count
}
... on RangeBucket {
__typename
from
to
count
}
... on StatsBucket {
__typename
min
max
}
Expand Down
2 changes: 1 addition & 1 deletion src/api/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,4 @@ const refineProductSearch = async ({
return results?.data;
};

export { getProductSearch, getAttributeMetadata, refineProductSearch };
export { getAttributeMetadata, getProductSearch, refineProductSearch };
1 change: 1 addition & 0 deletions src/components/CategoryFilters/CategoryFilters.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('PLP widget/CategoryFilters', () => {
const { container } = render(
<CategoryFilters
loading={true}
pageLoading={false}
totalCount={1}
facets={[]}
categoryName=""
Expand Down
22 changes: 14 additions & 8 deletions src/components/CategoryFilters/CategoryFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { FilterButton } from '../FilterButton';

interface CategoryFiltersProps {
loading: boolean;
pageLoading: boolean;
totalCount: number;
facets: Facet[];
categoryName: string;
Expand All @@ -26,6 +27,7 @@ interface CategoryFiltersProps {

export const CategoryFilters: FunctionComponent<CategoryFiltersProps> = ({
loading,
pageLoading,
totalCount,
facets,
categoryName,
Expand All @@ -50,14 +52,18 @@ export const CategoryFilters: FunctionComponent<CategoryFiltersProps> = ({
)}
</div>

<div className="flex pb-4 w-full h-full">
<FilterButton
displayFilter={() => setShowFilters(false)}
type="desktop"
title={translation.Filter.hideTitle}
/>
</div>
<Facets searchFacets={facets} />
{!pageLoading && (
<>
<div className="flex pb-4 w-full h-full">
<FilterButton
displayFilter={() => setShowFilters(false)}
type="desktop"
title={translation.Filter.hideTitle}
/>
</div>
<Facets searchFacets={facets} />
</>
)}
</div>
);
};
24 changes: 19 additions & 5 deletions src/components/Facets/Facets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ export const Facets: FunctionComponent<FacetsProps> = ({
? productsCtx.currencySymbol
: '$';
const label = `${currencySymbol}${
range?.from
range?.from &&
parseFloat(currencyRate) * parseInt(range.to.toFixed(0), 10)
? (
parseFloat(currencyRate) * parseInt(range.from.toFixed(0), 10)
).toFixed(2)
parseFloat(currencyRate) * parseInt(range.from?.toFixed(0), 10)
)?.toFixed(2)
: 0
}${
range?.to
range?.to && parseFloat(currencyRate) * parseInt(range.to.toFixed(0), 10)
? ` - ${currencySymbol}${(
parseFloat(currencyRate) * parseInt(range.to.toFixed(0), 10)
).toFixed(2)}`
Expand All @@ -56,6 +57,17 @@ export const Facets: FunctionComponent<FacetsProps> = ({
};

const formatBinaryLabel = (filter: FacetFilter, option: string) => {
if (productsCtx.categoryPath) {
const category = searchCtx.categoryNames.find(
(facet) =>
facet.attribute === filter.attribute && facet.value === option
);

if (category?.name) {
return category.name;
}
}

const title = filter.attribute?.split('_');
if (option === 'yes') {
return title.join(' ');
Expand Down Expand Up @@ -88,7 +100,7 @@ export const Facets: FunctionComponent<FacetsProps> = ({
<div className="flex flex-wrap gap-3" key={filter.attribute}>
{filter.in?.map((option) => (
<Pill
key={formatBinaryLabel(filter, option)}
key={filter.attribute}
label={formatBinaryLabel(filter, option)}
onClick={() =>
searchCtx.updateFilterOptions(filter, option)
Expand Down Expand Up @@ -123,6 +135,8 @@ export const Facets: FunctionComponent<FacetsProps> = ({
filterData={facet as PriceFacet}
/>
);
case 'CategoryView':
return <ScalarFacet key={facet.attribute} filterData={facet} />;
default:
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Facets/Scalar/ScalarFacet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface ScalarFacetProps {
export const ScalarFacet: FunctionComponent<ScalarFacetProps> = ({
filterData,
}) => {
const { isSelected, onChange } = useScalarFacet(filterData.attribute);
const { isSelected, onChange } = useScalarFacet(filterData);

return (
<InputButtonGroup
Expand Down
14 changes: 11 additions & 3 deletions src/components/InputButtonGroup/InputButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type InputButtonGroupOnChangeProps = {
value: string;
selected?: boolean;
};

export type InputButtonGroupOnChange = (
arg0: InputButtonGroupOnChangeProps
) => void;
Expand All @@ -30,7 +31,8 @@ export type Bucket = {
count: number;
to?: number;
from?: number;
__typename: 'ScalarBucket' | 'RangeBucket';
name?: string;
__typename: 'ScalarBucket' | 'RangeBucket' | 'CategoryView';
};
export interface InputButtonGroupProps {
title: string;
Expand Down Expand Up @@ -75,19 +77,25 @@ export const InputButtonGroup: FunctionComponent<InputButtonGroupProps> = ({
? productsCtx.currencySymbol
: '$';
const label = `${currencySymbol}${
bucket.from
bucket?.from &&
parseFloat(currencyRate) * parseInt(bucket.from.toFixed(0), 10)
? (
parseFloat(currencyRate) * parseInt(bucket.from.toFixed(0), 10)
).toFixed(2)
: 0
}${
bucket.to
bucket?.to &&
parseFloat(currencyRate) * parseInt(bucket.to.toFixed(0), 10)
? ` - ${currencySymbol}${(
parseFloat(currencyRate) * parseInt(bucket.to.toFixed(0), 10)
).toFixed(2)}`
: translation.InputButtonGroup.priceRange
}`;
return label;
} else if (bucket.__typename === 'CategoryView') {
return productsCtx.categoryPath
? bucket.name ?? bucket.title
: bucket.title;
} else if (bucket.title === BOOLEAN_YES) {
return title;
} else if (bucket.title === BOOLEAN_NO) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ProductItem/ProductItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const ProductItem: FunctionComponent<ProductProps> = ({
className="!text-primary hover:no-underline hover:text-primary"
>
<div className="ds-sdk-product-item__main relative flex flex-col justify-between h-full">
<div className="ds-sdk-product-item__image relative w-full h-full rounded-md overflow-hidden min-h-[20rem]">
<div className="ds-sdk-product-item__image relative w-full h-full rounded-md overflow-hidden">
{/*
NOTE:
we could use <picture> <source...
Expand Down
2 changes: 1 addition & 1 deletion src/components/ProductList/ProductList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const ProductList: FunctionComponent<ProductListProps> = ({
style={{
gridTemplateColumns: `repeat(${numberOfColumns}, minmax(0, 1fr))`,
}}
className="ds-sdk-product-list__grid mt-md grid grid-cols-1 gap-y-8 gap-x-2xl sm:grid-cols-2 xl:gap-x-8"
className="ds-sdk-product-list__grid mt-md grid grid-cols-1 gap-y-8 gap-x-2xl sm:grid-cols-2 md:grid-cols-3 xl:gap-x-8"
>
{products?.map((product) => (
<ProductItem
Expand Down
1 change: 1 addition & 0 deletions src/containers/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const App: FunctionComponent = () => {
<div className="flex">
<CategoryFilters
loading={productsCtx.loading}
pageLoading={productsCtx.pageLoading}
facets={productsCtx.facets}
totalCount={productsCtx.totalCount}
categoryName={productsCtx.categoryName ?? ''}
Expand Down
37 changes: 34 additions & 3 deletions src/context/products.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ const ProductsContext = createContext<{
pageSizeOptions: PageSizeOption[];
setRoute: RedirectRouteFunc | undefined;
refineProduct: (optionIds: string[], sku: string) => any;
pageLoading: boolean;
setPageLoading: (loading: boolean) => void;
categoryPath: string | undefined;
}>({
variables: {
phrase: '',
Expand Down Expand Up @@ -96,6 +99,9 @@ const ProductsContext = createContext<{
pageSizeOptions: [],
setRoute: undefined,
refineProduct: () => {},
pageLoading: false,
setPageLoading: () => {},
categoryPath: undefined,
});

const ProductsContextProvider = ({ children }: WithChildrenProps) => {
Expand All @@ -118,6 +124,7 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
const showAllLabel = translation.ProductContainers.showAll;

const [loading, setLoading] = useState(true);
const [pageLoading, setPageLoading] = useState(true);
const [items, setItems] = useState<Product[]>([]);
const [currentPage, setCurrentPage] = useState<number>(pageDefault);
const [pageSize, setPageSize] = useState<number>(pageSizeDefault);
Expand All @@ -139,6 +146,7 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
const minQueryLength = useMemo(() => {
return storeCtx?.config?.minQueryLength || DEFAULT_MIN_QUERY_LENGTH;
}, [storeCtx?.config.minQueryLength]);
const categoryPath = storeCtx.config?.currentCategoryUrlPath;

const variables = useMemo(() => {
return {
Expand All @@ -154,9 +162,10 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
searchCtx.phrase,
searchCtx.filters,
searchCtx.sort,
storeCtx.context,
storeCtx.config.displayOutOfStock,
currentPage,
pageSize,
currentPage,
]);

const handleRefineProductSearch = async (
Expand Down Expand Up @@ -194,14 +203,16 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
pageSizeOptions,
setRoute: storeCtx.route,
refineProduct: handleRefineProductSearch,
pageLoading,
setPageLoading,
categoryPath,
};

const searchProducts = async () => {
try {
setLoading(true);
moveToTop();
if (checkMinQueryLength()) {
const categoryPath = storeCtx.config?.currentCategoryUrlPath;
const filters = [...variables.filter];

handleCategorySearch(categoryPath, filters);
Expand All @@ -218,6 +229,7 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
setFacets(data?.productSearch?.facets || []);
setTotalCount(data?.productSearch?.total_count || 0);
setTotalPages(data?.productSearch?.page_info?.total_pages || 1);
handleCategoryNames(data?.productSearch?.facets || []);

getPageSizeOptions(data?.productSearch?.total_count);

Expand All @@ -227,8 +239,10 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
);
}
setLoading(false);
setPageLoading(false);
} catch (error) {
setLoading(false);
setPageLoading(false);
}
};

Expand Down Expand Up @@ -258,7 +272,7 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
pageSizeArray.forEach((option) => {
optionsArray.push({
label: option,
value: parseInt(option),
value: parseInt(option, 10),
});
});

Expand Down Expand Up @@ -300,6 +314,23 @@ const ProductsContextProvider = ({ children }: WithChildrenProps) => {
}
};

const handleCategoryNames = (facets: Facet[]) => {
facets.map((facet) => {
const bucketType = facet?.buckets[0]?.__typename;
if (bucketType === 'CategoryView') {
const names = facet.buckets.map((bucket) => {
if (bucket.__typename === 'CategoryView')
return {
name: bucket.name,
value: bucket.title,
attribute: facet.attribute,
};
});
searchCtx.setCategoryNames(names);
}
});
};

useEffect(() => {
if (attributeMetadataCtx.filterableInSearch) {
searchProducts();
Expand Down
9 changes: 8 additions & 1 deletion src/context/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ interface SearchContextProps {
setCategoryPath: any;
setFilters: any;
setSort: any;
setCategoryNames: any;
categoryNames: { name: string; value: string; attribute: string }[];
createFilter: (filter: FacetFilter) => void;
updateFilter: (filter: FacetFilter) => void;
updateFilterOptions(filter: FacetFilter, option: string): void;
Expand All @@ -57,6 +59,9 @@ const SearchProvider: FunctionComponent = ({ children }) => {
const [phrase, setPhrase] = useState<string>(phraseFromUrl);
const [categoryPath, setCategoryPath] = useState<string>('');
const [filters, setFilters] = useState<SearchClauseInput[]>([]);
const [categoryNames, setCategoryNames] = useState<
{ name: string; value: string; attribute: string }[]
>([]);
const [sort, setSort] = useState<ProductSearchSortInput[]>(sortDefault);

const createFilter = (filter: SearchClauseInput) => {
Expand Down Expand Up @@ -112,9 +117,11 @@ const SearchProvider: FunctionComponent = ({ children }) => {
categoryPath,
filters,
sort,
categoryNames,
setPhrase,
setCategoryPath,
setFilters,
setCategoryNames,
setSort,
createFilter,
updateFilter,
Expand All @@ -133,4 +140,4 @@ const useSearch = () => {
return searchCtx;
};

export { useSearch, SearchProvider };
export { SearchProvider, useSearch };
Loading

0 comments on commit cda8e18

Please sign in to comment.