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

Added a not found view to product grid #2656

Merged
merged 15 commits into from
Aug 11, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
1 change: 1 addition & 0 deletions imports/plugins/core/ui/client/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ export { Overlay } from "./modal";
export * from "./tabs";
export { default as Select } from "./select/select.react";
export { default as ClickToCopy } from "./clickToCopy/clickToCopy";
export * from "./notFound";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as NotFound } from "./notFound";
100 changes: 100 additions & 0 deletions imports/plugins/core/ui/client/components/notFound/notFound.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React from "react";
import PropTypes from "prop-types";
import classnames from "classnames";
import { Components, registerComponent } from "@reactioncommerce/reaction-components";
import { Icon } from "../icon";

/**
* React component for displaying a not-found view
* @param {props} props React props
* @return {Node} React node containing not-found view
*/
const NotFound = (props) => {
// ClassName for base wrapper,
// If one is provied in props, the default is not used
const baseClassName = classnames({
"container-fluid-sm": typeof props.className === "undefined"
}, props.className);

// ClassName for content wrapper
// If one is provied in props, the default is not used
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in comment

const contentClassName = classnames({
"empty-view-message": typeof props.contentClassName === "undefined"
}, props.contentClassName);

return (
<div className={baseClassName}>
<div className={contentClassName}>
{ props.icon &&
<Icon icon={props.icon} />
}

{ props.title &&
<Components.Translation defaultValue={props.title} i18nKey={props.i18nKeyTitle} />
}

{ props.message &&
<Components.Translation defaultValue={props.message} i18nKey={props.i18nKeyMessage} />
}

{props.children}
</div>
</div>
);
};

NotFound.propTypes = {
/**
* Children
* @type {ReactNode}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this more consistent? I feel like we call this different things different place (e.g. Node/ReactNode/JSX. Is there a difference?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just go with Node prop type.

@machikoyasuda what do you think? Maybe we can set up a type in jsdoc that knows Node is react node when the docs are generated?

*/
children: PropTypes.node,

/**
* Baase wrapper className
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in comment

* @summary String className of `classnames` compatable object for the base wrapper
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in comment

* @type {String|Object}
*/
className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),

/**
* Content className
* @summary String className of `classnames` compatable object for the content wrapper
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in comment (compatible)

* @type {String|Object}
*/
contentClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),

/**
* i18n key for message
* @type {String}
*/
i18nKeyMessage: PropTypes.string,

/**
* i18n key for title
* @type {String}
*/
i18nKeyTitle: PropTypes.string,

/**
* Icon name
* @type {String}
*/
icon: PropTypes.string,

/**
* Message text
* @type {String}
*/
message: PropTypes.string,

/**
* Title
* @type {String}
*/
title: PropTypes.string
};

registerComponent("NotFound", NotFound);

export default NotFound;
22 changes: 14 additions & 8 deletions imports/plugins/included/product-variant/components/products.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class Products extends Component {
loadProducts: PropTypes.func,
products: PropTypes.array,
productsSubscription: PropTypes.object,
ready: PropTypes.func
ready: PropTypes.func,
showNotFound: PropTypes.bool
};

handleClick = (event) => {
Expand Down Expand Up @@ -43,9 +44,7 @@ class Products extends Component {
renderSpinner() {
if (this.props.productsSubscription.ready() === false) {
return (
<div className="spinner-container">
<div className="spinner" />
</div>
<Components.Loading />
);
}
}
Expand All @@ -66,7 +65,15 @@ class Products extends Component {
}

render() {
if (this.props.ready()) {
if (this.props.showNotFound) {
return (
<Components.NotFound
i18nKeyTitle="productGrid.noProductsFound"
icon="fa fa-barcode"
title="No Products Found"
/>
);
} else if (this.props.ready()) {
return (
<div id="container-main">
{this.renderProductGrid()}
Expand All @@ -75,10 +82,9 @@ class Products extends Component {
</div>
);
}

return (
<div className="spinner-container spinner-container-lg">
<div className="spinner" />
</div>
<Components.Loading />
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ const wrapComponent = (Comp) => (
static propTypes = {
canLoadMoreProducts: PropTypes.bool,
products: PropTypes.array,
productsSubscription: PropTypes.object
productsSubscription: PropTypes.object,
showNotFound: PropTypes.bool
};

constructor(props) {
Expand All @@ -61,6 +62,10 @@ const wrapComponent = (Comp) => (
}

ready = () => {
if (this.props.showNotFound === true) {
return false;
}

const isInitialLoad = this.state.initialLoad === true;
const isReady = this.props.productsSubscription.ready();

Expand All @@ -71,6 +76,7 @@ const wrapComponent = (Comp) => (
if (isReady) {
return true;
}

return false;
}

Expand All @@ -94,6 +100,7 @@ const wrapComponent = (Comp) => (
productsSubscription={this.props.productsSubscription}
loadMoreProducts={this.loadMoreProducts}
loadProducts={this.loadProducts}
showNotFound={this.props.showNotFound}
/>
);
}
Expand All @@ -116,8 +123,13 @@ function composer(props, onData) {

// if we get an invalid slug, don't return all products
if (!tag && slug) {
onData(null, {
showNotFound: true
});

return;
}

const currentTag = ReactionProduct.getTag();

const sort = {
Expand Down
3 changes: 3 additions & 0 deletions imports/plugins/included/product-variant/server/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"shortcut": {},
"dashboard": {},
"settings": {}
},
"productGrid": {
"noProductsFound": "No Products Found"
}
}
}
Expand Down