Add customer search

This commit is contained in:
dominik-zeglen 2019-11-25 12:29:07 +01:00
parent ebf386dfb5
commit 42b55e860b
13 changed files with 135 additions and 10 deletions

View file

@ -4,7 +4,14 @@ import hotkeys from "hotkeys-js";
import React from "react";
import { useIntl } from "react-intl";
import { getActions, getViews, hasActions, hasViews } from "./modes/utils";
import {
getActions,
getCustomers,
getViews,
hasActions,
hasCustomers,
hasViews
} from "./modes/utils";
import NavigatorInput from "./NavigatorInput";
import NavigatorSection from "./NavigatorSection";
import { QuickSearchAction } from "./types";
@ -12,6 +19,13 @@ import useQuickSearch from "./useQuickSearch";
const navigatorHotkey = "ctrl+m, command+m";
function getItemOffset(
actions: QuickSearchAction[],
cbs: Array<typeof getViews>
): number {
return cbs.reduce((acc, cb) => cb(actions).length + acc, 0);
}
const Navigator: React.FC = () => {
const [visible, setVisible] = React.useState(false);
const input = React.useRef(null);
@ -78,7 +92,19 @@ const Navigator: React.FC = () => {
getItemProps={getItemProps}
highlightedIndex={highlightedIndex}
items={getActions(actions)}
offset={getViews(actions).length}
offset={getItemOffset(actions, [getViews])}
/>
)}
{hasCustomers(actions) && (
<NavigatorSection
label={intl.formatMessage({
defaultMessage: "Search in Customers",
description: "navigator section header"
})}
getItemProps={getItemProps}
highlightedIndex={highlightedIndex}
items={getCustomers(actions)}
offset={getItemOffset(actions, [getViews, getActions])}
/>
)}
</div>

View file

@ -52,7 +52,7 @@ const NavigatorInput = React.forwardRef<HTMLInputElement, NavigatorInputProps>(
<div className={classes.root}>
{mode !== "default" && (
<span className={classes.adornment}>
{mode === "orders" ? "#" : ">"}
{mode === "orders" ? "#" : mode === "customers" ? "@" : ">"}
</span>
)}
<input

View file

@ -0,0 +1,36 @@
import { IntlShape } from "react-intl";
import { customerUrl } from "@saleor/customers/urls";
import { UseNavigatorResult } from "@saleor/hooks/useNavigator";
import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers";
import { QuickSearchAction } from "../types";
import messages from "./messages";
export function searchInCustomers(
intl: IntlShape,
navigate: UseNavigatorResult,
customers: SearchCustomers_search_edges_node[]
): QuickSearchAction[] {
return customers.map(customer => ({
label:
customer.firstName && customer.lastName
? intl.formatMessage(messages.customerWithName, {
firstName: customer.firstName,
lastName: customer.lastName
})
: customer.email,
onClick: () => navigate(customerUrl(customer.id)),
score: 1,
type: "customer"
}));
}
function getCustomersModeActions(
intl: IntlShape,
navigate: UseNavigatorResult,
customers: SearchCustomers_search_edges_node[]
): QuickSearchAction[] {
return searchInCustomers(intl, navigate, customers);
}
export default getCustomersModeActions;

View file

@ -3,8 +3,10 @@ import { IntlShape } from "react-intl";
import { UseNavigatorResult } from "@saleor/hooks/useNavigator";
import { OrderDraftCreate } from "@saleor/orders/types/OrderDraftCreate";
import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers";
import { QuickSearchAction } from "../../types";
import { searchInCommands } from "../commands";
import { searchInCustomers } from "../customers";
import searchInViews from "./views";
const threshold = 0.05;
@ -14,15 +16,22 @@ function getDefaultModeActions(
query: string,
intl: IntlShape,
navigate: UseNavigatorResult,
customers: SearchCustomers_search_edges_node[],
createOrder: MutationFunction<OrderDraftCreate, {}>
): QuickSearchAction[] {
return [
const actions = [
...searchInViews(query, intl, navigate),
...searchInCommands(query, intl, navigate, createOrder)
]
.filter(action => action.score >= threshold)
.sort((a, b) => (a.score <= b.score ? 1 : -1))
.slice(0, maxActions);
if (query !== "") {
return [...actions, ...searchInCustomers(intl, navigate, customers)];
}
return actions;
}
export default getDefaultModeActions;

View file

@ -5,6 +5,7 @@ import { OrderDraftCreate } from "@saleor/orders/types/OrderDraftCreate";
import { MutationFunction } from "react-apollo";
import { QuickSearchAction, QuickSearchMode } from "../types";
import getCommandModeActions from "./commands";
import getCustomersModeActions from "./customers";
import getDefaultModeActions from "./default";
import getOrdersModeActions from "./orders";
import { ActionQueries } from "./types";
@ -22,10 +23,18 @@ function getModeActions(
switch (mode) {
case "commands":
return getCommandModeActions(query, intl, cbs.navigate, cbs.createOrder);
case "customers":
return getCustomersModeActions(intl, cbs.navigate, queries.customers);
case "orders":
return getOrdersModeActions(query, intl, cbs.navigate, queries.order);
default:
return getDefaultModeActions(query, intl, cbs.navigate, cbs.createOrder);
return getDefaultModeActions(
query,
intl,
cbs.navigate,
queries.customers,
cbs.createOrder
);
}
}

View file

@ -25,6 +25,9 @@ const messages = defineMessages({
defaultMessage: "Create Order",
description: "button"
},
customerWithName: {
defaultMessage: "{firstName} {lastName}"
},
goToOrder: {
defaultMessage: "Go to order #{orderNumber}",
description: "navigator action"

View file

@ -1,5 +1,7 @@
import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers";
import { CheckIfOrderExists_order } from "../queries/types/CheckIfOrderExists";
export interface ActionQueries {
customers: SearchCustomers_search_edges_node[];
order: CheckIfOrderExists_order;
}

View file

@ -13,3 +13,12 @@ export function getViews(actions: QuickSearchAction[]): QuickSearchAction[] {
export function hasViews(actions: QuickSearchAction[]): boolean {
return getViews(actions).length > 0;
}
export function getCustomers(
actions: QuickSearchAction[]
): QuickSearchAction[] {
return actions.filter(action => action.type === "customer");
}
export function hasCustomers(actions: QuickSearchAction[]): boolean {
return getCustomers(actions).length > 0;
}

View file

@ -1,4 +1,4 @@
export type QuickSearchActionType = "action" | "view";
export type QuickSearchActionType = "action" | "customer" | "view";
export interface QuickSearchAction {
label: string;

View file

@ -1,12 +1,14 @@
import { RefObject, useEffect, useState } from "react";
import { useIntl } from "react-intl";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import { ChangeEvent, FormChange } from "@saleor/hooks/useForm";
import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen";
import useNavigator from "@saleor/hooks/useNavigator";
import { maybe } from "@saleor/misc";
import { useOrderDraftCreateMutation } from "@saleor/orders/mutations";
import { orderUrl } from "@saleor/orders/urls";
import useCustomerSearch from "@saleor/searches/useCustomerSearch";
import getModeActions from "./modes";
import { getGqlOrderId, isQueryValidOrderNumber } from "./modes/orders";
import useCheckIfOrderExists from "./queries/useCheckIfOrderExists";
@ -27,6 +29,12 @@ function useQuickSearch(
const intl = useIntl();
const navigate = useNavigator();
const [{ data: orderData }, getOrderData] = useCheckIfOrderExists();
const { result: customers, search: searchCustomers } = useCustomerSearch({
variables: {
...DEFAULT_INITIAL_SEARCH_DATA,
first: 5
}
});
const [createOrder] = useOrderDraftCreateMutation({
onCompleted: result => {
if (result.draftOrderCreate.errors.length === 0) {
@ -72,6 +80,9 @@ function useQuickSearch(
case "> ":
setMode("commands");
break;
case "@ ":
setMode("customers");
break;
case "# ":
setMode("orders");
break;
@ -84,6 +95,10 @@ function useQuickSearch(
}
setQuery(value);
}
if ((["customers", "default"] as QuickSearchMode[]).includes(mode)) {
searchCustomers(value);
}
};
return [
@ -95,6 +110,10 @@ function useQuickSearch(
query,
intl,
{
customers: maybe(
() => customers.data.search.edges.map(edge => edge.node),
[]
),
order: maybe(() => orderData.order)
},
{

View file

@ -15,22 +15,30 @@ export const clients: SearchCustomers_search_edges_node[] = [
{
__typename: "User" as "User",
email: "test.client1@example.com",
id: "c1"
firstName: "John",
id: "c1",
lastName: "Doe"
},
{
__typename: "User" as "User",
email: "test.client2@example.com",
id: "c2"
firstName: "Dough",
id: "c2",
lastName: "Jones"
},
{
__typename: "User" as "User",
email: "test.client3@example.com",
id: "c3"
firstName: "Jonas",
id: "c3",
lastName: "Dough"
},
{
__typename: "User" as "User",
email: "test.client4@example.com",
id: "c4"
firstName: "Bill",
id: "c4",
lastName: "Jonas"
}
];
export const orders: OrderList_orders_edges_node[] = [

View file

@ -10,6 +10,8 @@ export interface SearchCustomers_search_edges_node {
__typename: "User";
id: string;
email: string;
firstName: string;
lastName: string;
}
export interface SearchCustomers_search_edges {

View file

@ -15,6 +15,8 @@ export const searchCustomers = gql`
node {
id
email
firstName
lastName
}
}
pageInfo {