From e6be141e9f78b1ab7f94e072120529ec98a978ae Mon Sep 17 00:00:00 2001 From: Wojciech Mista Date: Mon, 29 Jul 2024 13:15:15 +0200 Subject: [PATCH 1/2] Fix search by order number in Navigator (#5063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use search by order number * fixes * Update src/components/NavigatorSearch/modes/orders.ts Co-authored-by: Paweł Chyła * lint * add test for making search query * improve test --------- Co-authored-by: Paweł Chyła --- .changeset/sixty-guests-doubt.md | 5 +++ .../NavigatorSearchSection.tsx | 2 +- src/components/NavigatorSearch/modes/index.ts | 2 +- .../NavigatorSearch/modes/orders.ts | 43 +++++++++---------- src/components/NavigatorSearch/modes/types.ts | 10 ++--- .../NavigatorSearch/queries/queries.ts | 15 ++++--- .../queries/useCheckIfOrderExists.ts | 17 -------- .../queries/useQuickOrderSearch.test.ts | 31 +++++++++++++ .../queries/useQuickOrderSearch.ts | 28 ++++++++++++ .../NavigatorSearch/useQuickSearch.ts | 12 +++--- src/graphql/hooks.generated.ts | 40 +++++++++-------- src/graphql/types.generated.ts | 7 +-- 12 files changed, 134 insertions(+), 78 deletions(-) create mode 100644 .changeset/sixty-guests-doubt.md delete mode 100644 src/components/NavigatorSearch/queries/useCheckIfOrderExists.ts create mode 100644 src/components/NavigatorSearch/queries/useQuickOrderSearch.test.ts create mode 100644 src/components/NavigatorSearch/queries/useQuickOrderSearch.ts diff --git a/.changeset/sixty-guests-doubt.md b/.changeset/sixty-guests-doubt.md new file mode 100644 index 00000000000..353b3e507fb --- /dev/null +++ b/.changeset/sixty-guests-doubt.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +You can now search by order number in Navigator search. diff --git a/src/components/NavigatorSearch/NavigatorSearchSection.tsx b/src/components/NavigatorSearch/NavigatorSearchSection.tsx index 99c151809a0..43ed8196958 100644 --- a/src/components/NavigatorSearch/NavigatorSearchSection.tsx +++ b/src/components/NavigatorSearch/NavigatorSearchSection.tsx @@ -56,7 +56,7 @@ const NavigatorSearchSection: React.FC = props => { {item.label} {item.caption && ( - + {item.caption} )} diff --git a/src/components/NavigatorSearch/modes/index.ts b/src/components/NavigatorSearch/modes/index.ts index 666e4ad551f..105e377216e 100644 --- a/src/components/NavigatorSearch/modes/index.ts +++ b/src/components/NavigatorSearch/modes/index.ts @@ -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); } diff --git a/src/components/NavigatorSearch/modes/orders.ts b/src/components/NavigatorSearch/modes/orders.ts index c6157b8e654..31e83b8e7d3 100644 --- a/src/components/NavigatorSearch/modes/orders.ts +++ b/src/components/NavigatorSearch/modes/orders.ts @@ -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"; @@ -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; diff --git a/src/components/NavigatorSearch/modes/types.ts b/src/components/NavigatorSearch/modes/types.ts index baec023150e..1e3d757a478 100644 --- a/src/components/NavigatorSearch/modes/types.ts +++ b/src/components/NavigatorSearch/modes/types.ts @@ -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; - order: CheckIfOrderExistsQuery["order"]; + orders: QuickOrderSearchResult; } diff --git a/src/components/NavigatorSearch/queries/queries.ts b/src/components/NavigatorSearch/queries/queries.ts index 0b6694ee02b..b9fb6d1f85a 100644 --- a/src/components/NavigatorSearch/queries/queries.ts +++ b/src/components/NavigatorSearch/queries/queries.ts @@ -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 + } + } } } `; diff --git a/src/components/NavigatorSearch/queries/useCheckIfOrderExists.ts b/src/components/NavigatorSearch/queries/useCheckIfOrderExists.ts deleted file mode 100644 index a90c0cbd568..00000000000 --- a/src/components/NavigatorSearch/queries/useCheckIfOrderExists.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { CheckIfOrderExistsQueryHookResult, useCheckIfOrderExistsQuery } from "@dashboard/graphql"; -import useDebounce from "@dashboard/hooks/useDebounce"; -import { useState } from "react"; - -function useCheckIfOrderExists(): [CheckIfOrderExistsQueryHookResult, (query: string) => void] { - const [id, setId] = useState(""); - const setIdDebounced = useDebounce(setId); - const result = useCheckIfOrderExistsQuery({ - skip: id === "", - variables: { - id, - }, - }); - - return [result, setIdDebounced]; -} -export default useCheckIfOrderExists; diff --git a/src/components/NavigatorSearch/queries/useQuickOrderSearch.test.ts b/src/components/NavigatorSearch/queries/useQuickOrderSearch.test.ts new file mode 100644 index 00000000000..2cdb2df50fd --- /dev/null +++ b/src/components/NavigatorSearch/queries/useQuickOrderSearch.test.ts @@ -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", + }, + }); + }); +}); diff --git a/src/components/NavigatorSearch/queries/useQuickOrderSearch.ts b/src/components/NavigatorSearch/queries/useQuickOrderSearch.ts new file mode 100644 index 00000000000..c806c1b3f69 --- /dev/null +++ b/src/components/NavigatorSearch/queries/useQuickOrderSearch.ts @@ -0,0 +1,28 @@ +import { + SearchOrdersByNumberQuery, + SearchOrdersByNumberQueryHookResult, + useSearchOrdersByNumberQuery, +} from "@dashboard/graphql"; +import useDebounce from "@dashboard/hooks/useDebounce"; +import { useState } from "react"; + +type OrderNode = NonNullable["edges"][0]["node"]; +export type QuickOrderSearchResult = OrderNode[]; + +export function useQuickOrderSearch(): [ + SearchOrdersByNumberQueryHookResult, + (query: string) => void, +] { + const [query, setQuery] = useState(""); + const setQueryDebounced = useDebounce(setQuery); + + const result = useSearchOrdersByNumberQuery({ + skip: query === "", + variables: { + first: 1, + query, + }, + }); + + return [result, setQueryDebounced]; +} diff --git a/src/components/NavigatorSearch/useQuickSearch.ts b/src/components/NavigatorSearch/useQuickSearch.ts index fc207d9deda..a9b58bca452 100644 --- a/src/components/NavigatorSearch/useQuickSearch.ts +++ b/src/components/NavigatorSearch/useQuickSearch.ts @@ -4,7 +4,6 @@ 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"; @@ -12,10 +11,10 @@ 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[]]; @@ -24,7 +23,8 @@ function useQuickSearch(open: boolean, input: RefObject): UseQ const [mode, setMode] = useState("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, @@ -85,7 +85,7 @@ function useQuickSearch(open: boolean, input: RefObject): UseQ } if (mode === "orders" && isQueryValidOrderNumber(value)) { - getOrderData(getGqlOrderId(value)); + getOrderData(value); } if (mode === "catalog") { @@ -110,7 +110,7 @@ function useQuickSearch(open: boolean, input: RefObject): UseQ { catalog, customers: mapEdgesToItems(customers?.data?.search) || [], - order: maybe(() => orderData.order), + orders: mapEdgesToItems(orderData?.orders) || [], }, { createOrder, diff --git a/src/graphql/hooks.generated.ts b/src/graphql/hooks.generated.ts index 470cec05f54..d19fc81fcfc 100644 --- a/src/graphql/hooks.generated.ts +++ b/src/graphql/hooks.generated.ts @@ -6419,42 +6419,48 @@ export function useChannelListLazyQuery(baseOptions?: ApolloReactHooks.LazyQuery export type ChannelListQueryHookResult = ReturnType; export type ChannelListLazyQueryHookResult = ReturnType; export type ChannelListQueryResult = Apollo.QueryResult; -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) { +export function useSearchOrdersByNumberQuery(baseOptions: ApolloReactHooks.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return ApolloReactHooks.useQuery(CheckIfOrderExistsDocument, options); + return ApolloReactHooks.useQuery(SearchOrdersByNumberDocument, options); } -export function useCheckIfOrderExistsLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { +export function useSearchOrdersByNumberLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return ApolloReactHooks.useLazyQuery(CheckIfOrderExistsDocument, options); + return ApolloReactHooks.useLazyQuery(SearchOrdersByNumberDocument, options); } -export type CheckIfOrderExistsQueryHookResult = ReturnType; -export type CheckIfOrderExistsLazyQueryHookResult = ReturnType; -export type CheckIfOrderExistsQueryResult = Apollo.QueryResult; +export type SearchOrdersByNumberQueryHookResult = ReturnType; +export type SearchOrdersByNumberLazyQueryHookResult = ReturnType; +export type SearchOrdersByNumberQueryResult = Apollo.QueryResult; export const SearchCatalogDocument = gql` query SearchCatalog($first: Int!, $query: String!) { categories(first: $first, filter: {search: $query}) { diff --git a/src/graphql/types.generated.ts b/src/graphql/types.generated.ts index 5e2237f147e..3449e1c8b28 100644 --- a/src/graphql/types.generated.ts +++ b/src/graphql/types.generated.ts @@ -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 | 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']; From 0d14016bb6bed84f6d53e13fec357cd4d102228c Mon Sep 17 00:00:00 2001 From: Wojciech Mista Date: Mon, 29 Jul 2024 13:41:20 +0200 Subject: [PATCH 2/2] Fix incorrect grid columns on tablets in page detail views (#5073) * add missing tablet columns * changeset --- .changeset/shy-lizards-arrive.md | 5 +++++ src/components/Layouts/Detail/Root.tsx | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 .changeset/shy-lizards-arrive.md diff --git a/.changeset/shy-lizards-arrive.md b/.changeset/shy-lizards-arrive.md new file mode 100644 index 00000000000..ef355e7bbe1 --- /dev/null +++ b/.changeset/shy-lizards-arrive.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +You can now view channel and product details pages on tablets diff --git a/src/components/Layouts/Detail/Root.tsx b/src/components/Layouts/Detail/Root.tsx index 7588b12bbae..58a04ab2617 100644 --- a/src/components/Layouts/Detail/Root.tsx +++ b/src/components/Layouts/Detail/Root.tsx @@ -20,12 +20,14 @@ export const RootLayout: React.FC = ({ if (gridTemplateColumns instanceof Object) { return { mobile: gridTemplateColumns.mobile ?? 1, + tablet: gridTemplateColumns.tablet, ...gridTemplateColumns, }; } return { mobile: 1, + tablet: gridTemplateColumns, desktop: gridTemplateColumns, }; }, [gridTemplateColumns]);