diff --git a/app/helpers/auction_helper.rb b/app/helpers/auction_helper.rb new file mode 100644 index 00000000..0b0ac44d --- /dev/null +++ b/app/helpers/auction_helper.rb @@ -0,0 +1,9 @@ +module AuctionHelper + def auction_status(auction) + if auction.available? + 'Open' + else + 'Closed' + end + end +end diff --git a/app/models/presenter/auction.rb b/app/models/presenter/auction.rb index 3e05c5eb..e42db273 100644 --- a/app/models/presenter/auction.rb +++ b/app/models/presenter/auction.rb @@ -59,11 +59,19 @@ def available? ) end + def over? + model.end_datetime < Time.now + end + def user_is_winning_bidder?(user) return false if !current_bid? user.id == current_bid.bidder_id end + def user_is_bidder?(user) + bids.detect {|b| user.id == b.bidder_id } != nil + end + def html_description return '' if description.blank? markdown.render(description) diff --git a/app/views/auctions/_win_header.html.erb b/app/views/auctions/_win_header.html.erb new file mode 100644 index 00000000..624999c2 --- /dev/null +++ b/app/views/auctions/_win_header.html.erb @@ -0,0 +1,54 @@ +<% if auction.over? %> + <% if auction.bids? %> + <% if current_user %> + <% if auction.user_is_winning_bidder?(current_user) %> +
+

You are the winner

+

Congratulations! We will contact you with further instructions.

+
+ <% elsif auction.user_is_bidder?(current_user) %> +
+

You are not the winner

+

Someone else placed a lower bid than you.

+
+ <% end %> + <% else %> +
+
+

Auction Now Closed

+
+
+ <% end %> + <% else %> +
+
+

Auction Now Closed

+

This auction ended with no bids.

+
+
+ <% end %> +<% elsif auction.available? && auction.bids? && current_user && auction.user_is_bidder?(current_user) %> + <% if flash["bid"] %> +
+
+

Bid Submitted! You currently have the winning bid.

+

If your bid is selected as the winner, we will contact you with further instructions. View your bids »

+
+
+ <% elsif auction.user_is_winning_bidder?(current_user) %> +
+
+

You currently have the winning bid.

+

If your bid is selected as the winner, we will contact you with further instructions.

+
+
+ <% else %> +
+
+

You currently do not have the winning bid.

+

You must enter a new lower bid to win this auction.

+
+
+ <% end %> +<%# display nothing if in the future %> +<% end %> diff --git a/app/views/auctions/show.html.erb b/app/views/auctions/show.html.erb index 3817228f..19b98c36 100644 --- a/app/views/auctions/show.html.erb +++ b/app/views/auctions/show.html.erb @@ -1,11 +1,4 @@ -<% if flash["bid"] %> -
-
-

Bid Submitted! You currently have the winning bid.

-

If your bid is selected as the winner, we will contact you with further instructions. View your bids »

-
-
-<% end %> +<%= render partial: 'win_header', locals: {auction: @auction} %>

« Back to open projects

@@ -19,18 +12,23 @@

Status:

-

<% if @auction.available? %>Open<% else %>Closed<% end %>

-

Current Bid:

+

<%= auction_status(@auction) %>

+ + <% if @auction.over? && @auction.bids? %> +

Winning bid (<%= @auction.current_bidder_name %>):

+ <% else %> +

Current bid:

+ <% end %>

<%= number_to_currency(@auction.current_bid_amount) %> - <%= - link_to( - pluralize(@auction.bids.length, 'bid'), - auction_bids_path(@auction.id) - ) - %> - + <%= + link_to( + pluralize(@auction.bids.length, 'bid'), + auction_bids_path(@auction.id) + ) + %> +

-

Bid deadline:

+

<% if @auction.over? %>Auction ended at:<% else %>Bid deadline:<% end %>

<%= @auction.end_datetime.strftime("%m/%d/%Y at %I:%M %Z") %>

BID » diff --git a/spec/factories/auctions.rb b/spec/factories/auctions.rb index e5d49aa7..69eca678 100644 --- a/spec/factories/auctions.rb +++ b/spec/factories/auctions.rb @@ -9,13 +9,16 @@ trait :with_bidders do after(:build) do |instance| - (1..rand(10)+1).each do |i| - amount = 3499 - (100 * i) - rand(30) - instance.bids << FactoryGirl.create(:bid, auction: instance, amount: amount) + Timecop.freeze(instance.start_datetime) do + Timecop.scale(3600) + (1..4).each do |i| + amount = 3499 - (20 * i) - rand(10) + instance.bids << FactoryGirl.create(:bid, auction: instance, amount: amount) + end end end end - + trait :closed do end_datetime { Time.now - 1.day } end diff --git a/spec/features/bidder_interacts_with_auction_spec.rb b/spec/features/bidder_interacts_with_auction_spec.rb index 350c7bc4..310cae9e 100644 --- a/spec/features/bidder_interacts_with_auction_spec.rb +++ b/spec/features/bidder_interacts_with_auction_spec.rb @@ -85,7 +85,7 @@ click_on("Submit") # returns us back to the bid page - expect(page).to have_content("Current Bid:") + expect(page).to have_content("Current bid:") expect(page).to have_content("$800.00") end @@ -103,7 +103,7 @@ click_on("Submit") # returns us back to the bid page - expect(page).to have_content("Current Bid:") + expect(page).to have_content("Current bid:") expect(page).to have_content("$999.00") expect(page).to have_content("You currently have the winning bid.") end @@ -194,6 +194,103 @@ end end + scenario "Viewing auction page for a closed auction where a user is not authenticated" do + create_closed_auction + auction = Presenter::Auction.new(@auction) + visit auction_path(auction.id) + + expect(page).to have_css('.usa-alert-info') + expect(page).to have_css('.auction-alert') + expect(page).to have_content("Winning bid (#{auction.current_bidder_name}):") + expect(page).not_to have_content("Current bid:") + + expect(page).to have_content("Auction ended at:") + expect(page).not_to have_content("Bid deadline:") + end + + scenario "Viewing auction page for a closed auction where authenticated user is the winner" do + create_closed_auction + + visit "/" + sign_in_bidder + + bid = nil + Timecop.freeze(@auction.end_datetime) do + bid = @auction.bids.create(bidder_id: @bidder.id, amount: 1) + end + expect(bid).to be_valid + @auction.reload + + auction = Presenter::Auction.new(@auction) + + expect(auction.current_bidder_name).to eq(@bidder.name) + visit auction_path(auction.id) + + expect(page).to have_css('.usa-alert-success') + expect(page).to have_content("You are the winner") + expect(page).to have_content("Winning bid (#{auction.current_bidder_name}):") + expect(page).not_to have_content("Current bid:") + + expect(page).to have_content("Auction ended at:") + expect(page).not_to have_content("Bid deadline:") + end + + scenario "Viewing auction page for a closed auction where authenticated user is not the winner" do + create_closed_auction + + visit '/' + sign_in_bidder + + auction = Presenter::Auction.new(@auction) + + bid = nil + Timecop.freeze(@auction.start_datetime) do + bid = @auction.bids.create(bidder_id: @bidder.id, amount: 3498) + end + expect(bid).to be_valid + + visit auction_path(auction.id) + + expect(page).to have_css('.usa-alert-error') + expect(page).to have_content("You are not the winner") + expect(page).to have_content("Winning bid (#{auction.current_bidder_name}):") + expect(page).not_to have_content("Current bid:") + + expect(page).to have_content("Auction ended at:") + expect(page).not_to have_content("Bid deadline:") + end + +scenario "Viewing auction page for a closed auction where authenticated user has not placed bids" do + create_closed_auction + auction = Presenter::Auction.new(@auction) + + visit '/' + sign_in_bidder + + visit auction_path(auction.id) + + expect(page).to_not have_css('.usa-alert-error') + expect(page).to_not have_content("You are not the winner") + expect(page).to have_content("Winning bid (#{auction.current_bidder_name}):") + expect(page).not_to have_content("Current bid:") + + expect(page).to have_content("Auction ended at:") + expect(page).not_to have_content("Bid deadline:") + end + + scenario "Viewing auction page for a closed auction with no bidders" do + create_closed_bidless_auction + auction = Presenter::Auction.new(@auction) + visit auction_path(auction.id) + + expect(page).to have_content("This auction ended with no bids.") + expect(page).to have_content("Current bid:") + + expect(page).to have_content("Auction ended at:") + expect(page).not_to have_content("Bid deadline:") + end + + scenario "Viewing bid history for a closed auction" do Timecop.scale(36000) do create_closed_auction diff --git a/spec/models/presenter/auction_spec.rb b/spec/models/presenter/auction_spec.rb index e7239661..a2e50003 100644 --- a/spec/models/presenter/auction_spec.rb +++ b/spec/models/presenter/auction_spec.rb @@ -47,12 +47,52 @@ end end + describe '#user_is_winning_bidder?' do + let(:ar_auction) { FactoryGirl.create(:auction, :with_bidders) } + + context 'when the user is currently the winner' do + let(:bidder) { auction.bids.first.bidder } + + it 'should return true' do + expect(auction.user_is_winning_bidder?(bidder)).to be_truthy + end + end + + context 'when the user is not the current winner' do + let(:bidder) { auction.bids.last.bidder } + + it 'should return false' do + expect(auction.user_is_winning_bidder?(bidder)).to be_falsey + end + end + end + + describe '#user_is_bidder?' do + let(:ar_auction) { FactoryGirl.create(:auction, :with_bidders) } + + context 'when the user has placed a bid on the project' do + let(:bidder) { auction.bids.last.bidder } + + it 'should return true' do + expect(auction.user_is_bidder?(bidder)).to be_truthy + end + end + + context 'when the user has not placed a bid on the project' do + let(:bidder) { FactoryGirl.create(:user) } + + it 'should return false' do + expect(auction.user_is_bidder?(bidder)).to be_falsey + end + end + end + describe '#available?' do context 'when the auction has expired' do let(:ar_auction) { FactoryGirl.create(:auction, :closed) } it 'should be false' do - expect(auction.available?).to eq(false) + expect(auction).to_not be_available end end @@ -60,7 +100,7 @@ let(:ar_auction) { FactoryGirl.create(:auction, :future) } it 'should be false' do - expect(auction.available?).to eq(false) + expect(auction).to_not be_available end end @@ -68,7 +108,33 @@ let(:ar_auction) { FactoryGirl.create(:auction) } it 'should be false' do - expect(auction.available?).to eq(true) + expect(auction).to be_available + end + end + end + + describe '#over?' do + context 'when the auction has expired' do + let(:ar_auction) { FactoryGirl.create(:auction, :closed) } + + it 'should be true' do + expect(auction).to be_over + end + end + + context 'when the auction is still running' do + let(:ar_auction) { FactoryGirl.create(:auction) } + + it 'should not be true' do + expect(auction).to_not be_over + end + end + + context 'when the auction has not started' do + let(:ar_auction) { FactoryGirl.create(:auction, :future) } + + it 'should be false' do + expect(auction).to_not be_over end end end diff --git a/spec/support/feature_helpers.rb b/spec/support/feature_helpers.rb index 58cfecb3..0ad67171 100644 --- a/spec/support/feature_helpers.rb +++ b/spec/support/feature_helpers.rb @@ -9,6 +9,12 @@ def create_bidless_auction(end_datetime: Time.now + 3.days) return @auction, @bidders end +def create_closed_bidless_auction + create_bidless_auction + @auction.end_datetime = Time.now - 1.day + @auction.save +end + def create_current_auction @auction = FactoryGirl.create(:auction, :with_bidders) @bidders = @auction.bids @@ -37,7 +43,7 @@ def sign_in_bidder end def create_authed_bidder - @bidder = FactoryGirl.create(:user, github_id: current_user_uid) + @bidder = FactoryGirl.create(:user, github_id: current_user_uid, name: 'Doris Doogooder') end def show_page