From 6f2bff218fb0e070adf5e9f5523ccafadecaad09 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 12:31:32 +0100 Subject: [PATCH 01/13] wip --- src/hooks/makeQuery.ts | 6 +++--- src/hooks/makeSearch.ts | 18 ++++++++++++++++++ src/hooks/useDebounce.ts | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/hooks/makeSearch.ts create mode 100644 src/hooks/useDebounce.ts diff --git a/src/hooks/makeQuery.ts b/src/hooks/makeQuery.ts index a16909766..1d0e3013d 100644 --- a/src/hooks/makeQuery.ts +++ b/src/hooks/makeQuery.ts @@ -16,7 +16,7 @@ export interface LoadMore { ) => Promise>; } -type UseQuery = QueryResult & +export type UseQueryResult = QueryResult & LoadMore; type UseQueryOpts = Partial<{ displayLoader: boolean; @@ -26,7 +26,7 @@ type UseQueryOpts = Partial<{ }>; type UseQueryHook = ( opts: UseQueryOpts -) => UseQuery; +) => UseQueryResult; function makeQuery( query: DocumentNode @@ -36,7 +36,7 @@ function makeQuery( require, skip, variables - }: UseQueryOpts): UseQuery { + }: UseQueryOpts): UseQueryResult { const notify = useNotifier(); const intl = useIntl(); const [, dispatchAppState] = useAppState(); diff --git a/src/hooks/makeSearch.ts b/src/hooks/makeSearch.ts new file mode 100644 index 000000000..c4b4dc42c --- /dev/null +++ b/src/hooks/makeSearch.ts @@ -0,0 +1,18 @@ +import { DocumentNode } from "graphql"; +import { useState } from "react"; + +import Debounce from "../components/Debounce"; +import { UseQueryResult } from "./makeQuery"; + +export interface SearchQueryVariables { + after?: string; + first: number; + query: string; +} + +function makeSearch( + query: DocumentNode, + loadMoreFn: (result: UseQueryResult) => void +): UseSearchHook { + const [searchQuery, setSearchQuery] = useState(""); +} diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts new file mode 100644 index 000000000..69be1e40e --- /dev/null +++ b/src/hooks/useDebounce.ts @@ -0,0 +1,19 @@ +import { useEffect, useRef } from "react"; + +export type UseDebounceFn = (...args: T[]) => void; +function useDebounce( + debounceFn: UseDebounceFn, + time = 200 +): UseDebounceFn { + const timer = useRef(null); + useEffect(() => () => clearTimeout(timer.current)); + + return (...args: T[]) => { + if (timer.current) { + clearTimeout(timer.current); + } + timer.current = setTimeout(() => debounceFn(...args), time); + }; +} + +export default useDebounce; From 4daec82206b5d71f559b629f2f13c6a14cc759c6 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 16:01:54 +0100 Subject: [PATCH 02/13] Add search hooks --- src/hooks/makeQuery.ts | 2 +- src/hooks/makeSearch.ts | 49 +++++++++++++++++++++++++++++---- src/hooks/makeTopLevelSearch.ts | 45 ++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 src/hooks/makeTopLevelSearch.ts diff --git a/src/hooks/makeQuery.ts b/src/hooks/makeQuery.ts index 1d0e3013d..6aa28b7a5 100644 --- a/src/hooks/makeQuery.ts +++ b/src/hooks/makeQuery.ts @@ -31,7 +31,7 @@ type UseQueryHook = ( function makeQuery( query: DocumentNode ): UseQueryHook { - function useQuery({ + function useQuery({ displayLoader, require, skip, diff --git a/src/hooks/makeSearch.ts b/src/hooks/makeSearch.ts index c4b4dc42c..240274503 100644 --- a/src/hooks/makeSearch.ts +++ b/src/hooks/makeSearch.ts @@ -1,18 +1,57 @@ import { DocumentNode } from "graphql"; import { useState } from "react"; +import { QueryResult } from "react-apollo"; -import Debounce from "../components/Debounce"; -import { UseQueryResult } from "./makeQuery"; +import makeQuery, { UseQueryResult } from "./makeQuery"; +import useDebounce from "./useDebounce"; -export interface SearchQueryVariables { +export interface SearchVariables { after?: string; first: number; query: string; } -function makeSearch( +export interface UseSearchResult { + loadMore: () => void; + result: QueryResult; + search: (query: string) => void; +} +export type UseSearchOpts = Partial<{ + skip: boolean; + variables: TVariables; +}>; +export type UseSearchHook = ( + opts: UseSearchOpts +) => UseSearchResult; + +function makeSearch( query: DocumentNode, loadMoreFn: (result: UseQueryResult) => void ): UseSearchHook { - const [searchQuery, setSearchQuery] = useState(""); + const useSearchQuery = makeQuery(query); + + function useSearch( + opts: UseSearchOpts + ): UseSearchResult { + const [searchQuery, setSearchQuery] = useState(""); + const debouncedSearch = useDebounce(setSearchQuery); + const result = useSearchQuery({ + ...opts, + displayLoader: true, + variables: { + ...opts.variables, + query: searchQuery + } + }); + + return { + loadMore: () => loadMoreFn(result), + result, + search: debouncedSearch + }; + } + + return useSearch; } + +export default makeSearch; diff --git a/src/hooks/makeTopLevelSearch.ts b/src/hooks/makeTopLevelSearch.ts new file mode 100644 index 000000000..1a039546a --- /dev/null +++ b/src/hooks/makeTopLevelSearch.ts @@ -0,0 +1,45 @@ +import { DocumentNode } from "graphql"; + +import { PageInfoFragment } from "@saleor/types/PageInfoFragment"; +import makeSearch, { SearchVariables, UseSearchHook } from "./makeSearch"; + +export interface SearchData { + search: { + edges: Array<{ + node: any; + }>; + pageInfo: PageInfoFragment; + }; +} + +function makeTopLevelSearch< + TData extends SearchData, + TVariables extends SearchVariables +>(query: DocumentNode): UseSearchHook { + return makeSearch(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 + } + ); + } + }); +} From 0a7f65727af6b9b42341463d84910d039c5e6053 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 16:23:17 +0100 Subject: [PATCH 03/13] Use service account search hook --- src/hooks/makeTopLevelSearch.ts | 2 + .../types/SearchServiceAccount.ts | 0 .../useServiceAccountSearch.ts} | 4 +- .../WebhookCreatePage/WebhookCreatePage.tsx | 6 +- .../WebhooksDetailsPage.tsx | 10 +- src/webhooks/views/WebhooksCreate.tsx | 110 +++++------ src/webhooks/views/WebhooksDetails.tsx | 177 +++++++++--------- 7 files changed, 155 insertions(+), 154 deletions(-) rename src/{containers/SearchServiceAccount => searches}/types/SearchServiceAccount.ts (100%) rename src/{containers/SearchServiceAccount/index.tsx => searches/useServiceAccountSearch.ts} (86%) diff --git a/src/hooks/makeTopLevelSearch.ts b/src/hooks/makeTopLevelSearch.ts index 1a039546a..1b163be8d 100644 --- a/src/hooks/makeTopLevelSearch.ts +++ b/src/hooks/makeTopLevelSearch.ts @@ -43,3 +43,5 @@ function makeTopLevelSearch< } }); } + +export default makeTopLevelSearch; diff --git a/src/containers/SearchServiceAccount/types/SearchServiceAccount.ts b/src/searches/types/SearchServiceAccount.ts similarity index 100% rename from src/containers/SearchServiceAccount/types/SearchServiceAccount.ts rename to src/searches/types/SearchServiceAccount.ts diff --git a/src/containers/SearchServiceAccount/index.tsx b/src/searches/useServiceAccountSearch.ts similarity index 86% rename from src/containers/SearchServiceAccount/index.tsx rename to src/searches/useServiceAccountSearch.ts index dd8cfa60f..3b3ed11d8 100644 --- a/src/containers/SearchServiceAccount/index.tsx +++ b/src/searches/useServiceAccountSearch.ts @@ -1,7 +1,7 @@ import gql from "graphql-tag"; +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import { pageInfoFragment } from "@saleor/queries"; -import TopLevelSearch from "../TopLevelSearch"; import { SearchServiceAccount, SearchServiceAccountVariables @@ -28,7 +28,7 @@ export const searchServiceAccount = gql` } `; -export default TopLevelSearch< +export default makeTopLevelSearch< SearchServiceAccount, SearchServiceAccountVariables >(searchServiceAccount); diff --git a/src/webhooks/components/WebhookCreatePage/WebhookCreatePage.tsx b/src/webhooks/components/WebhookCreatePage/WebhookCreatePage.tsx index 4aaddff03..1cc8adc58 100644 --- a/src/webhooks/components/WebhookCreatePage/WebhookCreatePage.tsx +++ b/src/webhooks/components/WebhookCreatePage/WebhookCreatePage.tsx @@ -6,9 +6,9 @@ import FormSpacer from "@saleor/components/FormSpacer"; import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; -import { SearchServiceAccount_search_edges_node } from "@saleor/containers/SearchServiceAccount/types/SearchServiceAccount"; import { sectionNames } from "@saleor/intl"; import { maybe } from "@saleor/misc"; +import { SearchServiceAccount_search_edges_node } from "@saleor/searches/types/SearchServiceAccount"; import { WebhookEventTypeEnum } from "@saleor/types/globalTypes"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import WebhookEvents from "@saleor/webhooks/components/WebhookEvents"; @@ -19,7 +19,6 @@ import React from "react"; import { useIntl } from "react-intl"; export interface FormData { - id: string; events: WebhookEventTypeEnum[]; isActive: boolean; name: string; @@ -52,9 +51,8 @@ const WebhookCreatePage: React.FC = ({ const initialForm: FormData = { allEvents: false, events: [], - id: null, isActive: false, - name: null, + name: "", secretKey: "", serviceAccount: "", targetUrl: "" diff --git a/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx b/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx index ba88c0932..3b72e7f86 100644 --- a/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx +++ b/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx @@ -1,3 +1,6 @@ +import React from "react"; +import { useIntl } from "react-intl"; + import AppHeader from "@saleor/components/AppHeader"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Container from "@saleor/components/Container"; @@ -6,10 +9,10 @@ import FormSpacer from "@saleor/components/FormSpacer"; import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; -import { SearchServiceAccount_search_edges_node } from "@saleor/containers/SearchServiceAccount/types/SearchServiceAccount"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { sectionNames } from "@saleor/intl"; import { maybe } from "@saleor/misc"; +import { SearchServiceAccount_search_edges_node } from "@saleor/searches/types/SearchServiceAccount"; import { WebhookEventTypeEnum } from "@saleor/types/globalTypes"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import WebhookEvents from "@saleor/webhooks/components/WebhookEvents"; @@ -18,11 +21,7 @@ import WebhookStatus from "@saleor/webhooks/components/WebhookStatus"; import { WebhookCreate_webhookCreate_webhookErrors } from "@saleor/webhooks/types/WebhookCreate"; import { WebhookDetails_webhook } from "@saleor/webhooks/types/WebhookDetails"; -import React from "react"; -import { useIntl } from "react-intl"; - export interface FormData { - id: string; events: WebhookEventTypeEnum[]; isActive: boolean; name: string; @@ -63,7 +62,6 @@ const WebhooksDetailsPage: React.FC = ({ events: maybe(() => webhook.events, []) .map(event => event.eventType) .filter(event => event !== WebhookEventTypeEnum.ANY_EVENTS), - id: maybe(() => webhook.id, null), isActive: maybe(() => webhook.isActive, false), name: maybe(() => webhook.name, ""), secretKey: maybe(() => webhook.secretKey, ""), diff --git a/src/webhooks/views/WebhooksCreate.tsx b/src/webhooks/views/WebhooksCreate.tsx index cd2ad303d..c822598e0 100644 --- a/src/webhooks/views/WebhooksCreate.tsx +++ b/src/webhooks/views/WebhooksCreate.tsx @@ -1,8 +1,8 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; -import SearchServiceAccount from "@saleor/containers/SearchServiceAccount"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; +import useServiceAccountSearch from "@saleor/searches/useServiceAccountSearch"; import { WebhookEventTypeEnum } from "@saleor/types/globalTypes"; import { WebhookCreate as WebhookCreateData } from "@saleor/webhooks/types/WebhookCreate"; import React from "react"; @@ -26,6 +26,12 @@ export const WebhooksCreate: React.FC = () => { const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); + const { + search: searchServiceAccount, + result: searchServiceAccountOpt + } = useServiceAccountSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const onSubmit = (data: WebhookCreateData) => { if (data.webhookCreate.webhookErrors.length === 0) { @@ -39,62 +45,56 @@ export const WebhooksCreate: React.FC = () => { const handleBack = () => navigate(webhooksListUrl()); return ( - - {({ search: searchServiceAccount, result: searchServiceAccountOpt }) => ( - - {(webhookCreate, webhookCreateOpts) => { - const handleSubmit = (data: FormData) => - webhookCreate({ - variables: { - input: { - events: data.allEvents - ? [WebhookEventTypeEnum.ANY_EVENTS] - : data.events, - isActive: data.isActive, - name: data.name, - secretKey: data.secretKey, - serviceAccount: data.serviceAccount, - targetUrl: data.targetUrl - } - } - }); + + {(webhookCreate, webhookCreateOpts) => { + const handleSubmit = (data: FormData) => + webhookCreate({ + variables: { + input: { + events: data.allEvents + ? [WebhookEventTypeEnum.ANY_EVENTS] + : data.events, + isActive: data.isActive, + name: data.name, + secretKey: data.secretKey, + serviceAccount: data.serviceAccount, + targetUrl: data.targetUrl + } + } + }); - const formTransitionState = getMutationState( - webhookCreateOpts.called, - webhookCreateOpts.loading, - maybe(() => webhookCreateOpts.data.webhookCreate.webhookErrors) - ); + const formTransitionState = getMutationState( + webhookCreateOpts.called, + webhookCreateOpts.loading, + maybe(() => webhookCreateOpts.data.webhookCreate.webhookErrors) + ); - return ( - <> - - webhookCreateOpts.data.webhookCreate.webhookErrors, - [] - )} - fetchServiceAccounts={searchServiceAccount} - services={maybe(() => - searchServiceAccountOpt.data.search.edges.map( - edge => edge.node - ) - )} - onBack={handleBack} - onSubmit={handleSubmit} - saveButtonBarState={formTransitionState} - /> - - ); - }} - - )} - + return ( + <> + + webhookCreateOpts.data.webhookCreate.webhookErrors, + [] + )} + fetchServiceAccounts={searchServiceAccount} + services={maybe(() => + searchServiceAccountOpt.data.search.edges.map(edge => edge.node) + )} + onBack={handleBack} + onSubmit={handleSubmit} + saveButtonBarState={formTransitionState} + /> + + ); + }} + ); }; WebhooksCreate.displayName = "WebhooksCreate"; diff --git a/src/webhooks/views/WebhooksDetails.tsx b/src/webhooks/views/WebhooksDetails.tsx index 68b231851..f3dfb3de5 100644 --- a/src/webhooks/views/WebhooksDetails.tsx +++ b/src/webhooks/views/WebhooksDetails.tsx @@ -1,14 +1,15 @@ +import React from "react"; +import { useIntl } from "react-intl"; + import { WindowTitle } from "@saleor/components/WindowTitle"; -import SearchServiceAccount from "@saleor/containers/SearchServiceAccount"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; +import useServiceAccountSearch from "@saleor/searches/useServiceAccountSearch"; import { WebhookEventTypeEnum } from "@saleor/types/globalTypes"; import WebhookDeleteDialog from "@saleor/webhooks/components/WebhookDeleteDialog"; import { WebhookDelete } from "@saleor/webhooks/types/WebhookDelete"; import { WebhookUpdate } from "@saleor/webhooks/types/WebhookUpdate"; -import React from "react"; -import { useIntl } from "react-intl"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../config"; import { getMutationState, maybe } from "../../misc"; import WebhooksDetailsPage from "../components/WebhooksDetailsPage"; @@ -33,6 +34,12 @@ export const WebhooksDetails: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); + const { + search: searchServiceAccount, + result: searchServiceAccountOpt + } = useServiceAccountSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const closeModal = () => navigate( @@ -72,96 +79,92 @@ export const WebhooksDetails: React.FC = ({ }; return ( - - {({ search: searchServiceAccount, result: searchServiceAccountOpt }) => ( - - {(webhookUpdate, webhookUpdateOpts) => ( - - {(webhookDelete, webhookDeleteOpts) => ( - - {webhookDetails => { - const formTransitionState = getMutationState( - webhookUpdateOpts.called, - webhookUpdateOpts.loading, - maybe( - () => webhookUpdateOpts.data.webhookUpdate.webhookErrors - ) - ); + + {(webhookUpdate, webhookUpdateOpts) => ( + + {(webhookDelete, webhookDeleteOpts) => ( + + {webhookDetails => { + const formTransitionState = getMutationState( + webhookUpdateOpts.called, + webhookUpdateOpts.loading, + maybe( + () => webhookUpdateOpts.data.webhookUpdate.webhookErrors + ) + ); - const handleRemoveConfirm = () => - webhookDelete({ - variables: { - id - } - }); + const handleRemoveConfirm = () => + webhookDelete({ + variables: { + id + } + }); - const formErrors = maybe( - () => webhookUpdateOpts.data.webhookUpdate.webhookErrors, - [] - ); + const formErrors = maybe( + () => webhookUpdateOpts.data.webhookUpdate.webhookErrors, + [] + ); - const deleteTransitionState = getMutationState( - webhookDeleteOpts.called, - webhookDeleteOpts.loading, - maybe(() => webhookDeleteOpts.data.webhookDelete.errors) - ); + const deleteTransitionState = getMutationState( + webhookDeleteOpts.called, + webhookDeleteOpts.loading, + maybe(() => webhookDeleteOpts.data.webhookDelete.errors) + ); - return ( - <> - webhookDetails.data.webhook.name)} - /> - webhookDetails.data.webhook)} - fetchServiceAccounts={searchServiceAccount} - services={maybe(() => - searchServiceAccountOpt.data.search.edges.map( - edge => edge.node - ) - )} - onBack={() => navigate(webhooksListUrl())} - onDelete={() => openModal("remove")} - onSubmit={data => { - webhookUpdate({ - variables: { - id, - input: { - events: data.allEvents - ? [WebhookEventTypeEnum.ANY_EVENTS] - : data.events, - isActive: data.isActive, - name: data.name, - secretKey: data.secretKey, - serviceAccount: data.serviceAccount, - targetUrl: data.targetUrl - } - } - }); - }} - /> - webhookDetails.data.webhook.name, - "..." - )} - onClose={closeModal} - onConfirm={handleRemoveConfirm} - open={params.action === "remove"} - /> - - ); - }} - - )} - + return ( + <> + webhookDetails.data.webhook.name)} + /> + webhookDetails.data.webhook)} + fetchServiceAccounts={searchServiceAccount} + services={maybe(() => + searchServiceAccountOpt.data.search.edges.map( + edge => edge.node + ) + )} + onBack={() => navigate(webhooksListUrl())} + onDelete={() => openModal("remove")} + onSubmit={data => { + webhookUpdate({ + variables: { + id, + input: { + events: data.allEvents + ? [WebhookEventTypeEnum.ANY_EVENTS] + : data.events, + isActive: data.isActive, + name: data.name, + secretKey: data.secretKey, + serviceAccount: data.serviceAccount, + targetUrl: data.targetUrl + } + } + }); + }} + /> + webhookDetails.data.webhook.name, + "..." + )} + onClose={closeModal} + onConfirm={handleRemoveConfirm} + open={params.action === "remove"} + /> + + ); + }} + )} - + )} - + ); }; WebhooksDetails.displayName = "WebhooksDetails"; From e67727af037c22693cd2774584922022b05176cd Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 16:47:12 +0100 Subject: [PATCH 04/13] Use category search hook --- .../AssignCategoryDialog.tsx | 2 +- src/discounts/views/SaleDetails.tsx | 70 +- src/discounts/views/VoucherDetails.tsx | 70 +- .../MenuItemDialog/MenuItemDialog.tsx | 2 +- src/navigation/views/MenuDetails/index.tsx | 575 ++++++++------- .../ProductCreatePage/ProductCreatePage.tsx | 2 +- .../ProductUpdatePage/ProductUpdatePage.tsx | 2 +- src/products/views/ProductCreate.tsx | 317 +++++---- .../views/ProductUpdate/ProductUpdate.tsx | 662 +++++++++--------- .../types/SearchCategories.ts | 0 .../useCategorySearch.ts} | 4 +- 11 files changed, 835 insertions(+), 871 deletions(-) rename src/{containers/SearchCategories => searches}/types/SearchCategories.ts (100%) rename src/{containers/SearchCategories/index.tsx => searches/useCategorySearch.ts} (78%) diff --git a/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx b/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx index cecd2b136..169c0ead7 100644 --- a/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx +++ b/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx @@ -19,7 +19,7 @@ import FormSpacer from "@saleor/components/FormSpacer"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; import { buttonMessages } from "@saleor/intl"; -import { SearchCategories_search_edges_node } from "../../containers/SearchCategories/types/SearchCategories"; +import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; import Checkbox from "../Checkbox"; export interface FormData { diff --git a/src/discounts/views/SaleDetails.tsx b/src/discounts/views/SaleDetails.tsx index 987c2557d..272dadc3c 100644 --- a/src/discounts/views/SaleDetails.tsx +++ b/src/discounts/views/SaleDetails.tsx @@ -16,10 +16,10 @@ import usePaginator, { } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; import { commonMessages, sectionNames } from "@saleor/intl"; +import useCategorySearch from "@saleor/searches/useCategorySearch"; import { categoryUrl } from "../../categories/urls"; import { collectionUrl } from "../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; -import SearchCategories from "../../containers/SearchCategories"; import SearchCollections from "../../containers/SearchCollections"; import SearchProducts from "../../containers/SearchProducts"; import { decimal, getMutationState, joinDateTime, maybe } from "../../misc"; @@ -66,6 +66,12 @@ export const SaleDetails: React.FC = ({ id, params }) => { params.ids ); const intl = useIntl(); + const { + search: searchCategories, + result: searchCategoriesOpts + } = useCategorySearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: SaleDetailsPageTab) => { @@ -377,43 +383,33 @@ export const SaleDetails: React.FC = ({ id, params }) => { /> )} - - {({ - search: searchCategories, - result: searchCategoriesOpts - }) => ( - - searchCategoriesOpts.data.search.edges - .map(edge => edge.node) - .filter( - suggestedCategory => - suggestedCategory.id - ) - )} - confirmButtonState={assignTransitionState} - open={params.action === "assign-category"} - onFetch={searchCategories} - loading={searchCategoriesOpts.loading} - onClose={closeModal} - onSubmit={categories => - saleCataloguesAdd({ - variables: { - ...paginationState, - id, - input: { - categories: categories.map( - product => product.id - ) - } - } - }) - } - /> + + searchCategoriesOpts.data.search.edges + .map(edge => edge.node) + .filter( + suggestedCategory => suggestedCategory.id + ) )} - + confirmButtonState={assignTransitionState} + open={params.action === "assign-category"} + onFetch={searchCategories} + loading={searchCategoriesOpts.loading} + onClose={closeModal} + onSubmit={categories => + saleCataloguesAdd({ + variables: { + ...paginationState, + id, + input: { + categories: categories.map( + product => product.id + ) + } + } + }) + } + /> diff --git a/src/discounts/views/VoucherDetails.tsx b/src/discounts/views/VoucherDetails.tsx index 2ade5b3f9..9a6cb144a 100644 --- a/src/discounts/views/VoucherDetails.tsx +++ b/src/discounts/views/VoucherDetails.tsx @@ -16,10 +16,10 @@ import usePaginator, { } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; import { commonMessages, sectionNames } from "@saleor/intl"; +import useCategorySearch from "@saleor/searches/useCategorySearch"; import { categoryUrl } from "../../categories/urls"; import { collectionUrl } from "../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; -import SearchCategories from "../../containers/SearchCategories"; import SearchCollections from "../../containers/SearchCollections"; import SearchProducts from "../../containers/SearchProducts"; import { decimal, getMutationState, joinDateTime, maybe } from "../../misc"; @@ -68,6 +68,12 @@ export const VoucherDetails: React.FC = ({ params.ids ); const intl = useIntl(); + const { + search: searchCategories, + result: searchCategoriesOpts + } = useCategorySearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: VoucherDetailsPageTab) => { @@ -420,43 +426,33 @@ export const VoucherDetails: React.FC = ({ toggle={toggle} toggleAll={toggleAll} /> - - {({ - search: searchCategories, - result: searchCategoriesOpts - }) => ( - - searchCategoriesOpts.data.search.edges - .map(edge => edge.node) - .filter( - suggestedCategory => - suggestedCategory.id - ) - )} - confirmButtonState={assignTransitionState} - open={params.action === "assign-category"} - onFetch={searchCategories} - loading={searchCategoriesOpts.loading} - onClose={closeModal} - onSubmit={categories => - voucherCataloguesAdd({ - variables: { - ...paginationState, - id, - input: { - categories: categories.map( - product => product.id - ) - } - } - }) - } - /> + + searchCategoriesOpts.data.search.edges + .map(edge => edge.node) + .filter( + suggestedCategory => suggestedCategory.id + ) )} - + confirmButtonState={assignTransitionState} + open={params.action === "assign-category"} + onFetch={searchCategories} + loading={searchCategoriesOpts.loading} + onClose={closeModal} + onSubmit={categories => + voucherCataloguesAdd({ + variables: { + ...paginationState, + id, + input: { + categories: categories.map( + product => product.id + ) + } + } + }) + } + /> diff --git a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx index 30f2c9945..6dac3b907 100644 --- a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx +++ b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx @@ -14,13 +14,13 @@ import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import FormSpacer from "@saleor/components/FormSpacer"; -import { SearchCategories_search_edges_node } from "@saleor/containers/SearchCategories/types/SearchCategories"; import { SearchCollections_search_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import { SearchPages_search_edges_node } from "@saleor/containers/SearchPages/types/SearchPages"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { buttonMessages, sectionNames } from "@saleor/intl"; +import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; import { UserError } from "@saleor/types"; import { getErrors, getFieldError } from "@saleor/utils/errors"; import { getMenuItemByValue, IMenu } from "@saleor/utils/menu"; diff --git a/src/navigation/views/MenuDetails/index.tsx b/src/navigation/views/MenuDetails/index.tsx index eb4f5b801..60e53e06d 100644 --- a/src/navigation/views/MenuDetails/index.tsx +++ b/src/navigation/views/MenuDetails/index.tsx @@ -5,10 +5,10 @@ import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; +import useCategorySearch from "@saleor/searches/useCategorySearch"; import { categoryUrl } from "../../../categories/urls"; import { collectionUrl } from "../../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; -import SearchCategories from "../../../containers/SearchCategories"; import SearchCollections from "../../../containers/SearchCollections"; import SearchPages from "../../../containers/SearchPages"; import { getMutationState, maybe } from "../../../misc"; @@ -59,6 +59,9 @@ const MenuDetails: React.FC = ({ id, params }) => { const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); + const categorySearch = useCategorySearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const closeModal = () => navigate( @@ -97,324 +100,304 @@ const MenuDetails: React.FC = ({ id, params }) => { return ( {pageSearch => ( - - {categorySearch => ( - - {collectionSearch => ( - - {({ data, loading, refetch }) => { - const handleQueryChange = (query: string) => { - categorySearch.search(query); - collectionSearch.search(query); - pageSearch.search(query); - }; + + {collectionSearch => ( + + {({ data, loading, refetch }) => { + const handleQueryChange = (query: string) => { + categorySearch.search(query); + collectionSearch.search(query); + pageSearch.search(query); + }; - const categories = maybe( - () => - categorySearch.result.data.search.edges.map( - edge => edge.node - ), - [] - ); + const categories = maybe( + () => + categorySearch.result.data.search.edges.map( + edge => edge.node + ), + [] + ); - const collections = maybe( - () => - collectionSearch.result.data.search.edges.map( - edge => edge.node - ), - [] - ); + const collections = maybe( + () => + collectionSearch.result.data.search.edges.map( + edge => edge.node + ), + [] + ); - const pages = maybe( - () => - pageSearch.result.data.search.edges.map( - edge => edge.node - ), - [] - ); + const pages = maybe( + () => + pageSearch.result.data.search.edges.map(edge => edge.node), + [] + ); - return ( - + handleDelete(data, navigate, notify, intl) + } + > + {(menuDelete, menuDeleteOpts) => ( + - handleDelete(data, navigate, notify, intl) + handleUpdate(data, notify, refetch, intl) } > - {(menuDelete, menuDeleteOpts) => ( - - handleUpdate(data, notify, refetch, intl) - } - > - {(menuUpdate, menuUpdateOpts) => { - const deleteState = getMutationState( - menuDeleteOpts.called, - menuDeleteOpts.loading, - maybe( - () => menuDeleteOpts.data.menuDelete.errors - ) - ); + {(menuUpdate, menuUpdateOpts) => { + const deleteState = getMutationState( + menuDeleteOpts.called, + menuDeleteOpts.loading, + maybe(() => menuDeleteOpts.data.menuDelete.errors) + ); - const updateState = getMutationState( - menuUpdateOpts.called, - menuUpdateOpts.loading, - maybe( - () => menuUpdateOpts.data.menuUpdate.errors - ), - maybe( - () => menuUpdateOpts.data.menuItemMove.errors - ) - ); + const updateState = getMutationState( + menuUpdateOpts.called, + menuUpdateOpts.loading, + maybe(() => menuUpdateOpts.data.menuUpdate.errors), + maybe(() => menuUpdateOpts.data.menuItemMove.errors) + ); - // This is a workaround to let know - // that it should clean operation stack if mutations - // were successful - const handleSubmit = async ( - data: MenuDetailsSubmitData - ) => { - try { - const result = await menuUpdate({ - variables: { - id, - moves: getMoves(data), - name: data.name, - removeIds: getRemoveIds(data) - } - }); - if (result) { - if ( - result.data.menuItemBulkDelete.errors - .length > 0 || - result.data.menuItemMove.errors.length > - 0 || - result.data.menuUpdate.errors.length > 0 - ) { - return false; - } - } - return true; - } catch { + // This is a workaround to let know + // that it should clean operation stack if mutations + // were successful + const handleSubmit = async ( + data: MenuDetailsSubmitData + ) => { + try { + const result = await menuUpdate({ + variables: { + id, + moves: getMoves(data), + name: data.name, + removeIds: getRemoveIds(data) + } + }); + if (result) { + if ( + result.data.menuItemBulkDelete.errors.length > + 0 || + result.data.menuItemMove.errors.length > 0 || + result.data.menuUpdate.errors.length > 0 + ) { return false; } - }; + } + return true; + } catch { + return false; + } + }; - return ( - <> - data.menu)} - onBack={() => navigate(menuListUrl())} - onDelete={() => - navigate( - menuUrl(id, { - action: "remove" - }) + return ( + <> + data.menu)} + onBack={() => navigate(menuListUrl())} + onDelete={() => + navigate( + menuUrl(id, { + action: "remove" + }) + ) + } + onItemAdd={() => + navigate( + menuUrl(id, { + action: "add-item" + }) + ) + } + onItemClick={handleItemClick} + onItemEdit={itemId => + navigate( + menuUrl(id, { + action: "edit-item", + id: itemId + }) + ) + } + onSubmit={handleSubmit} + saveButtonState={updateState} + /> + + menuDelete({ variables: { id } }) + } + variant="delete" + title={intl.formatMessage({ + defaultMessage: "Delete Menu", + description: "dialog header", + id: "menuDetailsDeleteMenuHeader" + })} + > + + + {maybe(() => data.menu.name, "...")} + ) - } - onItemAdd={() => - navigate( - menuUrl(id, { - action: "add-item" - }) - ) - } - onItemClick={handleItemClick} - onItemEdit={itemId => - navigate( - menuUrl(id, { - action: "edit-item", - id: itemId - }) - ) - } - onSubmit={handleSubmit} - saveButtonState={updateState} + }} /> - - menuDelete({ variables: { id } }) - } - variant="delete" - title={intl.formatMessage({ - defaultMessage: "Delete Menu", - description: "dialog header", - id: "menuDetailsDeleteMenuHeader" - })} - > - - - {maybe( - () => data.menu.name, - "..." - )} - - ) - }} - /> - - + + - - handleItemCreate( - data, - notify, - closeModal, - intl - ) - } - > - {(menuItemCreate, menuItemCreateOpts) => { - const handleSubmit = ( - data: MenuItemDialogFormData - ) => { - const variables: MenuItemCreateVariables = { - input: getMenuItemCreateInputData( - id, - data - ) - }; - - menuItemCreate({ variables }); - }; - - const formTransitionState = getMutationState( - menuItemCreateOpts.called, - menuItemCreateOpts.loading, - maybe( - () => - menuItemCreateOpts.data - .menuItemCreate.errors - ) - ); - - return ( - - menuItemCreateOpts.data - .menuItemCreate.errors, - [] - )} - pages={pages} - loading={ - categorySearch.result.loading || - collectionSearch.result.loading - } - confirmButtonState={ - formTransitionState - } - disabled={menuItemCreateOpts.loading} - onClose={closeModal} - onSubmit={handleSubmit} - onQueryChange={handleQueryChange} - /> - ); - }} - - - handleItemUpdate( - data, + + handleItemCreate( + data, + notify, + closeModal, + intl + ) + } + > + {(menuItemCreate, menuItemCreateOpts) => { + const handleSubmit = ( + data: MenuItemDialogFormData + ) => { + const variables: MenuItemCreateVariables = { + input: getMenuItemCreateInputData( id, - navigate, - notify, - intl + data ) - } - > - {(menuItemUpdate, menuItemUpdateOpts) => { - const handleSubmit = ( - data: MenuItemDialogFormData - ) => { - const variables: MenuItemUpdateVariables = { - id: params.id, - input: getMenuItemInputData(data) - }; + }; - menuItemUpdate({ variables }); - }; + menuItemCreate({ variables }); + }; - const menuItem = maybe(() => - getNode( - data.menu.items, - findNode(data.menu.items, params.id) - ) - ); + const formTransitionState = getMutationState( + menuItemCreateOpts.called, + menuItemCreateOpts.loading, + maybe( + () => + menuItemCreateOpts.data.menuItemCreate + .errors + ) + ); - const formTransitionState = getMutationState( - menuItemUpdateOpts.called, - menuItemUpdateOpts.loading, - maybe( - () => - menuItemUpdateOpts.data - .menuItemUpdate.errors - ) - ); + return ( + + menuItemCreateOpts.data.menuItemCreate + .errors, + [] + )} + pages={pages} + loading={ + categorySearch.result.loading || + collectionSearch.result.loading + } + confirmButtonState={formTransitionState} + disabled={menuItemCreateOpts.loading} + onClose={closeModal} + onSubmit={handleSubmit} + onQueryChange={handleQueryChange} + /> + ); + }} + + + handleItemUpdate( + data, + id, + navigate, + notify, + intl + ) + } + > + {(menuItemUpdate, menuItemUpdateOpts) => { + const handleSubmit = ( + data: MenuItemDialogFormData + ) => { + const variables: MenuItemUpdateVariables = { + id: params.id, + input: getMenuItemInputData(data) + }; - const initialFormData: MenuItemDialogFormData = { - id: maybe(() => getItemId(menuItem)), - name: maybe(() => menuItem.name, "..."), - type: maybe( - () => getItemType(menuItem), - "category" - ) - }; + menuItemUpdate({ variables }); + }; - return ( - - menuItemUpdateOpts.data - .menuItemUpdate.errors, - [] - )} - pages={pages} - initial={initialFormData} - initialDisplayValue={getInitialDisplayValue( - menuItem - )} - loading={ - categorySearch.result.loading || - collectionSearch.result.loading - } - confirmButtonState={ - formTransitionState - } - disabled={menuItemUpdateOpts.loading} - onClose={closeModal} - onSubmit={handleSubmit} - onQueryChange={handleQueryChange} - /> - ); - }} - - - ); - }} - - )} - - ); - }} - - )} - + const menuItem = maybe(() => + getNode( + data.menu.items, + findNode(data.menu.items, params.id) + ) + ); + + const formTransitionState = getMutationState( + menuItemUpdateOpts.called, + menuItemUpdateOpts.loading, + maybe( + () => + menuItemUpdateOpts.data.menuItemUpdate + .errors + ) + ); + + const initialFormData: MenuItemDialogFormData = { + id: maybe(() => getItemId(menuItem)), + name: maybe(() => menuItem.name, "..."), + type: maybe( + () => getItemType(menuItem), + "category" + ) + }; + + return ( + + menuItemUpdateOpts.data.menuItemUpdate + .errors, + [] + )} + pages={pages} + initial={initialFormData} + initialDisplayValue={getInitialDisplayValue( + menuItem + )} + loading={ + categorySearch.result.loading || + collectionSearch.result.loading + } + confirmButtonState={formTransitionState} + disabled={menuItemUpdateOpts.loading} + onClose={closeModal} + onSubmit={handleSubmit} + onQueryChange={handleQueryChange} + /> + ); + }} + + + ); + }} + + )} + + ); + }} + )} - + )} ); diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index 15bb0ca8b..5d74fb815 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -13,7 +13,6 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import { SearchCategories_search_edges_node } from "@saleor/containers/SearchCategories/types/SearchCategories"; import { SearchCollections_search_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/containers/SearchProductTypes/types/SearchProductTypes"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; @@ -25,6 +24,7 @@ import { ProductAttributeValueChoices, ProductType } from "@saleor/products/utils/data"; +import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { FetchMoreProps, UserError } from "../../../types"; diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index 0859c6d4a..57dd2ee01 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -12,13 +12,13 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import { SearchCategories_search_edges_node } from "@saleor/containers/SearchCategories/types/SearchCategories"; import { SearchCollections_search_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useFormset from "@saleor/hooks/useFormset"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { sectionNames } from "@saleor/intl"; import { maybe } from "@saleor/misc"; +import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; import { FetchMoreProps, ListActions, UserError } from "@saleor/types"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index fded16046..8c20a480c 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -6,8 +6,8 @@ import SearchProductTypes from "@saleor/containers/SearchProductTypes"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; +import useCategorySearch from "@saleor/searches/useCategorySearch"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../config"; -import SearchCategories from "../../containers/SearchCategories"; import SearchCollections from "../../containers/SearchCollections"; import { decimal, getMutationState, maybe } from "../../misc"; import ProductCreatePage, { @@ -26,174 +26,171 @@ export const ProductUpdate: React.FC = () => { const notify = useNotifier(); const shop = useShop(); const intl = useIntl(); + const { + loadMore: loadMoreCategories, + search: searchCategory, + result: searchCategoryOpts + } = useCategorySearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const handleBack = () => navigate(productListUrl()); return ( - + {({ - loadMore: loadMoreCategories, - search: searchCategory, - result: searchCategoryOpts + loadMore: loadMoreCollections, + search: searchCollection, + result: searchCollectionOpts }) => ( - + {({ - loadMore: loadMoreCollections, - search: searchCollection, - result: searchCollectionOpts - }) => ( - - {({ - loadMore: loadMoreProductTypes, - search: searchProductTypes, - result: searchProductTypesOpts - }) => { - const handleSuccess = (data: ProductCreate) => { - if (data.productCreate.errors.length === 0) { - notify({ - text: intl.formatMessage({ - defaultMessage: "Product created" - }) - }); - navigate(productUrl(data.productCreate.product.id)); - } else { - const attributeError = data.productCreate.errors.find( - err => err.field === "attributes" - ); - if (!!attributeError) { - notify({ text: attributeError.message }); - } - } - }; - - return ( - - {( - productCreate, - { - called: productCreateCalled, - data: productCreateData, - loading: productCreateDataLoading - } - ) => { - const handleSubmit = ( - formData: ProductCreatePageSubmitData - ) => { - productCreate({ - variables: { - attributes: formData.attributes.map(attribute => ({ - id: attribute.id, - values: attribute.value - })), - basePrice: decimal(formData.basePrice), - category: formData.category, - chargeTaxes: formData.chargeTaxes, - collections: formData.collections, - descriptionJson: JSON.stringify( - formData.description - ), - isPublished: formData.isPublished, - name: formData.name, - productType: formData.productType, - publicationDate: - formData.publicationDate !== "" - ? formData.publicationDate - : null, - seo: { - description: formData.seoDescription, - title: formData.seoTitle - }, - sku: formData.sku, - stockQuantity: - formData.stockQuantity !== null - ? formData.stockQuantity - : 0 - } - }); - }; - - const formTransitionState = getMutationState( - productCreateCalled, - productCreateDataLoading, - maybe(() => productCreateData.productCreate.errors) - ); - return ( - <> - - shop.defaultCurrency)} - categories={maybe( - () => searchCategoryOpts.data.search.edges, - [] - ).map(edge => edge.node)} - collections={maybe( - () => searchCollectionOpts.data.search.edges, - [] - ).map(edge => edge.node)} - disabled={productCreateDataLoading} - errors={maybe( - () => productCreateData.productCreate.errors, - [] - )} - fetchCategories={searchCategory} - fetchCollections={searchCollection} - fetchProductTypes={searchProductTypes} - header={intl.formatMessage({ - defaultMessage: "New Product", - description: "page header" - })} - productTypes={maybe(() => - searchProductTypesOpts.data.search.edges.map( - edge => edge.node - ) - )} - onBack={handleBack} - onSubmit={handleSubmit} - saveButtonBarState={formTransitionState} - fetchMoreCategories={{ - hasMore: maybe( - () => - searchCategoryOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCategoryOpts.loading, - onFetchMore: loadMoreCategories - }} - fetchMoreCollections={{ - hasMore: maybe( - () => - searchCollectionOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCollectionOpts.loading, - onFetchMore: loadMoreCollections - }} - fetchMoreProductTypes={{ - hasMore: maybe( - () => - searchProductTypesOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchProductTypesOpts.loading, - onFetchMore: loadMoreProductTypes - }} - /> - - ); - }} - + loadMore: loadMoreProductTypes, + search: searchProductTypes, + result: searchProductTypesOpts + }) => { + const handleSuccess = (data: ProductCreate) => { + if (data.productCreate.errors.length === 0) { + notify({ + text: intl.formatMessage({ + defaultMessage: "Product created" + }) + }); + navigate(productUrl(data.productCreate.product.id)); + } else { + const attributeError = data.productCreate.errors.find( + err => err.field === "attributes" ); - }} - - )} - + if (!!attributeError) { + notify({ text: attributeError.message }); + } + } + }; + + return ( + + {( + productCreate, + { + called: productCreateCalled, + data: productCreateData, + loading: productCreateDataLoading + } + ) => { + const handleSubmit = ( + formData: ProductCreatePageSubmitData + ) => { + productCreate({ + variables: { + attributes: formData.attributes.map(attribute => ({ + id: attribute.id, + values: attribute.value + })), + basePrice: decimal(formData.basePrice), + category: formData.category, + chargeTaxes: formData.chargeTaxes, + collections: formData.collections, + descriptionJson: JSON.stringify(formData.description), + isPublished: formData.isPublished, + name: formData.name, + productType: formData.productType, + publicationDate: + formData.publicationDate !== "" + ? formData.publicationDate + : null, + seo: { + description: formData.seoDescription, + title: formData.seoTitle + }, + sku: formData.sku, + stockQuantity: + formData.stockQuantity !== null + ? formData.stockQuantity + : 0 + } + }); + }; + + const formTransitionState = getMutationState( + productCreateCalled, + productCreateDataLoading, + maybe(() => productCreateData.productCreate.errors) + ); + return ( + <> + + shop.defaultCurrency)} + categories={maybe( + () => searchCategoryOpts.data.search.edges, + [] + ).map(edge => edge.node)} + collections={maybe( + () => searchCollectionOpts.data.search.edges, + [] + ).map(edge => edge.node)} + disabled={productCreateDataLoading} + errors={maybe( + () => productCreateData.productCreate.errors, + [] + )} + fetchCategories={searchCategory} + fetchCollections={searchCollection} + fetchProductTypes={searchProductTypes} + header={intl.formatMessage({ + defaultMessage: "New Product", + description: "page header" + })} + productTypes={maybe(() => + searchProductTypesOpts.data.search.edges.map( + edge => edge.node + ) + )} + onBack={handleBack} + onSubmit={handleSubmit} + saveButtonBarState={formTransitionState} + fetchMoreCategories={{ + hasMore: maybe( + () => + searchCategoryOpts.data.search.pageInfo + .hasNextPage + ), + loading: searchCategoryOpts.loading, + onFetchMore: loadMoreCategories + }} + fetchMoreCollections={{ + hasMore: maybe( + () => + searchCollectionOpts.data.search.pageInfo + .hasNextPage + ), + loading: searchCollectionOpts.loading, + onFetchMore: loadMoreCollections + }} + fetchMoreProductTypes={{ + hasMore: maybe( + () => + searchProductTypesOpts.data.search.pageInfo + .hasNextPage + ), + loading: searchProductTypesOpts.loading, + onFetchMore: loadMoreProductTypes + }} + /> + + ); + }} + + ); + }} + )} - + ); }; export default ProductUpdate; diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 33ed7c1a2..a4357c3b9 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -14,8 +14,8 @@ import useShop from "@saleor/hooks/useShop"; import { commonMessages } from "@saleor/intl"; import ProductVariantCreateDialog from "@saleor/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog"; import { ProductVariantBulkCreate } from "@saleor/products/types/ProductVariantBulkCreate"; +import useCategorySearch from "@saleor/searches/useCategorySearch"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; -import SearchCategories from "../../../containers/SearchCategories"; import SearchCollections from "../../../containers/SearchCollections"; import { getMutationState, maybe } from "../../../misc"; import ProductUpdatePage from "../../components/ProductUpdatePage"; @@ -55,6 +55,13 @@ export const ProductUpdate: React.FC = ({ id, params }) => { ); const intl = useIntl(); const shop = useShop(); + const { + loadMore: loadMoreCategories, + search: searchCategories, + result: searchCategoriesOpts + } = useCategorySearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const openModal = (action: ProductUrlDialog) => navigate( @@ -64,356 +71,341 @@ export const ProductUpdate: React.FC = ({ id, params }) => { ); return ( - + {({ - loadMore: loadMoreCategories, - search: searchCategories, - result: searchCategoriesOpts + loadMore: loadMoreCollections, + search: searchCollections, + result: searchCollectionsOpts }) => ( - - {({ - loadMore: loadMoreCollections, - search: searchCollections, - result: searchCollectionsOpts - }) => ( - - {({ data, loading, refetch }) => { - const handleDelete = () => { - notify({ - text: intl.formatMessage({ - defaultMessage: "Product removed" - }) - }); - navigate(productListUrl()); - }; - const handleUpdate = (data: ProductUpdateMutationResult) => { - if (data.productUpdate.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - } else { - const attributeError = data.productUpdate.errors.find( - err => err.field === "attributes" - ); - if (!!attributeError) { - notify({ text: attributeError.message }); - } - } - }; + + {({ data, loading, refetch }) => { + const handleDelete = () => { + notify({ + text: intl.formatMessage({ + defaultMessage: "Product removed" + }) + }); + navigate(productListUrl()); + }; + const handleUpdate = (data: ProductUpdateMutationResult) => { + if (data.productUpdate.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + } else { + const attributeError = data.productUpdate.errors.find( + err => err.field === "attributes" + ); + if (!!attributeError) { + notify({ text: attributeError.message }); + } + } + }; - const handleImageCreate = (data: ProductImageCreate) => { - const imageError = data.productImageCreate.errors.find( - error => - error.field === - ("image" as keyof ProductImageCreateVariables) + const handleImageCreate = (data: ProductImageCreate) => { + const imageError = data.productImageCreate.errors.find( + error => + error.field === ("image" as keyof ProductImageCreateVariables) + ); + if (imageError) { + notify({ + text: imageError.message + }); + } + }; + const handleImageDeleteSuccess = () => + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + const handleVariantAdd = () => navigate(productVariantAddUrl(id)); + + const handleBulkProductVariantCreate = ( + data: ProductVariantBulkCreate + ) => { + if (data.productVariantBulkCreate.errors.length === 0) { + navigate(productUrl(id), true); + refetch(); + } + }; + + const handleBulkProductVariantDelete = ( + data: ProductVariantBulkDelete + ) => { + if (data.productVariantBulkDelete.errors.length === 0) { + navigate(productUrl(id), true); + reset(); + refetch(); + } + }; + + const handleVariantCreatorOpen = () => + navigate( + productUrl(id, { + ...params, + action: "create-variants" + }) + ); + + const product = data ? data.product : undefined; + return ( + + {({ + bulkProductVariantCreate, + bulkProductVariantDelete, + createProductImage, + deleteProduct, + deleteProductImage, + reorderProductImages, + updateProduct, + updateSimpleProduct + }) => { + const handleImageDelete = (id: string) => () => + deleteProductImage.mutate({ id }); + const handleImageEdit = (imageId: string) => () => + navigate(productImageUrl(id, imageId)); + const handleSubmit = createUpdateHandler( + product, + updateProduct.mutate, + updateSimpleProduct.mutate ); - if (imageError) { - notify({ - text: imageError.message - }); - } - }; - const handleImageDeleteSuccess = () => - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - const handleVariantAdd = () => - navigate(productVariantAddUrl(id)); - - const handleBulkProductVariantCreate = ( - data: ProductVariantBulkCreate - ) => { - if (data.productVariantBulkCreate.errors.length === 0) { - navigate(productUrl(id), true); - refetch(); - } - }; - - const handleBulkProductVariantDelete = ( - data: ProductVariantBulkDelete - ) => { - if (data.productVariantBulkDelete.errors.length === 0) { - navigate(productUrl(id), true); - reset(); - refetch(); - } - }; - - const handleVariantCreatorOpen = () => - navigate( - productUrl(id, { - ...params, - action: "create-variants" - }) + const handleImageUpload = createImageUploadHandler( + id, + createProductImage.mutate + ); + const handleImageReorder = createImageReorderHandler( + product, + reorderProductImages.mutate ); - const product = data ? data.product : undefined; - return ( - - {({ - bulkProductVariantCreate, - bulkProductVariantDelete, - createProductImage, - deleteProduct, - deleteProductImage, - reorderProductImages, - updateProduct, - updateSimpleProduct - }) => { - const handleImageDelete = (id: string) => () => - deleteProductImage.mutate({ id }); - const handleImageEdit = (imageId: string) => () => - navigate(productImageUrl(id, imageId)); - const handleSubmit = createUpdateHandler( - product, - updateProduct.mutate, - updateSimpleProduct.mutate - ); - const handleImageUpload = createImageUploadHandler( - id, - createProductImage.mutate - ); - const handleImageReorder = createImageReorderHandler( - product, - reorderProductImages.mutate - ); + const disableFormSave = + createProductImage.opts.loading || + deleteProduct.opts.loading || + reorderProductImages.opts.loading || + updateProduct.opts.loading || + loading; + const formTransitionState = getMutationState( + updateProduct.opts.called || + updateSimpleProduct.opts.called, + updateProduct.opts.loading || + updateSimpleProduct.opts.loading, + maybe(() => updateProduct.opts.data.productUpdate.errors), + maybe( + () => updateSimpleProduct.opts.data.productUpdate.errors + ), + maybe( + () => + updateSimpleProduct.opts.data.productVariantUpdate + .errors + ) + ); + const deleteTransitionState = getMutationState( + deleteProduct.opts.called, + deleteProduct.opts.loading, + maybe(() => deleteProduct.opts.data.productDelete.errors) + ); - const disableFormSave = - createProductImage.opts.loading || - deleteProduct.opts.loading || - reorderProductImages.opts.loading || - updateProduct.opts.loading || - loading; - const formTransitionState = getMutationState( - updateProduct.opts.called || - updateSimpleProduct.opts.called, - updateProduct.opts.loading || - updateSimpleProduct.opts.loading, - maybe( - () => updateProduct.opts.data.productUpdate.errors - ), - maybe( - () => - updateSimpleProduct.opts.data.productUpdate.errors - ), - maybe( - () => - updateSimpleProduct.opts.data.productVariantUpdate - .errors - ) - ); - const deleteTransitionState = getMutationState( - deleteProduct.opts.called, - deleteProduct.opts.loading, - maybe( - () => deleteProduct.opts.data.productDelete.errors - ) - ); + const bulkProductVariantDeleteTransitionState = getMutationState( + bulkProductVariantDelete.opts.called, + bulkProductVariantDelete.opts.loading, + maybe( + () => + bulkProductVariantDelete.opts.data + .productVariantBulkDelete.errors + ) + ); - const bulkProductVariantDeleteTransitionState = getMutationState( - bulkProductVariantDelete.opts.called, - bulkProductVariantDelete.opts.loading, - maybe( - () => - bulkProductVariantDelete.opts.data - .productVariantBulkDelete.errors - ) - ); + const categories = maybe( + () => searchCategoriesOpts.data.search.edges, + [] + ).map(edge => edge.node); + const collections = maybe( + () => searchCollectionsOpts.data.search.edges, + [] + ).map(edge => edge.node); + const errors = maybe( + () => updateProduct.opts.data.productUpdate.errors, + [] + ); - const categories = maybe( - () => searchCategoriesOpts.data.search.edges, - [] - ).map(edge => edge.node); - const collections = maybe( - () => searchCollectionsOpts.data.search.edges, - [] - ).map(edge => edge.node); - const errors = maybe( - () => updateProduct.opts.data.productUpdate.errors, - [] - ); - - return ( - <> - data.product.name)} /> - data.product.images)} - header={maybe(() => product.name)} - placeholderImage={placeholderImg} - product={product} - variants={maybe(() => product.variants)} - onBack={() => { - navigate(productListUrl()); - }} - onDelete={() => openModal("remove")} - onProductShow={() => { - if (product) { - window.open(product.url); - } - }} - onImageReorder={handleImageReorder} - onSubmit={handleSubmit} - onVariantAdd={handleVariantAdd} - onVariantsAdd={handleVariantCreatorOpen} - onVariantShow={variantId => () => - navigate( - productVariantEditUrl(product.id, variantId) - )} - onImageUpload={handleImageUpload} - onImageEdit={handleImageEdit} - onImageDelete={handleImageDelete} - toolbar={ - - navigate( - productUrl(id, { - action: "remove-variants", - ids: listElements - }) - ) - } - > - - - } - isChecked={isSelected} - selected={listElements.length} - toggle={toggle} - toggleAll={toggleAll} - fetchMoreCategories={{ - hasMore: maybe( - () => - searchCategoriesOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCategoriesOpts.loading, - onFetchMore: loadMoreCategories - }} - fetchMoreCollections={{ - hasMore: maybe( - () => - searchCollectionsOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCollectionsOpts.loading, - onFetchMore: loadMoreCollections - }} - /> - navigate(productUrl(id), true)} - confirmButtonState={deleteTransitionState} - onConfirm={() => deleteProduct.mutate({ id })} - variant="delete" - title={intl.formatMessage({ - defaultMessage: "Delete Product", - description: "dialog header" - })} - > - - - - - navigate(productUrl(id), true)} - confirmButtonState={ - bulkProductVariantDeleteTransitionState - } - onConfirm={() => - bulkProductVariantDelete.mutate({ - ids: params.ids - }) - } - variant="delete" - title={intl.formatMessage({ - defaultMessage: "Delete Product Variants", - description: "dialog header" - })} - > - - params.ids.length), - displayQuantity: ( - - {maybe(() => params.ids.length)} - - ) - }} - /> - - - - data.product.basePrice.amount.toFixed(2) - )} - errors={maybe( - () => - bulkProductVariantCreate.opts.data - .productVariantBulkCreate.bulkProductErrors, - [] - )} - open={params.action === "create-variants"} - attributes={maybe( - () => data.product.productType.variantAttributes, - [] - )} - currencySymbol={maybe(() => shop.defaultCurrency)} - onClose={() => + return ( + <> + data.product.name)} /> + data.product.images)} + header={maybe(() => product.name)} + placeholderImage={placeholderImg} + product={product} + variants={maybe(() => product.variants)} + onBack={() => { + navigate(productListUrl()); + }} + onDelete={() => openModal("remove")} + onProductShow={() => { + if (product) { + window.open(product.url); + } + }} + onImageReorder={handleImageReorder} + onSubmit={handleSubmit} + onVariantAdd={handleVariantAdd} + onVariantsAdd={handleVariantCreatorOpen} + onVariantShow={variantId => () => + navigate( + productVariantEditUrl(product.id, variantId) + )} + onImageUpload={handleImageUpload} + onImageEdit={handleImageEdit} + onImageDelete={handleImageDelete} + toolbar={ + navigate( productUrl(id, { - ...params, - action: undefined + action: "remove-variants", + ids: listElements }) ) } - onSubmit={inputs => - bulkProductVariantCreate.mutate({ - id, - inputs - }) - } + > + + + } + isChecked={isSelected} + selected={listElements.length} + toggle={toggle} + toggleAll={toggleAll} + fetchMoreCategories={{ + hasMore: maybe( + () => + searchCategoriesOpts.data.search.pageInfo + .hasNextPage + ), + loading: searchCategoriesOpts.loading, + onFetchMore: loadMoreCategories + }} + fetchMoreCollections={{ + hasMore: maybe( + () => + searchCollectionsOpts.data.search.pageInfo + .hasNextPage + ), + loading: searchCollectionsOpts.loading, + onFetchMore: loadMoreCollections + }} + /> + navigate(productUrl(id), true)} + confirmButtonState={deleteTransitionState} + onConfirm={() => deleteProduct.mutate({ id })} + variant="delete" + title={intl.formatMessage({ + defaultMessage: "Delete Product", + description: "dialog header" + })} + > + + - - ); - }} - - ); - }} - - )} - + + + navigate(productUrl(id), true)} + confirmButtonState={ + bulkProductVariantDeleteTransitionState + } + onConfirm={() => + bulkProductVariantDelete.mutate({ + ids: params.ids + }) + } + variant="delete" + title={intl.formatMessage({ + defaultMessage: "Delete Product Variants", + description: "dialog header" + })} + > + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + + + + data.product.basePrice.amount.toFixed(2) + )} + errors={maybe( + () => + bulkProductVariantCreate.opts.data + .productVariantBulkCreate.bulkProductErrors, + [] + )} + open={params.action === "create-variants"} + attributes={maybe( + () => data.product.productType.variantAttributes, + [] + )} + currencySymbol={maybe(() => shop.defaultCurrency)} + onClose={() => + navigate( + productUrl(id, { + ...params, + action: undefined + }) + ) + } + onSubmit={inputs => + bulkProductVariantCreate.mutate({ + id, + inputs + }) + } + /> + + ); + }} + + ); + }} + )} - + ); }; export default ProductUpdate; diff --git a/src/containers/SearchCategories/types/SearchCategories.ts b/src/searches/types/SearchCategories.ts similarity index 100% rename from src/containers/SearchCategories/types/SearchCategories.ts rename to src/searches/types/SearchCategories.ts diff --git a/src/containers/SearchCategories/index.tsx b/src/searches/useCategorySearch.ts similarity index 78% rename from src/containers/SearchCategories/index.tsx rename to src/searches/useCategorySearch.ts index cdaebb8b1..2958bbf77 100644 --- a/src/containers/SearchCategories/index.tsx +++ b/src/searches/useCategorySearch.ts @@ -1,7 +1,7 @@ import gql from "graphql-tag"; +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import { pageInfoFragment } from "@saleor/queries"; -import TopLevelSearch from "../TopLevelSearch"; import { SearchCategories, SearchCategoriesVariables @@ -24,6 +24,6 @@ export const searchCategories = gql` } `; -export default TopLevelSearch( +export default makeTopLevelSearch( searchCategories ); From 3f28673c9498111b8625238e2ee06268bb2bf180 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 17:04:53 +0100 Subject: [PATCH 05/13] Use collection search hook --- .../AssignCollectionDialog.tsx | 2 +- src/discounts/views/SaleDetails.tsx | 70 +- src/discounts/views/VoucherDetails.tsx | 70 +- .../MenuItemDialog/MenuItemDialog.tsx | 2 +- src/navigation/views/MenuDetails/index.tsx | 530 +++++++-------- .../ProductCreatePage/ProductCreatePage.tsx | 2 +- .../ProductUpdatePage/ProductUpdatePage.tsx | 2 +- src/products/views/ProductCreate.tsx | 301 ++++----- .../views/ProductUpdate/ProductUpdate.tsx | 632 +++++++++--------- .../types/SearchCollections.ts | 0 .../useCollectionSearch.ts} | 9 +- 11 files changed, 786 insertions(+), 834 deletions(-) rename src/{containers/SearchCollections => searches}/types/SearchCollections.ts (100%) rename src/{containers/SearchCollections/index.tsx => searches/useCollectionSearch.ts} (75%) diff --git a/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx b/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx index 97da47a3e..c0491c3c3 100644 --- a/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx +++ b/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx @@ -15,7 +15,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; import { buttonMessages } from "@saleor/intl"; -import { SearchCollections_search_edges_node } from "../../containers/SearchCollections/types/SearchCollections"; +import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections"; import Checkbox from "../Checkbox"; import ConfirmButton, { ConfirmButtonTransitionState diff --git a/src/discounts/views/SaleDetails.tsx b/src/discounts/views/SaleDetails.tsx index 272dadc3c..40d302530 100644 --- a/src/discounts/views/SaleDetails.tsx +++ b/src/discounts/views/SaleDetails.tsx @@ -17,10 +17,10 @@ import usePaginator, { import useShop from "@saleor/hooks/useShop"; import { commonMessages, sectionNames } from "@saleor/intl"; import useCategorySearch from "@saleor/searches/useCategorySearch"; +import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import { categoryUrl } from "../../categories/urls"; import { collectionUrl } from "../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; -import SearchCollections from "../../containers/SearchCollections"; import SearchProducts from "../../containers/SearchProducts"; import { decimal, getMutationState, joinDateTime, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; @@ -72,6 +72,12 @@ export const SaleDetails: React.FC = ({ id, params }) => { } = useCategorySearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + search: searchCollections, + result: searchCollectionsOpts + } = useCollectionSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: SaleDetailsPageTab) => { @@ -410,43 +416,33 @@ export const SaleDetails: React.FC = ({ id, params }) => { }) } /> - - {({ - search: searchCollections, - result: searchCollectionsOpts - }) => ( - - searchCollectionsOpts.data.search.edges - .map(edge => edge.node) - .filter( - suggestedCategory => - suggestedCategory.id - ) - )} - confirmButtonState={assignTransitionState} - open={params.action === "assign-collection"} - onFetch={searchCollections} - loading={searchCollectionsOpts.loading} - onClose={closeModal} - onSubmit={collections => - saleCataloguesAdd({ - variables: { - ...paginationState, - id, - input: { - collections: collections.map( - product => product.id - ) - } - } - }) - } - /> + + searchCollectionsOpts.data.search.edges + .map(edge => edge.node) + .filter( + suggestedCategory => suggestedCategory.id + ) )} - + confirmButtonState={assignTransitionState} + open={params.action === "assign-collection"} + onFetch={searchCollections} + loading={searchCollectionsOpts.loading} + onClose={closeModal} + onSubmit={collections => + saleCataloguesAdd({ + variables: { + ...paginationState, + id, + input: { + collections: collections.map( + product => product.id + ) + } + } + }) + } + /> = ({ } = useCategorySearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + search: searchCollections, + result: searchCollectionsOpts + } = useCollectionSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: VoucherDetailsPageTab) => { @@ -453,43 +459,33 @@ export const VoucherDetails: React.FC = ({ }) } /> - - {({ - search: searchCollections, - result: searchCollectionsOpts - }) => ( - - searchCollectionsOpts.data.search.edges - .map(edge => edge.node) - .filter( - suggestedCategory => - suggestedCategory.id - ) - )} - confirmButtonState={assignTransitionState} - open={params.action === "assign-collection"} - onFetch={searchCollections} - loading={searchCollectionsOpts.loading} - onClose={closeModal} - onSubmit={collections => - voucherCataloguesAdd({ - variables: { - ...paginationState, - id, - input: { - collections: collections.map( - product => product.id - ) - } - } - }) - } - /> + + searchCollectionsOpts.data.search.edges + .map(edge => edge.node) + .filter( + suggestedCategory => suggestedCategory.id + ) )} - + confirmButtonState={assignTransitionState} + open={params.action === "assign-collection"} + onFetch={searchCollections} + loading={searchCollectionsOpts.loading} + onClose={closeModal} + onSubmit={collections => + voucherCataloguesAdd({ + variables: { + ...paginationState, + id, + input: { + collections: collections.map( + product => product.id + ) + } + } + }) + } + /> shop.countries, [])} diff --git a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx index 6dac3b907..5b5620654 100644 --- a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx +++ b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx @@ -14,13 +14,13 @@ import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import FormSpacer from "@saleor/components/FormSpacer"; -import { SearchCollections_search_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import { SearchPages_search_edges_node } from "@saleor/containers/SearchPages/types/SearchPages"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { buttonMessages, sectionNames } from "@saleor/intl"; import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; +import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections"; import { UserError } from "@saleor/types"; import { getErrors, getFieldError } from "@saleor/utils/errors"; import { getMenuItemByValue, IMenu } from "@saleor/utils/menu"; diff --git a/src/navigation/views/MenuDetails/index.tsx b/src/navigation/views/MenuDetails/index.tsx index 60e53e06d..227cddf6b 100644 --- a/src/navigation/views/MenuDetails/index.tsx +++ b/src/navigation/views/MenuDetails/index.tsx @@ -6,10 +6,10 @@ import ActionDialog from "@saleor/components/ActionDialog"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useCategorySearch from "@saleor/searches/useCategorySearch"; +import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import { categoryUrl } from "../../../categories/urls"; import { collectionUrl } from "../../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; -import SearchCollections from "../../../containers/SearchCollections"; import SearchPages from "../../../containers/SearchPages"; import { getMutationState, maybe } from "../../../misc"; import { pageUrl } from "../../../pages/urls"; @@ -62,6 +62,9 @@ const MenuDetails: React.FC = ({ id, params }) => { const categorySearch = useCategorySearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const collectionSearch = useCollectionSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const closeModal = () => navigate( @@ -100,304 +103,279 @@ const MenuDetails: React.FC = ({ id, params }) => { return ( {pageSearch => ( - - {collectionSearch => ( - - {({ data, loading, refetch }) => { - const handleQueryChange = (query: string) => { - categorySearch.search(query); - collectionSearch.search(query); - pageSearch.search(query); - }; + + {({ data, loading, refetch }) => { + const handleQueryChange = (query: string) => { + categorySearch.search(query); + collectionSearch.search(query); + pageSearch.search(query); + }; - const categories = maybe( - () => - categorySearch.result.data.search.edges.map( - edge => edge.node - ), - [] - ); + const categories = maybe( + () => + categorySearch.result.data.search.edges.map(edge => edge.node), + [] + ); - const collections = maybe( - () => - collectionSearch.result.data.search.edges.map( - edge => edge.node - ), - [] - ); + const collections = maybe( + () => + collectionSearch.result.data.search.edges.map( + edge => edge.node + ), + [] + ); - const pages = maybe( - () => - pageSearch.result.data.search.edges.map(edge => edge.node), - [] - ); + const pages = maybe( + () => pageSearch.result.data.search.edges.map(edge => edge.node), + [] + ); - return ( - handleDelete(data, navigate, notify, intl)} + > + {(menuDelete, menuDeleteOpts) => ( + - handleDelete(data, navigate, notify, intl) + handleUpdate(data, notify, refetch, intl) } > - {(menuDelete, menuDeleteOpts) => ( - - handleUpdate(data, notify, refetch, intl) - } - > - {(menuUpdate, menuUpdateOpts) => { - const deleteState = getMutationState( - menuDeleteOpts.called, - menuDeleteOpts.loading, - maybe(() => menuDeleteOpts.data.menuDelete.errors) - ); + {(menuUpdate, menuUpdateOpts) => { + const deleteState = getMutationState( + menuDeleteOpts.called, + menuDeleteOpts.loading, + maybe(() => menuDeleteOpts.data.menuDelete.errors) + ); - const updateState = getMutationState( - menuUpdateOpts.called, - menuUpdateOpts.loading, - maybe(() => menuUpdateOpts.data.menuUpdate.errors), - maybe(() => menuUpdateOpts.data.menuItemMove.errors) - ); + const updateState = getMutationState( + menuUpdateOpts.called, + menuUpdateOpts.loading, + maybe(() => menuUpdateOpts.data.menuUpdate.errors), + maybe(() => menuUpdateOpts.data.menuItemMove.errors) + ); - // This is a workaround to let know - // that it should clean operation stack if mutations - // were successful - const handleSubmit = async ( - data: MenuDetailsSubmitData - ) => { - try { - const result = await menuUpdate({ - variables: { - id, - moves: getMoves(data), - name: data.name, - removeIds: getRemoveIds(data) - } - }); - if (result) { - if ( - result.data.menuItemBulkDelete.errors.length > - 0 || - result.data.menuItemMove.errors.length > 0 || - result.data.menuUpdate.errors.length > 0 - ) { - return false; - } - } - return true; - } catch { + // This is a workaround to let know + // that it should clean operation stack if mutations + // were successful + const handleSubmit = async ( + data: MenuDetailsSubmitData + ) => { + try { + const result = await menuUpdate({ + variables: { + id, + moves: getMoves(data), + name: data.name, + removeIds: getRemoveIds(data) + } + }); + if (result) { + if ( + result.data.menuItemBulkDelete.errors.length > + 0 || + result.data.menuItemMove.errors.length > 0 || + result.data.menuUpdate.errors.length > 0 + ) { return false; } - }; + } + return true; + } catch { + return false; + } + }; - return ( - <> - data.menu)} - onBack={() => navigate(menuListUrl())} - onDelete={() => - navigate( - menuUrl(id, { - action: "remove" - }) + return ( + <> + data.menu)} + onBack={() => navigate(menuListUrl())} + onDelete={() => + navigate( + menuUrl(id, { + action: "remove" + }) + ) + } + onItemAdd={() => + navigate( + menuUrl(id, { + action: "add-item" + }) + ) + } + onItemClick={handleItemClick} + onItemEdit={itemId => + navigate( + menuUrl(id, { + action: "edit-item", + id: itemId + }) + ) + } + onSubmit={handleSubmit} + saveButtonState={updateState} + /> + menuDelete({ variables: { id } })} + variant="delete" + title={intl.formatMessage({ + defaultMessage: "Delete Menu", + description: "dialog header", + id: "menuDetailsDeleteMenuHeader" + })} + > + + + {maybe(() => data.menu.name, "...")} + ) - } - onItemAdd={() => - navigate( - menuUrl(id, { - action: "add-item" - }) - ) - } - onItemClick={handleItemClick} - onItemEdit={itemId => - navigate( - menuUrl(id, { - action: "edit-item", - id: itemId - }) - ) - } - onSubmit={handleSubmit} - saveButtonState={updateState} + }} /> - - menuDelete({ variables: { id } }) - } - variant="delete" - title={intl.formatMessage({ - defaultMessage: "Delete Menu", - description: "dialog header", - id: "menuDetailsDeleteMenuHeader" - })} - > - - - {maybe(() => data.menu.name, "...")} - - ) - }} - /> - - + + - - handleItemCreate( - data, - notify, - closeModal, - intl - ) - } - > - {(menuItemCreate, menuItemCreateOpts) => { - const handleSubmit = ( - data: MenuItemDialogFormData - ) => { - const variables: MenuItemCreateVariables = { - input: getMenuItemCreateInputData( - id, - data - ) - }; + + handleItemCreate(data, notify, closeModal, intl) + } + > + {(menuItemCreate, menuItemCreateOpts) => { + const handleSubmit = ( + data: MenuItemDialogFormData + ) => { + const variables: MenuItemCreateVariables = { + input: getMenuItemCreateInputData(id, data) + }; - menuItemCreate({ variables }); - }; + menuItemCreate({ variables }); + }; - const formTransitionState = getMutationState( - menuItemCreateOpts.called, - menuItemCreateOpts.loading, - maybe( - () => - menuItemCreateOpts.data.menuItemCreate - .errors - ) - ); + const formTransitionState = getMutationState( + menuItemCreateOpts.called, + menuItemCreateOpts.loading, + maybe( + () => + menuItemCreateOpts.data.menuItemCreate + .errors + ) + ); - return ( - - menuItemCreateOpts.data.menuItemCreate - .errors, - [] - )} - pages={pages} - loading={ - categorySearch.result.loading || - collectionSearch.result.loading - } - confirmButtonState={formTransitionState} - disabled={menuItemCreateOpts.loading} - onClose={closeModal} - onSubmit={handleSubmit} - onQueryChange={handleQueryChange} - /> - ); - }} - - - handleItemUpdate( - data, - id, - navigate, - notify, - intl - ) - } - > - {(menuItemUpdate, menuItemUpdateOpts) => { - const handleSubmit = ( - data: MenuItemDialogFormData - ) => { - const variables: MenuItemUpdateVariables = { - id: params.id, - input: getMenuItemInputData(data) - }; + return ( + + menuItemCreateOpts.data.menuItemCreate + .errors, + [] + )} + pages={pages} + loading={ + categorySearch.result.loading || + collectionSearch.result.loading + } + confirmButtonState={formTransitionState} + disabled={menuItemCreateOpts.loading} + onClose={closeModal} + onSubmit={handleSubmit} + onQueryChange={handleQueryChange} + /> + ); + }} + + + handleItemUpdate(data, id, navigate, notify, intl) + } + > + {(menuItemUpdate, menuItemUpdateOpts) => { + const handleSubmit = ( + data: MenuItemDialogFormData + ) => { + const variables: MenuItemUpdateVariables = { + id: params.id, + input: getMenuItemInputData(data) + }; - menuItemUpdate({ variables }); - }; + menuItemUpdate({ variables }); + }; - const menuItem = maybe(() => - getNode( - data.menu.items, - findNode(data.menu.items, params.id) - ) - ); + const menuItem = maybe(() => + getNode( + data.menu.items, + findNode(data.menu.items, params.id) + ) + ); - const formTransitionState = getMutationState( - menuItemUpdateOpts.called, - menuItemUpdateOpts.loading, - maybe( - () => - menuItemUpdateOpts.data.menuItemUpdate - .errors - ) - ); + const formTransitionState = getMutationState( + menuItemUpdateOpts.called, + menuItemUpdateOpts.loading, + maybe( + () => + menuItemUpdateOpts.data.menuItemUpdate + .errors + ) + ); - const initialFormData: MenuItemDialogFormData = { - id: maybe(() => getItemId(menuItem)), - name: maybe(() => menuItem.name, "..."), - type: maybe( - () => getItemType(menuItem), - "category" - ) - }; + const initialFormData: MenuItemDialogFormData = { + id: maybe(() => getItemId(menuItem)), + name: maybe(() => menuItem.name, "..."), + type: maybe( + () => getItemType(menuItem), + "category" + ) + }; - return ( - - menuItemUpdateOpts.data.menuItemUpdate - .errors, - [] - )} - pages={pages} - initial={initialFormData} - initialDisplayValue={getInitialDisplayValue( - menuItem - )} - loading={ - categorySearch.result.loading || - collectionSearch.result.loading - } - confirmButtonState={formTransitionState} - disabled={menuItemUpdateOpts.loading} - onClose={closeModal} - onSubmit={handleSubmit} - onQueryChange={handleQueryChange} - /> - ); - }} - - - ); - }} - - )} - - ); - }} - - )} - + return ( + + menuItemUpdateOpts.data.menuItemUpdate + .errors, + [] + )} + pages={pages} + initial={initialFormData} + initialDisplayValue={getInitialDisplayValue( + menuItem + )} + loading={ + categorySearch.result.loading || + collectionSearch.result.loading + } + confirmButtonState={formTransitionState} + disabled={menuItemUpdateOpts.loading} + onClose={closeModal} + onSubmit={handleSubmit} + onQueryChange={handleQueryChange} + /> + ); + }} + + + ); + }} + + )} + + ); + }} + )} ); diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index 5d74fb815..be5bd60a2 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -13,7 +13,6 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import { SearchCollections_search_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/containers/SearchProductTypes/types/SearchProductTypes"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useFormset from "@saleor/hooks/useFormset"; @@ -25,6 +24,7 @@ import { ProductType } from "@saleor/products/utils/data"; import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; +import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { FetchMoreProps, UserError } from "../../../types"; diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index 57dd2ee01..7269dcec6 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -12,13 +12,13 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import { SearchCollections_search_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useFormset from "@saleor/hooks/useFormset"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { sectionNames } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; +import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections"; import { FetchMoreProps, ListActions, UserError } from "@saleor/types"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index 8c20a480c..7c4dafa80 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -7,8 +7,8 @@ import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; import useCategorySearch from "@saleor/searches/useCategorySearch"; +import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../config"; -import SearchCollections from "../../containers/SearchCollections"; import { decimal, getMutationState, maybe } from "../../misc"; import ProductCreatePage, { ProductCreatePageSubmitData @@ -33,164 +33,159 @@ export const ProductUpdate: React.FC = () => { } = useCategorySearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + loadMore: loadMoreCollections, + search: searchCollection, + result: searchCollectionOpts + } = useCollectionSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const handleBack = () => navigate(productListUrl()); return ( - + {({ - loadMore: loadMoreCollections, - search: searchCollection, - result: searchCollectionOpts - }) => ( - - {({ - loadMore: loadMoreProductTypes, - search: searchProductTypes, - result: searchProductTypesOpts - }) => { - const handleSuccess = (data: ProductCreate) => { - if (data.productCreate.errors.length === 0) { - notify({ - text: intl.formatMessage({ - defaultMessage: "Product created" - }) - }); - navigate(productUrl(data.productCreate.product.id)); - } else { - const attributeError = data.productCreate.errors.find( - err => err.field === "attributes" - ); - if (!!attributeError) { - notify({ text: attributeError.message }); - } - } - }; - - return ( - - {( - productCreate, - { - called: productCreateCalled, - data: productCreateData, - loading: productCreateDataLoading - } - ) => { - const handleSubmit = ( - formData: ProductCreatePageSubmitData - ) => { - productCreate({ - variables: { - attributes: formData.attributes.map(attribute => ({ - id: attribute.id, - values: attribute.value - })), - basePrice: decimal(formData.basePrice), - category: formData.category, - chargeTaxes: formData.chargeTaxes, - collections: formData.collections, - descriptionJson: JSON.stringify(formData.description), - isPublished: formData.isPublished, - name: formData.name, - productType: formData.productType, - publicationDate: - formData.publicationDate !== "" - ? formData.publicationDate - : null, - seo: { - description: formData.seoDescription, - title: formData.seoTitle - }, - sku: formData.sku, - stockQuantity: - formData.stockQuantity !== null - ? formData.stockQuantity - : 0 - } - }); - }; - - const formTransitionState = getMutationState( - productCreateCalled, - productCreateDataLoading, - maybe(() => productCreateData.productCreate.errors) - ); - return ( - <> - - shop.defaultCurrency)} - categories={maybe( - () => searchCategoryOpts.data.search.edges, - [] - ).map(edge => edge.node)} - collections={maybe( - () => searchCollectionOpts.data.search.edges, - [] - ).map(edge => edge.node)} - disabled={productCreateDataLoading} - errors={maybe( - () => productCreateData.productCreate.errors, - [] - )} - fetchCategories={searchCategory} - fetchCollections={searchCollection} - fetchProductTypes={searchProductTypes} - header={intl.formatMessage({ - defaultMessage: "New Product", - description: "page header" - })} - productTypes={maybe(() => - searchProductTypesOpts.data.search.edges.map( - edge => edge.node - ) - )} - onBack={handleBack} - onSubmit={handleSubmit} - saveButtonBarState={formTransitionState} - fetchMoreCategories={{ - hasMore: maybe( - () => - searchCategoryOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCategoryOpts.loading, - onFetchMore: loadMoreCategories - }} - fetchMoreCollections={{ - hasMore: maybe( - () => - searchCollectionOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCollectionOpts.loading, - onFetchMore: loadMoreCollections - }} - fetchMoreProductTypes={{ - hasMore: maybe( - () => - searchProductTypesOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchProductTypesOpts.loading, - onFetchMore: loadMoreProductTypes - }} - /> - - ); - }} - + loadMore: loadMoreProductTypes, + search: searchProductTypes, + result: searchProductTypesOpts + }) => { + const handleSuccess = (data: ProductCreate) => { + if (data.productCreate.errors.length === 0) { + notify({ + text: intl.formatMessage({ + defaultMessage: "Product created" + }) + }); + navigate(productUrl(data.productCreate.product.id)); + } else { + const attributeError = data.productCreate.errors.find( + err => err.field === "attributes" ); - }} - - )} - + if (!!attributeError) { + notify({ text: attributeError.message }); + } + } + }; + + return ( + + {( + productCreate, + { + called: productCreateCalled, + data: productCreateData, + loading: productCreateDataLoading + } + ) => { + const handleSubmit = (formData: ProductCreatePageSubmitData) => { + productCreate({ + variables: { + attributes: formData.attributes.map(attribute => ({ + id: attribute.id, + values: attribute.value + })), + basePrice: decimal(formData.basePrice), + category: formData.category, + chargeTaxes: formData.chargeTaxes, + collections: formData.collections, + descriptionJson: JSON.stringify(formData.description), + isPublished: formData.isPublished, + name: formData.name, + productType: formData.productType, + publicationDate: + formData.publicationDate !== "" + ? formData.publicationDate + : null, + seo: { + description: formData.seoDescription, + title: formData.seoTitle + }, + sku: formData.sku, + stockQuantity: + formData.stockQuantity !== null + ? formData.stockQuantity + : 0 + } + }); + }; + + const formTransitionState = getMutationState( + productCreateCalled, + productCreateDataLoading, + maybe(() => productCreateData.productCreate.errors) + ); + return ( + <> + + shop.defaultCurrency)} + categories={maybe( + () => searchCategoryOpts.data.search.edges, + [] + ).map(edge => edge.node)} + collections={maybe( + () => searchCollectionOpts.data.search.edges, + [] + ).map(edge => edge.node)} + disabled={productCreateDataLoading} + errors={maybe( + () => productCreateData.productCreate.errors, + [] + )} + fetchCategories={searchCategory} + fetchCollections={searchCollection} + fetchProductTypes={searchProductTypes} + header={intl.formatMessage({ + defaultMessage: "New Product", + description: "page header" + })} + productTypes={maybe(() => + searchProductTypesOpts.data.search.edges.map( + edge => edge.node + ) + )} + onBack={handleBack} + onSubmit={handleSubmit} + saveButtonBarState={formTransitionState} + fetchMoreCategories={{ + hasMore: maybe( + () => + searchCategoryOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCategoryOpts.loading, + onFetchMore: loadMoreCategories + }} + fetchMoreCollections={{ + hasMore: maybe( + () => + searchCollectionOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCollectionOpts.loading, + onFetchMore: loadMoreCollections + }} + fetchMoreProductTypes={{ + hasMore: maybe( + () => + searchProductTypesOpts.data.search.pageInfo + .hasNextPage + ), + loading: searchProductTypesOpts.loading, + onFetchMore: loadMoreProductTypes + }} + /> + + ); + }} + + ); + }} + ); }; export default ProductUpdate; diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index a4357c3b9..f03294abd 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -15,8 +15,8 @@ import { commonMessages } from "@saleor/intl"; import ProductVariantCreateDialog from "@saleor/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog"; import { ProductVariantBulkCreate } from "@saleor/products/types/ProductVariantBulkCreate"; import useCategorySearch from "@saleor/searches/useCategorySearch"; +import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; -import SearchCollections from "../../../containers/SearchCollections"; import { getMutationState, maybe } from "../../../misc"; import ProductUpdatePage from "../../components/ProductUpdatePage"; import ProductUpdateOperations from "../../containers/ProductUpdateOperations"; @@ -62,6 +62,13 @@ export const ProductUpdate: React.FC = ({ id, params }) => { } = useCategorySearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + loadMore: loadMoreCollections, + search: searchCollections, + result: searchCollectionsOpts + } = useCollectionSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const openModal = (action: ProductUrlDialog) => navigate( @@ -71,341 +78,320 @@ export const ProductUpdate: React.FC = ({ id, params }) => { ); return ( - - {({ - loadMore: loadMoreCollections, - search: searchCollections, - result: searchCollectionsOpts - }) => ( - - {({ data, loading, refetch }) => { - const handleDelete = () => { - notify({ - text: intl.formatMessage({ - defaultMessage: "Product removed" - }) - }); - navigate(productListUrl()); - }; - const handleUpdate = (data: ProductUpdateMutationResult) => { - if (data.productUpdate.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - } else { - const attributeError = data.productUpdate.errors.find( - err => err.field === "attributes" - ); - if (!!attributeError) { - notify({ text: attributeError.message }); - } - } - }; + + {({ data, loading, refetch }) => { + const handleDelete = () => { + notify({ + text: intl.formatMessage({ + defaultMessage: "Product removed" + }) + }); + navigate(productListUrl()); + }; + const handleUpdate = (data: ProductUpdateMutationResult) => { + if (data.productUpdate.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + } else { + const attributeError = data.productUpdate.errors.find( + err => err.field === "attributes" + ); + if (!!attributeError) { + notify({ text: attributeError.message }); + } + } + }; - const handleImageCreate = (data: ProductImageCreate) => { - const imageError = data.productImageCreate.errors.find( - error => - error.field === ("image" as keyof ProductImageCreateVariables) + const handleImageCreate = (data: ProductImageCreate) => { + const imageError = data.productImageCreate.errors.find( + error => + error.field === ("image" as keyof ProductImageCreateVariables) + ); + if (imageError) { + notify({ + text: imageError.message + }); + } + }; + const handleImageDeleteSuccess = () => + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + const handleVariantAdd = () => navigate(productVariantAddUrl(id)); + + const handleBulkProductVariantCreate = ( + data: ProductVariantBulkCreate + ) => { + if (data.productVariantBulkCreate.errors.length === 0) { + navigate(productUrl(id), true); + refetch(); + } + }; + + const handleBulkProductVariantDelete = ( + data: ProductVariantBulkDelete + ) => { + if (data.productVariantBulkDelete.errors.length === 0) { + navigate(productUrl(id), true); + reset(); + refetch(); + } + }; + + const handleVariantCreatorOpen = () => + navigate( + productUrl(id, { + ...params, + action: "create-variants" + }) + ); + + const product = data ? data.product : undefined; + return ( + + {({ + bulkProductVariantCreate, + bulkProductVariantDelete, + createProductImage, + deleteProduct, + deleteProductImage, + reorderProductImages, + updateProduct, + updateSimpleProduct + }) => { + const handleImageDelete = (id: string) => () => + deleteProductImage.mutate({ id }); + const handleImageEdit = (imageId: string) => () => + navigate(productImageUrl(id, imageId)); + const handleSubmit = createUpdateHandler( + product, + updateProduct.mutate, + updateSimpleProduct.mutate ); - if (imageError) { - notify({ - text: imageError.message - }); - } - }; - const handleImageDeleteSuccess = () => - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - const handleVariantAdd = () => navigate(productVariantAddUrl(id)); - - const handleBulkProductVariantCreate = ( - data: ProductVariantBulkCreate - ) => { - if (data.productVariantBulkCreate.errors.length === 0) { - navigate(productUrl(id), true); - refetch(); - } - }; - - const handleBulkProductVariantDelete = ( - data: ProductVariantBulkDelete - ) => { - if (data.productVariantBulkDelete.errors.length === 0) { - navigate(productUrl(id), true); - reset(); - refetch(); - } - }; - - const handleVariantCreatorOpen = () => - navigate( - productUrl(id, { - ...params, - action: "create-variants" - }) + const handleImageUpload = createImageUploadHandler( + id, + createProductImage.mutate + ); + const handleImageReorder = createImageReorderHandler( + product, + reorderProductImages.mutate ); - const product = data ? data.product : undefined; - return ( - - {({ - bulkProductVariantCreate, - bulkProductVariantDelete, - createProductImage, - deleteProduct, - deleteProductImage, - reorderProductImages, - updateProduct, - updateSimpleProduct - }) => { - const handleImageDelete = (id: string) => () => - deleteProductImage.mutate({ id }); - const handleImageEdit = (imageId: string) => () => - navigate(productImageUrl(id, imageId)); - const handleSubmit = createUpdateHandler( - product, - updateProduct.mutate, - updateSimpleProduct.mutate - ); - const handleImageUpload = createImageUploadHandler( - id, - createProductImage.mutate - ); - const handleImageReorder = createImageReorderHandler( - product, - reorderProductImages.mutate - ); + const disableFormSave = + createProductImage.opts.loading || + deleteProduct.opts.loading || + reorderProductImages.opts.loading || + updateProduct.opts.loading || + loading; + const formTransitionState = getMutationState( + updateProduct.opts.called || updateSimpleProduct.opts.called, + updateProduct.opts.loading || updateSimpleProduct.opts.loading, + maybe(() => updateProduct.opts.data.productUpdate.errors), + maybe(() => updateSimpleProduct.opts.data.productUpdate.errors), + maybe( + () => + updateSimpleProduct.opts.data.productVariantUpdate.errors + ) + ); + const deleteTransitionState = getMutationState( + deleteProduct.opts.called, + deleteProduct.opts.loading, + maybe(() => deleteProduct.opts.data.productDelete.errors) + ); - const disableFormSave = - createProductImage.opts.loading || - deleteProduct.opts.loading || - reorderProductImages.opts.loading || - updateProduct.opts.loading || - loading; - const formTransitionState = getMutationState( - updateProduct.opts.called || - updateSimpleProduct.opts.called, - updateProduct.opts.loading || - updateSimpleProduct.opts.loading, - maybe(() => updateProduct.opts.data.productUpdate.errors), - maybe( - () => updateSimpleProduct.opts.data.productUpdate.errors - ), - maybe( - () => - updateSimpleProduct.opts.data.productVariantUpdate - .errors - ) - ); - const deleteTransitionState = getMutationState( - deleteProduct.opts.called, - deleteProduct.opts.loading, - maybe(() => deleteProduct.opts.data.productDelete.errors) - ); + const bulkProductVariantDeleteTransitionState = getMutationState( + bulkProductVariantDelete.opts.called, + bulkProductVariantDelete.opts.loading, + maybe( + () => + bulkProductVariantDelete.opts.data.productVariantBulkDelete + .errors + ) + ); - const bulkProductVariantDeleteTransitionState = getMutationState( - bulkProductVariantDelete.opts.called, - bulkProductVariantDelete.opts.loading, - maybe( - () => - bulkProductVariantDelete.opts.data - .productVariantBulkDelete.errors - ) - ); + const categories = maybe( + () => searchCategoriesOpts.data.search.edges, + [] + ).map(edge => edge.node); + const collections = maybe( + () => searchCollectionsOpts.data.search.edges, + [] + ).map(edge => edge.node); + const errors = maybe( + () => updateProduct.opts.data.productUpdate.errors, + [] + ); - const categories = maybe( - () => searchCategoriesOpts.data.search.edges, - [] - ).map(edge => edge.node); - const collections = maybe( - () => searchCollectionsOpts.data.search.edges, - [] - ).map(edge => edge.node); - const errors = maybe( - () => updateProduct.opts.data.productUpdate.errors, - [] - ); - - return ( - <> - data.product.name)} /> - data.product.images)} - header={maybe(() => product.name)} - placeholderImage={placeholderImg} - product={product} - variants={maybe(() => product.variants)} - onBack={() => { - navigate(productListUrl()); - }} - onDelete={() => openModal("remove")} - onProductShow={() => { - if (product) { - window.open(product.url); - } - }} - onImageReorder={handleImageReorder} - onSubmit={handleSubmit} - onVariantAdd={handleVariantAdd} - onVariantsAdd={handleVariantCreatorOpen} - onVariantShow={variantId => () => - navigate( - productVariantEditUrl(product.id, variantId) - )} - onImageUpload={handleImageUpload} - onImageEdit={handleImageEdit} - onImageDelete={handleImageDelete} - toolbar={ - - navigate( - productUrl(id, { - action: "remove-variants", - ids: listElements - }) - ) - } - > - - - } - isChecked={isSelected} - selected={listElements.length} - toggle={toggle} - toggleAll={toggleAll} - fetchMoreCategories={{ - hasMore: maybe( - () => - searchCategoriesOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCategoriesOpts.loading, - onFetchMore: loadMoreCategories - }} - fetchMoreCollections={{ - hasMore: maybe( - () => - searchCollectionsOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchCollectionsOpts.loading, - onFetchMore: loadMoreCollections - }} - /> - navigate(productUrl(id), true)} - confirmButtonState={deleteTransitionState} - onConfirm={() => deleteProduct.mutate({ id })} - variant="delete" - title={intl.formatMessage({ - defaultMessage: "Delete Product", - description: "dialog header" - })} - > - - - - - navigate(productUrl(id), true)} - confirmButtonState={ - bulkProductVariantDeleteTransitionState - } - onConfirm={() => - bulkProductVariantDelete.mutate({ - ids: params.ids - }) - } - variant="delete" - title={intl.formatMessage({ - defaultMessage: "Delete Product Variants", - description: "dialog header" - })} - > - - params.ids.length), - displayQuantity: ( - - {maybe(() => params.ids.length)} - - ) - }} - /> - - - - data.product.basePrice.amount.toFixed(2) - )} - errors={maybe( - () => - bulkProductVariantCreate.opts.data - .productVariantBulkCreate.bulkProductErrors, - [] - )} - open={params.action === "create-variants"} - attributes={maybe( - () => data.product.productType.variantAttributes, - [] - )} - currencySymbol={maybe(() => shop.defaultCurrency)} - onClose={() => + return ( + <> + data.product.name)} /> + data.product.images)} + header={maybe(() => product.name)} + placeholderImage={placeholderImg} + product={product} + variants={maybe(() => product.variants)} + onBack={() => { + navigate(productListUrl()); + }} + onDelete={() => openModal("remove")} + onProductShow={() => { + if (product) { + window.open(product.url); + } + }} + onImageReorder={handleImageReorder} + onSubmit={handleSubmit} + onVariantAdd={handleVariantAdd} + onVariantsAdd={handleVariantCreatorOpen} + onVariantShow={variantId => () => + navigate(productVariantEditUrl(product.id, variantId))} + onImageUpload={handleImageUpload} + onImageEdit={handleImageEdit} + onImageDelete={handleImageDelete} + toolbar={ + navigate( productUrl(id, { - ...params, - action: undefined + action: "remove-variants", + ids: listElements }) ) } - onSubmit={inputs => - bulkProductVariantCreate.mutate({ - id, - inputs - }) - } + > + + + } + isChecked={isSelected} + selected={listElements.length} + toggle={toggle} + toggleAll={toggleAll} + fetchMoreCategories={{ + hasMore: maybe( + () => + searchCategoriesOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCategoriesOpts.loading, + onFetchMore: loadMoreCategories + }} + fetchMoreCollections={{ + hasMore: maybe( + () => + searchCollectionsOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCollectionsOpts.loading, + onFetchMore: loadMoreCollections + }} + /> + navigate(productUrl(id), true)} + confirmButtonState={deleteTransitionState} + onConfirm={() => deleteProduct.mutate({ id })} + variant="delete" + title={intl.formatMessage({ + defaultMessage: "Delete Product", + description: "dialog header" + })} + > + + - - ); - }} - - ); - }} - - )} - + + + navigate(productUrl(id), true)} + confirmButtonState={bulkProductVariantDeleteTransitionState} + onConfirm={() => + bulkProductVariantDelete.mutate({ + ids: params.ids + }) + } + variant="delete" + title={intl.formatMessage({ + defaultMessage: "Delete Product Variants", + description: "dialog header" + })} + > + + params.ids.length), + displayQuantity: ( + {maybe(() => params.ids.length)} + ) + }} + /> + + + + data.product.basePrice.amount.toFixed(2) + )} + errors={maybe( + () => + bulkProductVariantCreate.opts.data + .productVariantBulkCreate.bulkProductErrors, + [] + )} + open={params.action === "create-variants"} + attributes={maybe( + () => data.product.productType.variantAttributes, + [] + )} + currencySymbol={maybe(() => shop.defaultCurrency)} + onClose={() => + navigate( + productUrl(id, { + ...params, + action: undefined + }) + ) + } + onSubmit={inputs => + bulkProductVariantCreate.mutate({ + id, + inputs + }) + } + /> + + ); + }} + + ); + }} + ); }; export default ProductUpdate; diff --git a/src/containers/SearchCollections/types/SearchCollections.ts b/src/searches/types/SearchCollections.ts similarity index 100% rename from src/containers/SearchCollections/types/SearchCollections.ts rename to src/searches/types/SearchCollections.ts diff --git a/src/containers/SearchCollections/index.tsx b/src/searches/useCollectionSearch.ts similarity index 75% rename from src/containers/SearchCollections/index.tsx rename to src/searches/useCollectionSearch.ts index 2ceafcb46..b3ca07df4 100644 --- a/src/containers/SearchCollections/index.tsx +++ b/src/searches/useCollectionSearch.ts @@ -1,7 +1,7 @@ import gql from "graphql-tag"; +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import { pageInfoFragment } from "@saleor/queries"; -import TopLevelSearch from "../TopLevelSearch"; import { SearchCollections, SearchCollectionsVariables @@ -24,6 +24,7 @@ export const searchCollections = gql` } `; -export default TopLevelSearch( - searchCollections -); +export default makeTopLevelSearch< + SearchCollections, + SearchCollectionsVariables +>(searchCollections); From b07b220b3c36e837e12a79a47bcb1dafcefd444f Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 17:32:35 +0100 Subject: [PATCH 06/13] Use customer search hook --- .../OrderCustomer/OrderCustomer.tsx | 2 +- .../OrderDraftPage/OrderDraftPage.tsx | 2 +- src/orders/fixtures.ts | 2 +- src/orders/views/OrderDetails/index.tsx | 1040 ++++++++--------- .../types/SearchCustomers.ts | 0 .../useCustomerSearch.ts} | 4 +- 6 files changed, 511 insertions(+), 539 deletions(-) rename src/{containers/SearchCustomers => searches}/types/SearchCustomers.ts (100%) rename src/{containers/SearchCustomers/index.ts => searches/useCustomerSearch.ts} (78%) diff --git a/src/orders/components/OrderCustomer/OrderCustomer.tsx b/src/orders/components/OrderCustomer/OrderCustomer.tsx index 0665e269a..59782696c 100644 --- a/src/orders/components/OrderCustomer/OrderCustomer.tsx +++ b/src/orders/components/OrderCustomer/OrderCustomer.tsx @@ -16,10 +16,10 @@ import SingleAutocompleteSelectField from "@saleor/components/SingleAutocomplete import Skeleton from "@saleor/components/Skeleton"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { buttonMessages } from "@saleor/intl"; +import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers"; import { FetchMoreProps, UserPermissionProps } from "@saleor/types"; import { PermissionEnum } from "@saleor/types/globalTypes"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; -import { SearchCustomers_search_edges_node } from "../../../containers/SearchCustomers/types/SearchCustomers"; import { customerUrl } from "../../../customers/urls"; import { createHref, maybe } from "../../../misc"; import { OrderDetails_order } from "../../types/OrderDetails"; diff --git a/src/orders/components/OrderDraftPage/OrderDraftPage.tsx b/src/orders/components/OrderDraftPage/OrderDraftPage.tsx index dbe3ea00c..d36642b84 100644 --- a/src/orders/components/OrderDraftPage/OrderDraftPage.tsx +++ b/src/orders/components/OrderDraftPage/OrderDraftPage.tsx @@ -13,8 +13,8 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import Skeleton from "@saleor/components/Skeleton"; import { sectionNames } from "@saleor/intl"; +import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers"; import { FetchMoreProps, UserPermissionProps } from "@saleor/types"; -import { SearchCustomers_search_edges_node } from "../../../containers/SearchCustomers/types/SearchCustomers"; import { maybe } from "../../../misc"; import { DraftOrderInput } from "../../../types/globalTypes"; import { OrderDetails_order } from "../../types/OrderDetails"; diff --git a/src/orders/fixtures.ts b/src/orders/fixtures.ts index af8a13c45..4463ec60c 100644 --- a/src/orders/fixtures.ts +++ b/src/orders/fixtures.ts @@ -1,5 +1,5 @@ +import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers"; import { MessageDescriptor } from "react-intl"; -import { SearchCustomers_search_edges_node } from "../containers/SearchCustomers/types/SearchCustomers"; import { transformOrderStatus, transformPaymentStatus } from "../misc"; import { FulfillmentStatus, diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index 6d48bebe7..ed9afac47 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -3,8 +3,8 @@ import React from "react"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useUser from "@saleor/hooks/useUser"; +import useCustomerSearch from "@saleor/searches/useCustomerSearch"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; -import SearchCustomers from "../../../containers/SearchCustomers"; import { customerUrl } from "../../../customers/urls"; import { getMutationState, maybe, transformAddressToForm } from "../../../misc"; import { productUrl } from "../../../products/urls"; @@ -74,6 +74,13 @@ interface OrderDetailsProps { export const OrderDetails: React.FC = ({ id, params }) => { const navigate = useNavigator(); const { user } = useUser(); + const { + loadMore: loadMoreCustomers, + search: searchUsers, + result: users + } = useCustomerSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); return ( = ({ id, params }) => { }) ); return ( - - {({ - loadMore: loadMoreCustomers, - search: searchUsers, - result: users - }) => ( - - {orderMessages => ( - - {({ - orderAddNote, - orderCancel, - orderCreateFulfillment, - orderDraftUpdate, - orderLinesAdd, - orderLineDelete, - orderLineUpdate, - orderPaymentCapture, - orderPaymentRefund, - orderVoid, - orderShippingMethodUpdate, - orderUpdate, - orderFulfillmentCancel, - orderFulfillmentUpdateTracking, - orderDraftCancel, - orderDraftFinalize, - orderPaymentMarkAsPaid - }) => { - const finalizeTransitionState = getMutationState( - orderDraftFinalize.opts.called, - orderDraftFinalize.opts.loading, - maybe( - () => - orderDraftFinalize.opts.data.draftOrderComplete - .errors - ) - ); - return ( + + {orderMessages => ( + + {({ + orderAddNote, + orderCancel, + orderCreateFulfillment, + orderDraftUpdate, + orderLinesAdd, + orderLineDelete, + orderLineUpdate, + orderPaymentCapture, + orderPaymentRefund, + orderVoid, + orderShippingMethodUpdate, + orderUpdate, + orderFulfillmentCancel, + orderFulfillmentUpdateTracking, + orderDraftCancel, + orderDraftFinalize, + orderPaymentMarkAsPaid + }) => { + const finalizeTransitionState = getMutationState( + orderDraftFinalize.opts.called, + orderDraftFinalize.opts.loading, + maybe( + () => + orderDraftFinalize.opts.data.draftOrderComplete.errors + ) + ); + return ( + <> + {maybe(() => order.status !== OrderStatus.DRAFT) ? ( <> - {maybe(() => order.status !== OrderStatus.DRAFT) ? ( - <> - "Order #" + data.order.number - )} - /> - - orderAddNote.mutate({ - input: variables, - order: id - }) - } - onBack={() => navigate(orderListUrl())} - order={order} - shippingMethods={maybe( - () => data.order.availableShippingMethods, - [] - )} - userPermissions={maybe( - () => user.permissions, - [] - )} - onOrderCancel={() => openModal("cancel")} - onOrderFulfill={() => openModal("fulfill")} - onFulfillmentCancel={fulfillmentId => - navigate( - orderUrl(id, { - action: "cancel-fulfillment", - id: fulfillmentId - }) - ) - } - onFulfillmentTrackingNumberUpdate={fulfillmentId => - navigate( - orderUrl(id, { - action: "edit-fulfillment", - id: fulfillmentId - }) - ) - } - onPaymentCapture={() => openModal("capture")} - onPaymentVoid={() => openModal("void")} - onPaymentRefund={() => openModal("refund")} - onProductClick={id => () => - navigate(productUrl(id))} - onBillingAddressEdit={() => - openModal("edit-billing-address") - } - onShippingAddressEdit={() => - openModal("edit-shipping-address") - } - onPaymentPaid={() => openModal("mark-paid")} - onProfileView={() => - navigate(customerUrl(order.user.id)) - } - /> - - orderCancel.opts.data.orderCancel.errors - ) - )} - number={maybe(() => order.number)} - open={params.action === "cancel"} - onClose={closeModal} - onSubmit={variables => - orderCancel.mutate({ - id, - ...variables - }) - } - /> - - orderPaymentMarkAsPaid.opts.data - .orderMarkAsPaid.errors - ) - )} - onClose={closeModal} - onConfirm={() => - orderPaymentMarkAsPaid.mutate({ - id - }) - } - open={params.action === "mark-paid"} - /> - orderVoid.opts.data.orderVoid.errors - ) - )} - open={params.action === "void"} - onClose={closeModal} - onConfirm={() => orderVoid.mutate({ id })} - /> - - orderPaymentCapture.opts.data.orderCapture - .errors - ) - )} - initial={maybe(() => order.total.gross.amount)} - open={params.action === "capture"} - variant="capture" - onClose={closeModal} - onSubmit={variables => - orderPaymentCapture.mutate({ - ...variables, - id - }) - } - /> - - orderPaymentRefund.opts.data.orderRefund - .errors - ) - )} - initial={maybe(() => order.total.gross.amount)} - open={params.action === "refund"} - variant="refund" - onClose={closeModal} - onSubmit={variables => - orderPaymentRefund.mutate({ - ...variables, - id - }) - } - /> - - orderCreateFulfillment.opts.data - .orderFulfillmentCreate.errors - ) - )} - open={params.action === "fulfill"} - lines={maybe(() => order.lines, []).filter( - line => line.quantityFulfilled < line.quantity - )} - onClose={closeModal} - onSubmit={variables => - orderCreateFulfillment.mutate({ - input: { - ...variables, - lines: maybe(() => order.lines, []) - .filter( - line => - line.quantityFulfilled < - line.quantity - ) - .map((line, lineIndex) => ({ - orderLineId: line.id, - quantity: variables.lines[lineIndex] - })) - .filter(line => line.quantity > 0) - }, - order: order.id - }) - } - /> - - orderFulfillmentCancel.opts.data - .orderFulfillmentCancel.errors - ) - )} - open={params.action === "cancel-fulfillment"} - onConfirm={variables => - orderFulfillmentCancel.mutate({ - id: params.id, - input: variables - }) - } - onClose={closeModal} - /> - - orderFulfillmentUpdateTracking.opts.data - .orderFulfillmentUpdateTracking.errors - ) - )} - open={params.action === "edit-fulfillment"} - trackingNumber={maybe( - () => - data.order.fulfillments.find( - fulfillment => - fulfillment.id === params.id - ).trackingNumber - )} - onConfirm={variables => - orderFulfillmentUpdateTracking.mutate({ - id: params.id, - input: { - ...variables, - notifyCustomer: true - } - }) - } - onClose={closeModal} - /> - - ) : ( - <> - "Draft order #" + data.order.number - )} - /> - - orderAddNote.mutate({ - input: variables, - order: id - }) - } - users={maybe( - () => - users.data.search.edges.map( - edge => edge.node - ), - [] - )} - hasMore={maybe( - () => users.data.search.pageInfo.hasNextPage, - false - )} - onFetchMore={loadMoreCustomers} - fetchUsers={searchUsers} - loading={users.loading} - usersLoading={users.loading} - onCustomerEdit={data => - orderDraftUpdate.mutate({ - id, - input: data - }) - } - onDraftFinalize={() => openModal("finalize")} - onDraftRemove={() => openModal("cancel")} - onOrderLineAdd={() => - openModal("add-order-line") - } - onBack={() => navigate(orderListUrl())} - order={order} - countries={maybe( - () => data.shop.countries, - [] - ).map(country => ({ - code: country.code, - label: country.country - }))} - onProductClick={id => () => - navigate(productUrl(encodeURIComponent(id)))} - onBillingAddressEdit={() => - openModal("edit-billing-address") - } - onShippingAddressEdit={() => - openModal("edit-shipping-address") - } - onShippingMethodEdit={() => - openModal("edit-shipping") - } - onOrderLineRemove={id => - orderLineDelete.mutate({ id }) - } - onOrderLineChange={(id, data) => - orderLineUpdate.mutate({ - id, - input: data - }) - } - saveButtonBarState="default" - onProfileView={() => - navigate(customerUrl(order.user.id)) - } - userPermissions={maybe( - () => user.permissions, - [] - )} - /> - - orderDraftCancel.opts.data - .draftOrderDelete.errors - ) - )} - onClose={closeModal} - onConfirm={() => - orderDraftCancel.mutate({ id }) - } - open={params.action === "cancel"} - orderNumber={maybe(() => order.number)} - /> - - orderDraftFinalize.mutate({ id }) - } - open={params.action === "finalize"} - orderNumber={maybe(() => order.number)} - warnings={orderDraftFinalizeWarnings(order)} - /> - - orderShippingMethodUpdate.opts.data - .orderUpdateShipping.errors - ) - )} - open={params.action === "edit-shipping"} - shippingMethod={maybe( - () => order.shippingMethod.id, - "..." - )} - shippingMethods={maybe( - () => order.availableShippingMethods - )} - onClose={closeModal} - onSubmit={variables => - orderShippingMethodUpdate.mutate({ - id, - input: { - shippingMethod: variables.shippingMethod - } - }) - } - /> - - {({ - 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 - })) - }) - } - /> - )} - - - )} - orderUpdate.opts.data.orderUpdate.errors - ) - )} - address={transformAddressToForm( - maybe(() => order.shippingAddress) - )} - countries={maybe(() => data.shop.countries, []).map( - country => ({ - code: country.code, - label: country.country + "Order #" + data.order.number)} + /> + + orderAddNote.mutate({ + input: variables, + order: id }) - )} - errors={maybe( - () => orderUpdate.opts.data.orderUpdate.errors, + } + onBack={() => navigate(orderListUrl())} + order={order} + shippingMethods={maybe( + () => data.order.availableShippingMethods, [] )} - open={params.action === "edit-shipping-address"} - variant="shipping" + userPermissions={maybe(() => user.permissions, [])} + onOrderCancel={() => openModal("cancel")} + onOrderFulfill={() => openModal("fulfill")} + onFulfillmentCancel={fulfillmentId => + navigate( + orderUrl(id, { + action: "cancel-fulfillment", + id: fulfillmentId + }) + ) + } + onFulfillmentTrackingNumberUpdate={fulfillmentId => + navigate( + orderUrl(id, { + action: "edit-fulfillment", + id: fulfillmentId + }) + ) + } + onPaymentCapture={() => openModal("capture")} + onPaymentVoid={() => openModal("void")} + onPaymentRefund={() => openModal("refund")} + onProductClick={id => () => + navigate(productUrl(id))} + onBillingAddressEdit={() => + openModal("edit-billing-address") + } + onShippingAddressEdit={() => + openModal("edit-shipping-address") + } + onPaymentPaid={() => openModal("mark-paid")} + onProfileView={() => + navigate(customerUrl(order.user.id)) + } + /> + orderCancel.opts.data.orderCancel.errors + ) + )} + number={maybe(() => order.number)} + open={params.action === "cancel"} onClose={closeModal} - onConfirm={shippingAddress => - orderUpdate.mutate({ + onSubmit={variables => + orderCancel.mutate({ id, - input: { - shippingAddress - } + ...variables }) } /> - orderUpdate.opts.data.orderUpdate.errors + () => + orderPaymentMarkAsPaid.opts.data + .orderMarkAsPaid.errors ) )} - address={transformAddressToForm( - maybe(() => order.billingAddress) - )} - countries={maybe(() => data.shop.countries, []).map( - country => ({ - code: country.code, - label: country.country - }) - )} - errors={maybe( - () => orderUpdate.opts.data.orderUpdate.errors, - [] - )} - open={params.action === "edit-billing-address"} - variant="billing" onClose={closeModal} - onConfirm={billingAddress => - orderUpdate.mutate({ - id, + onConfirm={() => + orderPaymentMarkAsPaid.mutate({ + id + }) + } + open={params.action === "mark-paid"} + /> + orderVoid.opts.data.orderVoid.errors) + )} + open={params.action === "void"} + onClose={closeModal} + onConfirm={() => orderVoid.mutate({ id })} + /> + + orderPaymentCapture.opts.data.orderCapture + .errors + ) + )} + initial={maybe(() => order.total.gross.amount)} + open={params.action === "capture"} + variant="capture" + onClose={closeModal} + onSubmit={variables => + orderPaymentCapture.mutate({ + ...variables, + id + }) + } + /> + + orderPaymentRefund.opts.data.orderRefund + .errors + ) + )} + initial={maybe(() => order.total.gross.amount)} + open={params.action === "refund"} + variant="refund" + onClose={closeModal} + onSubmit={variables => + orderPaymentRefund.mutate({ + ...variables, + id + }) + } + /> + + orderCreateFulfillment.opts.data + .orderFulfillmentCreate.errors + ) + )} + open={params.action === "fulfill"} + lines={maybe(() => order.lines, []).filter( + line => line.quantityFulfilled < line.quantity + )} + onClose={closeModal} + onSubmit={variables => + orderCreateFulfillment.mutate({ input: { - billingAddress + ...variables, + lines: maybe(() => order.lines, []) + .filter( + line => + line.quantityFulfilled < line.quantity + ) + .map((line, lineIndex) => ({ + orderLineId: line.id, + quantity: variables.lines[lineIndex] + })) + .filter(line => line.quantity > 0) + }, + order: order.id + }) + } + /> + + orderFulfillmentCancel.opts.data + .orderFulfillmentCancel.errors + ) + )} + open={params.action === "cancel-fulfillment"} + onConfirm={variables => + orderFulfillmentCancel.mutate({ + id: params.id, + input: variables + }) + } + onClose={closeModal} + /> + + orderFulfillmentUpdateTracking.opts.data + .orderFulfillmentUpdateTracking.errors + ) + )} + open={params.action === "edit-fulfillment"} + trackingNumber={maybe( + () => + data.order.fulfillments.find( + fulfillment => fulfillment.id === params.id + ).trackingNumber + )} + onConfirm={variables => + orderFulfillmentUpdateTracking.mutate({ + id: params.id, + input: { + ...variables, + notifyCustomer: true } }) } + onClose={closeModal} /> - ); - }} - - )} - + ) : ( + <> + "Draft order #" + data.order.number + )} + /> + + orderAddNote.mutate({ + input: variables, + order: id + }) + } + users={maybe( + () => + users.data.search.edges.map(edge => edge.node), + [] + )} + hasMore={maybe( + () => users.data.search.pageInfo.hasNextPage, + false + )} + onFetchMore={loadMoreCustomers} + fetchUsers={searchUsers} + loading={users.loading} + usersLoading={users.loading} + onCustomerEdit={data => + orderDraftUpdate.mutate({ + id, + input: data + }) + } + onDraftFinalize={() => openModal("finalize")} + onDraftRemove={() => openModal("cancel")} + onOrderLineAdd={() => openModal("add-order-line")} + onBack={() => navigate(orderListUrl())} + order={order} + countries={maybe(() => data.shop.countries, []).map( + country => ({ + code: country.code, + label: country.country + }) + )} + onProductClick={id => () => + navigate(productUrl(encodeURIComponent(id)))} + onBillingAddressEdit={() => + openModal("edit-billing-address") + } + onShippingAddressEdit={() => + openModal("edit-shipping-address") + } + onShippingMethodEdit={() => + openModal("edit-shipping") + } + onOrderLineRemove={id => + orderLineDelete.mutate({ id }) + } + onOrderLineChange={(id, data) => + orderLineUpdate.mutate({ + id, + input: data + }) + } + saveButtonBarState="default" + onProfileView={() => + navigate(customerUrl(order.user.id)) + } + userPermissions={maybe(() => user.permissions, [])} + /> + + orderDraftCancel.opts.data.draftOrderDelete + .errors + ) + )} + onClose={closeModal} + onConfirm={() => orderDraftCancel.mutate({ id })} + open={params.action === "cancel"} + orderNumber={maybe(() => order.number)} + /> + orderDraftFinalize.mutate({ id })} + open={params.action === "finalize"} + orderNumber={maybe(() => order.number)} + warnings={orderDraftFinalizeWarnings(order)} + /> + + orderShippingMethodUpdate.opts.data + .orderUpdateShipping.errors + ) + )} + open={params.action === "edit-shipping"} + shippingMethod={maybe( + () => order.shippingMethod.id, + "..." + )} + shippingMethods={maybe( + () => order.availableShippingMethods + )} + onClose={closeModal} + onSubmit={variables => + orderShippingMethodUpdate.mutate({ + id, + input: { + shippingMethod: variables.shippingMethod + } + }) + } + /> + + {({ + 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 + })) + }) + } + /> + )} + + + )} + orderUpdate.opts.data.orderUpdate.errors) + )} + address={transformAddressToForm( + maybe(() => order.shippingAddress) + )} + countries={maybe(() => data.shop.countries, []).map( + country => ({ + code: country.code, + label: country.country + }) + )} + errors={maybe( + () => orderUpdate.opts.data.orderUpdate.errors, + [] + )} + open={params.action === "edit-shipping-address"} + variant="shipping" + onClose={closeModal} + onConfirm={shippingAddress => + orderUpdate.mutate({ + id, + input: { + shippingAddress + } + }) + } + /> + orderUpdate.opts.data.orderUpdate.errors) + )} + address={transformAddressToForm( + maybe(() => order.billingAddress) + )} + countries={maybe(() => data.shop.countries, []).map( + country => ({ + code: country.code, + label: country.country + }) + )} + errors={maybe( + () => orderUpdate.opts.data.orderUpdate.errors, + [] + )} + open={params.action === "edit-billing-address"} + variant="billing" + onClose={closeModal} + onConfirm={billingAddress => + orderUpdate.mutate({ + id, + input: { + billingAddress + } + }) + } + /> + + ); + }} + )} - + ); }} diff --git a/src/containers/SearchCustomers/types/SearchCustomers.ts b/src/searches/types/SearchCustomers.ts similarity index 100% rename from src/containers/SearchCustomers/types/SearchCustomers.ts rename to src/searches/types/SearchCustomers.ts diff --git a/src/containers/SearchCustomers/index.ts b/src/searches/useCustomerSearch.ts similarity index 78% rename from src/containers/SearchCustomers/index.ts rename to src/searches/useCustomerSearch.ts index 0164f7826..bd046f0ab 100644 --- a/src/containers/SearchCustomers/index.ts +++ b/src/searches/useCustomerSearch.ts @@ -1,7 +1,7 @@ import gql from "graphql-tag"; +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import { pageInfoFragment } from "@saleor/queries"; -import TopLevelSearch from "../TopLevelSearch"; import { SearchCustomers, SearchCustomersVariables @@ -24,6 +24,6 @@ export const searchCustomers = gql` } `; -export default TopLevelSearch( +export default makeTopLevelSearch( searchCustomers ); From bd7130d1968503433228b2ea74bfcb10be01fbc8 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 17:40:23 +0100 Subject: [PATCH 07/13] Use page search hook --- .../MenuItemDialog/MenuItemDialog.tsx | 2 +- src/navigation/views/MenuDetails/index.tsx | 501 +++++++++--------- .../types/SearchPages.ts | 0 .../index.tsx => searches/usePageSearch.ts} | 6 +- 4 files changed, 249 insertions(+), 260 deletions(-) rename src/{containers/SearchPages => searches}/types/SearchPages.ts (100%) rename src/{containers/SearchPages/index.tsx => searches/usePageSearch.ts} (76%) diff --git a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx index 5b5620654..44c66ad92 100644 --- a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx +++ b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx @@ -14,13 +14,13 @@ import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import FormSpacer from "@saleor/components/FormSpacer"; -import { SearchPages_search_edges_node } from "@saleor/containers/SearchPages/types/SearchPages"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { buttonMessages, sectionNames } from "@saleor/intl"; import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections"; +import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages"; import { UserError } from "@saleor/types"; import { getErrors, getFieldError } from "@saleor/utils/errors"; import { getMenuItemByValue, IMenu } from "@saleor/utils/menu"; diff --git a/src/navigation/views/MenuDetails/index.tsx b/src/navigation/views/MenuDetails/index.tsx index 227cddf6b..be9d84514 100644 --- a/src/navigation/views/MenuDetails/index.tsx +++ b/src/navigation/views/MenuDetails/index.tsx @@ -7,10 +7,10 @@ import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; +import usePageSearch from "@saleor/searches/usePageSearch"; import { categoryUrl } from "../../../categories/urls"; import { collectionUrl } from "../../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; -import SearchPages from "../../../containers/SearchPages"; import { getMutationState, maybe } from "../../../misc"; import { pageUrl } from "../../../pages/urls"; import MenuDetailsPage, { @@ -65,6 +65,9 @@ const MenuDetails: React.FC = ({ id, params }) => { const collectionSearch = useCollectionSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const pageSearch = usePageSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const closeModal = () => navigate( @@ -101,283 +104,267 @@ const MenuDetails: React.FC = ({ id, params }) => { }; return ( - - {pageSearch => ( - - {({ data, loading, refetch }) => { - const handleQueryChange = (query: string) => { - categorySearch.search(query); - collectionSearch.search(query); - pageSearch.search(query); - }; + + {({ data, loading, refetch }) => { + const handleQueryChange = (query: string) => { + categorySearch.search(query); + collectionSearch.search(query); + pageSearch.search(query); + }; - const categories = maybe( - () => - categorySearch.result.data.search.edges.map(edge => edge.node), - [] - ); + const categories = maybe( + () => categorySearch.result.data.search.edges.map(edge => edge.node), + [] + ); - const collections = maybe( - () => - collectionSearch.result.data.search.edges.map( - edge => edge.node - ), - [] - ); + const collections = maybe( + () => + collectionSearch.result.data.search.edges.map(edge => edge.node), + [] + ); - const pages = maybe( - () => pageSearch.result.data.search.edges.map(edge => edge.node), - [] - ); + const pages = maybe( + () => pageSearch.result.data.search.edges.map(edge => edge.node), + [] + ); - return ( - handleDelete(data, navigate, notify, intl)} + return ( + handleDelete(data, navigate, notify, intl)} + > + {(menuDelete, menuDeleteOpts) => ( + handleUpdate(data, notify, refetch, intl)} > - {(menuDelete, menuDeleteOpts) => ( - - handleUpdate(data, notify, refetch, intl) - } - > - {(menuUpdate, menuUpdateOpts) => { - const deleteState = getMutationState( - menuDeleteOpts.called, - menuDeleteOpts.loading, - maybe(() => menuDeleteOpts.data.menuDelete.errors) - ); + {(menuUpdate, menuUpdateOpts) => { + const deleteState = getMutationState( + menuDeleteOpts.called, + menuDeleteOpts.loading, + maybe(() => menuDeleteOpts.data.menuDelete.errors) + ); - const updateState = getMutationState( - menuUpdateOpts.called, - menuUpdateOpts.loading, - maybe(() => menuUpdateOpts.data.menuUpdate.errors), - maybe(() => menuUpdateOpts.data.menuItemMove.errors) - ); + const updateState = getMutationState( + menuUpdateOpts.called, + menuUpdateOpts.loading, + maybe(() => menuUpdateOpts.data.menuUpdate.errors), + maybe(() => menuUpdateOpts.data.menuItemMove.errors) + ); - // This is a workaround to let know - // that it should clean operation stack if mutations - // were successful - const handleSubmit = async ( - data: MenuDetailsSubmitData - ) => { - try { - const result = await menuUpdate({ - variables: { - id, - moves: getMoves(data), - name: data.name, - removeIds: getRemoveIds(data) - } - }); - if (result) { - if ( - result.data.menuItemBulkDelete.errors.length > - 0 || - result.data.menuItemMove.errors.length > 0 || - result.data.menuUpdate.errors.length > 0 - ) { - return false; - } - } - return true; - } catch { + // This is a workaround to let know + // that it should clean operation stack if mutations + // were successful + const handleSubmit = async (data: MenuDetailsSubmitData) => { + try { + const result = await menuUpdate({ + variables: { + id, + moves: getMoves(data), + name: data.name, + removeIds: getRemoveIds(data) + } + }); + if (result) { + if ( + result.data.menuItemBulkDelete.errors.length > 0 || + result.data.menuItemMove.errors.length > 0 || + result.data.menuUpdate.errors.length > 0 + ) { return false; } - }; + } + return true; + } catch { + return false; + } + }; - return ( - <> - data.menu)} - onBack={() => navigate(menuListUrl())} - onDelete={() => - navigate( - menuUrl(id, { - action: "remove" - }) + return ( + <> + data.menu)} + onBack={() => navigate(menuListUrl())} + onDelete={() => + navigate( + menuUrl(id, { + action: "remove" + }) + ) + } + onItemAdd={() => + navigate( + menuUrl(id, { + action: "add-item" + }) + ) + } + onItemClick={handleItemClick} + onItemEdit={itemId => + navigate( + menuUrl(id, { + action: "edit-item", + id: itemId + }) + ) + } + onSubmit={handleSubmit} + saveButtonState={updateState} + /> + menuDelete({ variables: { id } })} + variant="delete" + title={intl.formatMessage({ + defaultMessage: "Delete Menu", + description: "dialog header", + id: "menuDetailsDeleteMenuHeader" + })} + > + + + {maybe(() => data.menu.name, "...")} + ) - } - onItemAdd={() => - navigate( - menuUrl(id, { - action: "add-item" - }) - ) - } - onItemClick={handleItemClick} - onItemEdit={itemId => - navigate( - menuUrl(id, { - action: "edit-item", - id: itemId - }) - ) - } - onSubmit={handleSubmit} - saveButtonState={updateState} + }} /> - menuDelete({ variables: { id } })} - variant="delete" - title={intl.formatMessage({ - defaultMessage: "Delete Menu", - description: "dialog header", - id: "menuDetailsDeleteMenuHeader" - })} - > - - - {maybe(() => data.menu.name, "...")} - - ) - }} - /> - - + + - - handleItemCreate(data, notify, closeModal, intl) - } - > - {(menuItemCreate, menuItemCreateOpts) => { - const handleSubmit = ( - data: MenuItemDialogFormData - ) => { - const variables: MenuItemCreateVariables = { - input: getMenuItemCreateInputData(id, data) - }; + + handleItemCreate(data, notify, closeModal, intl) + } + > + {(menuItemCreate, menuItemCreateOpts) => { + const handleSubmit = ( + data: MenuItemDialogFormData + ) => { + const variables: MenuItemCreateVariables = { + input: getMenuItemCreateInputData(id, data) + }; - menuItemCreate({ variables }); - }; + menuItemCreate({ variables }); + }; - const formTransitionState = getMutationState( - menuItemCreateOpts.called, - menuItemCreateOpts.loading, - maybe( - () => - menuItemCreateOpts.data.menuItemCreate - .errors - ) - ); + const formTransitionState = getMutationState( + menuItemCreateOpts.called, + menuItemCreateOpts.loading, + maybe( + () => + menuItemCreateOpts.data.menuItemCreate.errors + ) + ); - return ( - - menuItemCreateOpts.data.menuItemCreate - .errors, - [] - )} - pages={pages} - loading={ - categorySearch.result.loading || - collectionSearch.result.loading - } - confirmButtonState={formTransitionState} - disabled={menuItemCreateOpts.loading} - onClose={closeModal} - onSubmit={handleSubmit} - onQueryChange={handleQueryChange} - /> - ); - }} - - - handleItemUpdate(data, id, navigate, notify, intl) - } - > - {(menuItemUpdate, menuItemUpdateOpts) => { - const handleSubmit = ( - data: MenuItemDialogFormData - ) => { - const variables: MenuItemUpdateVariables = { - id: params.id, - input: getMenuItemInputData(data) - }; + return ( + + menuItemCreateOpts.data.menuItemCreate.errors, + [] + )} + pages={pages} + loading={ + categorySearch.result.loading || + collectionSearch.result.loading + } + confirmButtonState={formTransitionState} + disabled={menuItemCreateOpts.loading} + onClose={closeModal} + onSubmit={handleSubmit} + onQueryChange={handleQueryChange} + /> + ); + }} + + + handleItemUpdate(data, id, navigate, notify, intl) + } + > + {(menuItemUpdate, menuItemUpdateOpts) => { + const handleSubmit = ( + data: MenuItemDialogFormData + ) => { + const variables: MenuItemUpdateVariables = { + id: params.id, + input: getMenuItemInputData(data) + }; - menuItemUpdate({ variables }); - }; + menuItemUpdate({ variables }); + }; - const menuItem = maybe(() => - getNode( - data.menu.items, - findNode(data.menu.items, params.id) - ) - ); + const menuItem = maybe(() => + getNode( + data.menu.items, + findNode(data.menu.items, params.id) + ) + ); - const formTransitionState = getMutationState( - menuItemUpdateOpts.called, - menuItemUpdateOpts.loading, - maybe( - () => - menuItemUpdateOpts.data.menuItemUpdate - .errors - ) - ); + const formTransitionState = getMutationState( + menuItemUpdateOpts.called, + menuItemUpdateOpts.loading, + maybe( + () => + menuItemUpdateOpts.data.menuItemUpdate.errors + ) + ); - const initialFormData: MenuItemDialogFormData = { - id: maybe(() => getItemId(menuItem)), - name: maybe(() => menuItem.name, "..."), - type: maybe( - () => getItemType(menuItem), - "category" - ) - }; + const initialFormData: MenuItemDialogFormData = { + id: maybe(() => getItemId(menuItem)), + name: maybe(() => menuItem.name, "..."), + type: maybe( + () => getItemType(menuItem), + "category" + ) + }; - return ( - - menuItemUpdateOpts.data.menuItemUpdate - .errors, - [] - )} - pages={pages} - initial={initialFormData} - initialDisplayValue={getInitialDisplayValue( - menuItem - )} - loading={ - categorySearch.result.loading || - collectionSearch.result.loading - } - confirmButtonState={formTransitionState} - disabled={menuItemUpdateOpts.loading} - onClose={closeModal} - onSubmit={handleSubmit} - onQueryChange={handleQueryChange} - /> - ); - }} - - - ); - }} - - )} - - ); - }} - - )} - + return ( + + menuItemUpdateOpts.data.menuItemUpdate.errors, + [] + )} + pages={pages} + initial={initialFormData} + initialDisplayValue={getInitialDisplayValue( + menuItem + )} + loading={ + categorySearch.result.loading || + collectionSearch.result.loading + } + confirmButtonState={formTransitionState} + disabled={menuItemUpdateOpts.loading} + onClose={closeModal} + onSubmit={handleSubmit} + onQueryChange={handleQueryChange} + /> + ); + }} + + + ); + }} + + )} + + ); + }} + ); }; MenuDetails.displayName = "MenuDetails"; diff --git a/src/containers/SearchPages/types/SearchPages.ts b/src/searches/types/SearchPages.ts similarity index 100% rename from src/containers/SearchPages/types/SearchPages.ts rename to src/searches/types/SearchPages.ts diff --git a/src/containers/SearchPages/index.tsx b/src/searches/usePageSearch.ts similarity index 76% rename from src/containers/SearchPages/index.tsx rename to src/searches/usePageSearch.ts index bd6ce287e..75eebbde0 100644 --- a/src/containers/SearchPages/index.tsx +++ b/src/searches/usePageSearch.ts @@ -1,7 +1,7 @@ import gql from "graphql-tag"; +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import { pageInfoFragment } from "@saleor/queries"; -import TopLevelSearch from "../TopLevelSearch"; import { SearchPages, SearchPagesVariables } from "./types/SearchPages"; export const searchPages = gql` @@ -21,4 +21,6 @@ export const searchPages = gql` } `; -export default TopLevelSearch(searchPages); +export default makeTopLevelSearch( + searchPages +); From fff2a8caeaead86a935c91c9913f548ab7217cf1 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 17:50:40 +0100 Subject: [PATCH 08/13] Use product search hook --- src/collections/views/CollectionDetails.tsx | 45 ++++++------- .../AssignProductDialog.tsx | 2 +- src/discounts/views/SaleDetails.tsx | 67 +++++++++---------- src/discounts/views/VoucherDetails.tsx | 67 +++++++++---------- .../types/SearchProducts.ts | 0 .../useProductSearch.ts} | 4 +- 6 files changed, 89 insertions(+), 96 deletions(-) rename src/{containers/SearchProducts => searches}/types/SearchProducts.ts (100%) rename src/{containers/SearchProducts/index.tsx => searches/useProductSearch.ts} (80%) diff --git a/src/collections/views/CollectionDetails.tsx b/src/collections/views/CollectionDetails.tsx index 6832343bb..0fe3b6da9 100644 --- a/src/collections/views/CollectionDetails.tsx +++ b/src/collections/views/CollectionDetails.tsx @@ -13,8 +13,8 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import { commonMessages } from "@saleor/intl"; +import useProductSearch from "@saleor/searches/useProductSearch"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; -import SearchProducts from "../../containers/SearchProducts"; import { getMutationState, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; import { CollectionInput } from "../../types/globalTypes"; @@ -50,6 +50,9 @@ export const CollectionDetails: React.FC = ({ ); const paginate = usePaginator(); const intl = useIntl(); + const { search, result } = useProductSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const closeModal = () => navigate( @@ -284,29 +287,25 @@ export const CollectionDetails: React.FC = ({ toggle={toggle} toggleAll={toggleAll} /> - - {({ search, result }) => ( - - assignProduct.mutate({ - ...paginationState, - collectionId: id, - productIds: products.map(product => product.id) - }) - } - products={maybe(() => - result.data.search.edges - .map(edge => edge.node) - .filter(suggestedProduct => suggestedProduct.id) - )} - /> + + assignProduct.mutate({ + ...paginationState, + collectionId: id, + productIds: products.map(product => product.id) + }) + } + products={maybe(() => + result.data.search.edges + .map(edge => edge.node) + .filter(suggestedProduct => suggestedProduct.id) )} - + /> = ({ id, params }) => { } = useCollectionSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + search: searchProducts, + result: searchProductsOpts + } = useProductSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: SaleDetailsPageTab) => { @@ -353,42 +359,33 @@ export const SaleDetails: React.FC = ({ id, params }) => { toggle={toggle} toggleAll={toggleAll} /> - - {({ - search: searchProducts, - result: searchProductsOpts - }) => ( - - saleCataloguesAdd({ - variables: { - ...paginationState, - id, - input: { - products: products.map( - product => product.id - ) - } - } - }) - } - products={maybe(() => - searchProductsOpts.data.search.edges - .map(edge => edge.node) - .filter( - suggestedProduct => suggestedProduct.id + + saleCataloguesAdd({ + variables: { + ...paginationState, + id, + input: { + products: products.map( + product => product.id ) - )} - /> + } + } + }) + } + products={maybe(() => + searchProductsOpts.data.search.edges + .map(edge => edge.node) + .filter( + suggestedProduct => suggestedProduct.id + ) )} - + /> searchCategoriesOpts.data.search.edges diff --git a/src/discounts/views/VoucherDetails.tsx b/src/discounts/views/VoucherDetails.tsx index bb37763e8..9d12ea3f0 100644 --- a/src/discounts/views/VoucherDetails.tsx +++ b/src/discounts/views/VoucherDetails.tsx @@ -18,10 +18,10 @@ import useShop from "@saleor/hooks/useShop"; import { commonMessages, sectionNames } from "@saleor/intl"; import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; +import useProductSearch from "@saleor/searches/useProductSearch"; import { categoryUrl } from "../../categories/urls"; import { collectionUrl } from "../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; -import SearchProducts from "../../containers/SearchProducts"; import { decimal, getMutationState, joinDateTime, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; import { @@ -80,6 +80,12 @@ export const VoucherDetails: React.FC = ({ } = useCollectionSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + search: searchProducts, + result: searchProductsOpts + } = useProductSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: VoucherDetailsPageTab) => { @@ -509,42 +515,33 @@ export const VoucherDetails: React.FC = ({ [] )} /> - - {({ - search: searchProducts, - result: searchProductsOpts - }) => ( - - voucherCataloguesAdd({ - variables: { - ...paginationState, - id, - input: { - products: products.map( - product => product.id - ) - } - } - }) - } - products={maybe(() => - searchProductsOpts.data.search.edges - .map(edge => edge.node) - .filter( - suggestedProduct => suggestedProduct.id + + voucherCataloguesAdd({ + variables: { + ...paginationState, + id, + input: { + products: products.map( + product => product.id ) - )} - /> + } + } + }) + } + products={maybe(() => + searchProductsOpts.data.search.edges + .map(edge => edge.node) + .filter( + suggestedProduct => suggestedProduct.id + ) )} - + /> ( +export default makeTopLevelSearch( searchProducts ); From 13a8d398d2295a1dbe33107b3d87944a74bbe174 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 19 Nov 2019 18:00:14 +0100 Subject: [PATCH 09/13] Use product type search hook --- src/productTypes/fixtures.ts | 2 +- .../ProductCreatePage/ProductCreatePage.tsx | 2 +- src/products/utils/data.ts | 2 +- src/products/views/ProductCreate.tsx | 260 +++++++++--------- .../types/SearchProductTypes.ts | 10 +- .../useProductTypeSearch.ts} | 9 +- 6 files changed, 138 insertions(+), 147 deletions(-) rename src/{containers/SearchProductTypes => searches}/types/SearchProductTypes.ts (84%) rename src/{containers/SearchProductTypes/index.tsx => searches/useProductTypeSearch.ts} (82%) diff --git a/src/productTypes/fixtures.ts b/src/productTypes/fixtures.ts index 17ef73a82..ffd35d801 100644 --- a/src/productTypes/fixtures.ts +++ b/src/productTypes/fixtures.ts @@ -1,7 +1,7 @@ import { SearchProductTypes_search_edges_node, SearchProductTypes_search_edges_node_productAttributes -} from "@saleor/containers/SearchProductTypes/types/SearchProductTypes"; +} from "@saleor/searches/types/SearchProductTypes"; import { AttributeInputTypeEnum } from "../types/globalTypes"; import { ProductTypeDetails_productType } from "./types/ProductTypeDetails"; import { ProductTypeList_productTypes_edges_node } from "./types/ProductTypeList"; diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index be5bd60a2..af5293613 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -13,7 +13,6 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/containers/SearchProductTypes/types/SearchProductTypes"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useFormset from "@saleor/hooks/useFormset"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; @@ -25,6 +24,7 @@ import { } from "@saleor/products/utils/data"; import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections"; +import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/searches/types/SearchProductTypes"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { FetchMoreProps, UserError } from "../../../types"; diff --git a/src/products/utils/data.ts b/src/products/utils/data.ts index 4c3a2eec6..fd4abe9cf 100644 --- a/src/products/utils/data.ts +++ b/src/products/utils/data.ts @@ -2,13 +2,13 @@ import { RawDraftContentState } from "draft-js"; import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; -import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/containers/SearchProductTypes/types/SearchProductTypes"; import { maybe } from "@saleor/misc"; import { ProductDetails_product, ProductDetails_product_collections, ProductDetails_product_variants } from "@saleor/products/types/ProductDetails"; +import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/searches/types/SearchProductTypes"; import { ProductAttributeInput } from "../components/ProductAttributes"; import { VariantAttributeInput } from "../components/ProductVariantAttributes"; import { ProductVariant } from "../types/ProductVariant"; diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index 7c4dafa80..aec0d7120 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -2,12 +2,12 @@ import React from "react"; import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; -import SearchProductTypes from "@saleor/containers/SearchProductTypes"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; +import useProductTypeSearch from "@saleor/searches/useProductTypeSearch"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../config"; import { decimal, getMutationState, maybe } from "../../misc"; import ProductCreatePage, { @@ -40,152 +40,138 @@ export const ProductUpdate: React.FC = () => { } = useCollectionSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + loadMore: loadMoreProductTypes, + search: searchProductTypes, + result: searchProductTypesOpts + } = useProductTypeSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const handleBack = () => navigate(productListUrl()); + const handleSuccess = (data: ProductCreate) => { + if (data.productCreate.errors.length === 0) { + notify({ + text: intl.formatMessage({ + defaultMessage: "Product created" + }) + }); + navigate(productUrl(data.productCreate.product.id)); + } else { + const attributeError = data.productCreate.errors.find( + err => err.field === "attributes" + ); + if (!!attributeError) { + notify({ text: attributeError.message }); + } + } + }; + return ( - - {({ - loadMore: loadMoreProductTypes, - search: searchProductTypes, - result: searchProductTypesOpts - }) => { - const handleSuccess = (data: ProductCreate) => { - if (data.productCreate.errors.length === 0) { - notify({ - text: intl.formatMessage({ - defaultMessage: "Product created" - }) - }); - navigate(productUrl(data.productCreate.product.id)); - } else { - const attributeError = data.productCreate.errors.find( - err => err.field === "attributes" - ); - if (!!attributeError) { - notify({ text: attributeError.message }); + + {( + productCreate, + { + called: productCreateCalled, + data: productCreateData, + loading: productCreateDataLoading + } + ) => { + const handleSubmit = (formData: ProductCreatePageSubmitData) => { + productCreate({ + variables: { + attributes: formData.attributes.map(attribute => ({ + id: attribute.id, + values: attribute.value + })), + basePrice: decimal(formData.basePrice), + category: formData.category, + chargeTaxes: formData.chargeTaxes, + collections: formData.collections, + descriptionJson: JSON.stringify(formData.description), + isPublished: formData.isPublished, + name: formData.name, + productType: formData.productType, + publicationDate: + formData.publicationDate !== "" + ? formData.publicationDate + : null, + seo: { + description: formData.seoDescription, + title: formData.seoTitle + }, + sku: formData.sku, + stockQuantity: + formData.stockQuantity !== null ? formData.stockQuantity : 0 } - } + }); }; + const formTransitionState = getMutationState( + productCreateCalled, + productCreateDataLoading, + maybe(() => productCreateData.productCreate.errors) + ); return ( - - {( - productCreate, - { - called: productCreateCalled, - data: productCreateData, - loading: productCreateDataLoading - } - ) => { - const handleSubmit = (formData: ProductCreatePageSubmitData) => { - productCreate({ - variables: { - attributes: formData.attributes.map(attribute => ({ - id: attribute.id, - values: attribute.value - })), - basePrice: decimal(formData.basePrice), - category: formData.category, - chargeTaxes: formData.chargeTaxes, - collections: formData.collections, - descriptionJson: JSON.stringify(formData.description), - isPublished: formData.isPublished, - name: formData.name, - productType: formData.productType, - publicationDate: - formData.publicationDate !== "" - ? formData.publicationDate - : null, - seo: { - description: formData.seoDescription, - title: formData.seoTitle - }, - sku: formData.sku, - stockQuantity: - formData.stockQuantity !== null - ? formData.stockQuantity - : 0 - } - }); - }; - - const formTransitionState = getMutationState( - productCreateCalled, - productCreateDataLoading, - maybe(() => productCreateData.productCreate.errors) - ); - return ( - <> - - shop.defaultCurrency)} - categories={maybe( - () => searchCategoryOpts.data.search.edges, - [] - ).map(edge => edge.node)} - collections={maybe( - () => searchCollectionOpts.data.search.edges, - [] - ).map(edge => edge.node)} - disabled={productCreateDataLoading} - errors={maybe( - () => productCreateData.productCreate.errors, - [] - )} - fetchCategories={searchCategory} - fetchCollections={searchCollection} - fetchProductTypes={searchProductTypes} - header={intl.formatMessage({ - defaultMessage: "New Product", - description: "page header" - })} - productTypes={maybe(() => - searchProductTypesOpts.data.search.edges.map( - edge => edge.node - ) - )} - onBack={handleBack} - onSubmit={handleSubmit} - saveButtonBarState={formTransitionState} - fetchMoreCategories={{ - hasMore: maybe( - () => - searchCategoryOpts.data.search.pageInfo.hasNextPage - ), - loading: searchCategoryOpts.loading, - onFetchMore: loadMoreCategories - }} - fetchMoreCollections={{ - hasMore: maybe( - () => - searchCollectionOpts.data.search.pageInfo.hasNextPage - ), - loading: searchCollectionOpts.loading, - onFetchMore: loadMoreCollections - }} - fetchMoreProductTypes={{ - hasMore: maybe( - () => - searchProductTypesOpts.data.search.pageInfo - .hasNextPage - ), - loading: searchProductTypesOpts.loading, - onFetchMore: loadMoreProductTypes - }} - /> - - ); - }} - + <> + + shop.defaultCurrency)} + categories={maybe( + () => searchCategoryOpts.data.search.edges, + [] + ).map(edge => edge.node)} + collections={maybe( + () => searchCollectionOpts.data.search.edges, + [] + ).map(edge => edge.node)} + disabled={productCreateDataLoading} + errors={maybe(() => productCreateData.productCreate.errors, [])} + fetchCategories={searchCategory} + fetchCollections={searchCollection} + fetchProductTypes={searchProductTypes} + header={intl.formatMessage({ + defaultMessage: "New Product", + description: "page header" + })} + productTypes={maybe(() => + searchProductTypesOpts.data.search.edges.map(edge => edge.node) + )} + onBack={handleBack} + onSubmit={handleSubmit} + saveButtonBarState={formTransitionState} + fetchMoreCategories={{ + hasMore: maybe( + () => searchCategoryOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCategoryOpts.loading, + onFetchMore: loadMoreCategories + }} + fetchMoreCollections={{ + hasMore: maybe( + () => searchCollectionOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCollectionOpts.loading, + onFetchMore: loadMoreCollections + }} + fetchMoreProductTypes={{ + hasMore: maybe( + () => searchProductTypesOpts.data.search.pageInfo.hasNextPage + ), + loading: searchProductTypesOpts.loading, + onFetchMore: loadMoreProductTypes + }} + /> + ); }} - + ); }; export default ProductUpdate; diff --git a/src/containers/SearchProductTypes/types/SearchProductTypes.ts b/src/searches/types/SearchProductTypes.ts similarity index 84% rename from src/containers/SearchProductTypes/types/SearchProductTypes.ts rename to src/searches/types/SearchProductTypes.ts index 2aaf2fe5e..300ebc329 100644 --- a/src/containers/SearchProductTypes/types/SearchProductTypes.ts +++ b/src/searches/types/SearchProductTypes.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { AttributeInputTypeEnum } from "./../../../types/globalTypes"; +import { AttributeInputTypeEnum } from "./../../types/globalTypes"; // ==================================================== // GraphQL query operation: SearchProductTypes @@ -22,7 +22,9 @@ export interface SearchProductTypes_search_edges_node_productAttributes { slug: string | null; name: string | null; valueRequired: boolean; - values: (SearchProductTypes_search_edges_node_productAttributes_values | null)[] | null; + values: + | (SearchProductTypes_search_edges_node_productAttributes_values | null)[] + | null; } export interface SearchProductTypes_search_edges_node { @@ -30,7 +32,9 @@ export interface SearchProductTypes_search_edges_node { id: string; name: string; hasVariants: boolean; - productAttributes: (SearchProductTypes_search_edges_node_productAttributes | null)[] | null; + productAttributes: + | (SearchProductTypes_search_edges_node_productAttributes | null)[] + | null; } export interface SearchProductTypes_search_edges { diff --git a/src/containers/SearchProductTypes/index.tsx b/src/searches/useProductTypeSearch.ts similarity index 82% rename from src/containers/SearchProductTypes/index.tsx rename to src/searches/useProductTypeSearch.ts index 6adf1ef5a..60517f670 100644 --- a/src/containers/SearchProductTypes/index.tsx +++ b/src/searches/useProductTypeSearch.ts @@ -1,7 +1,7 @@ import gql from "graphql-tag"; +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import { pageInfoFragment } from "@saleor/queries"; -import TopLevelSearch from "../TopLevelSearch"; import { SearchProductTypes, SearchProductTypesVariables @@ -41,6 +41,7 @@ export const searchProductTypes = gql` } `; -export default TopLevelSearch( - searchProductTypes -); +export default makeTopLevelSearch< + SearchProductTypes, + SearchProductTypesVariables +>(searchProductTypes); From 135658eb11c691d47fdf7f3b5e193731ad289bd1 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 20 Nov 2019 11:24:42 +0100 Subject: [PATCH 10/13] 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, "...")} From 080eb0748a019e582379a81fcf9237fbe89e693b Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 20 Nov 2019 11:36:20 +0100 Subject: [PATCH 11/13] Update snapshots --- src/storybook/__snapshots__/Stories.test.ts.snap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 21cc3a558..9c231db02 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -125505,6 +125505,7 @@ exports[`Storyshots Views / Webhooks / Create webhook default 1`] = ` class="MuiInputBase-input-id MuiOutlinedInput-input-id" name="name" type="text" + value="" />