import Button from "@material-ui/core/Button"; import DialogContentText from "@material-ui/core/DialogContentText"; import ActionDialog from "@saleor/components/ActionDialog"; import AssignProductDialog from "@saleor/components/AssignProductDialog"; import NotFoundPage from "@saleor/components/NotFoundPage"; import { WindowTitle } from "@saleor/components/WindowTitle"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "@saleor/config"; import useBulkActions from "@saleor/hooks/useBulkActions"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import { commonMessages } from "@saleor/intl"; import useProductSearch from "@saleor/searches/useProductSearch"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler"; import { useMetadataUpdate, usePrivateMetadataUpdate } from "@saleor/utils/metadata/updateMetadata"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { getMutationState, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; import { CollectionInput } from "../../types/globalTypes"; import CollectionDetailsPage from "../components/CollectionDetailsPage/CollectionDetailsPage"; import { CollectionUpdateData } from "../components/CollectionDetailsPage/form"; import { useCollectionAssignProductMutation, useCollectionRemoveMutation, useCollectionUpdateMutation, useCollectionUpdateWithHomepageMutation, useUnassignCollectionProductMutation } from "../mutations"; import { TypedCollectionDetailsQuery } from "../queries"; import { CollectionUpdate } from "../types/CollectionUpdate"; import { collectionListUrl, collectionUrl, CollectionUrlDialog, CollectionUrlQueryParams } from "../urls"; interface CollectionDetailsProps { id: string; params: CollectionUrlQueryParams; } export const CollectionDetails: React.FC = ({ id, params }) => { const navigate = useNavigator(); const notify = useNotifier(); const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( params.ids ); const paginate = usePaginator(); const intl = useIntl(); const { search, loadMore, result } = useProductSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); const [updateMetadata] = useMetadataUpdate({}); const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const handleCollectionUpdate = (data: CollectionUpdate) => { if (data.collectionUpdate.errors.length === 0) { notify({ status: "success", text: intl.formatMessage(commonMessages.savedChanges) }); navigate(collectionUrl(id)); } else { const backgroundImageError = data.collectionUpdate.errors.find( error => error.field === ("backgroundImage" as keyof CollectionInput) ); if (backgroundImageError) { notify({ status: "error", text: intl.formatMessage(commonMessages.somethingWentWrong) }); } } }; const [updateCollection, updateCollectionOpts] = useCollectionUpdateMutation({ onCompleted: handleCollectionUpdate }); const [ updateCollectionWithHomepage, updateCollectionWithHomepageOpts ] = useCollectionUpdateWithHomepageMutation({ onCompleted: data => { if (data.homepageCollectionUpdate.errors.length === 0) { handleCollectionUpdate(data); } } }); const [assignProduct, assignProductOpts] = useCollectionAssignProductMutation( { onCompleted: data => { if (data.collectionAddProducts.errors.length === 0) { notify({ status: "success", text: intl.formatMessage({ defaultMessage: "Added product to collection" }) }); navigate(collectionUrl(id), true); } } } ); const [ unassignProduct, unassignProductOpts ] = useUnassignCollectionProductMutation({ onCompleted: data => { if (data.collectionRemoveProducts.errors.length === 0) { notify({ status: "success", text: intl.formatMessage({ defaultMessage: "Deleted product from collection" }) }); reset(); closeModal(); } } }); const [removeCollection, removeCollectionOpts] = useCollectionRemoveMutation({ onCompleted: data => { if (data.collectionDelete.errors.length === 0) { notify({ status: "success", text: intl.formatMessage({ defaultMessage: "Deleted collection" }) }); navigate(collectionListUrl()); } } }); const [openModal, closeModal] = createDialogActionHandlers< CollectionUrlDialog, CollectionUrlQueryParams >(navigate, params => collectionUrl(id, params), params); const paginationState = createPaginationState(PAGINATE_BY, params); const handleBack = () => navigate(collectionListUrl()); return ( {({ data, loading }) => { const collection = data?.collection; if (collection === null) { return ; } const handleUpdate = async (formData: CollectionUpdateData) => { const input: CollectionInput = { backgroundImageAlt: formData.backgroundImageAlt, descriptionJson: JSON.stringify(formData.description), isPublished: formData.isPublished, name: formData.name, publicationDate: formData.publicationDate, seo: { description: formData.seoDescription, title: formData.seoTitle }, slug: formData.slug }; const isFeatured = data.shop.homepageCollection ? data.shop.homepageCollection.id === data.collection.id : false; if (formData.isFeatured !== isFeatured) { const result = await updateCollectionWithHomepage({ variables: { homepageId: formData.isFeatured ? id : null, id, input } }); return [ ...result.data.collectionUpdate.errors, ...result.data.homepageCollectionUpdate.errors ]; } else { const result = await updateCollection({ variables: { id, input } }); return result.data.collectionUpdate.errors; } }; const handleSubmit = createMetadataUpdateHandler( data?.collection, handleUpdate, variables => updateMetadata({ variables }), variables => updatePrivateMetadata({ variables }) ); const formTransitionState = getMutationState( updateCollectionOpts.called || updateCollectionWithHomepageOpts.called, updateCollectionOpts.loading || updateCollectionWithHomepageOpts.loading, updateCollectionOpts.data?.collectionUpdate.errors, updateCollectionWithHomepageOpts.data?.collectionUpdate.errors, updateCollectionWithHomepageOpts.data?.homepageCollectionUpdate.errors ); const { loadNextPage, loadPreviousPage, pageInfo } = paginate( data?.collection?.products?.pageInfo, paginationState, params ); return ( <> data.collection.name)} /> openModal("assign")} onBack={handleBack} disabled={loading} collection={data?.collection} errors={updateCollectionOpts?.data?.collectionUpdate.errors || []} isFeatured={maybe( () => data.shop.homepageCollection.id === data.collection.id, false )} onCollectionRemove={() => openModal("remove")} onImageDelete={() => openModal("removeImage")} onImageUpload={file => updateCollection({ variables: { id, input: { backgroundImage: file } } }) } onSubmit={handleSubmit} onNextPage={loadNextPage} onPreviousPage={loadPreviousPage} pageInfo={pageInfo} onProductUnassign={(productId, event) => { event.stopPropagation(); unassignProduct({ variables: { collectionId: id, productIds: [productId], ...paginationState } }); }} onRowClick={id => () => navigate(productUrl(id))} saveButtonBarState={formTransitionState} toolbar={ } isChecked={isSelected} selected={listElements.length} toggle={toggle} toggleAll={toggleAll} /> assignProduct({ variables: { ...paginationState, collectionId: id, productIds: products.map(product => product.id) } }) } products={maybe(() => result.data.search.edges .map(edge => edge.node) .filter(suggestedProduct => suggestedProduct.id) )} /> removeCollection({ variables: { id } }) } open={params.action === "remove"} title={intl.formatMessage({ defaultMessage: "Delete Collection", description: "dialog title" })} variant="delete" > {maybe(() => data.collection.name, "...")} ) }} /> unassignProduct({ variables: { ...paginationState, collectionId: id, productIds: params.ids } }) } open={params.action === "unassign"} title={intl.formatMessage({ defaultMessage: "Unassign products from collection", description: "dialog title" })} > params.ids.length), displayQuantity: ( {maybe(() => params.ids.length)} ) }} /> updateCollection({ variables: { id, input: { backgroundImage: null } } }) } open={params.action === "removeImage"} title={intl.formatMessage({ defaultMessage: "Delete image", description: "dialog title" })} variant="delete" > ); }} ); }; export default CollectionDetails;