Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marketplace shop switcher #2412

Merged
merged 9 commits into from
Jun 12, 2017
16 changes: 15 additions & 1 deletion client/modules/core/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const reactionState = new ReactiveDict();
* Global reaction shop permissions methods and shop initialization
*/
export default {
shopId: null,
_shopId: new ReactiveVar(null),

Locale: new ReactiveVar({}),

Expand Down Expand Up @@ -245,10 +245,24 @@ export default {
});
},

get shopId() {
return this._shopId.get();
},

getShopId() {
return this.shopId;
},

set shopId(id) {
this._shopId.set(id);
},

setShopId(id) {
if (id) {
this.shopId = id;
}
},

getShopName() {
return this.shopName;
},
Expand Down
39 changes: 39 additions & 0 deletions imports/plugins/core/dashboard/client/components/toolbar.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { Component, PropTypes } from "react";
import Blaze from "meteor/gadicc:blaze-react-component";
import {
DropDownMenu,
MenuItem,
FlatButton,
Toolbar,
ToolbarGroup,
Expand All @@ -20,9 +22,12 @@ class PublishControls extends Component {
isEnabled: PropTypes.bool,
isPreview: PropTypes.bool,
onAddProduct: PropTypes.func,
onShopSelectChange: PropTypes.func,
onViewContextChange: PropTypes.func,
onVisibilityChange: PropTypes.func,
packageButtons: PropTypes.arrayOf(PropTypes.object),
shopId: PropTypes.string,
shops: PropTypes.arrayOf(PropTypes.object),
showViewAsControls: PropTypes.bool,
translation: PropTypes.shape({
lang: PropTypes.string
Expand All @@ -39,6 +44,13 @@ class PublishControls extends Component {
}
}

// Passthrough to shopSelectChange handler in container above
onShopSelectChange = (event, shopId) => {
if (typeof this.props.onShopSelectChange === "function") {
this.props.onShopSelectChange(event, shopId);
}
}

renderViewControls() {
if (this.props.showViewAsControls) {
return (
Expand All @@ -61,6 +73,32 @@ class PublishControls extends Component {
return null;
}

renderShopSelect() {
let menuItems;
if (Array.isArray(this.props.shops)) {
menuItems = this.props.shops.map((shop, index) => {
return (
<MenuItem
label={shop.name}
selectLabel={shop.name}
value={shop._id}
key={index}
/>
);
});
}

return (
<DropDownMenu
onChange={this.onShopSelectChange}
value={this.props.shopId}
closeOnClick={true}
>
{menuItems}
</DropDownMenu>
);
}

renderVisibilitySwitch() {
if (this.props.hasCreateProductAccess) {
return (
Expand Down Expand Up @@ -146,6 +184,7 @@ class PublishControls extends Component {
<Toolbar>
<ToolbarGroup firstChild={true}>
{this.renderVisibilitySwitch()}
{this.renderShopSelect()}
</ToolbarGroup>
<ToolbarGroup lastChild={true}>
{this.renderAddButton()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import { Meteor } from "meteor/meteor";
import { composeWithTracker } from "/lib/api/compose";
import { Reaction, i18next } from "/client/api";
import { Tags } from "/lib/collections";
import { Tags, Shops } from "/lib/collections";
import { TranslationProvider, AdminContextProvider } from "/imports/plugins/core/ui/client/providers";
import { isRevisionControlEnabled } from "/imports/plugins/core/revisions/lib/api";

Expand Down Expand Up @@ -50,9 +50,28 @@ const handleViewContextChange = (event, value) => {
}
};

/**
* Handler that fires when the shop selector is changed
* @param {Object} event - the `event` coming from the select change event
* @param {String} shopId - The `value` coming from the select change event
* @returns {undefined}
*/
const handleShopSelectChange = (event, shopId) => {
if (/^[A-Za-z0-9]{17}$/.test(shopId)) { // Make sure shopId is a valid ID
Reaction.setShopId(shopId);
}
};

function composer(props, onData) {
// Reactive data sources
const routeName = Reaction.Router.getRouteName();
const user = Meteor.user();
let shops;

if (user && user.roles) {
// Get all shops for which user has roles
shops = Shops.find({ _id: { $in: Object.keys(user.roles) } }).fetch();
}

// Standard variables
const packageButtons = [];
Expand Down Expand Up @@ -88,10 +107,13 @@ function composer(props, onData) {
isEnabled: isRevisionControlEnabled(),
isActionViewAtRootView: Reaction.isActionViewAtRootView(),
actionViewIsOpen: Reaction.isActionViewOpen(),
hasCreateProductAccess: Reaction.hasPermission("createProduct", Meteor.userId(), Reaction.getSellerShopId()),
hasCreateProductAccess: Reaction.hasPermission("createProduct", Meteor.userId(), Reaction.getShopId()),
shopId: Reaction.getShopId(),
shops: shops,

// Callbacks
onAddProduct: handleAddProduct,
onShopSelectChange: handleShopSelectChange,
onViewContextChange: handleViewContextChange
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@

<template name="CoreNavigationBar">
<div class="rui navbar">
<div class="showmenu">{{> button icon="bars" onClick=onMenuButtonClick}}</div>
{{> coreNavigationBrand}}
{{> shopSelect}}

{{#if isMarketplaceOwner}}
{{> shopSelect}}
<span>{{> React component=VerticalDivider}}</span>
{{/if}}
<span>
{{> React component=VerticalDivider}}
</span>

<div class="menu">
{{> tagNav tagNavProps}}
Expand Down
40 changes: 39 additions & 1 deletion imports/plugins/core/ui/client/components/menu/dropDownMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,53 @@ class DropDownMenu extends Component {
super(props);

this.state = {
label: undefined
label: undefined,
isOpen: false
};
}

componentWillReceiveProps(nextProps) {
if (this.isControlled) {
this.setState({
isOpen: nextProps.isOpen
});
}
}

get isOpen() {
return this.props.isOpen || this.state.isOpen;
}

get isControlled() {
return typeof this.props.isOpen === "boolean";
}

handleMenuItemChange = (event, value, menuItem) => {
this.setState({
label: menuItem.props.label || value
});

if (this.props.closeOnClick) {
this.handleOpen(false);
}

if (this.props.onChange) {
this.props.onChange(event, value);
}
}

handleOpen = (isOpen) => {
if (this.isControlled) {
if (this.props.onRequestOpen) {
this.props.onRequestOpen(isOpen);
}
} else {
this.setState({
isOpen: isOpen
});
}
}

get label() {
let label = this.state.label;
Children.forEach(this.props.children, (element) => {
Expand Down Expand Up @@ -53,6 +86,8 @@ class DropDownMenu extends Component {
label={this.label}
/>
}
isOpen={this.isOpen}
onRequestOpen={this.handleOpen}
>
<Menu value={this.props.value} onChange={this.handleMenuItemChange}>
{this.props.children}
Expand All @@ -65,9 +100,12 @@ class DropDownMenu extends Component {
DropDownMenu.propTypes = {
buttonElement: PropTypes.node,
children: PropTypes.node,
closeOnClick: PropTypes.bool,
isEnabled: PropTypes.bool,
isOpen: PropTypes.bool,
onChange: PropTypes.func,
onPublishClick: PropTypes.func,
onRequestOpen: PropTypes.func,
revisions: PropTypes.arrayOf(PropTypes.object),
translation: PropTypes.shape({
lang: PropTypes.string
Expand Down
44 changes: 37 additions & 7 deletions imports/plugins/core/ui/client/components/popover/popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ class Popover extends Component {
isOpen: false
}

componentWillReceiveProps(nextProps) {
if (this.isControlled) {
this.setState({
isOpen: nextProps.isOpen
});
}
}

get isOpen() {
return this.props.isOpen || this.state.isOpen;
}

get isControlled() {
return typeof this.props.isOpen === "boolean";
}

/**
* attachment
* @description Return the attachment for the tooltip or the default
Expand All @@ -25,19 +41,31 @@ class Popover extends Component {
}

handleOpen = () => {
this.setState({
isOpen: true
});
if (this.isControlled) {
if (this.props.onRequestOpen) {
this.props.onRequestOpen(true);
}
} else {
this.setState({
isOpen: true
});
}
}

handleClickOutside = () => {
this.setState({
isOpen: false
});
if (this.isControlled) {
if (this.props.onRequestOpen) {
this.props.onRequestOpen(false);
}
} else {
this.setState({
isOpen: false
});
}
}

renderPopoverChildren() {
if (this.state.isOpen) {
if (this.isOpen) {
return (
<PopoverContent
children={this.props.children}
Expand Down Expand Up @@ -96,7 +124,9 @@ Popover.propTypes = {
attachment: PropTypes.string,
buttonElement: PropTypes.node,
children: PropTypes.node,
isOpen: PropTypes.bool,
onDisplayButtonClick: PropTypes.func,
onRequestOpen: PropTypes.func,
showArrow: PropTypes.bool,
showDropdownButton: PropTypes.bool,
targetAttachment: PropTypes.string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template name="shopSelect">
{{#if sellerShops}}
{{#if shops}}
<div class="shops">
<div class="dropdown" role="shops">
<div class="dropdown-toggle"
Expand All @@ -8,18 +8,13 @@
aria-haspopup="true"
aria-expanded="false">

{{#if isChildShop}}
{{currentShopName}}
{{else if isOwnerShop}}
<span data-i18n="app.myShop">My Shop</span>
{{else}}
<span data-i18n="app.shops">Shops</span>
{{/if}}
<span>{{currentShopName}}</span>

<span class="caret"></span>
</div>
<ul class="dropdown-menu" role="menu">
{{#each sellerShops}}
<li class="{{class}}">
{{#each shops}}
<li class="{{isActiveShop _id}}">
<a class="shop" role="menuitem">{{name}}</a>
</li>
{{/each}}
Expand Down
Loading