-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Use "Completed Order" component in Profile page #3112
Changes from 14 commits
76a4763
c3b805f
8837002
faf620e
2e655bd
2974d80
5a44015
745a1d3
208f828
7cbf6a8
c884282
d1a0899
214c958
8ab74e0
d6030d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React, { Component } from "react"; | ||
import PropTypes from "prop-types"; | ||
import CompletedOrder from "../../../checkout/client/components/completedOrder"; | ||
|
||
/** | ||
* @summary React component to display an array of completed orders | ||
* @class OrdersList | ||
* @extends {Component} | ||
* @property {Array} allOrdersInfo - array of orders | ||
* @property {Function} handeleDisplayMedia - function to display order image | ||
*/ | ||
class OrdersList extends Component { | ||
static propTypes = { | ||
allOrdersInfo: PropTypes.array, | ||
handleDisplayMedia: PropTypes.func | ||
} | ||
render() { | ||
const { allOrdersInfo, handleDisplayMedia } = this.props; | ||
return ( | ||
<div> | ||
{allOrdersInfo.map((order) => { | ||
const orderKey = order.orderId; | ||
return ( | ||
<CompletedOrder | ||
key={orderKey} | ||
shops={order.shops} | ||
order={order.order} | ||
orderId={order.orderId} | ||
orderSummary={order.orderSummary} | ||
paymentMethods={order.paymentMethods} | ||
productImages={order.productImages} | ||
handleDisplayMedia={handleDisplayMedia} | ||
/> | ||
); | ||
})} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
export default OrdersList; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { compose, withProps } from "recompose"; | ||
import { Meteor } from "meteor/meteor"; | ||
import { Media } from "/lib/collections"; | ||
import { registerComponent, composeWithTracker } from "@reactioncommerce/reaction-components"; | ||
import OrdersList from "../components/ordersList"; | ||
|
||
|
||
const handlers = {}; | ||
|
||
handlers.handleDisplayMedia = (item) => { | ||
const variantId = item.variants._id; | ||
const productId = item.productId; | ||
|
||
const variantImage = Media.findOne({ | ||
"metadata.variantId": variantId, | ||
"metadata.productId": productId | ||
}); | ||
|
||
if (variantImage) { | ||
return variantImage; | ||
} | ||
|
||
const defaultImage = Media.findOne({ | ||
"metadata.productId": productId, | ||
"metadata.priority": 0 | ||
}); | ||
|
||
if (defaultImage) { | ||
return defaultImage; | ||
} | ||
return false; | ||
}; | ||
|
||
function composer(props, onData) { | ||
// Get user order from props | ||
const orders = props.orders; | ||
const allOrdersInfo = []; | ||
|
||
if (orders) { | ||
orders.map((order) => { | ||
const imageSub = Meteor.subscribe("CartImages", order.items); | ||
const orderSummary = { | ||
quantityTotal: order.getCount(), | ||
subtotal: order.getSubTotal(), | ||
shippingTotal: order.getShippingTotal(), | ||
tax: order.getTaxTotal(), | ||
discounts: order.getDiscounts(), | ||
total: order.getTotal(), | ||
shipping: order.shipping | ||
}; | ||
if (imageSub.ready()) { | ||
const productImages = Media.find().fetch(); | ||
const orderId = order._id; | ||
const orderInfo = { | ||
shops: order.getShopSummary(), | ||
order, | ||
orderId, | ||
orderSummary, | ||
paymentMethods: order.getUniquePaymentMethods(), | ||
productImages | ||
}; | ||
allOrdersInfo.push(orderInfo); | ||
} | ||
}); | ||
onData(null, { | ||
allOrdersInfo | ||
}); | ||
} else { | ||
onData(null, { | ||
orders | ||
}); | ||
} | ||
} | ||
|
||
|
||
registerComponent("OrdersList", OrdersList, [ | ||
withProps(handlers), | ||
composeWithTracker(composer) | ||
]); | ||
|
||
export default compose( | ||
withProps(handlers), | ||
composeWithTracker(composer) | ||
)(OrdersList); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<template name="userOrdersList"> | ||
{{#if hasData data=data}} | ||
<div> | ||
{{> React completedOrders }} | ||
</div> | ||
{{else}} | ||
<div class="alert alert-info"> | ||
<span data-i18n="cartCompleted.noOrdersFound">No orders found.</span> | ||
</div> | ||
{{/if}} | ||
</template> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { Meteor } from "meteor/meteor"; | ||
import { Template } from "meteor/templating"; | ||
import { Orders } from "/lib/collections"; | ||
import { Reaction } from "/client/api"; | ||
import CompletedOrder from "/imports/plugins/core/accounts/client/containers/userOrdersListContainer"; | ||
|
||
/** | ||
* @method getOrders | ||
* @summary returns user's orders | ||
* @since 1.5.1 | ||
* @return {Array} - an array of orders | ||
*/ | ||
function getOrders() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused as to why we are doing anything at all in the template. If we still need the template at all the only thing it should be doing is rendering the component. |
||
const targetUserId = Reaction.Router.getQueryParam("userId") || | ||
Meteor.userId(); | ||
return Orders.find({ userId: targetUserId }, { | ||
sort: { | ||
createdAt: -1 | ||
}, | ||
limit: 25 | ||
}); | ||
} | ||
|
||
/** | ||
* userOrdersList helpers | ||
* | ||
*/ | ||
Template.userOrdersList.helpers({ | ||
hasData(data) { | ||
if (data.hash.data) { | ||
if (data.hash.data.count() > 0) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
return false; | ||
}, | ||
|
||
// Returns React Component | ||
completedOrders() { | ||
const orders = getOrders(); | ||
return { component: CompletedOrder, | ||
orders | ||
}; | ||
} | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import React from "react"; | ||
import PropTypes from "prop-types"; | ||
import { Components } from "@reactioncommerce/reaction-components"; | ||
import { Router } from "/client/modules/router/"; | ||
import CompletedShopOrders from "./completedShopOrders"; | ||
import CompletedOrderPaymentMethod from "./completedOrderPaymentMethods"; | ||
import CompletedOrderSummary from "./completedOrderSummary"; | ||
|
@@ -27,8 +28,15 @@ const CompletedOrder = ({ order, orderId, shops, orderSummary, paymentMethods, h | |
/> | ||
); | ||
} | ||
return ( | ||
<div className="container order-completed"> | ||
|
||
let headerText; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This component should not need to be aware of what route it is in. It should be handled by passing in a prop. Components should be as dumb as possible. |
||
let isProfilePage = false; | ||
|
||
if (Router.getRouteName() === "account/profile") { | ||
headerText = (<p><strong>Order ID </strong>{orderId}</p>); | ||
isProfilePage = true; | ||
} else { | ||
headerText = ( | ||
<div className="order-details-header"> | ||
{/* This is the left side / main content */} | ||
<h3><Components.Translation defaultValue="Thank You" i18nKey={"cartCompleted.thankYou"} /></h3> | ||
|
@@ -37,10 +45,15 @@ const CompletedOrder = ({ order, orderId, shops, orderSummary, paymentMethods, h | |
<AddEmail order={order} orderEmail={order.email} /> | ||
{/* This is the left side / main content*/} | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div className="container order-completed"> | ||
{ headerText } | ||
<div className="order-details-main"> | ||
<div className="order-details-content-title"> | ||
<Components.Translation defaultValue="Your Items" i18nKey={"cartCompleted.yourItems"} /> | ||
<p><Components.Translation defaultValue="Your Items" i18nKey={"cartCompleted.yourItems"} /></p> | ||
</div> | ||
{shops.map(function (shop) { | ||
const shopKey = Object.keys(shop); | ||
|
@@ -51,6 +64,7 @@ const CompletedOrder = ({ order, orderId, shops, orderSummary, paymentMethods, h | |
key={shopKey} | ||
shippingMethod={shop[shopKey].shippingMethod} | ||
handleDisplayMedia={handleDisplayMedia} | ||
isProfilePage={isProfilePage} | ||
/> | ||
); | ||
})} | ||
|
@@ -59,30 +73,36 @@ const CompletedOrder = ({ order, orderId, shops, orderSummary, paymentMethods, h | |
<div className="order-details-side"> | ||
|
||
{/* This is the right side / side content */} | ||
<div className="order-details-content-title"> | ||
<Components.Translation defaultValue="Shipping Address" i18nKey={"cartCompleted.shippingAddress"} /> | ||
</div> | ||
{orderSummary.shipping.map((shipment) => { | ||
if (shipment.address.fullName || shipment.address.address1) { | ||
return <div className="order-details-info-box" key={shipment._id}> | ||
<div className="order-details-info-box-content"> | ||
<p> | ||
{shipment.address.fullName}<br/> | ||
{shipment.address.address1}<br/> | ||
{shipment.address.city}, {shipment.address.region} {shipment.address.postal} {shipment.address.country} | ||
</p> | ||
</div> | ||
</div>; | ||
} | ||
})} | ||
<div className="shipping-payment-details"> | ||
<div className="shipping-info"> | ||
<div className="order-details-content-title"> | ||
<p> <Components.Translation defaultValue="Shipping Address" i18nKey={"cartCompleted.shippingAddress"} /></p> | ||
</div> | ||
{orderSummary.shipping.map((shipment) => { | ||
if (shipment.address.fullName || shipment.address.address1) { | ||
return <div className="order-details-info-box" key={shipment._id}> | ||
<div className="order-details-info-box-content"> | ||
<p> | ||
{shipment.address.fullName}<br/> | ||
{shipment.address.address1}<br/> | ||
{shipment.address.city}, {shipment.address.region} {shipment.address.postal} {shipment.address.country} | ||
</p> | ||
</div> | ||
</div>; | ||
} | ||
})} | ||
</div> | ||
|
||
<div className="order-details-content-title"> | ||
<Components.Translation defaultValue="Payment Method" i18nKey={"cartCompleted.paymentMethod"} /> | ||
<div className="payment-info"> | ||
<div className="order-details-content-title"> | ||
<p><Components.Translation defaultValue="Payment Method" i18nKey={"cartCompleted.paymentMethod"} /></p> | ||
</div> | ||
{paymentMethods.map(function (paymentMethod) { | ||
return <CompletedOrderPaymentMethod key={paymentMethod.key} paymentMethod={paymentMethod} />; | ||
})} | ||
</div> | ||
</div> | ||
{paymentMethods.map(function (paymentMethod) { | ||
return <CompletedOrderPaymentMethod key={paymentMethod.key} paymentMethod={paymentMethod} />; | ||
})} | ||
<CompletedOrderSummary shops={shops} orderSummary={orderSummary} /> | ||
<CompletedOrderSummary shops={shops} orderSummary={orderSummary} isProfilePage={isProfilePage} /> | ||
{/* This is the right side / side content */} | ||
</div> | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component should be handling both the found and not found cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I'll create functions to render found and not found cases in the component.