Created
April 29, 2019 06:07
-
-
Save tanvirraj/30e45f41e1ade8b96ec367d514036f9c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import React, { PureComponent } from "react"; | |
import styles from "./MerchantCatalogScreen.module.scss"; | |
import { connect } from "react-redux"; | |
import { List, Modal, message } from "antd"; | |
import { select } from "../../../../store/store"; | |
import { withNamespaces } from "react-i18next"; | |
import BrowserMeta, { | |
Themes | |
} from "../../../../components/BrowserMeta/BrowserMeta"; | |
import BreadcrumbNavigation from "../../../../components/BreadcrumbNavigation/BreadcrumbNavigation"; | |
import { ROUTES } from "../../../../screens/Router/Router.config"; | |
import { formatRoute } from "react-router-named-routes"; | |
import { ConfirmationModal } from "../../../../components/Modal/Modal"; | |
import DashboardContainer from "../../../../components/DashboardContainer/DashboardContainer"; | |
import EmptyState from "../../../../components/EmptyState/EmptyState"; | |
import SidePanelContentLayout from "../../../../layouts/SidePanelContentLayout/SidePanelContentLayout"; | |
import CatalogActionButtons from "./components/CatalogActionButtons/CatalogActionButtons"; | |
import CatalogSideMenu from "../../../../components/CatalogSideMenu/CatalogSideMenu"; | |
import CatalogHeader from "../../../../components/CatalogHeader/CatalogHeader"; | |
import CatalogItemCard from "../../../../components/CatalogItemCard/CatalogItemCard"; | |
import ItemFormSidebar from "../../../../components/ItemFormSidebar/ItemFormSidebar"; | |
import ItemCopySidebar, { | |
type ItemCopySidebarDataType | |
} from "./components/ItemCopySidebar/ItemCopySidebar"; | |
import ConfirmationMessage from "../../../../components/ConfirmationMessage/ConfirmationMessage"; | |
import MIcon from "@mdi/react"; | |
import { mdiFileDocumentBoxMultiple } from "@mdi/js"; | |
import { PRIVATE_ROUTER } from "../../../Router/Router.config"; | |
import { | |
MerchantError, | |
MerchantConstants | |
} from "../../../../utils/merchantConst"; | |
import { ItemParentType, CatalogStatus } from "../../../../utils/catalogConst"; | |
import { type TranslateType } from "../../../../types/types"; | |
import { type RouterMatchType } from "../../../../types/types"; | |
import { type MerchantType } from "../../../../types/merchantType"; | |
import { type CatalogType } from "../../../../types/catalogType"; | |
import { type CategoryType } from "../../../../types/catalogType"; | |
import { type ItemType } from "../../../../types/catalogType"; | |
type Props = { | |
/** redux: merchant */ | |
merchant: MerchantType, | |
/** redux: catalog */ | |
catalog: CatalogType, | |
/** redux: selected content */ | |
selectedContent: CatalogType | CategoryType, | |
/** redux: fetch merchant catalog from API */ | |
getCatalog: Function, | |
/** redux: fetch active catalog for a merchant */ | |
getActiveCatalog: Function, | |
/** redux: fetch merchant from API */ | |
getMerchantById: Function, | |
/** redux: Create item */ | |
createItem: Function, | |
/** redux: Edit item */ | |
editItem: Function, | |
/** redux: Delete item */ | |
deleteItem: Function, | |
/** redux: Copy item */ | |
copyItemToCategory: Function, | |
/** redux: Update item status */ | |
updateItemStatus: Function, | |
/** redux: loading fetch from API */ | |
loading: boolean, | |
/** router: url parameter */ | |
match: RouterMatchType, | |
/** router: current url */ | |
location: any, | |
/** router: router history */ | |
history: any, | |
/** redux: catalog error*/ | |
error: string | |
} & TranslateType; | |
type State = { | |
itemDisabledModalVisible: boolean, | |
itemCopySidebarVisible: boolean, | |
showItemFormSidebar: boolean, | |
showConfirmationMessage: boolean, | |
targetCategoryName: string, | |
selectedItem: ?ItemType | |
}; | |
/** | |
* Merchant Catalog | |
*/ | |
class MerchantCatalogScreen extends PureComponent<Props, State> { | |
state = { | |
itemDisabledModalVisible: false, | |
itemCopySidebarVisible: false, | |
showConfirmationMessage: false, | |
showItemFormSidebar: false, | |
targetCategoryName: "", | |
selectedItem: null | |
}; | |
componentDidMount() { | |
const { match, getCatalog, getActiveCatalog, getMerchantById } = this.props; | |
const { params } = match; | |
// Get the merchant and catalog id from the url id parameter | |
const merchantId = params.id; | |
const catalogId = params.catalogId; | |
// When there is no catalog id, fetch the active catalog for the merchant | |
if (catalogId == null) { | |
// TODO: Remove when catalogId available in merchant | |
getActiveCatalog(merchantId); | |
} else if (merchantId && catalogId) { | |
// Fetch merchant's catalog on first load | |
getCatalog(merchantId, catalogId); | |
} | |
if (merchantId) { | |
getMerchantById(merchantId); | |
} | |
} | |
componentDidUpdate(prevProps) { | |
const { match, history, catalog, error } = this.props; | |
const { params } = match; | |
const merchantId = params.id; | |
const catalogId = params.catalogId; | |
if (error && error === MerchantError.NO_CATALOG && !prevProps.error) { | |
Modal.error({ | |
title: "No active catalog found for the merchant", | |
onOk: () => { | |
history.replace(PRIVATE_ROUTER.ACCOUNT_MANAGER_DASHBOARD.path); | |
} | |
}); | |
} | |
// When there is no catalog id in the url, but a catalog id has been fetched | |
if ( | |
(catalogId == null && catalog.id) || | |
(catalog.id && catalog.id !== prevProps.catalog.id) | |
) { | |
// TODO: Remove when catalog id always exist for a merchant | |
// Replace route to add the fetched catalog id to the url | |
const newRoute = formatRoute(PRIVATE_ROUTER.MERCHANT_CATALOG.path, { | |
id: merchantId, | |
catalogId: catalog.id | |
}); | |
history.replace(newRoute); | |
} | |
} | |
// Open sidebars and set/remove selected item | |
openSidebar = (stateKey: string, selectedItem?: ItemType) => { | |
this.setState({ | |
[stateKey]: true, | |
selectedItem: selectedItem, | |
showConfirmationMessage: false | |
}); | |
}; | |
getCurrentCategoryInfo = () => { | |
const { selectedContent, catalog } = this.props; | |
let parentInfo = {}; | |
let categoryId = null; | |
let subCategoryId = null; | |
if (!selectedContent.id || selectedContent.merchant_id) { | |
// catalog | |
parentInfo.parentId = catalog.id; | |
parentInfo.parentType = ItemParentType.CATALOG; | |
} else { | |
// category | |
parentInfo.parentId = selectedContent.id; | |
parentInfo.parentType = ItemParentType.CATEGORY; | |
if (selectedContent.parent_id) { | |
categoryId = selectedContent.parent_id; | |
subCategoryId = selectedContent.id; | |
} else categoryId = selectedContent.id; | |
} | |
return { categoryId, subCategoryId }; | |
}; | |
// Submit new or edited item from sidebar | |
onItemSubmit = (item: ItemType) => { | |
const { selectedContent, catalog, createItem, editItem } = this.props; | |
const { selectedItem } = this.state; | |
let parentInfo = {}; | |
let categoryId = null; | |
let subCategoryId = null; | |
if (!selectedContent.id || selectedContent.merchant_id) { | |
// catalog | |
parentInfo.parentId = catalog.id; | |
parentInfo.parentType = ItemParentType.CATALOG; | |
} else { | |
// category | |
parentInfo.parentId = selectedContent.id; | |
parentInfo.parentType = ItemParentType.CATEGORY; | |
if (selectedContent.parent_id) { | |
categoryId = selectedContent.parent_id; | |
subCategoryId = selectedContent.id; | |
} else categoryId = selectedContent.id; | |
} | |
if (item.id) | |
editItem( | |
catalog.id, | |
{ | |
...item, | |
parent_item_id: selectedItem && selectedItem.parent_item_id, | |
global_item_id: item.id //TODO: Add this global_item_id conditionally | |
}, | |
categoryId, | |
subCategoryId | |
); | |
else { | |
createItem( | |
catalog.id, | |
{ ...item, ...parentInfo }, | |
categoryId, | |
subCategoryId | |
); | |
} | |
this.resetSidebars(); | |
}; | |
// Item is confirmed to be deleted | |
onItemDelete = (item: ItemType) => { | |
const { catalog, deleteItem, selectedContent } = this.props; | |
let categoryId = null; | |
let subCategoryId = null; | |
if (!selectedContent.merchant_id) { | |
if (selectedContent.parent_id) { | |
categoryId = selectedContent.parent_id; | |
subCategoryId = selectedContent.id; | |
} else categoryId = selectedContent.id; | |
} | |
deleteItem( | |
catalog.id, | |
item.id, | |
item.parent_item_id, | |
categoryId, | |
subCategoryId | |
); | |
this.resetSidebars(); | |
}; | |
// Item is confirmed to be copied | |
onItemCopy = (data: ItemCopySidebarDataType) => { | |
const { catalog, copyItemToCategory } = this.props; | |
const { selectedItem } = this.state; | |
let targetCategoryName = ""; | |
const foundCategory = catalog.categories.find( | |
c => c.id === data.categoryId | |
); | |
if (!!foundCategory) { | |
if (data.subCategoryId) { | |
const foundSubCategory = | |
foundCategory.sub_categories && | |
foundCategory.sub_categories.find( | |
subcat => subcat.id === data.subCategoryId | |
); | |
if (foundSubCategory) targetCategoryName = foundSubCategory.name; | |
} else targetCategoryName = foundCategory.name; | |
} | |
const categoryId = data.subCategoryId || data.categoryId; | |
if (selectedItem) | |
copyItemToCategory( | |
catalog.id, | |
selectedItem.parent_item_id, | |
categoryId | |
).then(success => { | |
if (success) { | |
this.setState({ | |
showConfirmationMessage: true, | |
targetCategoryName | |
}); | |
} else { | |
message.error("Copy Item Failed!"); | |
} | |
}); | |
this.setState({ | |
itemCopySidebarVisible: false | |
}); | |
}; | |
// Change status of item | |
onItemChangeStatus = (item: ItemType, status: boolean) => { | |
// User needs to confirm when disabling item | |
// show confirmation modal | |
if (status === false) { | |
this.openSidebar("itemDisabledModalVisible", item); | |
} else { | |
const { updateItemStatus, catalog } = this.props; | |
const { categoryId, subCategoryId } = this.getCurrentCategoryInfo(); | |
if (item) { | |
const itemStatusEnabled = 1; | |
updateItemStatus( | |
catalog.id, | |
categoryId, | |
subCategoryId, | |
item.parent_item_id, | |
itemStatusEnabled | |
); | |
} | |
} | |
}; | |
// Item is confirmed to be disabled | |
onItemDisabledConfirm = () => { | |
const { selectedItem } = this.state; | |
const { updateItemStatus, catalog } = this.props; | |
const { categoryId, subCategoryId } = this.getCurrentCategoryInfo(); | |
if (selectedItem) { | |
const itemStatusDisabled = 0; | |
updateItemStatus( | |
catalog.id, | |
categoryId, | |
subCategoryId, | |
selectedItem.parent_item_id, | |
itemStatusDisabled | |
); | |
} | |
this.resetSidebars(); | |
}; | |
// Close all sidebars and reset selected item | |
resetSidebars = () => { | |
this.setState({ | |
showItemFormSidebar: false, | |
itemCopySidebarVisible: false, | |
itemDisabledModalVisible: false, | |
showConfirmationMessage: false, | |
selectedItem: null | |
}); | |
}; | |
render() { | |
const { t, selectedContent, merchant, catalog } = this.props; | |
const { | |
itemDisabledModalVisible, | |
itemCopySidebarVisible, | |
showItemFormSidebar, | |
showConfirmationMessage, | |
targetCategoryName, | |
selectedItem | |
} = this.state; | |
return ( | |
<> | |
<BrowserMeta | |
title={t("merchantCatalog.title")} | |
theme={Themes.INTERNAL} | |
/> | |
{showConfirmationMessage && selectedItem && ( | |
<ConfirmationMessage | |
onClose={this.resetSidebars} | |
type="success" | |
message={t( | |
`'${ | |
selectedItem.name_localized | |
}' was copied to ${targetCategoryName} successfully` | |
)} | |
/> | |
)} | |
{merchant && ( | |
<BreadcrumbNavigation | |
showSeparatorAfterLastItem | |
breadcrumbs={[ | |
{ | |
label: t("default.breadcrumbHome"), | |
link: ROUTES.ACCOUNT_MANAGER_DASHBOARD.path | |
}, | |
{ | |
label: merchant.name, | |
link: formatRoute(ROUTES.MERCHANT_PROFILE.path, { | |
id: merchant.id | |
}) | |
} | |
]} | |
/> | |
)} | |
<DashboardContainer | |
title={catalog.name} | |
actions={ | |
merchant && | |
catalog && ( | |
<CatalogActionButtons catalog={catalog} merchant={merchant} /> | |
) | |
} | |
> | |
<SidePanelContentLayout | |
sidePanel={ | |
<CatalogSideMenu | |
onClickNewItem={() => this.openSidebar("showItemFormSidebar")} | |
/> | |
} | |
header={ | |
<CatalogHeader | |
title={ | |
selectedContent.merchant_id | |
? t("merchantCatalog.itemsLabel") | |
: selectedContent.name_localized | |
} | |
onClickNewItem={() => this.openSidebar("showItemFormSidebar")} | |
/> | |
} | |
> | |
<List | |
dataSource={selectedContent.items} | |
renderItem={(item, index) => ( | |
<CatalogItemCard | |
id={item.parent_item_id} | |
image={item.image} | |
name={item.name_localized} | |
price={item.price} | |
active={ | |
item.parent_status_id === CatalogStatus.ACTIVE && | |
item.status_id === CatalogStatus.ACTIVE | |
} | |
itemDisabled={ | |
item.parent_status_id === CatalogStatus.OFFLINE || | |
item.parent_status_id === CatalogStatus.INACTIVE | |
} | |
currency={item.currency} | |
onEdit={() => this.openSidebar("showItemFormSidebar", item)} | |
onDuplicate={() => | |
this.openSidebar("itemCopySidebarVisible", item) | |
} | |
onChangeStatus={status => | |
this.onItemChangeStatus(item, status) | |
} | |
/> | |
)} | |
locale={{ | |
emptyText: ( | |
<EmptyState | |
icon={ | |
<MIcon | |
color="currentColor" | |
path={mdiFileDocumentBoxMultiple} | |
size={"100px"} | |
/> | |
} | |
className={styles.emptyItemContainer} | |
text={t("merchantCatalog.emptyStateText")} | |
/> | |
) | |
}} | |
/> | |
</SidePanelContentLayout> | |
</DashboardContainer> | |
{/* Disable item for today (or indefinitely) */} | |
<ConfirmationModal | |
visible={itemDisabledModalVisible} | |
title={t("merchantCatalog.confirmationDisableItemTitle")} | |
body={t("merchantCatalog.confirmationDisableItemText")} | |
checkboxLabel={t( | |
"merchantCatalog.confirmationDisableItemCheckboxLabel" | |
)} | |
onConfirm={this.onItemDisabledConfirm} | |
onClose={this.resetSidebars} | |
/> | |
{/* Create or Edit Item sidebar */} | |
{merchant && ( | |
<ItemFormSidebar | |
visible={showItemFormSidebar} | |
currency={ | |
merchant.currency | |
? merchant.currency.code | |
: MerchantConstants.DEFAULT_CURRENCY.code | |
} | |
data={selectedItem} | |
onSubmit={this.onItemSubmit} | |
onDelete={this.onItemDelete} | |
onClose={this.resetSidebars} | |
/> | |
)} | |
{/* Copy Item sidebar */} | |
<ItemCopySidebar | |
visible={itemCopySidebarVisible} | |
categories={catalog.categories} | |
item={selectedItem} | |
onSubmit={item => this.onItemCopy(item)} | |
onClose={this.resetSidebars} | |
/> | |
</> | |
); | |
} | |
} | |
const selection = select(state => ({ | |
merchant: state.merchantModel.merchant | |
})); | |
const mapState = (state, ownProps) => ({ | |
catalog: state.catalogModel.catalog, | |
selectedContent: state.catalogModel.selectedContent, | |
loading: state.catalogModel.loading, | |
error: state.catalogModel.error, | |
...selection(state, ownProps) | |
}); | |
const mapDispatch = dispatch => ({ | |
getActiveCatalog: merchantId => | |
dispatch.catalogModel.getActiveCatalog({ merchantId }), | |
getCatalog: (merchantId, catalogId) => | |
dispatch.catalogModel.getCatalog({ merchantId, catalogId }), | |
getMerchantById: merchantId => | |
dispatch.merchantModel.getMerchantById({ merchantId }), | |
createItem: (catalogId, item, categoryId, subCategoryId) => | |
dispatch.catalogModel.createItem({ | |
catalogId, | |
item, | |
categoryId, | |
subCategoryId | |
}), | |
editItem: (catalogId, item, categoryId, subCategoryId) => | |
dispatch.catalogModel.editItem({ | |
catalogId, | |
item, | |
categoryId, | |
subCategoryId | |
}), | |
deleteItem: (catalogId, itemId, parentItemId, categoryId, subCategoryId) => | |
dispatch.catalogModel.deleteItem({ | |
catalogId, | |
itemId, | |
parentItemId, | |
categoryId, | |
subCategoryId | |
}), | |
copyItemToCategory: (catalogId, itemId, categoryId) => | |
dispatch.catalogModel.copyItemToCategory({ | |
catalogId, | |
itemId, | |
categoryId | |
}), | |
updateItemStatus: ( | |
catalogId, | |
categoryId, | |
subCategoryId, | |
itemParentId, | |
status | |
) => | |
dispatch.catalogModel.updateItemStatus({ | |
catalogId, | |
categoryId, | |
subCategoryId, | |
itemParentId, | |
status | |
}) | |
}); | |
export default withNamespaces()( | |
connect( | |
mapState, | |
mapDispatch | |
)(MerchantCatalogScreen) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment