Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions app/helpers/scenarios_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module ScenariosHelper
CHART_COLORS = ["#E07B39", "#D9632B", "#C99A2E", "#B8842B", "#E0954F", "#C76A28"].freeze

Check failure on line 2 in app/helpers/scenarios_helper.rb

View workflow job for this annotation

GitHub Actions / lint

Layout/SpaceInsideArrayLiteralBrackets: Use space inside array brackets.

Check failure on line 2 in app/helpers/scenarios_helper.rb

View workflow job for this annotation

GitHub Actions / lint

Layout/SpaceInsideArrayLiteralBrackets: Use space inside array brackets.

def allocation_chart_color(index)
CHART_COLORS[index % CHART_COLORS.length]
end
end
7 changes: 7 additions & 0 deletions app/models/allocation/one_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ def one_time?
true
end

def share_percentage
total = scenario.one_time_giving_amount
return 0 if total.zero?

(amount.to_i / total.to_f * 100).round
end

private

def within_total_giving_amount
Expand Down
6 changes: 6 additions & 0 deletions app/models/allocation/ongoing.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class Allocation::Ongoing < Allocation
PERPETUITY_PAYOUT_RATE = 0.05

validates :percentage,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
Expand All @@ -7,6 +9,10 @@ def dollar_amount
(percentage.to_i / 100.0 * scenario.ongoing_giving_amount).round
end

def perpetuity_annual_amount
(dollar_amount * PERPETUITY_PAYOUT_RATE).round
end

def ongoing?
true
end
Expand Down
96 changes: 72 additions & 24 deletions app/views/scenarios/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -37,49 +37,97 @@
</div>

<!-- Summary -->
<% ongoing_total = @scenario.ongoing_percentage_total %>
<% ongoing_amount = @scenario.ongoing_giving_amount %>
<% one_time_amount = @scenario.one_time_giving_amount %>
<% total_amount = @scenario.total_giving_amount.to_i %>
<div class="rounded-2xl border border-line bg-surface p-6 shadow-sm">
<h2 class="font-serif font-medium text-xl text-ink">Allocation summary</h2>
<p class="mt-2 text-sm text-ink-soft">Set your total above to see a full breakdown.</p>
<% if total_amount.positive? %>
<p class="mt-2 text-sm text-ink-soft">
On going <span class="font-medium text-brand"><%= number_to_currency(ongoing_amount, precision: 0) %></span>
+ One-time <span class="font-medium text-ink"><%= number_to_currency(one_time_amount, precision: 0) %></span>
= Total <span class="font-medium text-ink"><%= number_to_currency(total_amount, precision: 0) %></span>
</p>
<% else %>
<p class="mt-2 text-sm text-ink-soft">Set your total above to see a full breakdown.</p>
<% end %>

<div class="mt-5">
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-ink-faint">On going giving</h3>
<p class="mt-1 font-serif text-2xl font-medium text-ink"><%= number_to_currency(@scenario.ongoing_giving_amount, precision: 0) %></p>
<p class="mt-1 font-serif text-4xl font-medium text-ink"><%= number_to_currency(ongoing_amount, precision: 0) %></p>
<% if @scenario.ongoing_allocations.any? %>
<ul class="mt-3 space-y-2">
<% @scenario.ongoing_allocations.each do |allocation| %>
<li class="flex justify-between text-ink-soft">
<span><%= allocation.display_label %></span>
<span class="flex items-baseline gap-3">
<span class="font-medium text-ink"><%= allocation.percentage %>%</span>
<span class="text-ink-soft"><%= number_to_currency(allocation.dollar_amount, precision: 0) %></span>
</span>
<p class="mt-1 text-sm text-ink-soft">
<%= ongoing_total %>% allocated across <%= pluralize(@scenario.ongoing_allocations.count, "cause") %>
</p>

<% remaining = [100 - ongoing_total, 0].max %>
<div class="mt-4 flex h-3 gap-1 overflow-hidden rounded-full">
<% @scenario.ongoing_allocations.each_with_index do |allocation, index| %>
<div style="width: <%= allocation.percentage %>%; background-color: <%= allocation_chart_color(index) %>"></div>
<% end %>
<% if remaining.positive? %>
<div class="bg-line-soft" style="width: <%= remaining %>%"></div>
<% end %>
</div>

<ul class="mt-4 space-y-3">
<% @scenario.ongoing_allocations.each_with_index do |allocation, index| %>
<li>
<div class="flex items-baseline justify-between">
<span class="flex items-center gap-2 text-ink">
<span class="h-2.5 w-2.5 shrink-0 rounded-full" style="background-color: <%= allocation_chart_color(index) %>"></span>
<%= allocation.display_label %>
</span>
<span class="flex items-baseline gap-3">
<span class="font-medium text-ink"><%= allocation.percentage %>%</span>
<span class="text-ink-soft"><%= number_to_currency(allocation.dollar_amount, precision: 0) %></span>
</span>
</div>
<p class="ml-[18px] mt-0.5 text-xs text-ink-faint">
&infin; Est. <%= number_to_currency(allocation.perpetuity_annual_amount, precision: 0) %> /yr in perpetuity
</p>
</li>
<% end %>
</ul>
<% total = @scenario.ongoing_percentage_total %>
<p class="mt-3 text-sm font-medium <%= total == 100 ? "text-success" : "text-ink-faint" %>">
<%= total %>% of 100%<%= " — add #{100 - total}% more" if total < 100 %><%= " — #{total - 100}% over" if total > 100 %>
</p>
<% else %>
<p class="mt-3 text-ink-faint">No ongoing allocations yet.</p>
<% end %>
</div>

<div class="mt-6">
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-ink-faint">One time giving</h3>
<% if @scenario.one_time_allocations.any? %>
<% if @scenario.one_time_allocations.any? %>
<div class="mt-6 border-t border-line pt-6">
<div class="flex items-center justify-between">
<h3 class="flex items-center gap-2 text-[11px] font-semibold uppercase tracking-wide text-ink-faint">
One time giving
<span class="rounded border border-line px-1.5 py-0.5 text-[10px] font-medium tracking-normal text-ink-soft">ADD-ON</span>
</h3>
<span class="font-medium text-ink"><%= number_to_currency(one_time_amount, precision: 0) %></span>
</div>
<ul class="mt-3 space-y-2">
<% @scenario.one_time_allocations.each do |allocation| %>
<li class="flex justify-between text-ink-soft">
<span><%= allocation.display_label %></span>
<span class="font-medium text-ink"><%= number_to_currency(allocation.amount, precision: 0) %></span>
<li class="flex items-baseline justify-between">
<span class="flex items-center gap-2 text-ink">
<span class="h-2.5 w-2.5 shrink-0 rounded-full bg-danger"></span>
<%= allocation.display_label %>
</span>
<span class="flex items-baseline gap-3">
<span class="font-medium text-ink-soft"><%= allocation.share_percentage %>%</span>
<span class="text-ink-soft"><%= number_to_currency(allocation.amount, precision: 0) %></span>
</span>
</li>
<% end %>
</ul>
<% else %>
<p class="mt-3 text-ink-faint">No one-time allocations yet.</p>
<% end %>
</div>
</div>
<% end %>

<% if total_amount.positive? %>
<div class="mt-6 rounded-xl border border-line bg-surface-soft p-4 text-sm text-ink-soft">
On going <span class="font-medium text-brand"><%= number_to_currency(ongoing_amount, precision: 0) %></span>
+ One-time <span class="font-medium text-ink"><%= number_to_currency(one_time_amount, precision: 0) %></span>
= Total <span class="font-medium text-ink"><%= number_to_currency(total_amount, precision: 0) %></span>
</div>
<% end %>
</div>
</div>
</div>
12 changes: 12 additions & 0 deletions test/models/allocation/one_time_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require "test_helper"

class Allocation::OneTimeTest < ActiveSupport::TestCase
test "share_percentage is the allocation's share of one-time giving" do
assert_equal 100, allocations(:education_grant).share_percentage
end

test "share_percentage is zero when there is no one-time giving" do
allocation = Allocation::OneTime.new(amount: 500, scenario: scenarios(:two_boston))
assert_equal 0, allocation.share_percentage
end
end
11 changes: 11 additions & 0 deletions test/models/allocation/ongoing_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "test_helper"

class Allocation::OngoingTest < ActiveSupport::TestCase
test "dollar_amount is the percentage of ongoing giving" do
assert_equal 1500, allocations(:greatest_need).dollar_amount
end

test "perpetuity_annual_amount is 5% of the dollar amount" do
assert_equal 75, allocations(:greatest_need).perpetuity_annual_amount
end
end
Loading