From fa8231992f00405e194f266f58bedfa9ec94b375 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 20 Feb 2020 15:18:22 +0100 Subject: [PATCH] Explicitely return not found page --- babel.config.js | 3 +- package-lock.json | 35 ++++ package.json | 1 + src/categories/views/CategoryDetails.tsx | 8 +- .../views/CategoryList/CategoryList.tsx | 1 - src/collections/views/CollectionDetails.tsx | 10 +- src/components/AppLayout/AppLayout.tsx | 15 +- src/containers/AppState/AppState.tsx | 2 +- src/containers/AppState/state.ts | 2 +- src/customers/views/CustomerDetails.tsx | 176 +++++++++--------- src/hooks/makeQuery.ts | 22 +-- src/misc.ts | 4 + src/orders/views/OrderDetails/index.tsx | 18 +- .../views/ProductTypeUpdate/index.tsx | 17 +- src/products/views/ProductImage.tsx | 133 +++++++------ .../views/ProductUpdate/ProductUpdate.tsx | 20 +- src/products/views/ProductVariant.tsx | 26 ++- src/products/views/ProductVariantCreate.tsx | 15 +- src/queries.tsx | 20 +- .../views/ServiceDetails/ServiceDetails.tsx | 17 +- src/staff/views/StaffDetails.tsx | 22 ++- src/webhooks/views/WebhooksDetails.tsx | 38 ++-- 22 files changed, 337 insertions(+), 268 deletions(-) diff --git a/babel.config.js b/babel.config.js index 21951c808..c149a757e 100644 --- a/babel.config.js +++ b/babel.config.js @@ -23,6 +23,7 @@ module.exports = api => { const plugins = [ "@babel/plugin-proposal-numeric-separator", + "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-class-properties", [ "@babel/plugin-proposal-decorators", @@ -49,6 +50,6 @@ module.exports = api => { return { ignore, plugins, - presets, + presets }; }; diff --git a/package-lock.json b/package-lock.json index adf3c4aaf..4281d5478 100644 --- a/package-lock.json +++ b/package-lock.json @@ -849,6 +849,24 @@ "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" } }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz", + "integrity": "sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } + } + }, "@babel/plugin-proposal-unicode-property-regex": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.0.tgz", @@ -940,6 +958,23 @@ "@babel/helper-plugin-utils": "^7.0.0" } }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } + } + }, "@babel/plugin-syntax-top-level-await": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.0.tgz", diff --git a/package.json b/package.json index 543245d3f..9d119e7db 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "@babel/plugin-proposal-decorators": "^7.4.4", "@babel/plugin-proposal-numeric-separator": "^7.2.0", "@babel/plugin-proposal-object-rest-spread": "^7.5.4", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", "@babel/preset-env": "^7.5.4", "@babel/preset-react": "^7.7.4", "@babel/preset-typescript": "^7.7.4", diff --git a/src/categories/views/CategoryDetails.tsx b/src/categories/views/CategoryDetails.tsx index 3a6966ca0..9d20b5224 100644 --- a/src/categories/views/CategoryDetails.tsx +++ b/src/categories/views/CategoryDetails.tsx @@ -14,6 +14,7 @@ import usePaginator, { } from "@saleor/hooks/usePaginator"; import { commonMessages } from "@saleor/intl"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import { PAGINATE_BY } from "../../config"; import { maybe } from "../../misc"; import { TypedProductBulkDeleteMutation } from "../../products/mutations"; @@ -67,10 +68,15 @@ export const CategoryDetails: React.FC = ({ const paginationState = createPaginationState(PAGINATE_BY, params); const { data, loading, refetch } = useCategoryDetailsQuery({ displayLoader: true, - require: ["category"], variables: { ...paginationState, id } }); + const category = data?.category; + + if (category === null) { + return navigate(categoryListUrl())} />; + } + const handleCategoryDelete = (data: CategoryDelete) => { if (data.categoryDelete.errors.length === 0) { notify({ diff --git a/src/categories/views/CategoryList/CategoryList.tsx b/src/categories/views/CategoryList/CategoryList.tsx index d7b2d3f05..5363e67a8 100644 --- a/src/categories/views/CategoryList/CategoryList.tsx +++ b/src/categories/views/CategoryList/CategoryList.tsx @@ -68,7 +68,6 @@ export const CategoryList: React.FC = ({ params }) => { ); const { data, loading, refetch } = useRootCategoriesQuery({ displayLoader: true, - require: ["categories"], variables: queryVariables }); diff --git a/src/collections/views/CollectionDetails.tsx b/src/collections/views/CollectionDetails.tsx index 4161c96aa..37f272098 100644 --- a/src/collections/views/CollectionDetails.tsx +++ b/src/collections/views/CollectionDetails.tsx @@ -16,6 +16,7 @@ import usePaginator, { import { commonMessages } from "@saleor/intl"; import useProductSearch from "@saleor/searches/useProductSearch"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import { getMutationState, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; import { CollectionInput } from "../../types/globalTypes"; @@ -61,14 +62,19 @@ export const CollectionDetails: React.FC = ({ >(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 handleCollectionUpdate = (data: CollectionUpdate) => { if (data.collectionUpdate.errors.length === 0) { notify({ @@ -196,7 +202,7 @@ export const CollectionDetails: React.FC = ({ data.collection.name)} /> openModal("assign")} - onBack={() => navigate(collectionListUrl())} + onBack={handleBack} disabled={loading} collection={maybe(() => data.collection)} isFeatured={maybe( diff --git a/src/components/AppLayout/AppLayout.tsx b/src/components/AppLayout/AppLayout.tsx index 1db6cb01c..4b7dc68e5 100644 --- a/src/components/AppLayout/AppLayout.tsx +++ b/src/components/AppLayout/AppLayout.tsx @@ -29,7 +29,6 @@ import { maybe } from "@saleor/misc"; import { staffMemberDetailsUrl } from "@saleor/staff/urls"; import Container from "../Container"; import ErrorPage from "../ErrorPage"; -import NotFoundPage from "../NotFoundPage"; import AppActionContext from "./AppActionContext"; import AppHeaderContext from "./AppHeaderContext"; import { appLoaderHeight, drawerWidth, drawerWidthExpanded } from "./consts"; @@ -507,15 +506,11 @@ const AppLayout: React.FC = ({ children }) => {
- {appState.error ? ( - appState.error === "not-found" ? ( - - ) : ( - - ) - ) : ( - children - )} + {appState.error + ? appState.error === "unhandled" && ( + + ) + : children}
diff --git a/src/containers/AppState/AppState.tsx b/src/containers/AppState/AppState.tsx index 9f3b5a2cc..a8d3238e8 100644 --- a/src/containers/AppState/AppState.tsx +++ b/src/containers/AppState/AppState.tsx @@ -21,7 +21,7 @@ const AppStateProvider: React.FC = ({ children }) => { if (!!state.error) { dispatch({ payload: { - error: null + error: undefined }, type: "displayError" }); diff --git a/src/containers/AppState/state.ts b/src/containers/AppState/state.ts index efea07b71..efa2daa86 100644 --- a/src/containers/AppState/state.ts +++ b/src/containers/AppState/state.ts @@ -1,4 +1,4 @@ -export type AppError = "unhandled" | "not-found"; +export type AppError = "unhandled"; interface IAppState { error: AppError | null; diff --git a/src/customers/views/CustomerDetails.tsx b/src/customers/views/CustomerDetails.tsx index d2269f8fc..08d1533f7 100644 --- a/src/customers/views/CustomerDetails.tsx +++ b/src/customers/views/CustomerDetails.tsx @@ -7,6 +7,7 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import { maybe } from "../../misc"; import { orderListUrl, orderUrl } from "../../orders/urls"; import CustomerDetailsPage from "../components/CustomerDetailsPage/CustomerDetailsPage"; @@ -54,6 +55,9 @@ export const CustomerDetailsView: React.FC = ({ navigate(customerListUrl()); } }; + + const handleBack = () => navigate(customerListUrl()); + return ( = ({ {(removeCustomer, removeCustomerOpts) => ( {(updateCustomer, updateCustomerOpts) => ( - - {customerDetails => ( - <> - customerDetails.data.user.email)} - /> - customerDetails.data.user)} - disabled={ - customerDetails.loading || - updateCustomerOpts.loading || - removeCustomerOpts.loading - } - errors={maybe( - () => updateCustomerOpts.data.customerUpdate.errors - )} - saveButtonBar={updateCustomerOpts.status} - onAddressManageClick={() => - navigate(customerAddressesUrl(id)) - } - onBack={() => navigate(customerListUrl())} - onRowClick={id => navigate(orderUrl(id))} - onSubmit={formData => - updateCustomer({ - variables: { - id, - input: { - email: formData.email, - firstName: formData.firstName, - isActive: formData.isActive, - lastName: formData.lastName, - note: formData.note + + {customerDetails => { + const user = customerDetails.data?.user; + + if (user === null) { + return ; + } + + return ( + <> + customerDetails.data.user.email)} + /> + customerDetails.data.user)} + disabled={ + customerDetails.loading || + updateCustomerOpts.loading || + removeCustomerOpts.loading + } + errors={maybe( + () => updateCustomerOpts.data.customerUpdate.errors + )} + saveButtonBar={updateCustomerOpts.status} + onAddressManageClick={() => + navigate(customerAddressesUrl(id)) + } + onBack={handleBack} + onRowClick={id => navigate(orderUrl(id))} + onSubmit={formData => + updateCustomer({ + variables: { + id, + input: { + email: formData.email, + firstName: formData.firstName, + isActive: formData.isActive, + lastName: formData.lastName, + note: formData.note + } } - } - }) - } - onDelete={() => - navigate( - customerUrl(id, { - action: "remove" }) - ) - } - onViewAllOrdersClick={() => - navigate( - orderListUrl({ - customer: maybe(() => customerDetails.data.user.email) - }) - ) - } - /> - navigate(customerUrl(id), true)} - onConfirm={() => removeCustomer()} - title={intl.formatMessage({ - defaultMessage: "Delete Customer", - description: "dialog header" - })} - variant="delete" - open={params.action === "remove"} - > - - - {maybe( - () => customerDetails.data.user.email, - "..." - )} - - ) - }} - /> - - - - )} + } + onDelete={() => + navigate( + customerUrl(id, { + action: "remove" + }) + ) + } + onViewAllOrdersClick={() => + navigate( + orderListUrl({ + customer: maybe( + () => customerDetails.data.user.email + ) + }) + ) + } + /> + navigate(customerUrl(id), true)} + onConfirm={() => removeCustomer()} + title={intl.formatMessage({ + defaultMessage: "Delete Customer", + description: "dialog header" + })} + variant="delete" + open={params.action === "remove"} + > + + + {maybe( + () => customerDetails.data.user.email, + "..." + )} + + ) + }} + /> + + + + ); + }} )} diff --git a/src/hooks/makeQuery.ts b/src/hooks/makeQuery.ts index 6aa28b7a5..3cc28a19b 100644 --- a/src/hooks/makeQuery.ts +++ b/src/hooks/makeQuery.ts @@ -18,14 +18,13 @@ export interface LoadMore { export type UseQueryResult = QueryResult & LoadMore; -type UseQueryOpts = Partial<{ +type UseQueryOpts = Partial<{ displayLoader: boolean; - require: Array; skip: boolean; variables: TVariables; }>; type UseQueryHook = ( - opts: UseQueryOpts + opts: UseQueryOpts ) => UseQueryResult; function makeQuery( @@ -33,10 +32,9 @@ function makeQuery( ): UseQueryHook { function useQuery({ displayLoader, - require, skip, variables - }: UseQueryOpts): UseQueryResult { + }: UseQueryOpts): UseQueryResult { const notify = useNotifier(); const intl = useIntl(); const [, dispatchAppState] = useAppState(); @@ -89,20 +87,6 @@ function makeQuery( variables: { ...variables, ...extraVariables } }); - if ( - !queryData.loading && - require && - queryData.data && - !require.reduce((acc, key) => acc && queryData.data[key] !== null, true) - ) { - dispatchAppState({ - payload: { - error: "not-found" - }, - type: "displayError" - }); - } - return { ...queryData, loadMore diff --git a/src/misc.ts b/src/misc.ts index 5672298d9..4742424a9 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -380,3 +380,7 @@ export function transformFormToAddress( country: findInEnum(address.country, CountryCode) }; } + +export function getStringOrPlaceholder(s: string | undefined): string { + return s || "..."; +} diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index b5ee407d8..a0d86fb10 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -6,6 +6,7 @@ import useNavigator from "@saleor/hooks/useNavigator"; import useUser from "@saleor/hooks/useUser"; import useCustomerSearch from "@saleor/searches/useCustomerSearch"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import { customerUrl } from "../../../customers/urls"; import { getMutationState, maybe, transformAddressToForm } from "../../../misc"; import { productUrl } from "../../../products/urls"; @@ -90,14 +91,17 @@ export const OrderDetails: React.FC = ({ id, params }) => { variables: DEFAULT_INITIAL_SEARCH_DATA }); + const handleBack = () => navigate(orderListUrl()); + return ( - + {({ data, loading }) => { - const order = maybe(() => data.order); + const order = data?.order; + + if (order === null) { + return ; + } + const [openModal, closeModal] = createDialogActionHandlers< OrderUrlDialog, OrderUrlQueryParams @@ -166,7 +170,7 @@ export const OrderDetails: React.FC = ({ id, params }) => { order: id }) } - onBack={() => navigate(orderListUrl())} + onBack={handleBack} order={order} shippingMethods={maybe( () => data.order.availableShippingMethods, diff --git a/src/productTypes/views/ProductTypeUpdate/index.tsx b/src/productTypes/views/ProductTypeUpdate/index.tsx index 1f40c0a6f..492320261 100644 --- a/src/productTypes/views/ProductTypeUpdate/index.tsx +++ b/src/productTypes/views/ProductTypeUpdate/index.tsx @@ -13,6 +13,7 @@ import { maybe } from "@saleor/misc"; import AssignAttributeDialog from "@saleor/productTypes/components/AssignAttributeDialog"; import { ReorderEvent } from "@saleor/types"; import { AttributeTypeEnum } from "@saleor/types/globalTypes"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import ProductTypeAttributeUnassignDialog from "../../components/ProductTypeAttributeUnassignDialog"; import ProductTypeBulkAttributeUnassignDialog from "../../components/ProductTypeBulkAttributeUnassignDialog"; import ProductTypeDeleteDialog from "../../components/ProductTypeDeleteDialog"; @@ -54,15 +55,19 @@ export const ProductTypeUpdate: React.FC = ({ } }); + const handleBack = () => navigate(productTypeListUrl()); + return ( {({ errors, set: setErrors }) => ( - + {({ data, loading: dataLoading }) => { + const productType = data?.productType; + + if (productType === null) { + return ; + } + const closeModal = () => navigate(productTypeUrl(id), true); const handleAttributeAssignSuccess = (data: AssignAttribute) => { @@ -242,7 +247,7 @@ export const ProductTypeUpdate: React.FC = ({ }) ) } - onBack={() => navigate(productTypeListUrl())} + onBack={handleBack} onDelete={() => navigate( productTypeUrl(id, { diff --git a/src/products/views/ProductImage.tsx b/src/products/views/ProductImage.tsx index a89328949..48f49cfca 100644 --- a/src/products/views/ProductImage.tsx +++ b/src/products/views/ProductImage.tsx @@ -5,6 +5,7 @@ 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 NotFoundPage from "@saleor/components/NotFoundPage"; import { maybe } from "../../misc"; import ProductImagePage from "../components/ProductImagePage"; import { @@ -16,7 +17,8 @@ import { ProductImageUpdate } from "../types/ProductImageUpdate"; import { productImageUrl, ProductImageUrlQueryParams, - productUrl + productUrl, + productListUrl } from "../urls"; interface ProductImageProps { @@ -47,70 +49,77 @@ export const ProductImage: React.FC = ({ imageId, productId }} - require={["product"]} > - {({ data, loading }) => ( - - {(updateImage, updateResult) => ( - - {(deleteImage, deleteResult) => { - const handleDelete = () => - deleteImage({ variables: { id: imageId } }); - const handleImageClick = (id: string) => () => - navigate(productImageUrl(productId, id)); - const handleUpdate = (formData: { description: string }) => { - updateImage({ - variables: { - alt: formData.description, - id: imageId - } - }); - }; - const image = data && data.product && data.product.mainImage; + {({ data, loading }) => { + const product = data?.product; - return ( - <> - data.product.name)} - image={image || null} - images={maybe(() => data.product.images)} - onBack={handleBack} - onDelete={() => - navigate( - productImageUrl(productId, imageId, { - action: "remove" - }) - ) + if (product === null) { + return navigate(productListUrl())} />; + } + + return ( + + {(updateImage, updateResult) => ( + + {(deleteImage, deleteResult) => { + const handleDelete = () => + deleteImage({ variables: { id: imageId } }); + const handleImageClick = (id: string) => () => + navigate(productImageUrl(productId, id)); + const handleUpdate = (formData: { description: string }) => { + updateImage({ + variables: { + alt: formData.description, + id: imageId } - onRowClick={handleImageClick} - onSubmit={handleUpdate} - saveButtonBarState={updateResult.status} - /> - - navigate(productImageUrl(productId, imageId), true) - } - onConfirm={handleDelete} - open={params.action === "remove"} - title={intl.formatMessage({ - defaultMessage: "Delete Image", - description: "dialog header" - })} - variant="delete" - confirmButtonState={deleteResult.status} - > - - - - - - ); - }} - - )} - - )} + }); + }; + const image = data && data.product && data.product.mainImage; + + return ( + <> + data.product.name)} + image={image || null} + images={maybe(() => data.product.images)} + onBack={handleBack} + onDelete={() => + navigate( + productImageUrl(productId, imageId, { + action: "remove" + }) + ) + } + onRowClick={handleImageClick} + onSubmit={handleUpdate} + saveButtonBarState={updateResult.status} + /> + + navigate(productImageUrl(productId, imageId), true) + } + onConfirm={handleDelete} + open={params.action === "remove"} + title={intl.formatMessage({ + defaultMessage: "Delete Image", + description: "dialog header" + })} + variant="delete" + confirmButtonState={deleteResult.status} + > + + + + + + ); + }} + + )} + + ); + }} ); }; diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 1c68bfd3d..aee72a004 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -18,6 +18,7 @@ import { ProductVariantBulkCreate } from "@saleor/products/types/ProductVariantB import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import { getMutationState, maybe } from "../../../misc"; import ProductUpdatePage from "../../components/ProductUpdatePage"; import ProductUpdateOperations from "../../containers/ProductUpdateOperations"; @@ -76,13 +77,17 @@ export const ProductUpdate: React.FC = ({ id, params }) => { ProductUrlQueryParams >(navigate, params => productUrl(id, params), params); + const handleBack = () => navigate(productListUrl()); + return ( - + {({ data, loading, refetch }) => { + const product = data?.product; + + if (product === null) { + return ; + } + const handleDelete = () => { notify({ text: intl.formatMessage({ @@ -142,7 +147,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { } }; - const product = data ? data.product : undefined; return ( = ({ id, params }) => { placeholderImage={placeholderImg} product={product} variants={maybe(() => product.variants)} - onBack={() => { - navigate(productListUrl()); - }} + onBack={handleBack} onDelete={() => openModal("remove")} onProductShow={() => { if (product) { diff --git a/src/products/views/ProductVariant.tsx b/src/products/views/ProductVariant.tsx index 9a84078f5..4163cb982 100644 --- a/src/products/views/ProductVariant.tsx +++ b/src/products/views/ProductVariant.tsx @@ -6,6 +6,7 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import { decimal, maybe } from "../../misc"; import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog"; import ProductVariantPage, { @@ -13,7 +14,10 @@ import ProductVariantPage, { } from "../components/ProductVariantPage"; import ProductVariantOperations from "../containers/ProductVariantOperations"; import { TypedProductVariantQuery } from "../queries"; -import { VariantUpdate } from "../types/VariantUpdate"; +import { + VariantUpdate, + VariantUpdate_productVariantUpdate_productErrors +} from "../types/VariantUpdate"; import { productUrl, productVariantAddUrl, @@ -35,20 +39,24 @@ export const ProductVariant: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); - const [errors, setErrors] = useState([]); + const [errors, setErrors] = useState< + VariantUpdate_productVariantUpdate_productErrors[] + >([]); useEffect(() => { setErrors([]); }, [variantId]); + const handleBack = () => navigate(productUrl(productId)); + return ( - + {({ data, loading }) => { - const variant = data ? data.productVariant : undefined; - const handleBack = () => navigate(productUrl(productId)); + const variant = data?.productVariant; + + if (variant === null) { + return ; + } + const handleDelete = () => { notify({ text: intl.formatMessage({ diff --git a/src/products/views/ProductVariantCreate.tsx b/src/products/views/ProductVariantCreate.tsx index 03dc559d1..888ad7d79 100644 --- a/src/products/views/ProductVariantCreate.tsx +++ b/src/products/views/ProductVariantCreate.tsx @@ -5,6 +5,7 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; +import NotFoundPage from "@saleor/components/NotFoundPage"; import { decimal, maybe } from "../../misc"; import ProductVariantCreatePage, { ProductVariantCreatePageSubmitData @@ -12,7 +13,7 @@ import ProductVariantCreatePage, { import { TypedVariantCreateMutation } from "../mutations"; import { TypedProductVariantCreateQuery } from "../queries"; import { VariantCreate } from "../types/VariantCreate"; -import { productUrl, productVariantEditUrl } from "../urls"; +import { productUrl, productVariantEditUrl, productListUrl } from "../urls"; interface ProductUpdateProps { productId: string; @@ -25,12 +26,14 @@ export const ProductVariant: React.FC = ({ productId }) => { const intl = useIntl(); return ( - + {({ data, loading: productLoading }) => { + const product = data?.product; + + if (product === null) { + return navigate(productListUrl())} />; + } + const handleCreateSuccess = (data: VariantCreate) => { if (data.productVariantCreate.productErrors.length === 0) { notify({ diff --git a/src/queries.tsx b/src/queries.tsx index 1428f5db4..abe3e8bc0 100644 --- a/src/queries.tsx +++ b/src/queries.tsx @@ -28,7 +28,6 @@ export interface TypedQueryInnerProps { displayLoader?: boolean; skip?: boolean; variables?: TVariables; - require?: Array; } interface QueryProgressProps { @@ -65,7 +64,7 @@ class QueryProgress extends React.Component { export function TypedQuery( query: DocumentNode ): React.FC> { - return ({ children, displayLoader, skip, variables, require }) => { + return ({ children, displayLoader, skip, variables }) => { const pushMessage = useNotifier(); const [, dispatchAppState] = useAppState(); const intl = useIntl(); @@ -112,23 +111,6 @@ export function TypedQuery( variables: { ...variables, ...extraVariables } }); - if ( - !queryData.loading && - require && - queryData.data && - !require.reduce( - (acc, key) => acc && queryData.data[key] !== null, - true - ) - ) { - dispatchAppState({ - payload: { - error: "not-found" - }, - type: "displayError" - }); - } - if (displayLoader) { return ( = ({ const handleBack = () => navigate(serviceListUrl()); return ( - + {({ data, loading, refetch }) => { + const service = data?.serviceAccount; + + if (service === null) { + return ; + } + const onTokenCreate = (data: ServiceTokenCreate) => { if (maybe(() => data.serviceAccountTokenCreate.errors.length === 0)) { refetch(); @@ -151,9 +154,7 @@ export const ServiceDetails: React.FC = ({ return ( <> - data.serviceAccount.name)} - /> + = ({ id, params }) => { onCompleted: handleChangePassword }); + const handleBack = () => navigate(staffListUrl()); + return ( - + {({ data, loading }) => { + const staffMember = data?.user; + + if (staffMember === null) { + return ; + } + const handleStaffMemberUpdate = (data: StaffMemberUpdate) => { if (!maybe(() => data.staffUpdate.errors.length !== 0)) { notify({ @@ -100,6 +105,7 @@ export const StaffDetails: React.FC = ({ id, params }) => { navigate(staffMemberDetailsUrl(id)); } }; + return ( {(updateStaffMember, updateResult) => ( @@ -124,7 +130,7 @@ export const StaffDetails: React.FC = ({ id, params }) => { return ( <> data.user.email)} + title={staffMember?.email || "..."} /> = ({ id, params }) => { canEditStatus={!isUserSameAsViewer} canRemove={!isUserSameAsViewer} disabled={loading} - onBack={() => navigate(staffListUrl())} + onBack={handleBack} onChangePassword={() => navigate( staffMemberDetailsUrl(id, { @@ -176,7 +182,7 @@ export const StaffDetails: React.FC = ({ id, params }) => { ) } permissions={maybe(() => shop.permissions)} - staffMember={maybe(() => data.user)} + staffMember={staffMember} saveButtonBarState={updateResult.status} /> = ({ >(navigate, params => webhookUrl(id, params), params); const onWebhookDelete = (data: WebhookDelete) => { - if (data.webhookDelete.errors.length === 0) { + if (data.webhookDelete?.errors.length === 0) { notify({ text: intl.formatMessage(commonMessages.savedChanges) }); @@ -57,14 +58,19 @@ export const WebhooksDetails: React.FC = ({ }; const onWebhookUpdate = (data: WebhookUpdate) => { - if (data.webhookUpdate.webhookErrors.length === 0) { + const errors = data.webhookUpdate?.webhookErrors; + const webhook = data.webhookUpdate?.webhook; + + if (errors.length === 0 && webhook) { notify({ text: intl.formatMessage(commonMessages.savedChanges) }); - navigate(webhookUrl(data.webhookUpdate.webhook.id)); + navigate(webhookUrl(webhook.id)); } }; + const handleOnBack = () => navigate(webhookListUrl()); + return ( {(webhookUpdate, webhookUpdateOpts) => ( @@ -79,28 +85,33 @@ export const WebhooksDetails: React.FC = ({ } }); - const formErrors = maybe( - () => webhookUpdateOpts.data.webhookUpdate.webhookErrors, - [] - ); + const webhook = webhookDetails?.data?.webhook; + const formErrors = + webhookUpdateOpts.data?.webhookUpdate.webhookErrors || []; + + if (webhook === null) { + return ; + } return ( <> webhookDetails.data.webhook.name)} + title={getStringOrPlaceholder( + webhookDetails?.data?.webhook?.name + )} /> webhookDetails.data.webhook)} + webhook={webhook} fetchServiceAccounts={searchServiceAccount} services={maybe(() => searchServiceAccountOpt.data.search.edges.map( edge => edge.node ) )} - onBack={() => navigate(webhookListUrl())} + onBack={handleOnBack} onDelete={() => openModal("remove")} onSubmit={data => { webhookUpdate({ @@ -122,10 +133,7 @@ export const WebhooksDetails: React.FC = ({ /> webhookDetails.data.webhook.name, - "..." - )} + name={getStringOrPlaceholder(webhook?.name)} onClose={closeModal} onConfirm={handleRemoveConfirm} open={params.action === "remove"}