-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Update admin cart page dynamically #1715
Conversation
@@ -0,0 +1,10 @@ | |||
(function() { | |||
var defaultLocale = document.documentElement.lang; |
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.
Is there a default fallback language for when locale is not set?
I'd assume that would be English. In that case, this makes more sense:
var defaultLocale = document.documentElement.lang || 'en';
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.
It will always be set. I don't think we need to be defensive here.
Spree.formatMoney = function(amount, currency, options) { | ||
options = (options || {}); | ||
var locale = options.locale || defaultLocale; | ||
var format = new Intl.NumberFormat(locale, {style: 'currency', currency: currency}) |
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.
There's a big discussion whether semicolons should be always added or not in JS. I'd lean towards the "mandatory semicolons", simply because it prevents unexpected errors from happening. You can see one such example in this SO answer:
http://stackoverflow.com/a/8108912/336806
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.
Speaking of, is there any linter used for JS? What are the JS style rules (e.g. semicolons)
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.
Nope. Please feel free to file an issue.
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.
Filed
(function() { | ||
var defaultLocale = document.documentElement.lang; | ||
|
||
Spree.formatMoney = function(amount, currency, options) { |
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.
This function looks like something I'd like to be able to also use on frontend. It seems to be impossible without including solidus_backend
. Is there a central place where such functions could go?
Also, defaultLocale could be calculated in a centralized place.
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.
I can appreciate that, but I'm not 100% sure that this will be the permanent implementation of this method. We might have to end up including accounting.js
or similar, which we would not want cluttering up the frontend. For that reason, I want to keep this backend-only.
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.
I guess we can both agree that "temporary fix" tends to stay around much longer than what we planned it to stay. :)
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.
This is not a temporary fix. The frontend and backend have different javascript, different requirements, and different browser support.
@@ -124,6 +124,11 @@ button, .button { | |||
width: 100%; | |||
text-align: center; | |||
} | |||
|
|||
&[disabled], &.disabled { |
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.
I think the more preferred way would be to use :disabled
CSS3 selector. Although they are the same, some explanation why use one over the [disabled]
can be found here:
http://stackoverflow.com/a/20146936/336806
It works in cross-browser:
http://caniuse.com/#feat=css-sel3
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.
Good call 👍
<thead> | ||
<tr> | ||
<th><%= Spree::Adjustment.human_attribute_name(:name)%></th> | ||
<th><%= Spree::Adjustment.human_attribute_name(:amount)%></th> |
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.
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.
Nevermind, this is a solidus_i18n
issue
<% adjustments.eligible.group_by(&:label).each do |label, adjustments| %> | ||
<tr class="total"> | ||
<td><strong><%= label %>:</strong></td> | ||
<td class="total align-center"><span><%= Spree::Money.new(adjustments.sum(&:amount), currency: adjustments.first.order.try(:currency)) %></span></td> |
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.
Not related to these changes, but you could add this fix in:
currency: adjustments.first.order.try(:currency)
=>
currency: order.currency
...since you're always passing order
variable and it's always defined.
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.
Good call. We should address this in this PR
sku = order.line_items.first.variant.sku | ||
expect(page).to have_content("SKU: #{sku}") | ||
context "with a completed order" do | ||
let!(:order) { create(:completed_order_with_totals) } |
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.
I think it's better having this inlined inside of the it block:
order = create(:completed_order_with_totals)
It's always better to have the code contained in the single place, than trying to figure out where did this variable come from (especially if let!
is used and not let
).
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.
Using let is better for composability and is always preferred. This let actually overrides a let!(:order)
higher up in the file, which the local definition would not do. This is a good thing.
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.
Do you mean it's always preferred in solidus
project(s) or it's generally always preferred? Because I prefer not to use it and I can find some good arguments why it should be avoided:
https://robots.thoughtbot.com/lets-not
http://linduxed.com/blog/2014/08/24/writing-more-readable-rspec-tests/
Of course there are always arguments pro and contra. Just asking out of curiosity.
core/config/locales/en.yml
Outdated
@@ -711,6 +711,7 @@ en: | |||
add_action_of_type: Add action of type | |||
add_country: Add Country | |||
add_coupon_code: Add Coupon Code | |||
add_line_item: Add Item |
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.
Is there any process for reporting this new translation to solidus_i18n
? Perhaps an issue could be created on the solidus_i18n
repo when translation-changes/new-translation-is-added?
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.
There is a rake task in solidus_i18n
for this purpose. This question is way outside the scope of this PR.
Spree.formatMoney = function(amount, currency, options) { | ||
options = (options || {}); | ||
var locale = options.locale || defaultLocale; | ||
var format = new Intl.NumberFormat(locale, {style: 'currency', currency: currency}) |
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.
Filed
(function() { | ||
var defaultLocale = document.documentElement.lang; | ||
|
||
Spree.formatMoney = function(amount, currency, options) { |
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.
I guess we can both agree that "temporary fix" tends to stay around much longer than what we planned it to stay. :)
sku = order.line_items.first.variant.sku | ||
expect(page).to have_content("SKU: #{sku}") | ||
context "with a completed order" do | ||
let!(:order) { create(:completed_order_with_totals) } |
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.
Do you mean it's always preferred in solidus
project(s) or it's generally always preferred? Because I prefer not to use it and I can find some good arguments why it should be avoided:
https://robots.thoughtbot.com/lets-not
http://linduxed.com/blog/2014/08/24/writing-more-readable-rspec-tests/
Of course there are always arguments pro and contra. Just asking out of curiosity.
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.
A great UX improvement. 👍
I have some little code styling nits and I'm not sure if we should put all these backbone models and views into large files or if it would be better to have them separate overridable files instead.
As always 🍻 work!
<% adjustments.eligible.group_by(&:label).each do |label, adjustments| %> | ||
<tr class="total"> | ||
<td><strong><%= label %>:</strong></td> | ||
<td class="total align-center"><span><%= Spree::Money.new(adjustments.sum(&:amount), currency: adjustments.first.order.try(:currency)) %></span></td> |
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.
Good call. We should address this in this PR
}); | ||
model.fetch(options); | ||
return model; | ||
} |
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.
Maybe we should split this file into files for each model? So devs could override individual models (the order for instance)? Not sure though, if this could ever be the case.
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.
I agree. Going to split these into separate files and also move to a different namespace, Spree.Models.Order
, which will also make more sense as we add more models (like Spree.Models.Variant
)
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.
👍🏻 for the namespace
|
||
render: -> | ||
@$el.prop("disabled", !this.collection.length || this.collection.some( (item) -> item.isNew() )) | ||
|
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.
I kinda confuses me, that some files are coffeescript and some are javascript. I would prefer to go with JS from now on. But we should be consistent.
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.
Also maybe splitting these views into separate overridable files would be preferable?
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.
I also prefer JS, but this file was originally coffeescript and the changes were each incremental
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.
Ok. Fair enough.
this.$el.toggleClass('hidden', !lineItemCount) | ||
this.$('.order-total').text(this.model.get("display_total")) | ||
} | ||
}) |
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.
Also consider to split this file up
this.$('dd.order-shipment_state').html(this.renderState('shipment_state', this.model.get("shipment_state"))) | ||
|
||
this.$('.order-payment_state').toggleClass("hidden", !this.model.get("completed_at")) | ||
this.$('dd.order-payment_state').html(this.renderState('payment_state', this.model.get("payment_state"))) |
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.
Not a backbone expert, but do we really need to use this.$
over just $
?
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.
Yes. this.$
is scoped within the view's element. It's great!
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.
TIL. Indeed very nice 👌🏻
<a class="edit-line-item fa fa-edit no-text with-tip" href="#" title="{{ t "actions.edit" }}"></a> | ||
<a class="delete-line-item fa fa-trash no-text with-tip" href="#" title="{{ t "actions.delete" }}"></a> | ||
{{/if}} | ||
</td> |
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.
I think the indentation in this file messed up somehow.
} | ||
|
||
.select2-container.error { | ||
border-radius: 4px; |
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.
I believe we have a global $border-radius
variable we can use here.
:title => Spree.t(:order_adjustments) | ||
} %> | ||
<%= render :partial => "spree/admin/orders/carton", :collection => @order.cartons.order(:shipped_at), :locals => { :order => order } %> | ||
<%= render :partial => "spree/admin/orders/shipment", :collection => @order.shipments.order(:created_at), :locals => { :order => order } %> |
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.
We should only use Ruby 1.9 Hash syntax if we touch lines of code
<dt><%= Spree::Shipment.model_name.human %>: </dt> | ||
<dd id='shipment_status'><span class="state <%= @order.shipment_state %>"><%= Spree.t(@order.shipment_state, :scope => :shipment_states, :default => [:missing, "none"]) %></span></dd> | ||
<dt><%= Spree::Payment.model_name.human %>: </dt> | ||
<dd id='payment_status'><span class="state <%= @order.payment_state %>"><%= Spree.t(@order.payment_state, :scope => :payment_states, :default => [:missing, "none"]) %></span></dd> | ||
<dt data-hook='admin_order_tab_date_completed_title'><%= Spree::Order.human_attribute_name(:completed_at) %>:</dt> | ||
<dd id='date_complete'><%= pretty_time(@order.completed_at) %></dd> | ||
<% end %> |
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.
This view could profit from some indenting and usage of Ruby 1.9 hash syntax.
6610fe4
to
e7cc666
Compare
@tvdeyen This is ready for review :) Models and views are now namespaced and in the Tests have passed, but CircleCI is being CircleCI and hasn't updated github. |
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.
🎉 I really love the way this goes. Very well structured backend code. This is a huge improvement for us. Thanks for working on this, John! 🍬 🥃 🎂
Just one thought. Could we get rid off the need to create the Spree.Models
and Spree.Views
objects in each file by adding spree/backend/models/base
and spree/backend/views/base
files and require these instead? Nothing we need to tackle now.
This is ready to be merged IMO 👍
@@ -0,0 +1,9 @@ | |||
//= require spree/backend/routes |
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.
I don't think we need routes in this file
@jhawthorn I see a fixup commit. Maybe you need to rebase once more? |
This hack existed from before the "cart" page existed to allow stores which didn't perform deliveries to still edit items.
Works around an issue where an Order was being fetched by the server at the same time the spec was creating an order by factory. SQLite3::BusyException: database is locked:
This simplifies fetching the order from the API, which we will want to do in several places. It hides the implementation detail of the placeholder arrays for the line_items and shipments collections.
e7cc666
to
4ea9fb9
Compare
🚀 |
Built on top of #1710
This fully models the displayed information on the cart page in backbone, which allows it to update dynamically without relying on the previous
window.location.reload()
.This allows for smoother interaction by the user, and avoids undesirable changes from the refresh like closing in-progress edits.