From 135658eb11c691d47fdf7f3b5e193731ad289bd1 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 20 Nov 2019 11:24:42 +0100 Subject: [PATCH] Use exclusively search hooks --- src/config.ts | 4 +- src/containers/BaseSearch.tsx | 77 --------- src/containers/TopLevelSearch.tsx | 47 ------ src/orders/queries.ts | 4 +- src/orders/views/OrderDetails/index.tsx | 87 +++++----- .../AssignAttributeDialog.tsx | 2 +- .../useAvailableAttributeSearch}/index.tsx | 39 +++-- .../types/SearchAttributes.ts | 0 .../views/ProductTypeUpdate/index.tsx | 159 ++++++------------ 9 files changed, 127 insertions(+), 292 deletions(-) delete mode 100644 src/containers/BaseSearch.tsx delete mode 100644 src/containers/TopLevelSearch.tsx rename src/productTypes/{containers/SearchAttributes => hooks/useAvailableAttributeSearch}/index.tsx (52%) rename src/productTypes/{containers/SearchAttributes => hooks/useAvailableAttributeSearch}/types/SearchAttributes.ts (100%) diff --git a/src/config.ts b/src/config.ts index d6daba2f6..8c6b8febe 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,10 +1,10 @@ -import { SearchQueryVariables } from "./containers/BaseSearch"; +import { SearchVariables } from "./hooks/makeSearch"; import { ListSettings, ListViews } from "./types"; export const APP_MOUNT_URI = process.env.APP_MOUNT_URI || "/"; export const API_URI = process.env.API_URI || "/graphql/"; -export const DEFAULT_INITIAL_SEARCH_DATA: SearchQueryVariables = { +export const DEFAULT_INITIAL_SEARCH_DATA: SearchVariables = { after: null, first: 20, query: "" diff --git a/src/containers/BaseSearch.tsx b/src/containers/BaseSearch.tsx deleted file mode 100644 index 4562db65b..000000000 --- a/src/containers/BaseSearch.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { DocumentNode } from "graphql"; -import React from "react"; - -import Debounce from "../components/Debounce"; -import { TypedQuery, TypedQueryResult } from "../queries"; - -export interface SearchQueryVariables { - after?: string; - first: number; - query: string; -} - -interface BaseSearchProps< - TQuery, - TQueryVariables extends SearchQueryVariables -> { - children: (props: { - loadMore: () => void; - search: (query: string) => void; - result: TypedQueryResult; - }) => React.ReactElement; - variables: TQueryVariables; -} - -function BaseSearch( - query: DocumentNode, - loadMoreFn: (result: TypedQueryResult) => void -) { - const Query = TypedQuery(query); - - class BaseSearchComponent extends React.Component< - BaseSearchProps, - SearchQueryVariables - > { - state: SearchQueryVariables = { - first: this.props.variables.first, - query: this.props.variables.query - }; - - search = (query: string) => { - if (query === undefined) { - this.setState({ query: "" }); - } else { - this.setState({ query }); - } - }; - - render() { - const { children, variables } = this.props; - - return ( - - {search => ( - - {result => - children({ - loadMore: () => loadMoreFn(result), - result, - search - }) - } - - )} - - ); - } - } - return BaseSearchComponent; -} - -export default BaseSearch; diff --git a/src/containers/TopLevelSearch.tsx b/src/containers/TopLevelSearch.tsx deleted file mode 100644 index 85a90a301..000000000 --- a/src/containers/TopLevelSearch.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { DocumentNode } from "graphql"; - -import { PageInfoFragment } from "@saleor/types/PageInfoFragment"; -import BaseSearch, { SearchQueryVariables } from "./BaseSearch"; - -export interface SearchQuery { - search: { - edges: Array<{ - node: any; - }>; - pageInfo: PageInfoFragment; - }; -} - -function TopLevelSearch< - TQuery extends SearchQuery, - TQueryVariables extends SearchQueryVariables ->(query: DocumentNode) { - return BaseSearch(query, result => { - if (result.data.search.pageInfo.hasNextPage) { - result.loadMore( - (prev, next) => { - if ( - prev.search.pageInfo.endCursor === next.search.pageInfo.endCursor - ) { - return prev; - } - - return { - ...prev, - search: { - ...prev.search, - edges: [...prev.search.edges, ...next.search.edges], - pageInfo: next.search.pageInfo - } - }; - }, - { - ...result.variables, - after: result.data.search.pageInfo.endCursor - } - ); - } - }); -} - -export default TopLevelSearch; diff --git a/src/orders/queries.ts b/src/orders/queries.ts index 47a6add2f..a18c65894 100644 --- a/src/orders/queries.ts +++ b/src/orders/queries.ts @@ -1,6 +1,6 @@ import gql from "graphql-tag"; -import TopLevelSearch from "../containers/TopLevelSearch"; +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import { TypedQuery } from "../queries"; import { OrderDetails, OrderDetailsVariables } from "./types/OrderDetails"; import { @@ -314,7 +314,7 @@ export const searchOrderVariant = gql` } } `; -export const SearchOrderVariant = TopLevelSearch< +export const useOrderVariantSearch = makeTopLevelSearch< SearchOrderVariantType, SearchOrderVariantVariables >(searchOrderVariant); diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index ed9afac47..327eb2131 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -26,7 +26,7 @@ import OrderPaymentVoidDialog from "../../components/OrderPaymentVoidDialog"; import OrderProductAddDialog from "../../components/OrderProductAddDialog"; import OrderShippingMethodEditDialog from "../../components/OrderShippingMethodEditDialog"; import OrderOperations from "../../containers/OrderOperations"; -import { SearchOrderVariant, TypedOrderDetailsQuery } from "../../queries"; +import { TypedOrderDetailsQuery, useOrderVariantSearch } from "../../queries"; import { OrderDetails_order } from "../../types/OrderDetails"; import { orderListUrl, @@ -81,6 +81,13 @@ export const OrderDetails: React.FC = ({ id, params }) => { } = useCustomerSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + loadMore, + search: variantSearch, + result: variantSearchOpts + } = useOrderVariantSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); return ( = ({ id, params }) => { }) } /> - - {({ - loadMore, - search: variantSearch, - result: variantSearchOpts - }) => ( - - orderLinesAdd.opts.data - .draftOrderLinesCreate.errors - ) - )} - loading={variantSearchOpts.loading} - open={params.action === "add-order-line"} - hasMore={maybe( - () => - variantSearchOpts.data.search.pageInfo - .hasNextPage - )} - products={maybe(() => - variantSearchOpts.data.search.edges.map( - edge => edge.node - ) - )} - onClose={closeModal} - onFetch={variantSearch} - onFetchMore={loadMore} - onSubmit={variants => - orderLinesAdd.mutate({ - id, - input: variants.map(variant => ({ - quantity: 1, - variantId: variant.id - })) - }) - } - /> + + orderLinesAdd.opts.data.draftOrderLinesCreate + .errors + ) )} - + loading={variantSearchOpts.loading} + open={params.action === "add-order-line"} + hasMore={maybe( + () => + variantSearchOpts.data.search.pageInfo + .hasNextPage + )} + products={maybe(() => + variantSearchOpts.data.search.edges.map( + edge => edge.node + ) + )} + onClose={closeModal} + onFetch={variantSearch} + onFetchMore={loadMore} + onSubmit={variants => + orderLinesAdd.mutate({ + id, + input: variants.map(variant => ({ + quantity: 1, + variantId: variant.id + })) + }) + } + /> )} ({ actions: { diff --git a/src/productTypes/containers/SearchAttributes/index.tsx b/src/productTypes/hooks/useAvailableAttributeSearch/index.tsx similarity index 52% rename from src/productTypes/containers/SearchAttributes/index.tsx rename to src/productTypes/hooks/useAvailableAttributeSearch/index.tsx index 8f00cbf5b..6a3d7037d 100644 --- a/src/productTypes/containers/SearchAttributes/index.tsx +++ b/src/productTypes/hooks/useAvailableAttributeSearch/index.tsx @@ -1,7 +1,7 @@ import gql from "graphql-tag"; +import makeSearch from "@saleor/hooks/makeSearch"; import { pageInfoFragment } from "@saleor/queries"; -import BaseSearch from "../../../containers/BaseSearch"; import { SearchAttributes, SearchAttributesVariables @@ -37,24 +37,33 @@ export const searchAttributes = gql` } `; -export default BaseSearch( +export default makeSearch( searchAttributes, result => result.loadMore( - (prev, next) => ({ - ...prev, - productType: { - ...prev.productType, - availableAttributes: { - ...prev.productType.availableAttributes, - edges: [ - ...prev.productType.availableAttributes.edges, - ...next.productType.availableAttributes.edges - ], - pageInfo: next.productType.availableAttributes.pageInfo - } + (prev, next) => { + if ( + prev.productType.availableAttributes.pageInfo.endCursor === + next.productType.availableAttributes.pageInfo.endCursor + ) { + return prev; } - }), + + return { + ...prev, + productType: { + ...prev.productType, + availableAttributes: { + ...prev.productType.availableAttributes, + edges: [ + ...prev.productType.availableAttributes.edges, + ...next.productType.availableAttributes.edges + ], + pageInfo: next.productType.availableAttributes.pageInfo + } + } + }; + }, { after: result.data.productType.availableAttributes.pageInfo.endCursor } diff --git a/src/productTypes/containers/SearchAttributes/types/SearchAttributes.ts b/src/productTypes/hooks/useAvailableAttributeSearch/types/SearchAttributes.ts similarity index 100% rename from src/productTypes/containers/SearchAttributes/types/SearchAttributes.ts rename to src/productTypes/hooks/useAvailableAttributeSearch/types/SearchAttributes.ts diff --git a/src/productTypes/views/ProductTypeUpdate/index.tsx b/src/productTypes/views/ProductTypeUpdate/index.tsx index 73510adbd..5e01da310 100644 --- a/src/productTypes/views/ProductTypeUpdate/index.tsx +++ b/src/productTypes/views/ProductTypeUpdate/index.tsx @@ -4,6 +4,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import { attributeUrl } from "@saleor/attributes/urls"; import { WindowTitle } from "@saleor/components/WindowTitle"; +import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import useBulkActions from "@saleor/hooks/useBulkActions"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; @@ -19,7 +20,7 @@ import ProductTypeDetailsPage, { ProductTypeForm } from "../../components/ProductTypeDetailsPage"; import ProductTypeOperations from "../../containers/ProductTypeOperations"; -import SearchAttributes from "../../containers/SearchAttributes"; +import useAvailableAttributeSearch from "../../hooks/useAvailableAttributeSearch"; import { TypedProductTypeDetailsQuery } from "../../queries"; import { AssignAttribute } from "../../types/AssignAttribute"; import { ProductTypeDelete } from "../../types/ProductTypeDelete"; @@ -46,6 +47,12 @@ export const ProductTypeUpdate: React.FC = ({ const productAttributeListActions = useBulkActions(); const variantAttributeListActions = useBulkActions(); const intl = useIntl(); + const { loadMore, search, result } = useAvailableAttributeSearch({ + variables: { + ...DEFAULT_INITIAL_SEARCH_DATA, + id + } + }); return ( @@ -330,109 +337,55 @@ export const ProductTypeUpdate: React.FC = ({ ) }} /> - {!dataLoading && ( - - {({ search, result }) => { - const fetchMore = () => - result.loadMore( - (prev, next) => { - if ( - prev.productType.availableAttributes - .pageInfo.endCursor === - next.productType.availableAttributes - .pageInfo.endCursor - ) { - return prev; - } - return { - ...prev, - productType: { - ...prev.productType, - availableAttributes: { - ...prev.productType.availableAttributes, - edges: [ - ...prev.productType - .availableAttributes.edges, - ...next.productType - .availableAttributes.edges - ], - pageInfo: - next.productType.availableAttributes - .pageInfo - } - } - }; - }, - { - after: - result.data.productType.availableAttributes - .pageInfo.endCursor - } - ); - - return ( - <> - {Object.keys(AttributeTypeEnum).map(key => ( - - result.data.productType.availableAttributes.edges.map( - edge => edge.node + {!dataLoading && + Object.keys(AttributeTypeEnum).map(key => ( + + result.data.productType.availableAttributes.edges.map( + edge => edge.node + ) + )} + confirmButtonState={assignTransactionState} + errors={maybe( + () => + assignAttribute.opts.data.attributeAssign.errors.map( + err => err.message + ), + [] + )} + loading={result.loading} + onClose={closeModal} + onSubmit={handleAssignAttribute} + onFetch={search} + onFetchMore={loadMore} + onOpen={result.refetch} + hasMore={maybe( + () => + result.data.productType.availableAttributes + .pageInfo.hasNextPage, + false + )} + open={ + params.action === "assign-attribute" && + params.type === AttributeTypeEnum[key] + } + selected={maybe(() => params.ids, [])} + onToggle={attributeId => { + const ids = maybe(() => params.ids, []); + navigate( + productTypeUrl(id, { + ...params, + ids: ids.includes(attributeId) + ? params.ids.filter( + selectedId => selectedId !== attributeId ) - )} - confirmButtonState={assignTransactionState} - errors={maybe( - () => - assignAttribute.opts.data.attributeAssign.errors.map( - err => err.message - ), - [] - )} - loading={result.loading} - onClose={closeModal} - onSubmit={handleAssignAttribute} - onFetch={search} - onFetchMore={fetchMore} - onOpen={result.refetch} - hasMore={maybe( - () => - result.data.productType - .availableAttributes.pageInfo - .hasNextPage, - false - )} - open={ - params.action === "assign-attribute" && - params.type === AttributeTypeEnum[key] - } - selected={maybe(() => params.ids, [])} - onToggle={attributeId => { - const ids = maybe(() => params.ids, []); - navigate( - productTypeUrl(id, { - ...params, - ids: ids.includes(attributeId) - ? params.ids.filter( - selectedId => - selectedId !== attributeId - ) - : [...ids, attributeId] - }) - ); - }} - key={key} - /> - ))} - - ); - }} - - )} + : [...ids, attributeId] + }) + ); + }} + key={key} + /> + ))} data.productType.name, "...")}