The `CustomerEligibilityCard` component enables users to select customers who are eligible for this discount code. ## Properties |Name|Type|Description|Required| |---|---|---|---| |eligibility|`Field`|Whether the discount applies to all customers, specific customers, or specific customer segments.|Yes| |customerSelector|`React.ReactNode`|A widget that enables users to select customers.|Yes| |selectedCustomers|`Field`|A list of customers that the discount will apply to.|Yes| |customerSegmentSelector|`React.ReactNode`|A widget that enables users to select customer segments.|Yes| |selectedCustomerSegments|`Field`|A list of customer segments that the discount will apply to.|Yes| ## Example Code ```jsx?title:'MyApp.jsx' import React, { useState } from "react"; import { CustomerEligibilityCard, Eligibility, } from "@shopify/discount-app-components"; import CustomerSelector from "./CustomerSelector"; export default function MyApp() { const [selectedCustomerSegments, setSelectedCustomerSegments] = useState([]); const [selectedCustomers, setSelectedCustomers] = useState([]); const [eligibility, setEligibility] = useState(Eligibility.Customers); return ( } customerSegmentSelector={ } /> ); } ``` ### CustomerSelector The following code is an example of the `CustomerSelector` component: ```jsx?title:'CustomerSelector.tsx' import React, { useState } from "react"; import { TextField, Icon, Button } from "@shopify/polaris"; import { SearchMinor } from "@shopify/polaris-icons"; import CustomerPicker from "./CustomerPicker"; export default function CustomerSelector({ selectedCustomers, setSelectedCustomers, }) { const [isOpen, setIsOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); return (
{ setSearchQuery(nextSearchQuery); setIsOpen(true); }} value={searchQuery} autoComplete="off" prefix={} connectedRight={ } /> setIsOpen(false)} onSelect={(customers) => { setIsOpen(false); setSelectedCustomers(customers); }} />
); } ``` ### CustomerPicker To load the app user's customers, an authenticated server needs to proxy the GraphQL request. In the following `CustomerPicker` component, `./authenticatedGraphQL` is used to do so: ```jsx?title:'CustomerPicker.tsx' import React, { useState } from "React"; import { gql } from "graphql-request"; import { useInfiniteQuery } from "react-query"; import { unstable_Picker as Picker } from "@shopify/app-bridge-react"; import { fetchGraphQL } from "./authenticatedGraphQL"; // A request to proxy the GraphQL request // Use GraphQL Admin API to load the customers const CUSTOMER_PICKER_QUERY = gql` query GetCustomers($first: Int!, $searchQuery: String = "", $after: String) { customers( first: $first query: $searchQuery after: $after sortKey: NAME ) { edges { cursor node { id displayName email } } pageInfo { hasNextPage } } } `; const PAGE_SIZE = 20; export default function CustomerPicker({ isOpen, onCancel, onSelect, searchQuery, setSearchQuery, initialSelectedItems, }) { const [selectedItems, setSelectedItems] = useState(); let customers = []; let customerNodes = []; useEffect(() => { setSelectedItems(initialSelectedItems); }, [initialSelectedItems]); // The request to fetch customers specifies the page, search query, and page size const fetchCustomers = async ({ pageParam }) => fetchGraphQL(CUSTOMER_PICKER_QUERY, { first: PAGE_SIZE, searchQuery: searchQuery, after: pageParam, }); // This uses `useInfiniteQuery` from `react-query` to provide infinit loading const { data, error, isLoading: dataIsLoading, fetchNextPage, hasNextPage, isFetchingNextPage, } = useInfiniteQuery("GetCustomers", fetchCustomers, { getNextPageParam: (lastPage, pages) => { const edges = lastPage.data.customers.edges; return edges.length > 0 ? edges[edges.length - 1].cursor : null; }, }); // Format the API response for the picker if (!dataIsLoading && !error) { customerNodes = data.pages.reduce( (nodes, page) => [ ...nodes, ...page.data.customers.edges.map(({ node }) => node), ], [] ); customers = customerNodes.map((node) => ({ id: node.id, name: `${node.email} ${node.displayName}`, })); } return ( { onSelect( selectedItems.map((item) => customerNodes.find((node) => node.id === item.id) ) ); }} onSearch={(options) => { setSearchQuery(options.searchQuery); }} onLoadMore={() => { if (hasNextPage) { fetchNextPage(); } }} emptySearchLabel={{ title: "No Customer", description: "There is no customer for this search", withIllustration: true, }} loading={dataIsLoading || isFetchingNextPage} searchQueryPlaceholder="Search customers" primaryActionLabel="Select" secondaryActionLabel="Cancel" title="Customer Picker" /> ); } ``` ### CustomerSegmentSelector The following code is an example of the `CustomerSegmentSelector` component: ```jsx?title:'CustomerSegmentSelector.jsx' import React, { useState } from "react"; import { TextField, Icon, Button } from "@shopify/polaris"; import { SearchMinor } from "@shopify/polaris-icons"; import CustomerSegmentPicker from "./CustomerSegmentPicker"; function CustomerSegmentSelector({ selectedCustomerSegments, setSelectedCustomerSegments, }) { const [isOpen, setIsOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); return (
{ setSearchQuery(nextSearchQuery); setIsOpen(true); }} value={searchQuery} autoComplete="off" prefix={} connectedRight={
} /> setIsOpen(false)} onSelect={(customerSegments) => { setIsOpen(false); setSelectedCustomerSegments(customerSegments); }} />
); } ``` ### CustomerSegmentPicker The following code is an example of the `CustomerSegmentPicker` component. The `CustomerSegmentSelector` component uses the `CustomerSegmentPicker` component to load the user's segments. ```jsx?title:'CustomerSegmentPicker.jsx' import React, { useState } from "React"; import { gql } from "graphql-request"; import { useQuery } from "react-query"; import { unstable_Picker as Picker } from "@shopify/app-bridge-react"; import { fetchGraphQL } from "./authenticatedGraphQL"; // A request to proxy the GraphQL request const CUSTOMER_SEGMENT_PICKER_QUERY = gql` query GetCustomerSegments($first: Int!, $searchQuery: String) { segments(query: $searchQuery, first: $first) { edges { cursor node { id name } } } } `; function CustomerSegmentsPicker({ isOpen, onCancel, onSelect, searchQuery, setSearchQuery, initialSelectedItems, }) { const [selectedItems, setSelectedItems] = useState(); const graphQLClient = useGraphQLClient(); let customerSegments = []; let customerSegmentNodes = []; useEffect(() => { setSelectedItems(initialSelectedItems); }, [initialSelectedItems]); // The request to fetch customers specifies the page, search query, and page size const fetchCustomerSegments = async ({ pageParam }) => fetchGraphQL(CUSTOMER_SEGMENT_PICKER_QUERY, { first: PAGE_SIZE, searchQuery: searchQuery, }); const { data, error, isLoading: dataIsLoading, } = useQuery(["GetCustomerSegments", searchQuery], fetchCustomerSegments); if (!dataIsLoading && !error) { (customerSegmentNodes = data.data.segments.edges.map(({ node }) => node)), (customerSegments = customerSegmentNodes.map((node) => ({ id: node.id, name: node.name, }))); } return ( { onSelect( selectedItems.map((item) => customerSegmentNodes.find((node) => node.id === item.id) ) ); }} onSearch={(options) => { setSearchQuery(options.searchQuery); }} onLoadMore={() => { if (hasNextPage) { fetchNextPage(); } }} emptySearchLabel={{ title: "No Customer Segment", description: "There is no customer segment for this search", withIllustration: true, }} loading={dataIsLoading} searchQueryPlaceholder="Search customer segment" primaryActionLabel="Select" secondaryActionLabel="Cancel" title="Customer Segment Picker" /> ); } ```