diff --git a/imports/plugins/core/ui-navbar/client/components/brand.js b/imports/plugins/core/ui-navbar/client/components/brand.js deleted file mode 100644 index 038f52ddfd..0000000000 --- a/imports/plugins/core/ui-navbar/client/components/brand.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import { registerComponent } from "@reactioncommerce/reaction-components"; -import { Reaction } from "/client/api"; - -class Brand extends Component { - static propTypes = { - logo: PropTypes.string, - title: PropTypes.string - } - - handleClick = (event) => { - event.preventDefault(); - Reaction.Router.go("/"); - } - - render() { - const { logo, title } = this.props; - - return ( - - {this.props.logo && -
- {title} -
- } - {title} -
- ); - } -} - -registerComponent("Brand", Brand); - -export default Brand; diff --git a/imports/plugins/core/ui-navbar/client/components/navbar.js b/imports/plugins/core/ui-navbar/client/components/navbar.js deleted file mode 100644 index 54640921a7..0000000000 --- a/imports/plugins/core/ui-navbar/client/components/navbar.js +++ /dev/null @@ -1,137 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import { Components } from "@reactioncommerce/reaction-components"; - -class NavBar extends Component { - static propTypes = { - brandMedia: PropTypes.object, - hasProperPermission: PropTypes.bool, - searchEnabled: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - shop: PropTypes.object.isRequired, - visibility: PropTypes.object.isRequired - }; - - static defaultProps = { - visibility: { - hamburger: true, - brand: true, - tags: true, - search: true, - notifications: true, - languages: true, - currency: true, - mainDropdown: true - } - }; - - state = { - navBarVisible: false, - searchModalOpen: false - } - - toggleNavbarVisibility = () => { - const isVisible = this.state.navBarVisible; - this.setState({ navBarVisible: !isVisible }); - } - - handleCloseNavbar = () => { - this.setState({ navBarVisible: false }); - } - - handleOpenSearchModal = () => { - this.setState({ searchModalOpen: true }); - } - - handleCloseSearchModal = () => { - this.setState({ searchModalOpen: false }); - } - - renderBrand() { - const { brandMedia, shop } = this.props; - - const { name } = shop || {}; - const logo = brandMedia && brandMedia.url({ store: "large" }); - - return ( - - ); - } - - renderSearchButton() { - if (this.props.searchEnabled) { - return ( -
- - -
- ); - } - - return null; - } - - renderNotificationIcon() { - if (this.props.hasProperPermission) { - return ( -
- -
- ); - } - - return null; - } - - renderMainDropdown() { - return ( - - ); - } - - renderHamburgerButton() { - return ( -
- ); - } - - renderTagNav() { - return ( - - - {this.renderNotificationIcon()} - - ); - } - - render() { - return ( -
- {this.props.visibility.hamburger && this.renderHamburgerButton()} - {this.props.visibility.brand && this.renderBrand()} -
- {this.props.visibility.tags && this.renderTagNav()} -
- {this.props.visibility.search && this.renderSearchButton()} - {this.props.visibility.notifications && this.renderNotificationIcon()} - {this.props.visibility.currency && this.renderCurrency()} - {this.props.visibility.mainDropdown && this.renderMainDropdown()} -
- ); - } -} - -export default NavBar; diff --git a/imports/plugins/core/ui-navbar/client/components/navbarCheckout.js b/imports/plugins/core/ui-navbar/client/components/navbarCheckout.js deleted file mode 100644 index 490860acce..0000000000 --- a/imports/plugins/core/ui-navbar/client/components/navbarCheckout.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; -import NavBar from "../components/navbar"; - -const NavBarCheckout = (props, context) => { - const visibility = { - hamburger: false, - brand: true, - tags: false, - search: false, - notifications: false, - languages: false, - currency: false, - mainDropdown: false - }; - const newProps = { - ...props, - visibility - }; - return React.createElement(NavBar, newProps, context); -}; - -export default NavBarCheckout; diff --git a/imports/plugins/core/ui-navbar/client/containers/navbar.js b/imports/plugins/core/ui-navbar/client/containers/navbar.js deleted file mode 100644 index cc0b8ff9d3..0000000000 --- a/imports/plugins/core/ui-navbar/client/containers/navbar.js +++ /dev/null @@ -1,89 +0,0 @@ -import { registerComponent, composeWithTracker } from "@reactioncommerce/reaction-components"; -import { Meteor } from "meteor/meteor"; -import { Roles } from "meteor/alanning:roles"; -import { Reaction } from "/client/api"; -import NavBar from "../components/navbar"; -import { Shops } from "/lib/collections"; -import { Media } from "/imports/plugins/core/files/client"; - -/** - * @private - * @param {Object} props Props - * @param {Function} onData Call this to update props - * @returns {undefined} - */ -export function composer(props, onData) { - const shop = Shops.findOne({ _id: Reaction.getShopId() }); - if (!shop) throw new Error(`No shop found with shop ID ${Reaction.getShopId()}`); - - const searchPackage = Reaction.Apps({ provides: "ui-search" }); - const user = Meteor.user(); - let searchEnabled; - let searchTemplate; - let brandMedia; - - let shops; - - if (user && user.roles) { - // Get all shops for which user has roles - shops = Shops.find({ - $and: [ - { _id: { $in: Object.keys(user.roles) } }, - { $or: [{ "workflow.status": "active" }, { _id: Reaction.getPrimaryShopId() }] } - ] - }).fetch(); - } - - /** - * @method - * @summary Handle change in selected shop - * @param {script} event DOM Event - * @param {String} shopId - selected shopId - * @since 1.5.8 - * @returns {void} - * @private - */ - const handleShopSelectChange = (event, shopId) => { - Reaction.setShopId(shopId); - }; - - const isLoggedIn = !!(shop && user && !Roles.userIsInRole(user._id, "anonymous", shop._id)); - - if (searchPackage.length && isLoggedIn) { - searchEnabled = true; - searchTemplate = searchPackage[0].template; - } else { - searchEnabled = false; - } - - if (shop && Array.isArray(shop.brandAssets)) { - const brandAsset = shop.brandAssets.find((asset) => asset.type === "navbarBrandImage"); - brandMedia = brandAsset && Media.findOneLocal(brandAsset.mediaId); - } - - const hasProperPermission = Reaction.hasPermission("account/profile"); - - onData(null, { - brandMedia, - handleShopSelectChange, - hasProperPermission, - searchEnabled, - searchTemplate, - shop, - shops, - visibility: { - hamburger: true, - brand: true, - tags: isLoggedIn, - search: true, - notifications: true, - languages: true, - currency: true, - mainDropdown: true - } - }); -} - -registerComponent("NavBar", NavBar, composeWithTracker(composer)); - -export default composeWithTracker(composer)(NavBar); diff --git a/imports/plugins/core/ui-navbar/client/containers/navbarCheckout.js b/imports/plugins/core/ui-navbar/client/containers/navbarCheckout.js deleted file mode 100644 index 7a59f0475d..0000000000 --- a/imports/plugins/core/ui-navbar/client/containers/navbarCheckout.js +++ /dev/null @@ -1,7 +0,0 @@ -import { registerComponent, composeWithTracker } from "@reactioncommerce/reaction-components"; -import NavBarCheckout from "../components/navbarCheckout"; -import { composer } from "./navbar"; - -registerComponent("NavBarCheckout", NavBarCheckout, composeWithTracker(composer)); - -export default composeWithTracker(composer)(NavBarCheckout); diff --git a/imports/plugins/core/ui-navbar/client/index.js b/imports/plugins/core/ui-navbar/client/index.js deleted file mode 100644 index 639529c622..0000000000 --- a/imports/plugins/core/ui-navbar/client/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { default as Brand } from "./components/brand"; -export { default as Navbar } from "./containers/navbar"; -export { default as NavBarCheckout } from "./containers/navbarCheckout"; diff --git a/imports/plugins/core/ui-tagnav/client/components/tagGroup.js b/imports/plugins/core/ui-tagnav/client/components/tagGroup.js deleted file mode 100644 index ae6862ae8d..0000000000 --- a/imports/plugins/core/ui-tagnav/client/components/tagGroup.js +++ /dev/null @@ -1,175 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import _ from "lodash"; -import { Components, registerComponent } from "@reactioncommerce/reaction-components"; -import update from "immutability-helper"; -import { TagHelpers } from "/imports/plugins/core/ui-tagnav/client/helpers"; -import getTagSuggestions from "/imports/plugins/core/ui-tagnav/client/util/getTagSuggestions"; -import { getTagIds } from "/lib/selectors/tags"; -import { Router } from "/client/api"; - -class TagGroup extends Component { - constructor(props) { - super(props); - - const { parentTag, tagsByKey, tagIds } = props.tagGroupProps; - this.state = { - suggestions: [], - newTag: { - name: "" - }, - tagIds, - parentTag, - tagsByKey - }; - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - const { parentTag, tagsByKey, tagIds } = nextProps.tagGroupProps; - this.setState({ tagIds, parentTag, tagsByKey }); - } - - get tags() { - if (this.props.editable) { - return this.state.tagIds.map((tagId) => this.state.tagsByKey[tagId]); - } - - return this.props.tagGroupProps.subTagGroups; - } - - get className() { - if (this.props.blank) { - return "create"; - } - return ""; - } - - handleGetSuggestions = async (suggestionUpdateRequest) => { - const suggestions = await getTagSuggestions( - suggestionUpdateRequest.value, - { excludeTags: this.state.tagIds } - ); - - this.setState({ suggestions }); - } - - handleClearSuggestions = () => { - this.setState({ suggestions: [] }); - } - - handleNewTagSave = (event, tag) => { - if (this.props.onNewTagSave) { - this.props.onNewTagSave(tag, this.props.tagGroupProps.parentTag); - this.setState({ - newTag: { name: "" } - }); - } - } - - handleTagUpdate = (event, tag) => { - const newState = update(this.state, { - tagsByKey: { - [tag._id]: { - $set: tag - } - } - }); - - this.setState(newState); - } - - handleNewTagUpdate = (event, tag) => { // updates blank tag state being edited - this.setState({ newTag: tag }); - } - - tagGroupBodyProps = (tag) => { - const subTagGroups = _.compact(TagHelpers.subTags(tag)); - const tagsByKey = {}; - - if (Array.isArray(subTagGroups)) { - for (const tagItem of subTagGroups) { - tagsByKey[tagItem._id] = tagItem; - } - } - - return { - parentTag: tag, - tagsByKey: tagsByKey || {}, - tagIds: getTagIds({ tags: subTagGroups }) || [], - subTagGroups - }; - } - - renderTree(tags) { - if (Array.isArray(tags)) { - return tags.map((tag) => ( -
- - -
- )); - } - - return null; - } - - render() { - const { slug } = this.state.parentTag; - const url = Router.pathFor("tag", { - hash: { - slug - } - }); - return ( -
-
- {this.state.parentTag.name} - View All -
-
- {this.renderTree(this.tags)} - {this.props.editable && -
-
- -
-
- } -
-
- ); - } -} - -TagGroup.propTypes = { - blank: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - editable: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - onNewTagSave: PropTypes.func, - onTagRemove: PropTypes.func, - tagGroupProps: PropTypes.object -}; - -registerComponent("TagGroup", TagGroup); - -export default TagGroup; diff --git a/imports/plugins/core/ui-tagnav/client/components/tagGroupBody.js b/imports/plugins/core/ui-tagnav/client/components/tagGroupBody.js deleted file mode 100644 index 34ac341227..0000000000 --- a/imports/plugins/core/ui-tagnav/client/components/tagGroupBody.js +++ /dev/null @@ -1,177 +0,0 @@ -import _ from "lodash"; -import React, { Component } from "react"; -import update from "immutability-helper"; -import PropTypes from "prop-types"; -import { Components, registerComponent } from "@reactioncommerce/reaction-components"; -import getTagSuggestions from "/imports/plugins/core/ui-tagnav/client/util/getTagSuggestions"; - -class TagGroupBody extends Component { - constructor(props) { - super(props); - - const { parentTag, tagsByKey, tagIds } = props.tagGroupBodyProps; - this.state = { - suggestions: [], - newTag: { - name: "" - }, - tagIds, - parentTag, - tagsByKey - }; - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - const { parentTag, tagsByKey, tagIds } = nextProps.tagGroupBodyProps; - this.setState({ tagIds, parentTag, tagsByKey }); - } - - handleNewTagSave = (event, tag) => { - if (this.props.onNewTagSave) { - this.props.onNewTagSave(tag, this.state.parentTag); - this.setState({ - newTag: { name: "" } - }); - } - } - - handleTagUpdate = (event, tag) => { - const newState = update(this.state, { - tagsByKey: { - [tag._id]: { - $set: tag - } - } - }); - - this.setState(newState); - } - - handleNewTagUpdate = (event, tag) => { // updates blank tag state being edited - this.setState({ newTag: tag }); - } - - handleGetSuggestions = async (suggestionUpdateRequest) => { - const suggestions = await getTagSuggestions( - suggestionUpdateRequest.value, - { excludeTags: this.state.tagIds } - ); - - this.setState({ suggestions }); - } - - handleClearSuggestions = () => { - this.setState({ suggestions: [] }); - } - - handleMoveTag = (dragIndex, hoverIndex) => { - const tag = this.state.tagIds[dragIndex]; - if (!tag) { - return false; - } - // Apply new sort order to variant list - const newState = update(this.state, { - tagIds: { - $splice: [ - [dragIndex, 1], - [hoverIndex, 0, tag] - ] - } - }); - - // Set local state so the component does't have to wait for a round-trip - // to the server to get the updated list of variants - return this.setState(newState, () => { - _.debounce(() => this.props.onTagSort(this.state.tagIds, this.state.parentTag), 500)(); - }); - } - - handleTagSave = (event, tag) => { - if (this.props.onUpdateTag) { - this.props.onUpdateTag(tag._id, tag.name, this.state.parentTag._id); - } - } - - get tags() { - if (this.props.editable) { - return this.state.tagIds.map((tagId) => this.state.tagsByKey[tagId]); - } - - return this.props.tagGroupBodyProps.subTagGroups; - } - - genTagsList(tags, parentTag) { - if (Array.isArray(tags)) { - return tags.map((tag, index) => ( - - )); - } - - return null; - } - - render() { - return ( -
-
- {this.genTagsList(_.compact(this.tags), this.state.parentTag)} - {this.props.editable && -
- -
- } -
-
- ); - } -} - -TagGroupBody.propTypes = { - editable: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - onNewTagSave: PropTypes.func, - onTagClick: PropTypes.func, - onTagRemove: PropTypes.func, - onTagSort: PropTypes.func, - onUpdateTag: PropTypes.func, - tagGroupBodyProps: PropTypes.object -}; - -registerComponent("TagGroupBody", TagGroupBody); - -export default TagGroupBody; diff --git a/imports/plugins/core/ui-tagnav/client/components/tagGroupHeader.js b/imports/plugins/core/ui-tagnav/client/components/tagGroupHeader.js deleted file mode 100644 index 8dc8f6777c..0000000000 --- a/imports/plugins/core/ui-tagnav/client/components/tagGroupHeader.js +++ /dev/null @@ -1,74 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import { Components, registerComponent } from "@reactioncommerce/reaction-components"; -import getTagSuggestions from "/imports/plugins/core/ui-tagnav/client/util/getTagSuggestions"; - -class TagGroupHeader extends Component { - constructor(props) { - super(props); - this.state = { - suggestions: [], - tag: this.props.tag - }; - } - - handleGetSuggestions = async (suggestionUpdateRequest) => { - const suggestions = await getTagSuggestions( - suggestionUpdateRequest.value, - { excludeTags: this.state.tagIds } - ); - - this.setState({ suggestions }); - } - - handleTagUpdate = (event, tag) => { - this.setState({ tag }); - } - - handleTagSave = (event, tag) => { - if (this.props.onUpdateTag) { - this.props.onUpdateTag(tag._id, tag.name, this.props.parentTag._id); - } - } - - handleTagTreeMove = () => { - // needed to prevent move errors, pending fix for TagGroup draging - } - - render() { - return ( -
- -
- ); - } -} - -TagGroupHeader.propTypes = { - editable: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - onTagClick: PropTypes.func, - onTagRemove: PropTypes.func, - onUpdateTag: PropTypes.func, - parentTag: PropTypes.object, - tag: PropTypes.object -}; - -registerComponent("TagGroupHeader", TagGroupHeader); - -export default TagGroupHeader; diff --git a/imports/plugins/core/ui-tagnav/client/components/tagNav.js b/imports/plugins/core/ui-tagnav/client/components/tagNav.js deleted file mode 100644 index 7e15d26b67..0000000000 --- a/imports/plugins/core/ui-tagnav/client/components/tagNav.js +++ /dev/null @@ -1,154 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import _ from "lodash"; -import { Components } from "@reactioncommerce/reaction-components"; -import { getTagIds } from "/lib/selectors/tags"; -import { TagHelpers } from "/imports/plugins/core/ui-tagnav/client/helpers"; -import ShopSelect from "/imports/plugins/core/dashboard/client/components/shopSelect"; - -class TagNav extends Component { - constructor(props) { - super(props); - this.state = { - selectedTag: this.props.selectedTag || {} - }; - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ selectedTag: nextProps.selectedTag }); - } - - /** - * onShopSelectChange - * @method - * @summary Handle change in selected shop - * @param {Script} event onchange event - * @param {String} shopId - selected shopId - * @since 1.5.8 - * @returns {void} - */ - onShopSelectChange = (event, shopId) => { - if (this.props.handleShopSelectChange) { - this.props.handleShopSelectChange(event, shopId); - } - } - - renderEditButton() { - const { editContainerItem } = this.props.navButtonStyles; - return ( - - - - ); - } - - /** - * renderShopSelect - * @method - * @summary Handles shop options display on mobile view - * @returns {JSX} React node containing dropdown menu - */ - renderShopSelect() { - if (this.props.handleShopSelectChange) { - return ( - - ); - } - return null; - } - - tagGroupProps = (tag) => { - const subTagGroups = _.compact(TagHelpers.subTags(tag)); - const tagsByKey = {}; - - if (Array.isArray(subTagGroups)) { - for (const tagItem of subTagGroups) { - tagsByKey[tagItem._id] = tagItem; - } - } - - return { - parentTag: tag, - tagsByKey: tagsByKey || {}, - tagIds: getTagIds({ tags: subTagGroups }) || [], - subTagGroups - }; - } - - render() { - const { navbarOrientation, navbarPosition, navbarAnchor, navbarVisibility } = this.props; - return ( -
-
- - {this.props.children} -
- {this.renderShopSelect()} -
- -
- -
-
- {this.props.canEdit && this.renderEditButton()} -
-
- ); - } -} - -TagNav.propTypes = { - canEdit: PropTypes.bool, - children: PropTypes.node, - closeNavbar: PropTypes.func, - editable: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - handleShopSelectChange: PropTypes.func, - navButtonStyles: PropTypes.object, - navbarAnchor: PropTypes.string, - navbarOrientation: PropTypes.string, - navbarPosition: PropTypes.string, - navbarVisibility: PropTypes.string, - onEditButtonClick: PropTypes.func, - onMoveTag: PropTypes.func, - selectedTag: PropTypes.object, - shop: PropTypes.object, - shops: PropTypes.array -}; - -export default TagNav; diff --git a/imports/plugins/core/ui-tagnav/client/containers/tagNavContainer.js b/imports/plugins/core/ui-tagnav/client/containers/tagNavContainer.js deleted file mode 100644 index 80e164ea3d..0000000000 --- a/imports/plugins/core/ui-tagnav/client/containers/tagNavContainer.js +++ /dev/null @@ -1,468 +0,0 @@ -import _ from "lodash"; -import update from "immutability-helper"; -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import { compose } from "recompose"; -import { Components, registerComponent, composeWithTracker } from "@reactioncommerce/reaction-components"; -import { Reaction, Router } from "/client/api"; -import { getTagIds } from "/lib/selectors/tags"; -import { TagHelpers } from "/imports/plugins/core/ui-tagnav/client/helpers"; -import getTagSuggestions from "/imports/plugins/core/ui-tagnav/client/util/getTagSuggestions"; -import { Tags } from "/lib/collections"; -import TagNav from "../components/tagNav"; - -const navButtonStyles = { - editContainerItem: { - display: "flex", - marginLeft: 5 - } -}; - -const NavbarStates = { - Orientation: "stateNavbarOrientation", - Position: "stateNavbarPosition", - Anchor: "stateNavbarAnchor", - Visible: "stateNavbarVisible" -}; - -const NavbarOrientation = { - Vertical: "vertical", - Horizontal: "horizontal" -}; - -const NavbarPosition = { - Static: "static", - Fixed: "fixed" -}; - -const NavbarAnchor = { - Top: "top", - Right: "right", - Bottom: "bottom", - Left: "left", - None: "inline" -}; - -const TagNavHelpers = { - onTagCreate(tagName, parentTag) { - TagHelpers.createTag(tagName, undefined, parentTag); - }, - onTagRemove(tag, parentTag) { - TagHelpers.removeTag(tag, parentTag); - }, - onTagSort(tagIds, parentTag) { - TagHelpers.sortTags(tagIds, parentTag); - }, - onTagDragAdd(movedTagId, toListId, toIndex, ofList) { - TagHelpers.moveTagToNewParent(movedTagId, toListId, toIndex, ofList); - }, - onUpdateTag(tagId, tagName, parentTagId) { - TagHelpers.updateTag(tagId, tagName, parentTagId); - }, - isMobile() { - return window.matchMedia("(max-width: 991px)").matches; - }, - tagById(tagId, tags) { - return _.find(tags, (tag) => tag._id === tagId); - }, - hasSubTags(tagId, tags) { - const foundTag = this.tagById(tagId, tags); - - if (foundTag) { - if (Array.isArray(foundTag.relatedTagIds) && foundTag.relatedTagIds.length) { - return true; - } - } - return false; - } -}; - -const wrapComponent = (Comp) => ( - class TagNavContainer extends Component { - static propTypes = { - closeNavbar: PropTypes.func, - editButton: PropTypes.node, - editable: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - hasEditRights: PropTypes.bool, - isVisible: PropTypes.bool, - tagIds: PropTypes.arrayOf(PropTypes.string), - tagsAsArray: PropTypes.arrayOf(PropTypes.object), - tagsByKey: PropTypes.object - } - - constructor(props) { - super(props); - - this._isMounted = false; - - this.state = { - attachedBodyListener: false, - editable: false, - tagIds: props.tagIds || [], - tagsByKey: props.tagsByKey || {}, - selectedTag: null, - suggestions: [], - [NavbarStates.Visible]: props.isVisible, - newTag: { - name: "" - } - }; - - this.onWindowResize = this.onWindowResize.bind(this); - } - - componentDidMount() { - window.addEventListener("resize", this.onWindowResize); - this.onWindowResize(); - this._isMounted = true; - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - let selectedTag = {}; - const previousEdit = this.state.editable; - nextProps.tagsAsArray.forEach((tag) => { - if (this.isSelected(tag)) { - selectedTag = tag; - } - }); - - const { tagIds, tagsByKey, isVisible } = nextProps; - this.setState({ - [NavbarStates.Visible]: isVisible, - editable: previousEdit && this.canEdit, - tagIds, - tagsByKey, - selectedTag - }); - } - - componentWillUnmount() { - window.removeEventListener("resize", this.onWindowResize); - this._isMounted = false; - } - - onWindowResize = () => { - const matchQuery = window.matchMedia("(max-width: 991px)"); - if (matchQuery.matches) { - this.setState({ - [NavbarStates.Orientation]: NavbarOrientation.Vertical, - [NavbarStates.Position]: NavbarPosition.Fixed, - [NavbarStates.Anchor]: NavbarAnchor.Left - }); - } else { - this.setState({ - [NavbarStates.Orientation]: NavbarOrientation.Horizontal, - [NavbarStates.Position]: NavbarPosition.Static, - [NavbarStates.Anchor]: NavbarAnchor.None, - [NavbarStates.Visible]: false - }); - } - } - - canSaveTag(tag) { - // Blank tags cannot be saved - if (typeof tag.name === "string" && tag.name.trim().length === 0) { - return false; - } - - // If the tag does not have an id, then allow the save - if (!tag._id) { - return true; - } - - // Get the original tag from the props - // Tags from props are not mutated, and come from an outside source - const originalTag = this.props.tagsByKey[tag._id]; - - if (originalTag && originalTag.name !== tag.name) { - return true; - } - - return false; - } - - handleNewTagSave = (tag, parentTag) => { - if (this.canSaveTag(tag)) { - TagNavHelpers.onTagCreate(tag.name, parentTag); - this.setState({ newTag: { name: "" } }); - } - } - - handleNewTagUpdate = (tag) => { // updates the current tag state being edited - this.setState({ - newTag: tag - }); - } - - handleTagRemove = (tag, parentTag) => { - TagNavHelpers.onTagRemove(tag, parentTag); - } - - handleTagUpdate = (tag) => { - const newState = update(this.state, { - tagsByKey: { - [tag._id]: { - $set: tag - } - } - }); - - this.setState(newState); - } - - handleTagSave = (tag) => { - TagNavHelpers.onUpdateTag(tag._id, tag.name); - } - - handleMoveTag = (dragIndex, hoverIndex) => { - const tag = this.state.tagIds[dragIndex]; - - // Apply new sort order to variant list - const newState = update(this.state, { - tagIds: { - $splice: [ - [dragIndex, 1], - [hoverIndex, 0, tag] - ] - } - }); - - // Set local state so the component does't have to wait for a round-trip - // to the server to get the updated list of variants - this.setState(newState, () => { - _.debounce(() => TagNavHelpers.onTagSort(this.state.tagIds), 500)(); // Save the updated positions - }); - } - - handleGetSuggestions = async (suggestionUpdateRequest) => { - const suggestions = await getTagSuggestions( - suggestionUpdateRequest.value, - { excludeTags: this.state.tagIds } - ); - - this.setState({ suggestions }); - } - - handleClearSuggestions = () => { - this.setState({ suggestions: [] }); - } - - get canEdit() { - return this.props.hasEditRights; - } - - attachBodyListener = () => { - document.body.addEventListener("mouseover", this.closeDropdown); - this.setState({ attachedBodyListener: true }); - } - - detachhBodyListener = () => { - document.body.removeEventListener("mouseover", this.closeDropdown); - this.setState({ attachedBodyListener: false }); - } - - closeDropdown = (event) => { - const closestNavigationItem = event.target.closest(".navbar-item"); - - // on mouseover an element outside of tags, close dropdown - if (this._isMounted && !closestNavigationItem) { - this.closeDropdownTimeout = setTimeout(() => { - this.setState({ selectedTag: null }); - this.detachhBodyListener(); - }, 500); - } else if (this.closeDropdownTimeout) { - clearTimeout(this.closeDropdownTimeout); - } - } - - get navbarOrientation() { - return this.state[NavbarStates.Orientation]; - } - - get navbarPosition() { - return this.state[NavbarStates.Position]; - } - - get navbarAnchor() { - return this.state[NavbarStates.Anchor]; - } - - get navbarVisibility() { - const isVisible = this.state[NavbarStates.Visible] === true; - - if (isVisible) { - return "open"; - } - return "closed"; - } - - onTagSelect = (currentSelectedTag) => { - if (_.isEqual(currentSelectedTag, this.state.selectedTag)) { - this.setState({ selectedTag: null }); - } else { - this.setState({ selectedTag: currentSelectedTag }); - } - } - - isSelected(tag) { - let isSelected = false; - if (this.state.selectedTag && tag) { - isSelected = this.state.selectedTag._id === tag._id; - } - return isSelected; - } - - handleTagMouseOver = (event, tag) => { - const tagId = tag._id; - const tags = this.props.tagsAsArray; - - if (TagNavHelpers.isMobile()) { - return; - } - // While in edit mode, don't trigger the hover hide/show menu - if (this.state.editable === false) { - // User mode - // Don't show dropdown if there are no subtags - if (TagNavHelpers.hasSubTags(tagId, tags) === false) { - this.setState({ selectedTag: null }); - return; - } - - // Otherwise, show the menu - // And Attach an event listener to the document body - // This will check to see if the dropdown should be closed if the user - // leaves the tag nav bar - this.attachBodyListener(); - this.setState({ selectedTag: TagNavHelpers.tagById(tagId, tags) }); - } - } - - handleTagClick = (event, tag) => { - if (TagNavHelpers.isMobile()) { - const tagId = tag._id; - const tags = this.props.tagsAsArray; - const { selectedTag } = this.state; - const hasSubTags = TagNavHelpers.hasSubTags(tagId, tags); - - if (hasSubTags === false) { - // click close button to make navbar left disappear - this.props.closeNavbar(); - Router.go("tag", { slug: tag.slug }); - } else { - event.preventDefault(); - } - - if (selectedTag && selectedTag._id === tagId) { - this.setState({ selectedTag: null }); - } else if (hasSubTags) { - this.setState({ selectedTag: TagNavHelpers.tagById(tagId, tags) }); - } - } else { - Router.go("tag", { slug: tag.slug }); - } - } - - handleEditButtonClick = () => { - this.setState({ editable: !this.state.editable }); - } - - hasDropdownClassName(tag) { - if (Array.isArray(tag.relatedTagIds)) { - return "has-dropdown"; - } - return ""; - } - - navbarSelectedClassName = (tag) => { - const currentSelectedTag = this.state.selectedTag; - - if (currentSelectedTag) { - if (currentSelectedTag._id === tag._id) { - return "selected"; - } - } - return ""; - } - - get tags() { - if (this.state.editable) { - return this.state.tagIds.map((tagId) => this.state.tagsByKey[tagId]); - } - - return this.props.tagsAsArray; - } - - render() { - return ( -
- - -
- ); - } - } -); - -const composer = (props, onData) => { - let tags = Tags.find({ isTopLevel: true }, { sort: { position: 1 } }).fetch(); - tags = _.sortBy(tags, "position"); // puts tags without position at end of array - - const tagsByKey = {}; - - if (Array.isArray(tags)) { - for (const tag of tags) { - tagsByKey[tag._id] = tag; - } - } - - onData(null, { - name: "coreHeaderNavigation", - hasEditRights: Reaction.hasAdminAccess(), - tagsAsArray: tags, - isVisible: props.isVisible, - tagIds: getTagIds({ tags }), - tagsByKey - }); -}; - -registerComponent("TagNav", TagNav, [ - composeWithTracker(composer), - wrapComponent -]); - -export default compose( - composeWithTracker(composer), - wrapComponent -)(TagNav); diff --git a/imports/plugins/core/ui-tagnav/client/helpers/index.js b/imports/plugins/core/ui-tagnav/client/helpers/index.js deleted file mode 100644 index b59f8bf032..0000000000 --- a/imports/plugins/core/ui-tagnav/client/helpers/index.js +++ /dev/null @@ -1 +0,0 @@ -export { TagHelpers } from "./tags"; diff --git a/imports/plugins/core/ui-tagnav/client/helpers/tags.js b/imports/plugins/core/ui-tagnav/client/helpers/tags.js deleted file mode 100644 index a57d4825c6..0000000000 --- a/imports/plugins/core/ui-tagnav/client/helpers/tags.js +++ /dev/null @@ -1,178 +0,0 @@ -import _ from "lodash"; -import { Reaction, i18next } from "/client/api"; -import { Tags } from "/lib/collections"; -import { Meteor } from "meteor/meteor"; -import { Session } from "meteor/session"; -import { Template } from "meteor/templating"; - -/** - * @memberof Helpers - * @summary Reaction TagNav shared helpers - * @type {Object} - */ -export const TagHelpers = { - moveItem(oldArray, fromIndex, toIndex) { - const newArray = [...oldArray]; - newArray.splice(toIndex, 0, newArray.splice(fromIndex, 1)[0]); - return newArray; - }, - - subTags(parentTag) { - if (_.isArray(parentTag.relatedTagIds)) { - const tags = Tags.find({ - isTopLevel: false, - _id: { - $in: parentTag.relatedTagIds - } - }).fetch(); - - const subTags = parentTag.relatedTagIds.map((tagId) => _.find(tags, (tagObject) => tagObject._id === tagId)); - - return subTags; - } - - return []; - }, - - currentTag() { - return Session.get("currentTag"); - }, - - getTags() { - let tags = []; - - tags = Tags.find({ - isTopLevel: true - }, { - sort: { - position: 1 - } - }).fetch(); - /* - if (this.tagIds) { - for (let relatedTagId of this.tagIds) { - if (!_.find(tags, { - _id: relatedTagId - })) { - tags.push(Tags.findOne(relatedTagId)); - } - } - }*/ - - if (this.tag) { - Session.set("currentTag", this.tag._id); - } else { - Session.set("currentTag", ""); - } - - return tags; - // there are cases where - // we'll have no tags, and sort will error - // so we check length for safety - // if (tags) { - // tags.sort(function (a, b) { - // return a.position - b.position; - // }); - // return tags; - // } - }, - - createTag(tagName, tagId, parentTag) { - if (!tagName) { - return; - } - let parentTagId; - - if (parentTag) { - parentTagId = parentTag._id; - } - - Meteor.call("shop/updateHeaderTags", tagName, null, parentTagId, (error) => { - if (error) { - Alerts.toast(i18next.t("productDetail.tagExists"), "error"); - } - }); - }, - - updateTag(tagId, tagName, parentTagId) { - Meteor.call("shop/updateHeaderTags", tagName, tagId, parentTagId, (error) => { - if (error) { - Alerts.toast(i18next.t("productDetail.tagExists"), "error"); - } - }); - }, - - /* eslint no-unused-vars: 0 */ - // - // TODO review toIndex, ofList variable implementation in tags.js moveTagToNewParent - // - moveTagToNewParent(movedTagId, toListId, toIndex, ofList) { - if (movedTagId) { - if (toListId) { - const result = Tags.update(toListId, { - $addToSet: { - relatedTagIds: movedTagId - } - }); - - return result; - } - - const result = Tags.update(movedTagId, { - $set: { - isTopLevel: true - } - }); - - return result; - } - return 0; - }, - - sortTags(tagIds, parentTag) { - if (_.isArray(tagIds)) { - if (_.isEmpty(parentTag)) { - // Top level tags - for (const tagId of tagIds) { - Tags.update(tagId, { - $set: { - position: tagIds.indexOf(tagId) - } - }); - } - } else { - // Sub tags - Tags.update(parentTag._id, { - $set: { - relatedTagIds: _.compact(tagIds) - } - }); - } - } - }, - - removeTag(tag, parentTag) { - if (_.isEmpty(parentTag) === false) { - Tags.update(parentTag._id, { - $pullAll: { - relatedTagIds: [tag._id] - } - }); - } else if (tag.isTopLevel === true) { - Tags.update(tag._id, { - $set: { - isTopLevel: false - } - }); - } - } -}; - -/** - * @method reactionSubTags - * @summary Template method to return subTags - * @param parentTag {Object} Tag - * @returns {Array} Array of subtags or empty Array - * @memberof BlazeTemplateHelpers - */ -Template.registerHelper("reactionSubTags", TagHelpers.subTags); diff --git a/imports/plugins/core/ui-tagnav/client/index.js b/imports/plugins/core/ui-tagnav/client/index.js deleted file mode 100644 index d0a5e8df30..0000000000 --- a/imports/plugins/core/ui-tagnav/client/index.js +++ /dev/null @@ -1,5 +0,0 @@ -export { default as TagGroup } from "./components/tagGroup"; -export { default as TagGroupBody } from "./components/tagGroupBody"; -export { default as TagGroupHeader } from "./components/tagGroupHeader"; -export { default as TagNav } from "./components/tagNav"; -export { default as TagNavContainer } from "./containers/tagNavContainer"; diff --git a/imports/plugins/core/ui/client/containers/tagListContainer.js b/imports/plugins/core/ui/client/containers/tagListContainer.js index 3ae7c19dcd..566575f892 100644 --- a/imports/plugins/core/ui/client/containers/tagListContainer.js +++ b/imports/plugins/core/ui/client/containers/tagListContainer.js @@ -9,7 +9,7 @@ import { Reaction, i18next } from "/client/api"; import TagList from "../components/tags/tagList"; import { Tags } from "/lib/collections"; import { getTagIds } from "/lib/selectors/tags"; -import getTagSuggestions from "/imports/plugins/core/ui-tagnav/client/util/getTagSuggestions"; +import getTagSuggestions from "../helpers/getTagSuggestions"; const wrapComponent = (Comp) => ( class TagListContainer extends Component { diff --git a/imports/plugins/core/ui-tagnav/client/util/getTagSuggestions.js b/imports/plugins/core/ui/client/helpers/getTagSuggestions.js similarity index 100% rename from imports/plugins/core/ui-tagnav/client/util/getTagSuggestions.js rename to imports/plugins/core/ui/client/helpers/getTagSuggestions.js