Skip to content

Commit

Permalink
Fix search by order number in Navigator (#5063)
Browse files Browse the repository at this point in the history
* use search by order number

* fixes

* Update src/components/NavigatorSearch/modes/orders.ts

Co-authored-by: Paweł Chyła <[email protected]>

* lint

* add test for making search query

* improve test

---------

Co-authored-by: Paweł Chyła <[email protected]>
  • Loading branch information
Cloud11PL and poulch authored Jul 29, 2024
1 parent 862e5dc commit e6be141
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 78 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-guests-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

You can now search by order number in Navigator search.
2 changes: 1 addition & 1 deletion src/components/NavigatorSearch/NavigatorSearchSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const NavigatorSearchSection: React.FC<NavigatorSearchSectionProps> = props => {
<Text size={3}>{item.label}</Text>

{item.caption && (
<Text size={2} marginLeft={2}>
<Text size={2} marginLeft={2} color="default2">
{item.caption}
</Text>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/NavigatorSearch/modes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function getModeActions(
case "help":
return getHelpModeActions(query, intl, cbs.setMode);
case "orders":
return getOrdersModeActions(query, intl, cbs.navigate, queries.order);
return getOrdersModeActions(intl, cbs.navigate, queries.orders);
default:
return getDefaultModeActions(query, intl, cbs.navigate, cbs.createOrder, cbs.setMode);
}
Expand Down
43 changes: 21 additions & 22 deletions src/components/NavigatorSearch/modes/orders.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// @ts-strict-ignore
import { CheckIfOrderExistsQuery } from "@dashboard/graphql";
import { UseNavigatorResult } from "@dashboard/hooks/useNavigator";
import { maybe, transformOrderStatus } from "@dashboard/misc";
import { transformOrderStatus } from "@dashboard/misc";
import { orderUrl } from "@dashboard/orders/urls";
import { IntlShape } from "react-intl";

import { QuickOrderSearchResult } from "../queries/useQuickOrderSearch";
import { QuickSearchAction } from "../types";
import messages from "./messages";

Expand All @@ -17,31 +17,30 @@ export function getGqlOrderId(orderNumber: string): string {
}

function getOrdersModeActions(
query: string,
intl: IntlShape,
navigate: UseNavigatorResult,
order: CheckIfOrderExistsQuery["order"],
orders: QuickOrderSearchResult,
): QuickSearchAction[] {
const gqlId = getGqlOrderId(query);

if (isQueryValidOrderNumber(query) && maybe(() => order.id === gqlId)) {
return [
{
extraInfo: transformOrderStatus(order.status, intl).localized,
label: intl.formatMessage(messages.goToOrder, {
orderNumber: query,
}),
onClick: () => {
navigate(orderUrl(gqlId));

return false;
},
type: "action",
},
];
if (!orders) {
return [];
}

return [];
return orders.map(order => {
const orderNumber = order?.number ?? "";

return {
extraInfo: transformOrderStatus(order.status, intl).localized,
label: intl.formatMessage(messages.goToOrder, {
orderNumber,
}),
onClick: () => {
navigate(orderUrl(order.id));

return false;
},
type: "action",
};
});
}

export default getOrdersModeActions;
10 changes: 4 additions & 6 deletions src/components/NavigatorSearch/modes/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
// @ts-strict-ignore
import {
CheckIfOrderExistsQuery,
SearchCatalogQuery,
SearchCustomersQuery,
} from "@dashboard/graphql";
import { SearchCatalogQuery, SearchCustomersQuery } from "@dashboard/graphql";
import { RelayToFlat } from "@dashboard/types";

import { QuickOrderSearchResult } from "../queries/useQuickOrderSearch";

export interface ActionQueries {
catalog: SearchCatalogQuery;
customers: RelayToFlat<SearchCustomersQuery["search"]>;
order: CheckIfOrderExistsQuery["order"];
orders: QuickOrderSearchResult;
}
15 changes: 10 additions & 5 deletions src/components/NavigatorSearch/queries/queries.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { gql } from "@apollo/client";

export const checkIfOrderExists = gql`
query CheckIfOrderExists($id: ID!) {
order(id: $id) {
id
status
export const searchOrdersByNumber = gql`
query SearchOrdersByNumber($first: Int!, $query: [String!]) {
orders(first: $first, filter: { numbers: $query }) {
edges {
node {
id
number
status
}
}
}
}
`;
Expand Down
17 changes: 0 additions & 17 deletions src/components/NavigatorSearch/queries/useCheckIfOrderExists.ts

This file was deleted.

31 changes: 31 additions & 0 deletions src/components/NavigatorSearch/queries/useQuickOrderSearch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { act, renderHook } from "@testing-library/react-hooks";

import { useQuickOrderSearch } from "./useQuickOrderSearch";

const useSearchOrdersByNumberQuery = jest.fn();

jest.mock("@dashboard/graphql", () => ({
SearchOrdersByNumberQuery: {},
useSearchOrdersByNumberQuery: (props: any) => useSearchOrdersByNumberQuery(props),
}));
jest.mock("@dashboard/hooks/useDebounce", () => (fn: any) => fn);

describe("useQuickOrderSearch", () => {
it("invokes search query", () => {
// Arrange
const { result } = renderHook(() => useQuickOrderSearch());
const [, setQueryDebounced] = result.current;

// Act
act(() => setQueryDebounced("1234"));

// Assert
expect(useSearchOrdersByNumberQuery).toHaveBeenCalledWith({
skip: false,
variables: {
first: 1,
query: "1234",
},
});
});
});
28 changes: 28 additions & 0 deletions src/components/NavigatorSearch/queries/useQuickOrderSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
SearchOrdersByNumberQuery,
SearchOrdersByNumberQueryHookResult,
useSearchOrdersByNumberQuery,
} from "@dashboard/graphql";
import useDebounce from "@dashboard/hooks/useDebounce";
import { useState } from "react";

type OrderNode = NonNullable<SearchOrdersByNumberQuery["orders"]>["edges"][0]["node"];
export type QuickOrderSearchResult = OrderNode[];

export function useQuickOrderSearch(): [
SearchOrdersByNumberQueryHookResult,
(query: string) => void,
] {
const [query, setQuery] = useState<string>("");
const setQueryDebounced = useDebounce(setQuery);

const result = useSearchOrdersByNumberQuery({
skip: query === "",
variables: {
first: 1,
query,
},
});

return [result, setQueryDebounced];
}
12 changes: 6 additions & 6 deletions src/components/NavigatorSearch/useQuickSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ import { useOrderDraftCreateMutation } from "@dashboard/graphql";
import { ChangeEvent, FormChange } from "@dashboard/hooks/useForm";
import useModalDialogOpen from "@dashboard/hooks/useModalDialogOpen";
import useNavigator from "@dashboard/hooks/useNavigator";
import { maybe } from "@dashboard/misc";
import { orderUrl } from "@dashboard/orders/urls";
import useCustomerSearch from "@dashboard/searches/useCustomerSearch";
import { mapEdgesToItems } from "@dashboard/utils/maps";
import { RefObject, useEffect, useState } from "react";
import { useIntl } from "react-intl";

import getModeActions from "./modes";
import { getGqlOrderId, isQueryValidOrderNumber } from "./modes/orders";
import { isQueryValidOrderNumber } from "./modes/orders";
import { getMode } from "./modes/utils";
import useSearchCatalog from "./queries/useCatalogSearch";
import useCheckIfOrderExists from "./queries/useCheckIfOrderExists";
import { useQuickOrderSearch } from "./queries/useQuickOrderSearch";
import { QuickSearchAction, QuickSearchMode } from "./types";

type UseQuickSearch = [string, QuickSearchMode, FormChange, QuickSearchAction[]];
Expand All @@ -24,7 +23,8 @@ function useQuickSearch(open: boolean, input: RefObject<HTMLInputElement>): UseQ
const [mode, setMode] = useState<QuickSearchMode>("default");
const intl = useIntl();
const navigate = useNavigator();
const [{ data: orderData }, getOrderData] = useCheckIfOrderExists();
const [{ data: orderData }, getOrderData] = useQuickOrderSearch();

const { result: customers, search: searchCustomers } = useCustomerSearch({
variables: {
...DEFAULT_INITIAL_SEARCH_DATA,
Expand Down Expand Up @@ -85,7 +85,7 @@ function useQuickSearch(open: boolean, input: RefObject<HTMLInputElement>): UseQ
}

if (mode === "orders" && isQueryValidOrderNumber(value)) {
getOrderData(getGqlOrderId(value));
getOrderData(value);
}

if (mode === "catalog") {
Expand All @@ -110,7 +110,7 @@ function useQuickSearch(open: boolean, input: RefObject<HTMLInputElement>): UseQ
{
catalog,
customers: mapEdgesToItems(customers?.data?.search) || [],
order: maybe(() => orderData.order),
orders: mapEdgesToItems(orderData?.orders) || [],
},
{
createOrder,
Expand Down
40 changes: 23 additions & 17 deletions src/graphql/hooks.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6419,42 +6419,48 @@ export function useChannelListLazyQuery(baseOptions?: ApolloReactHooks.LazyQuery
export type ChannelListQueryHookResult = ReturnType<typeof useChannelListQuery>;
export type ChannelListLazyQueryHookResult = ReturnType<typeof useChannelListLazyQuery>;
export type ChannelListQueryResult = Apollo.QueryResult<Types.ChannelListQuery, Types.ChannelListQueryVariables>;
export const CheckIfOrderExistsDocument = gql`
query CheckIfOrderExists($id: ID!) {
order(id: $id) {
id
status
export const SearchOrdersByNumberDocument = gql`
query SearchOrdersByNumber($first: Int!, $query: [String!]) {
orders(first: $first, filter: {numbers: $query}) {
edges {
node {
id
number
status
}
}
}
}
`;

/**
* __useCheckIfOrderExistsQuery__
* __useSearchOrdersByNumberQuery__
*
* To run a query within a React component, call `useCheckIfOrderExistsQuery` and pass it any options that fit your needs.
* When your component renders, `useCheckIfOrderExistsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* To run a query within a React component, call `useSearchOrdersByNumberQuery` and pass it any options that fit your needs.
* When your component renders, `useSearchOrdersByNumberQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useCheckIfOrderExistsQuery({
* const { data, loading, error } = useSearchOrdersByNumberQuery({
* variables: {
* id: // value for 'id'
* first: // value for 'first'
* query: // value for 'query'
* },
* });
*/
export function useCheckIfOrderExistsQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.CheckIfOrderExistsQuery, Types.CheckIfOrderExistsQueryVariables>) {
export function useSearchOrdersByNumberQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.SearchOrdersByNumberQuery, Types.SearchOrdersByNumberQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useQuery<Types.CheckIfOrderExistsQuery, Types.CheckIfOrderExistsQueryVariables>(CheckIfOrderExistsDocument, options);
return ApolloReactHooks.useQuery<Types.SearchOrdersByNumberQuery, Types.SearchOrdersByNumberQueryVariables>(SearchOrdersByNumberDocument, options);
}
export function useCheckIfOrderExistsLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.CheckIfOrderExistsQuery, Types.CheckIfOrderExistsQueryVariables>) {
export function useSearchOrdersByNumberLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.SearchOrdersByNumberQuery, Types.SearchOrdersByNumberQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useLazyQuery<Types.CheckIfOrderExistsQuery, Types.CheckIfOrderExistsQueryVariables>(CheckIfOrderExistsDocument, options);
return ApolloReactHooks.useLazyQuery<Types.SearchOrdersByNumberQuery, Types.SearchOrdersByNumberQueryVariables>(SearchOrdersByNumberDocument, options);
}
export type CheckIfOrderExistsQueryHookResult = ReturnType<typeof useCheckIfOrderExistsQuery>;
export type CheckIfOrderExistsLazyQueryHookResult = ReturnType<typeof useCheckIfOrderExistsLazyQuery>;
export type CheckIfOrderExistsQueryResult = Apollo.QueryResult<Types.CheckIfOrderExistsQuery, Types.CheckIfOrderExistsQueryVariables>;
export type SearchOrdersByNumberQueryHookResult = ReturnType<typeof useSearchOrdersByNumberQuery>;
export type SearchOrdersByNumberLazyQueryHookResult = ReturnType<typeof useSearchOrdersByNumberLazyQuery>;
export type SearchOrdersByNumberQueryResult = Apollo.QueryResult<Types.SearchOrdersByNumberQuery, Types.SearchOrdersByNumberQueryVariables>;
export const SearchCatalogDocument = gql`
query SearchCatalog($first: Int!, $query: String!) {
categories(first: $first, filter: {search: $query}) {
Expand Down
7 changes: 4 additions & 3 deletions src/graphql/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9462,12 +9462,13 @@ export type ChannelListQueryVariables = Exact<{ [key: string]: never; }>;

export type ChannelListQuery = { __typename: 'Query', channels: Array<{ __typename: 'Channel', id: string, name: string }> | null };

export type CheckIfOrderExistsQueryVariables = Exact<{
id: Scalars['ID'];
export type SearchOrdersByNumberQueryVariables = Exact<{
first: Scalars['Int'];
query?: InputMaybe<Array<Scalars['String']> | Scalars['String']>;
}>;


export type CheckIfOrderExistsQuery = { __typename: 'Query', order: { __typename: 'Order', id: string, status: OrderStatus } | null };
export type SearchOrdersByNumberQuery = { __typename: 'Query', orders: { __typename: 'OrderCountableConnection', edges: Array<{ __typename: 'OrderCountableEdge', node: { __typename: 'Order', id: string, number: string, status: OrderStatus } }> } | null };

export type SearchCatalogQueryVariables = Exact<{
first: Scalars['Int'];
Expand Down

0 comments on commit e6be141

Please sign in to comment.