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

Add global shop selector for multi-shop usage #297

Merged
merged 46 commits into from
Sep 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c71da80
feat: request adminUIShops as part of viewer query
loan-laux Jul 9, 2020
349f77a
chore: release v3.0.0-beta.8
rosshadden Jun 17, 2020
db21122
Fix linting errors, comma-spacing
Jun 18, 2020
facc20a
chore: updated docker image tag
rosshadden Jun 18, 2020
1728531
fix: Update defaultParcelSize only when it exists
Manizuca Jul 16, 2020
849c84e
feat: turn ShopLogoWithData into a shop selector + add shopId prefix …
loan-laux Aug 4, 2020
bdbe9ca
feat: refactor useCurrentShopId to get shopId from URL param
loan-laux Aug 5, 2020
adf1e60
feat: concatenate shopId in sidebar URLs
loan-laux Aug 5, 2020
e6e31bb
fix: concatenate shopId in sidebar URLs
loan-laux Aug 5, 2020
6f1846b
chore: make withOpaqueShopId call useCurrentShopId hook
loan-laux Aug 5, 2020
8f6e3e2
chore: remove withPrimaryShopId from ShopLogoWithData
loan-laux Aug 5, 2020
529b2c2
fix: use shopId in create product URL
loan-laux Aug 5, 2020
3d55c0e
chore: remove debugger statements
loan-laux Aug 24, 2020
7ed8e43
Fix: Fix hasPermission method
mikoscz Aug 3, 2020
5e82fd5
release v3.0.0-beta.9
kieckhafer Aug 4, 2020
c7603c2
feat: Enable mock TLS termination on calls to Hydra
samkelleher Aug 5, 2020
85e487e
chore: update changelog
kieckhafer Aug 5, 2020
234c505
fix: await resetStore in initApollo
loan-laux Aug 24, 2020
e5454a7
fix: make getPDPUrl concatenate shopId
loan-laux Aug 24, 2020
fb5eda1
fix: update getPDPUrl usage for VariantList
loan-laux Aug 24, 2020
32c7eb3
fix: use positional URL param instead of GET param
loan-laux Aug 24, 2020
5687e19
fix: include shopId in ProductHeader links
loan-laux Aug 25, 2020
bacf647
chore: remove unused component file
loan-laux Aug 25, 2020
666483f
fix: update route paths in ProductDetail
loan-laux Aug 25, 2020
2db0a63
feat: add create shop page
loan-laux Aug 26, 2020
12dd25d
chore: redirect to /new-shop for first shop creation
loan-laux Aug 26, 2020
7354e5c
feat: redirect to shop after creation
loan-laux Aug 26, 2020
9144db5
feat: add createRouteWithPrefix and createRouteWithNoPrefix flags to …
loan-laux Aug 27, 2020
f329883
chore: fix linting
loan-laux Aug 27, 2020
13c6eba
fix: match and replace first segment of URL only with shop ID
loan-laux Aug 27, 2020
ddf1b75
fix: make product editor back button use shopId URL
loan-laux Aug 27, 2020
5718c5b
fix: use shopId in home page links
loan-laux Aug 27, 2020
09561e7
fix: remove unused code and use shopId in useProduct URLs
loan-laux Aug 28, 2020
1f026e0
fix: use shopId in tag URLs
loan-laux Aug 28, 2020
5a70bbc
fix: use currentShopId for getTags query
loan-laux Aug 30, 2020
2e2ae9f
fix: use shopId in product URL from tag product table
loan-laux Aug 30, 2020
b50b682
fix: use shopId in settings routes
loan-laux Aug 30, 2020
4ac62c6
fix: make fetchShop re-fetch on shopId change
loan-laux Aug 31, 2020
294c35a
chore: add comment and remove useless fetch policy
loan-laux Aug 31, 2020
5e1ba7a
fix: linting
loan-laux Aug 31, 2020
3540b1e
chore: rename ShopLogoWithData to ShopSelectorWithData
loan-laux Aug 31, 2020
61d8c44
chore: slim down ShopLogoWithData
loan-laux Aug 31, 2020
c14586b
feat: use ShopLogoWithData in OperatorLanding
loan-laux Aug 31, 2020
5cf54e8
style: CSS colors
loan-laux Sep 1, 2020
0ece619
style: finish shop selector styling
loan-laux Sep 1, 2020
c93ed2d
style: make shop selector arrow light grey
loan-laux Sep 14, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,44 @@
# v3.0.0-beta.9

### Features

- feat: Enable mock TLS termination on calls to Hydra ([#302](https://github.com/reactioncommerce/reaction-admin/pull/302))

### Fixes

- fix: Update defaultParcelSize only when it exists ([#295](https://github.com/reactioncommerce/reaction-admin/pull/295))
- fix: Reaction.hasPermission method shopId ([#298](https://github.com/reactioncommerce/reaction-admin/pull/298))

## Contributors

Thanks to @manizuca and @mikoscz for contributing to this release! 🎉

# v3.0.0-beta.8

### Features

- feat: Added GraphQL-powered accounts page ([#276](https://github.com/reactioncommerce/reaction-admin/pull/276))

### Fixes

- fix: Set empty tax fields to null ([#258](https://github.com/reactioncommerce/reaction-admin/pull/258))

## Contributors

Thanks to @loan-laux and @derBretti for contributing to this release! 🎉

# v3.0.0-beta.7

This is the seventh beta release of the Reaction Admin project that is designed to work with our new Reaction API.

### Refactors

refactor: de-meteorize discount codes view ([#255](http://github.com/reactioncommerce/reaction-admin/pull/255))
- refactor: de-meteorize discount codes view ([#255](http://github.com/reactioncommerce/reaction-admin/pull/255))

### Fixes

fix: navigation tree not showing up ([#278](http://github.com/reactioncommerce/reaction-admin/pull/278))
fix: use network-only fetchPolicy for tag table ([#254](http://github.com/reactioncommerce/reaction-admin/pull/254))
- fix: navigation tree not showing up ([#278](http://github.com/reactioncommerce/reaction-admin/pull/278))
- fix: use network-only fetchPolicy for tag table ([#254](http://github.com/reactioncommerce/reaction-admin/pull/254))

## Contributors

Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ networks:

services:
reaction-admin:
image: reactioncommerce/admin:3.0.0-beta.7
image: reactioncommerce/admin:3.0.0-beta.9
env_file:
- ./.env
networks:
Expand Down
62 changes: 13 additions & 49 deletions imports/client/ui/components/ShopLogoWithData/ShopLogoWithData.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import React from "react";
import PropTypes from "prop-types";
import { compose } from "recompose";
import classNames from "classnames";
import gql from "graphql-tag";
import { Query } from "react-apollo";
import { Link } from "react-router-dom";
import Typography from "@material-ui/core/Typography";
import withStyles from "@material-ui/core/styles/withStyles";
import { withComponents } from "@reactioncommerce/components-context";
import withPrimaryShopId from "/imports/plugins/core/graphql/lib/hocs/withPrimaryShopId";
Expand Down Expand Up @@ -47,29 +44,15 @@ const styles = (theme) => ({
* @param {Object} props Component props
* @returns {Node} React component
*/
function ShopLogoWithData({ className, classes, shopId, shouldShowShopName, linkTo, size }) {
function ShopLogoWithData({ classes, shopId, size }) {
if (!shopId) {
return (
<Link
className={classNames(classes.root, className)}
to={linkTo}
>
<img
alt="Reaction Commerce"
className={classes.logo}
src={defaultLogo}
width={size}
/>
{shouldShowShopName &&
<Typography
variant="h3"
component="span"
className={classes.logoName}
>
Reaction Commerce
</Typography>
}
</Link>
<img
alt="Reaction Commerce"
className={classes.logo}
src={defaultLogo}
width={size}
/>
);
}

Expand All @@ -84,26 +67,12 @@ function ShopLogoWithData({ className, classes, shopId, shouldShowShopName, link
const customLogoFromUrlInput = shop.shopLogoUrls && shop.shopLogoUrls.primaryShopLogoUrl;

return (
<Link
className={classNames(classes.root, className)}
to={linkTo}
>
<img
alt={shop.name}
className={classes.logo}
src={customLogoFromUrlInput || customLogoFromUpload || defaultLogo}
width={size}
/>
{shouldShowShopName &&
<Typography
variant="h3"
component="span"
className={classes.logoName}
>
{shop.name}
</Typography>
}
</Link>
<img
alt={shop.name}
className={classes.logo}
src={customLogoFromUrlInput || customLogoFromUpload || defaultLogo}
width={size}
/>
);
}

Expand All @@ -116,17 +85,12 @@ function ShopLogoWithData({ className, classes, shopId, shouldShowShopName, link
}

ShopLogoWithData.propTypes = {
className: PropTypes.string,
classes: PropTypes.object,
linkTo: PropTypes.string,
shopId: PropTypes.string,
shouldShowShopName: PropTypes.bool,
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
};

ShopLogoWithData.defaultProps = {
linkTo: "/",
shouldShowShopName: false,
size: 60
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import React from "react";
import PropTypes from "prop-types";
import { compose } from "recompose";
import classNames from "classnames";
import { Link, useLocation } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import InputBase from "@material-ui/core/InputBase";
import MenuItem from "@material-ui/core/MenuItem";
import Select from "@material-ui/core/Select";
import Typography from "@material-ui/core/Typography";
import withStyles from "@material-ui/core/styles/withStyles";
import { withComponents } from "@reactioncommerce/components-context";

const defaultLogo = "/resources/reaction-logo-circular.svg";

const styles = (theme) => ({
root: {
display: "flex",
alignItems: "center"
},
logo: {
marginRight: theme.spacing(2)
},
menuItem: {
"& a span": {
color: theme.palette.colors.black90
}
},
selectMenu: {
"& a span": {
color: theme.palette.colors.black15
}
},
dummyShopName: {
color: theme.palette.colors.black15
},
newShopLink: {
"color": theme.palette.colors.darkBlue,
"&:hover": {
color: theme.palette.colors.darkBlue
}
},
plusIcon: {
display: "flex",
justifyContent: "center"
},
selectArrow: {
color: theme.palette.colors.black15
}
});

const ShopSelectorInput = withStyles(() => ({
input: {
"border": "none",
"&:focus": {
border: "none",
background: "transparent"
}
}
}))(InputBase);

/**
* ShopSelectorWithData
* @param {Object} props Component props
* @returns {Node} React component
*/
function ShopSelectorWithData({ className, classes, shouldShowShopName, shopId, linkTo, size, viewer }) {
const location = useLocation();

let adminUIShops = [];

if (viewer?.adminUIShops) {
({ adminUIShops } = viewer);
} else {
return (
<Link
className={classNames(classes.root, className)}
to={linkTo}
>
<img
alt="Reaction Commerce"
className={classes.logo}
src={defaultLogo}
width={size}
/>
{shouldShowShopName &&
<Typography
className={classes.dummyShopName}
component="span"
variant="h3"
>
Reaction Commerce
</Typography>
}
</Link>
);
}

return (
<Select classes={{ selectMenu: classes.selectMenu, icon: classes.selectArrow }} value={shopId} input={<ShopSelectorInput />}>
{adminUIShops.map((shop) => {
const customLogoFromUpload = shop.brandAssets && shop.brandAssets.navbarBrandImage && shop.brandAssets.navbarBrandImage.large;
const customLogoFromUrlInput = shop.shopLogoUrls && shop.shopLogoUrls.primaryShopLogoUrl;
// Replace only the first segment of the URL with the shop ID and keep the rest (if any)
const linkUrl = location.pathname.replace(/(\/.[^/]*(\/.*)?)/g, (match, firstUrlSegment, restOfUrl) => `/${shop._id}${restOfUrl || ""}`);

return (
<MenuItem className={classes.menuItem} value={shop._id} key={shop._id}>
<Link
className={classNames(classes.root, className)}
to={linkUrl}
>
<img
alt={shop.name}
className={classes.logo}
src={customLogoFromUrlInput || customLogoFromUpload || defaultLogo}
width={size}
/>
{shouldShowShopName &&
<Typography
variant="h3"
component="span"
>
{shop.name}
</Typography>
}
</Link>
</MenuItem>
);
})}
<MenuItem className={classes.menuItem} value="new-shop" key="new-shop">
<Link
className={classNames([classes.root, className, classes.newShopLink])}
to={"/new-shop"}
>
<div className={classNames([classes.logo, classes.plusIcon])} style={{ width: size }}>
<FontAwesomeIcon icon={faPlus} />
</div>
<Typography
variant="h3"
component="span"
>
New Shop
</Typography>
</Link>
</MenuItem>
</Select>
);
}

ShopSelectorWithData.propTypes = {
className: PropTypes.string,
classes: PropTypes.object,
linkTo: PropTypes.string,
shopId: PropTypes.string,
shouldShowShopName: PropTypes.bool,
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
viewer: PropTypes.object
};

ShopSelectorWithData.defaultProps = {
linkTo: "/",
shouldShowShopName: false,
size: 60
};

export default compose(
withComponents,
withStyles(styles, { name: "RuiShopSelectorWithData" })
)(ShopSelectorWithData);
1 change: 1 addition & 0 deletions imports/client/ui/components/ShopSelectorWithData/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./ShopSelectorWithData";
18 changes: 13 additions & 5 deletions imports/client/ui/components/Sidebar/Sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import CloseIcon from "mdi-material-ui/Close";
import { Translation } from "/imports/plugins/core/ui/client/components";
import useIsAppLoading from "/imports/client/ui/hooks/useIsAppLoading.js";
import useCurrentShopId from "../../hooks/useCurrentShopId";
import ShopLogoWithData from "../ShopLogoWithData";
import ShopSelectorWithData from "../ShopSelectorWithData";
import useOperatorRoutes from "../../hooks/useOperatorRoutes";

const activeClassName = "nav-item-active";
Expand Down Expand Up @@ -97,7 +97,8 @@ function Sidebar(props) {
isMobile,
isSidebarOpen,
onDrawerClose,
setIsSettingsOpen
setIsSettingsOpen,
viewer
} = props;

const [isAppLoading] = useIsAppLoading();
Expand Down Expand Up @@ -132,7 +133,7 @@ function Sidebar(props) {
<NavLink
activeClassName={activeClassName}
className={classes.link}
to={route.href || route.path}
to={(route.href || route.path).replace(":shopId", currentShopId)}
key={route.path}
onClick={() => {
setIsSettingsOpen(false);
Expand Down Expand Up @@ -164,7 +165,13 @@ function Sidebar(props) {
position="sticky"
>
<Toolbar className={classes.toolbar}>
<ShopLogoWithData className={classes.shopLogo} shouldShowShopName size={32} />
<ShopSelectorWithData
className={classes.shopLogo}
shouldShowShopName
shopId={currentShopId}
size={32}
viewer={viewer}
/>

<Hidden mdUp>
<Fab classes={{ root: classes.closeButton }} onClick={onDrawerClose} size="small">
Expand All @@ -187,7 +194,8 @@ Sidebar.propTypes = {
isMobile: PropTypes.bool,
isSidebarOpen: PropTypes.bool.isRequired,
onDrawerClose: PropTypes.func.isRequired,
setIsSettingsOpen: PropTypes.func.isRequired
setIsSettingsOpen: PropTypes.func.isRequired,
viewer: PropTypes.object
};

Sidebar.defaultProps = {
Expand Down
Loading