Skip to content

Commit

Permalink
Merge pull request #17 from bigcommerce/feature/advanced-filters
Browse files Browse the repository at this point in the history
feat(pattern): optimize filter samples code
  • Loading branch information
davelinke authored Jan 14, 2025
2 parents 1298a6c + cdc8f30 commit 10ca600
Show file tree
Hide file tree
Showing 17 changed files with 1,220 additions and 2,011 deletions.
8 changes: 4 additions & 4 deletions packages/examples-site/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import PageAnchorNav from "./pages/AnchorNavPage/AnchorNavPage";
import CardGridPage from "./pages/CardGridPage";
import InstallScreenApp from "./pages/InstallScreenPage/AppExample";
import InstallScreenChannel from "./pages/InstallScreenPage/ChannelExample";
import PageFiltersSearch from "./pages/FiltersSearchPage/FiltersSearchPage";
import PageFiltersDropdowns from "./pages/FiltersDropdownsPage/FiltersDropdownsPage";
import PageFiltersAdvanced from "./pages/FiltersAdvPage/FiltersAdvancedPage";
import PageFiltersAdvancedAdditive from "./pages/FiltersAdvancedAdditivePage/FiltersAdvancedAdditivePage";
import PageFiltersSearch from "./pages/Filters/FiltersSearchPage/FiltersSearchPage";
import PageFiltersDropdowns from "./pages/Filters/FiltersDropdownsPage/FiltersDropdownsPage";
import PageFiltersAdvanced from "./pages/Filters/FiltersAdvPage/FiltersAdvancedPage";
import PageFiltersAdvancedAdditive from "./pages/Filters/FiltersAdvancedAdditivePage/FiltersAdvancedAdditivePage";

export const alertsManager = createAlertsManager();

Expand Down
59 changes: 59 additions & 0 deletions packages/examples-site/src/common/ProductsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { FunctionComponent } from "react";
import { Flex, FlexItem, Panel } from "@bigcommerce/big-design";
import { Header, Page } from "@bigcommerce/big-design-patterns";
import { useNavigate } from "react-router";
import { theme } from "@bigcommerce/big-design-theme";

/**
* PageList component - Displays a page with a list of items in a table.
*/

export interface ProductPageProps {
headerTitle: string;
headerDescription: string;
filters: React.ReactNode;
products: React.ReactNode;
}

const ProductsPage: FunctionComponent<ProductPageProps> = ({
headerTitle,
headerDescription,
filters,
products,
}) => {
// NAVIGATION
const navigate = useNavigate();

return (
<>
<Page
header={
<Header
description={headerDescription}
title={headerTitle}
backLink={{
text: "Back to patterns",
onClick: () => navigate("/"),
href: "#",
}}
/>
}
>
<Flex flexDirection="column" flexGap={theme.spacing.xLarge}>
<FlexItem>
{
//The most common way of organizing information within the BigDesign patterns is with the use of panels.
//In this case we only have one panel, but you can have multiple panels within a page.
}
<Panel header="Items list">
{filters}
{products}
</Panel>
</FlexItem>
</Flex>
</Page>
</>
);
};

export default ProductsPage;
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,6 @@ import { theme as defaultTheme } from "@bigcommerce/big-design-theme";
import styled from "styled-components";
import { BoxProps } from "@bigcommerce/big-design";

export const StyledPanelContents = styled.div<BoxProps>`
display: block;
box-sizing: border-box;
margin-inline: -${({ theme }) => theme.spacing.medium};
max-width: calc(
100% + ${({ theme }) => theme.spacing.medium}px +
${({ theme }) => theme.spacing.medium}px
);
overflow-x: auto;
@media (min-width: ${({ theme }) => theme.breakpointValues.tablet}) {
margin-inline: -${({ theme }) => theme.spacing.xLarge};
max-width: calc(
100% + ${({ theme }) => theme.spacing.xLarge}px +
${({ theme }) => theme.spacing.xLarge}px
);
}
`;

// Provides default theme props to ensure consistent styling if not provided externally
StyledPanelContents.defaultProps = { theme: defaultTheme };

export const StyledProductImage = styled.div<BoxProps>`
display: block;
box-sizing: border-box;
Expand All @@ -41,12 +20,23 @@ export const StyledProductImage = styled.div<BoxProps>`

StyledProductImage.defaultProps = { theme: defaultTheme };


export const StyledBulkActions = styled.div<BoxProps>`
display: block;
@media (min-width: ${({ theme }) => theme.breakpointValues.tablet}) {
min-width: 300px;
}
export const StyledPanelContents = styled.div<BoxProps>`
display: block;
box-sizing: border-box;
margin-inline: -${({ theme }) => theme.spacing.medium};
max-width: calc(
100% + ${({ theme }) => theme.spacing.medium}px +
${({ theme }) => theme.spacing.medium}px
);
overflow-x: auto;
@media (min-width: ${({ theme }) => theme.breakpointValues.tablet}) {
margin-inline: -${({ theme }) => theme.spacing.xLarge};
max-width: calc(
100% + ${({ theme }) => theme.spacing.xLarge}px +
${({ theme }) => theme.spacing.xLarge}px
);
}
`;

StyledBulkActions.defaultProps = { theme: defaultTheme };
// Provides default theme props to ensure consistent styling if not provided externally
StyledPanelContents.defaultProps = { theme: defaultTheme };
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import React, { FunctionComponent, useState, useEffect } from "react";
import React, { FunctionComponent, useEffect, useState } from "react";
import {
Flex,
FlexItem,
Box,
Button,
Panel,
Search,
Table,
TableItem,
Text,
Expand All @@ -14,25 +10,20 @@ import {
} from "@bigcommerce/big-design";
import { InfoIllustration } from "bigcommerce-design-patterns";
import { MoreHorizIcon } from "@bigcommerce/big-design-icons";
import { Header, Page } from "@bigcommerce/big-design-patterns";
import { useNavigate } from "react-router";
import { useLocation } from "react-router-dom";
import { theme } from "@bigcommerce/big-design-theme";
import {
StyledPanelContents,
StyledProductImage,
} from "./FiltersSearchPage.styled";
} from "./ProductsTable.styled";

import { DummyItem } from "../../data/dummyProducts";
import { getCategories, getProducts } from "../../data/services";
import { Category } from "../../data/dummyCategories";
import { findCategoryById } from "../../helpers/categories";
import { formatPrice } from "../../helpers/price";
import { DummyItem } from "../data/dummyProducts";
import { findCategoryById } from "../helpers/categories";
import { formatPrice } from "../helpers/price";

/**
* Mock data for the items to be displayed in the table.
*/
interface Item extends DummyItem, TableItem {}
export interface Item extends DummyItem, TableItem {}

/**
* Column definitions for the table.
Expand All @@ -59,15 +50,20 @@ const sort = (items: Item[], columnHash: string, direction: string) => {
);
};

/**
* PageList component - Displays a page with a list of items in a table.
*/
const PageFiltersSearch: FunctionComponent = () => {
// NAVIGATION
const location = useLocation();

const navigate = useNavigate();

interface ProductsTableProps {
items: Item[];
itemsLoaded: boolean;
productCats: any;
emptyFilterCriteria: boolean;
}

//const ProductsTable: FunctionComponent = () => {
const ProductsTable: FunctionComponent<ProductsTableProps> = ({
items,
itemsLoaded,
productCats,
emptyFilterCriteria,
}) => {
// TABLE HEADERS
const columns = [
{
Expand Down Expand Up @@ -153,7 +149,6 @@ const PageFiltersSearch: FunctionComponent = () => {

// DATA HANDLING
const [currentItems, setCurrentItems] = useState<Item[]>([]);
const [itemsLoaded, setItemsLoaded] = useState(false);

const setTableItems = (
themItems: any,
Expand Down Expand Up @@ -192,49 +187,10 @@ const PageFiltersSearch: FunctionComponent = () => {
setTableItems(orderedItems);
};

// SEARCH
const [searchValue, setSearchValue] = useState("");
const onSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchValue(event.target.value);
// let's reset the items to the original data if the search value is empty
if (!event.target.value) {
setItems(allItems);
setTableItems(allItems);
}
};
// search submission handler
const onSearchSubmit = () => {
if (searchValue) {
// let's find the items
const foundItems = items.filter((item) =>
item.name.toLowerCase().includes(searchValue.toLowerCase())
);
// set the items
setItems(foundItems);
setTableItems(foundItems);
}
};

// EFFECTS

// fetch categories and product all at once

const [productCats, setProductCats] = useState<Category[]>([]);
const [items, setItems] = useState<Item[]>([]);
const [allItems, setAllItems] = useState<Item[]>([]);
// set the table items when the items change
useEffect(() => {
Promise.all([getCategories(), getProducts()]).then(
([categories, products]) => {
setProductCats(categories as Category[]);
setAllItems(products as Item[]);
setItems(products as Item[]);
setTableItems(products as Item[]);
setItemsLoaded(true);
}
);
}, []);

// PAGE ELEMENTS
setTableItems(items);
}, [items]);

// Empty state
const EmptyState = (
Expand All @@ -252,8 +208,8 @@ const PageFiltersSearch: FunctionComponent = () => {
<Text color="secondary60">
{
// differentiate from empty search or empty products and show a loader element if the data is being fetched
searchValue
? `No products were found for query “${searchValue}`
emptyFilterCriteria
? `No products were found for the criteria`
: "You have no products yet."
}
</Text>
Expand All @@ -263,72 +219,36 @@ const PageFiltersSearch: FunctionComponent = () => {
);

return (
<>
<Page
header={
<Header
description="Filtering data using simple search"
title="Simple search"
backLink={{
text: "Back to patterns",
onClick: () => navigate("/"),
href: "#",
}}
/>
}
>
<Flex flexDirection="column" flexGap={theme.spacing.xLarge}>
<FlexItem>
{
//The most common way of organizing information within the BigDesign patterns is with the use of panels.
//In this case we only have one panel, but you can have multiple panels within a page.
}
<Panel header="Items list">
{
//search
}
<Box marginBottom="medium">
<Search
onChange={onSearchChange}
onSubmit={onSearchSubmit}
value={searchValue}
/>
</Box>
<StyledPanelContents>
{
//The Table component is used to display tabular data.
//It allows you to display a list of items in a table format.
//The table can be customized with different columns and actions.
//The table also allows you to select items and perform actions on them.
//In this case, the table is displaying a list of products.
}
<Table
columns={columns as any}
itemName="Products"
items={currentItems}
keyField="sku"
pagination={{
currentPage,
totalItems: items.length,
onPageChange,
itemsPerPageOptions,
onItemsPerPageChange,
itemsPerPage,
}}
sortable={{
columnHash,
direction,
onSort,
}}
emptyComponent={EmptyState}
/>
</StyledPanelContents>
</Panel>
</FlexItem>
</Flex>
</Page>
</>
<StyledPanelContents>
{
//The Table component is used to display tabular data.
//It allows you to display a list of items in a table format.
//The table can be customized with different columns and actions.
//The table also allows you to select items and perform actions on them.
//In this case, the table is displaying a list of products.
}
<Table
columns={columns as any}
itemName="Products"
items={currentItems}
keyField="sku"
pagination={{
currentPage,
totalItems: items.length,
onPageChange,
itemsPerPageOptions,
onItemsPerPageChange,
itemsPerPage,
}}
sortable={{
columnHash,
direction,
onSort,
}}
emptyComponent={EmptyState}
/>
</StyledPanelContents>
);
};

export default PageFiltersSearch;
export default ProductsTable;
Loading

0 comments on commit 10ca600

Please sign in to comment.