Skip to content

Commit

Permalink
Marketplace: Sprout Delivery::Window object
Browse files Browse the repository at this point in the history
- #1185

So, the `delivery_window` field which can either be a plain string or a
particular date or even a date range is a much more sophisticated
object.

I took some time last night to explore what it could look like to use
`ActiveModel::Type`s  to create a value object which can take
responsibility for representing the data more appropriately.

That said, I think `store_model` will be better ™️, but I didn't want
to try to dig into that just yet.
  • Loading branch information
zspencer committed Apr 8, 2023
1 parent df64d31 commit 8d69ebc
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 18 deletions.
10 changes: 1 addition & 9 deletions app/furniture/marketplace/cart.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Cart < Record

# this feels like it is starting to want to be it's own model...
has_encrypted :delivery_address
attribute :delivery_window, ::Marketplace::Delivery::WindowType.new
has_encrypted :contact_phone_number
has_encrypted :contact_email

Expand All @@ -33,15 +34,6 @@ def delivery
@delivery ||= becomes(Delivery)
end

def delivery_window
return marketplace.delivery_window if marketplace&.delivery_window.present?
return nil if super.blank?

DateTime.parse(super) || 48.hours.from_now
rescue Date::Error => _e
48.hours.from_now
end

def delivery_fee
return marketplace.delivery_fee if delivery_address.present?

Expand Down
7 changes: 1 addition & 6 deletions app/furniture/marketplace/cart/deliveries/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
<div id="<%= dom_id(delivery) %>">
<%= form_with model: delivery.location do |delivery_form| %>
<%= render "text_field", attribute: :delivery_address, form: delivery_form %>

<%- if delivery.marketplace.delivery_window.present? %>
<%= render "text_field", attribute: :delivery_window, form: delivery_form, disabled?: true %>
<%- else %>
<%= render "datetime_field", attribute: :delivery_window, form: delivery_form %>
<%- end %>
<%= render "window_field", attribute: :window, form: delivery_form %>
<%= render "email_field", attribute: :contact_email, form: delivery_form %>
<%= render "text_field", attribute: :contact_phone_number, form: delivery_form %>
<%= delivery_form.submit %>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<%- delivery = form.object%>
<%- disabled = delivery.marketplace.delivery_window.present? %>
<%- window = form.object.send(attribute) %>

<%- if window.value.is_a?(DateTime) || delivery.marketplace.delivery_window.blank? %>
<%= render "datetime_field", attribute: attribute, form: form, disabled?: disabled %>
<%- else %>
<%= render "text_field", attribute: attribute, form: form, disabled?: disabled %>
<%- end %>
1 change: 1 addition & 0 deletions app/furniture/marketplace/cart/delivery.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class Cart
class Delivery < Cart
extend StripsNamespaceFromModelName
location(routed_as: :resource, parent: :cart)
attribute :delivery_window, ::Marketplace::Delivery::WindowType.new

validates :contact_email, presence: true
validates :contact_phone_number, presence: true
Expand Down
2 changes: 1 addition & 1 deletion app/furniture/marketplace/carts/_cart.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
Orders placed by <%= cart.marketplace.order_by %>
are delivered on <%= cart.marketplace.delivery_window %>
<%- elsif cart.delivery_window.present? %>
Place orders <%= cart.marketplace.order_by %> to ensure an on-time delivery for <%= l(cart.delivery_window, format: :day_month_date_hour_minute) %><br />
Place orders <%= cart.marketplace.order_by %> to ensure an on-time delivery for <%= render(cart.delivery_window) %>
<%= render Marketplace::Cart::Delivery::EditButtonComponent.new(cart.delivery) %>
<%- end %>
</p>
Expand Down
5 changes: 5 additions & 0 deletions app/furniture/marketplace/delivery.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Marketplace
class Delivery < Order
attribute :delivery_window, ::Marketplace::Delivery::WindowType.new
end
end
21 changes: 21 additions & 0 deletions app/furniture/marketplace/delivery/window.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Marketplace
class Delivery
class Window < Model
attr_writer :value

def value
return nil if @value.blank?

DateTime.iso8601(@value)
rescue Date::Error => _e
@value
end

delegate :strftime, to: :value

def eql?(other)
value.eql?(other.value)
end
end
end
end
13 changes: 13 additions & 0 deletions app/furniture/marketplace/delivery/window_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Marketplace
class Delivery
class WindowType < ActiveRecord::Type::Value
def deserialize(value)
Window.new(value: value)
end
end

def cast(value)
Window.value(value: value)
end
end
end
5 changes: 5 additions & 0 deletions app/furniture/marketplace/delivery/windows/_window.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%- if window.value.is_a?(DateTime) %>
<%= l(window.value, format: :day_month_date_hour_minute) %>
<%- else %>
<%= window.value %>
<%- end %>
5 changes: 5 additions & 0 deletions app/furniture/marketplace/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Order < Record
has_many :products, through: :ordered_products, inverse_of: :orders

has_encrypted :delivery_address
attribute :delivery_window, Delivery::WindowType.new
has_encrypted :contact_phone_number
has_encrypted :contact_email

Expand All @@ -28,6 +29,10 @@ def tax_total
ordered_products.sum(0, &:tax_amount)
end

def delivery
becomes(Delivery)
end

delegate :delivery_fee, to: :marketplace

def marketplace_name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
<tr><th colspan="3">Delivery Details</th></tr>
<tr>
<td class="text-right">Delivery Schedule:</td>
<td><%= order.delivery_window %></td>
<td><%= render(order.delivery.window) %></td>
</tr>
<tr>
<td class="text-right">Buyer Email:</td>
Expand Down
3 changes: 2 additions & 1 deletion app/views/application/_datetime_field.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<%- disabled = local_assigns.fetch(:disabled?, false)%>
<div>
<%= form.label attribute %>
<%= form.datetime_field attribute %>
<%= form.datetime_field attribute, disabled: disabled %>
<%= render partial: "error", locals: { model: form.object, attribute: attribute } %>
</div>
27 changes: 27 additions & 0 deletions spec/furniture/marketplace/delivery/window_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require "rails_helper"

RSpec.describe Marketplace::Delivery::Window do
subject(:window) { described_class.new(value: value) }

describe "#value" do
subject(:deserialize) { window.value }

context "when the value is blank" do
let(:value) { "" }

it { is_expected.to be_nil }
end

context "when the value is an iso8601 String" do
let(:value) { DateTime.parse("2023-01-01 3:00pm").iso8601 }

it { is_expected.to eql(DateTime.parse("2023-01-01 3:00pm")) }
end

context "when the value is a plain string" do
let(:value) { "This Evening" }

it { is_expected.to eql(value) }
end
end
end
11 changes: 11 additions & 0 deletions spec/furniture/marketplace/delivery/window_type_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "rails_helper"

RSpec.describe Marketplace::Delivery::WindowType do
subject(:type) { described_class.new }

describe "#deserialize" do
subject(:deserialize) { type.deserialize("words") }

it { is_expected.to eql(Marketplace::Delivery::Window.new(value: "words")) }
end
end

0 comments on commit 8d69ebc

Please sign in to comment.