import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField, Typography } from "@material-ui/core"; import AutocompleteSelectMenu from "@saleor/components/AutocompleteSelectMenu"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import FormSpacer from "@saleor/components/FormSpacer"; import { MenuErrorFragment } from "@saleor/fragments/types/MenuErrorFragment"; 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 { getFieldError, getFormErrors } from "@saleor/utils/errors"; import getMenuErrorMessage from "@saleor/utils/errors/menu"; import { getMenuItemByValue, IMenu } from "@saleor/utils/menu"; import isUrl from "is-url"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; export type MenuItemType = "category" | "collection" | "link" | "page"; export interface MenuItemData { id: string; type: MenuItemType; } export interface MenuItemDialogFormData extends MenuItemData { name: string; } export interface MenuItemDialogProps { confirmButtonState: ConfirmButtonTransitionState; disabled: boolean; errors: MenuErrorFragment[]; initial?: MenuItemDialogFormData; initialDisplayValue?: string; loading: boolean; open: boolean; collections: SearchCollections_search_edges_node[]; categories: SearchCategories_search_edges_node[]; pages: SearchPages_search_edges_node[]; onClose: () => void; onSubmit: (data: MenuItemDialogFormData) => void; onQueryChange: (query: string) => void; } const defaultInitial: MenuItemDialogFormData = { id: "", name: "", type: "category" }; function getMenuItemData(value: string): MenuItemData { const [type, ...idParts] = value.split(":"); return { id: idParts.join(":"), type: type as MenuItemType }; } function getDisplayValue(menu: IMenu, value: string): string { const menuItemData = getMenuItemData(value); if (menuItemData.type === "link") { return menuItemData.id; } return getMenuItemByValue(menu, value).label.toString(); } const MenuItemDialog: React.FC = ({ confirmButtonState, disabled, errors: apiErrors, initial, initialDisplayValue, loading, onClose, onSubmit, onQueryChange, open, categories, collections, pages }) => { const intl = useIntl(); const errors = useModalDialogErrors(apiErrors, open); const [displayValue, setDisplayValue] = React.useState( initialDisplayValue || "" ); const [data, setData] = useStateFromProps( initial || defaultInitial ); const [url, setUrl] = React.useState(undefined); // Reset input state after closing dialog useModalDialogOpen(open, { onClose: () => { setData(initial || defaultInitial); setDisplayValue(initialDisplayValue); setUrl(undefined); } }); // Refresh initial display value if changed React.useEffect(() => setDisplayValue(initialDisplayValue), [ initialDisplayValue ]); const mutationErrors = errors.filter(err => err.field === null); const formErrors = getFormErrors(["name"], errors); const testIds = ["category", "collection", "page", "url"]; const idError = ["category", "collection", "page", "url"] .map(field => getFieldError(errors, field)) .reduce((acc, err) => acc || err); let options: IMenu = []; if (categories.length > 0) { options = [ ...options, { children: categories.map(category => ({ children: [], data: {}, label: category.name, value: "category:" + category.id })), data: {}, label: intl.formatMessage(sectionNames.categories) } ]; } if (collections.length > 0) { options = [ ...options, { children: collections.map(collection => ({ children: [], data: {}, label: collection.name, value: "collection:" + collection.id })), data: {}, label: intl.formatMessage(sectionNames.collections) } ]; } if (pages.length > 0) { options = [ ...options, { children: pages.map(page => ({ children: [], data: {}, label: page.title, value: "page:" + page.id })), data: {}, label: intl.formatMessage(sectionNames.pages) } ]; } if (url) { options = [ { children: [], data: {}, label: ( {url} }} /> ), value: "link:" + url } ]; } const handleQueryChange = (query: string) => { if (isUrl(query)) { setUrl(query); } else if (isUrl("http://" + query)) { setUrl("http://" + query); } else if (url) { setUrl(undefined); } onQueryChange(query); }; const handleSelectChange = (event: React.ChangeEvent) => { const value = event.target.value; const menuItemData = getMenuItemData(value); setData(value => ({ ...value, ...menuItemData })); setDisplayValue(getDisplayValue(options, value)); }; const handleSubmit = () => onSubmit(data); return ( {!!initial ? intl.formatMessage({ defaultMessage: "Edit Item", description: "edit menu item, header", id: "menuItemDialogEditItem" }) : intl.formatMessage({ defaultMessage: "Add Item", description: "create new menu item, header", id: "menuItemDialogAddItem" })} setData(value => ({ ...value, name: event.target.value })) } name="name" error={!!formErrors.name} helperText={getMenuErrorMessage(formErrors.name, intl)} /> {mutationErrors.length > 0 && ( <> {mutationErrors.map(err => ( {getMenuErrorMessage(err, intl)} ))} )} ); }; MenuItemDialog.displayName = "MenuItemDialog"; export default MenuItemDialog;