diff --git a/lib/algora/bounties/bounties.ex b/lib/algora/bounties/bounties.ex
index e69b680da..3cc78049c 100644
--- a/lib/algora/bounties/bounties.ex
+++ b/lib/algora/bounties/bounties.ex
@@ -429,8 +429,12 @@ defmodule Algora.Bounties do
@spec notify_bounty(%{owner: User.t(), bounty: Bounty.t()}, opts :: []) ::
{:ok, nil} | {:error, atom()}
- def notify_bounty(%{owner: _owner, bounty: bounty}, _opts) do
- Algora.Admin.alert("Notify bounty: #{inspect(bounty)}", :error)
+ def notify_bounty(%{owner: owner, bounty: bounty}, _opts) do
+ Algora.Admin.alert(
+ "New contract offer: #{AlgoraWeb.Endpoint.url()}/#{owner.handle}/contracts/#{bounty.id}",
+ :critical
+ )
+
{:ok, nil}
end
@@ -906,11 +910,9 @@ defmodule Algora.Bounties do
end
end
- def calculate_contract_amount(amount), do: Money.mult!(amount, Decimal.new("1.13"))
-
def final_contract_amount(:marketplace, amount), do: amount
- def final_contract_amount(:bring_your_own, amount), do: calculate_contract_amount(amount)
+ def final_contract_amount(:bring_your_own, amount), do: Money.mult!(amount, Decimal.new("1.13"))
@spec create_payment_session(
%{owner: User.t(), amount: Money.t(), description: String.t()},
diff --git a/lib/algora/payments/payments.ex b/lib/algora/payments/payments.ex
index a7a27bec3..059ca1ecc 100644
--- a/lib/algora/payments/payments.ex
+++ b/lib/algora/payments/payments.ex
@@ -9,6 +9,7 @@ defmodule Algora.Payments do
alias Algora.Bounties
alias Algora.Bounties.Bounty
alias Algora.Bounties.Claim
+ alias Algora.Bounties.Jobs.PromptPayoutConnect
alias Algora.Bounties.Tip
alias Algora.Jobs.JobPosting
alias Algora.MoneyUtils
@@ -737,7 +738,7 @@ defmodule Algora.Payments do
{:error, :no_active_account} ->
case %{credit_id: credit.id}
- |> Bounties.Jobs.PromptPayoutConnect.new()
+ |> PromptPayoutConnect.new()
|> Oban.insert() do
{:ok, _job} -> {:cont, :ok}
error -> {:halt, error}
@@ -761,4 +762,81 @@ defmodule Algora.Payments do
end
end)
end
+
+ def process_release(
+ %Stripe.Charge{id: charge_id, captured: true, payment_intent: payment_intent_id},
+ group_id,
+ amount,
+ recipient
+ ) do
+ Repo.transact(fn ->
+ tx = Repo.get_by(Transaction, group_id: group_id, type: :charge, status: :succeeded)
+
+ user = Repo.get_by(User, id: tx.user_id)
+ bounty = Repo.get_by(Bounty, id: tx.bounty_id)
+
+ Algora.Admin.alert(
+ "Release #{amount} escrow to #{recipient.handle} for #{AlgoraWeb.Endpoint.url()}/#{user.handle}/contracts/#{bounty.id}",
+ :critical
+ )
+
+ debit_id = Nanoid.generate()
+ credit_id = Nanoid.generate()
+
+ with {:ok, debit0} <- Repo.fetch_by(Transaction, group_id: group_id, type: :debit, status: :requires_release),
+ {:ok, _} <-
+ debit0
+ |> change(%{
+ net_amount: Money.sub!(debit0.net_amount, amount),
+ gross_amount: Money.sub!(debit0.gross_amount, amount)
+ })
+ |> Repo.update(),
+ {:ok, credit0} <- Repo.fetch_by(Transaction, group_id: group_id, type: :credit, status: :requires_release),
+ {:ok, _} <-
+ credit0
+ |> change(%{
+ net_amount: Money.add!(credit0.net_amount, amount),
+ gross_amount: Money.add!(credit0.gross_amount, amount)
+ })
+ |> Repo.update(),
+ {:ok, _debit} <-
+ Repo.insert(%Transaction{
+ id: debit_id,
+ provider: "stripe",
+ provider_id: charge_id,
+ provider_charge_id: charge_id,
+ provider_payment_intent_id: payment_intent_id,
+ type: :debit,
+ status: :succeeded,
+ succeeded_at: DateTime.utc_now(),
+ bounty_id: tx.bounty_id,
+ user_id: tx.user_id,
+ gross_amount: amount,
+ net_amount: amount,
+ total_fee: Money.zero(:USD),
+ linked_transaction_id: credit_id,
+ group_id: group_id
+ }),
+ {:ok, _credit} <-
+ Repo.insert(%Transaction{
+ id: credit_id,
+ provider: "stripe",
+ provider_id: charge_id,
+ provider_charge_id: charge_id,
+ provider_payment_intent_id: payment_intent_id,
+ type: :credit,
+ status: :initialized,
+ succeeded_at: DateTime.utc_now(),
+ bounty_id: tx.bounty_id,
+ user_id: recipient.id,
+ gross_amount: amount,
+ net_amount: amount,
+ total_fee: Money.zero(:USD),
+ linked_transaction_id: debit_id,
+ group_id: group_id
+ }) do
+ {:ok, nil}
+ end
+ end)
+ end
end
diff --git a/lib/algora/settings/settings.ex b/lib/algora/settings/settings.ex
index 54b9b164e..239d16290 100644
--- a/lib/algora/settings/settings.ex
+++ b/lib/algora/settings/settings.ex
@@ -127,6 +127,7 @@ defmodule Algora.Settings do
projects = Accounts.list_contributed_projects(user, limit: 2)
avatar_url = profile["avatar_url"] || user.avatar_url
hourly_rate = match["hourly_rate"] || profile["hourly_rate"]
+ hours_per_week = match["hours_per_week"] || profile["hours_per_week"] || user.hours_per_week
[
%{
@@ -134,7 +135,8 @@ defmodule Algora.Settings do
projects: projects,
badge_variant: match["badge_variant"],
badge_text: match["badge_text"],
- hourly_rate: if(hourly_rate, do: Money.new(:USD, hourly_rate, no_fraction_if_integer: true))
+ hourly_rate: if(hourly_rate, do: Money.new(:USD, hourly_rate, no_fraction_if_integer: true)),
+ hours_per_week: hours_per_week
}
]
else
diff --git a/lib/algora_web/forms/contract_form.ex b/lib/algora_web/forms/contract_form.ex
index dd4aa8daf..cb04d5d71 100644
--- a/lib/algora_web/forms/contract_form.ex
+++ b/lib/algora_web/forms/contract_form.ex
@@ -225,9 +225,7 @@ defmodule AlgoraWeb.Forms.ContractForm do
- {Money.to_string!(
- Bounties.calculate_contract_amount(get_change(@form.source, :amount))
- )}
+ {Money.to_string!(get_change(@form.source, :amount))}
diff --git a/lib/algora_web/live/contract_live.ex b/lib/algora_web/live/contract_live.ex
index c38627bd6..e7952e5c9 100644
--- a/lib/algora_web/live/contract_live.ex
+++ b/lib/algora_web/live/contract_live.ex
@@ -12,6 +12,7 @@ defmodule AlgoraWeb.ContractLive do
alias Algora.Chat
alias Algora.Organizations.Member
alias Algora.Payments
+ alias Algora.Payments.Transaction
alias Algora.Repo
alias Algora.Types.USD
alias Algora.Util
@@ -42,6 +43,27 @@ defmodule AlgoraWeb.ContractLive do
end
end
+ defmodule ReleaseBountyForm do
+ @moduledoc false
+ use Ecto.Schema
+
+ import Ecto.Changeset
+
+ @primary_key false
+ embedded_schema do
+ field :amount, USD
+ field :hours, :decimal
+ end
+
+ def changeset(form, attrs) do
+ form
+ |> cast(attrs, [:amount, :hours])
+ |> validate_required([:amount])
+ |> validate_number(:hours, greater_than: 0)
+ |> Algora.Validations.validate_money_positive(:amount)
+ end
+ end
+
@impl true
def mount(%{"id" => bounty_id}, _session, socket) do
bounty =
@@ -111,6 +133,9 @@ defmodule AlgoraWeb.ContractLive do
reward_changeset = RewardBountyForm.changeset(%RewardBountyForm{}, %{amount: bounty.amount, tip_percentage: 0})
+ release_changeset =
+ ReleaseBountyForm.changeset(%ReleaseBountyForm{}, %{amount: bounty.amount, hours: bounty.hours_per_week})
+
{:ok, thread} = Chat.get_or_create_bounty_thread(bounty)
messages = thread.id |> Chat.list_messages() |> Repo.preload(:sender)
participants = thread.id |> Chat.list_participants() |> Repo.preload(:user)
@@ -139,12 +164,15 @@ defmodule AlgoraWeb.ContractLive do
|> assign(:ticket_body_html, ticket_body_html)
|> assign(:show_reward_modal, false)
|> assign(:show_authorize_modal, false)
+ |> assign(:show_release_modal, false)
|> assign(:selected_context, nil)
+ |> assign(:tx_id, nil)
|> assign(:line_items, [])
|> assign(:thread, thread)
|> assign(:messages, messages)
|> assign(:participants, participants)
|> assign(:reward_form, to_form(reward_changeset))
+ |> assign(:release_form, to_form(release_changeset))
|> assign_contractor(bounty.shared_with)
|> assign_transactions()
|> assign_line_items(reward_changeset)}
@@ -206,6 +234,27 @@ defmodule AlgoraWeb.ContractLive do
{:noreply, assign(socket, :show_authorize_modal, true)}
end
+ @impl true
+ def handle_event("release", %{"tx_id" => tx_id}, socket) do
+ tx = Repo.get(Transaction, tx_id)
+
+ release_changeset =
+ ReleaseBountyForm.changeset(%ReleaseBountyForm{}, %{
+ amount: tx.net_amount,
+ hours:
+ tx.net_amount
+ |> Money.to_decimal()
+ |> Decimal.mult(socket.assigns.bounty.hours_per_week)
+ |> Decimal.div(Money.to_decimal(socket.assigns.bounty.amount))
+ })
+
+ {:noreply,
+ socket
+ |> assign(:release_form, to_form(release_changeset))
+ |> assign(:show_release_modal, true)
+ |> assign(:tx_id, tx_id)}
+ end
+
@impl true
def handle_event("close_drawer", _params, socket) do
{:noreply, close_drawers(socket)}
@@ -221,6 +270,65 @@ defmodule AlgoraWeb.ContractLive do
|> assign_line_items(changeset)}
end
+ @impl true
+ def handle_event("validate_hours", %{"release_bounty_form" => %{"hours" => hours}}, socket) do
+ hours =
+ Decimal.new(
+ case hours do
+ "" -> "0"
+ hours -> hours
+ end
+ )
+
+ changeset =
+ Ecto.Changeset.change(socket.assigns.release_form.source, %{
+ hours: hours,
+ amount: Money.mult!(socket.assigns.bounty.amount, Decimal.div(hours, socket.assigns.bounty.hours_per_week))
+ })
+
+ {:noreply,
+ socket
+ |> assign(:release_form, to_form(changeset))
+ |> assign_line_items(changeset)}
+ end
+
+ @impl true
+ def handle_event("validate_amount", %{"release_bounty_form" => %{"amount" => amount}}, socket) do
+ amount =
+ Money.new(
+ :USD,
+ case amount do
+ "" -> "0"
+ amount -> amount
+ end
+ )
+
+ changeset =
+ Ecto.Changeset.change(socket.assigns.release_form.source, %{
+ amount: amount,
+ hours:
+ amount
+ |> Money.to_decimal()
+ |> Decimal.mult(socket.assigns.bounty.hours_per_week)
+ |> Decimal.div(Money.to_decimal(socket.assigns.bounty.amount))
+ })
+
+ {:noreply,
+ socket
+ |> assign(:release_form, to_form(changeset))
+ |> assign_line_items(changeset)}
+ end
+
+ @impl true
+ def handle_event("validate_release", %{"release_bounty_form" => params}, socket) do
+ changeset = ReleaseBountyForm.changeset(%ReleaseBountyForm{}, params)
+
+ {:noreply,
+ socket
+ |> assign(:release_form, to_form(changeset))
+ |> assign_line_items(changeset)}
+ end
+
@impl true
def handle_event("pay_with_stripe", %{"reward_bounty_form" => params}, socket) do
changeset = RewardBountyForm.changeset(%RewardBountyForm{}, params)
@@ -254,19 +362,31 @@ defmodule AlgoraWeb.ContractLive do
end
@impl true
- def handle_event("release_funds", %{"tx_id" => tx_id}, socket) do
- with tx when not is_nil(tx) <- Enum.find(socket.assigns.transactions, &(&1.id == tx_id)),
- {:ok, charge} <- Algora.PSP.Charge.retrieve(tx.provider_charge_id),
- {:ok, _} <- Algora.Payments.process_charge("charge.succeeded", charge, tx.group_id) do
- {:noreply, socket}
- else
- {:error, reason} ->
- Logger.error("Failed to release funds: #{inspect(reason)}")
- {:noreply, put_flash(socket, :error, "Something went wrong")}
+ def handle_event("release_funds", %{"release_bounty_form" => params}, socket) do
+ changeset = ReleaseBountyForm.changeset(%ReleaseBountyForm{}, params)
- _ ->
- Logger.error("Failed to release funds: transaction not found")
- {:noreply, put_flash(socket, :error, "Something went wrong")}
+ case apply_action(changeset, :save) do
+ {:ok, data} ->
+ with tx when not is_nil(tx) <- Enum.find(socket.assigns.transactions, &(&1.id == socket.assigns.tx_id)),
+ {:ok, charge} <- Algora.PSP.Charge.retrieve(tx.provider_charge_id),
+ {:ok, _} <- Algora.Payments.process_release(charge, tx.group_id, data.amount, socket.assigns.contractor) do
+ {:noreply,
+ socket
+ |> assign(:show_release_modal, false)
+ |> put_flash(:info, "Funds released!")
+ |> assign_transactions()}
+ else
+ {:error, reason} ->
+ Logger.error("Failed to release funds: #{inspect(reason)}")
+ {:noreply, put_flash(socket, :error, "Something went wrong")}
+
+ _ ->
+ Logger.error("Failed to release funds: transaction not found")
+ {:noreply, put_flash(socket, :error, "Something went wrong")}
+ end
+
+ {:error, changeset} ->
+ {:noreply, assign(socket, :release_form, to_form(changeset))}
end
end
@@ -356,7 +476,7 @@ defmodule AlgoraWeb.ContractLive do
<% end %>
<%= if @can_create_bounty && @transactions == [] do %>
- <.button phx-click="reward">
+ <.button phx-click="reward" variant="secondary">
Make payment
<% end %>
@@ -484,11 +604,10 @@ defmodule AlgoraWeb.ContractLive do
transaction.status == :requires_release
}
size="sm"
- phx-click="release_funds"
- phx-disable-with="Releasing..."
+ phx-click="release"
phx-value-tx_id={transaction.id}
>
- Release funds
+ Partial release
@@ -616,6 +735,93 @@ defmodule AlgoraWeb.ContractLive do
+ <.drawer :if={@current_user} show={@show_release_modal} on_cancel="close_drawer">
+ <.drawer_header>
+ <.drawer_title>Release funds
+ <.drawer_description>
+ {@contractor.name} will be paid once you release the funds.
+
+
+ <.drawer_content class="mt-4">
+ <.form for={@release_form} phx-change="validate_release" phx-submit="release_funds">
+
+
+ <.card>
+ <.card_header>
+ <.card_title>Release Details
+
+ <.card_content class="pt-0">
+
+ <.input
+ label="Hours"
+ icon="tabler-clock"
+ field={@release_form[:hours]}
+ phx-change="validate_hours"
+ />
+ <.input
+ label="Amount"
+ icon="tabler-currency-dollar"
+ field={@release_form[:amount]}
+ phx-change="validate_amount"
+ />
+
+
+
+ <.card>
+ <.card_header>
+ <.card_title>Payment Summary
+
+ <.card_content class="pt-0">
+
+ <%= for line_item <- @line_items do %>
+
+
-
+ <%= if line_item.image do %>
+ <.avatar>
+ <.avatar_image src={line_item.image} />
+ <.avatar_fallback>
+ {Util.initials(line_item.title)}
+
+
+ <% else %>
+
+ <% end %>
+
+
{line_item.title}
+
{line_item.description}
+
+
+
-
+ {Money.to_string!(line_item.amount)}
+
+
+ <% end %>
+
+
+
-
+
+
Total due
+
+
-
+ {LineItem.gross_amount(@line_items)}
+
+
+
+
+
+
+
+ <.button variant="secondary" phx-click="close_drawer" type="button">
+ Cancel
+
+ <.button type="submit">
+ Release funds <.icon name="tabler-arrow-right" class="-mr-1 ml-2 h-4 w-4" />
+
+
+
+
+
+
<.drawer :if={@current_user} show={@show_authorize_modal} on_cancel="close_drawer">
<.drawer_header>
<.drawer_title>Authorize payment
@@ -840,6 +1046,7 @@ defmodule AlgoraWeb.ContractLive do
socket
|> assign(:show_reward_modal, false)
|> assign(:show_authorize_modal, false)
+ |> assign(:show_release_modal, false)
end
defp assign_contractor(socket, shared_with) do
@@ -859,12 +1066,24 @@ defmodule AlgoraWeb.ContractLive do
defp assign_transactions(socket) do
transactions =
[
- user_id: socket.assigns.bounty.owner.id,
status: [:succeeded, :requires_capture, :requires_release],
bounty_id: socket.assigns.bounty.id
]
|> Payments.list_transactions()
- |> Enum.filter(&(&1.type == :charge or &1.status in [:succeeded, :requires_release]))
+ |> Enum.filter(fn tx -> Money.positive?(tx.net_amount) end)
+ |> Enum.filter(fn tx ->
+ cond do
+ socket.assigns.can_create_bounty ->
+ tx.type == :charge or
+ (tx.type == :debit and tx.status in [:succeeded, :requires_release])
+
+ socket.assigns.current_user.id == socket.assigns.contractor.id ->
+ tx.type == :credit and tx.status == :succeeded
+
+ true ->
+ false
+ end
+ end)
balance = calculate_balance(transactions)
volume = calculate_volume(transactions)
diff --git a/lib/algora_web/live/org/dashboard_live.ex b/lib/algora_web/live/org/dashboard_live.ex
index 6a31081a9..2f1622ec9 100644
--- a/lib/algora_web/live/org/dashboard_live.ex
+++ b/lib/algora_web/live/org/dashboard_live.ex
@@ -82,6 +82,12 @@ defmodule AlgoraWeb.Org.DashboardLive do
matches = Algora.Settings.get_org_matches(previewed_user)
+ contributions =
+ matches
+ |> Enum.map(& &1.user.id)
+ |> Algora.Workspace.list_user_contributions()
+ |> Enum.group_by(& &1.user.id)
+
admins_last_active = Algora.Admin.admins_last_active()
developers =
@@ -106,6 +112,7 @@ defmodule AlgoraWeb.Org.DashboardLive do
|> assign(:contributors, contributors)
|> assign(:previewed_user, previewed_user)
|> assign(:matches, matches)
+ |> assign(:contributions, contributions)
|> assign(:developers, developers)
|> assign(:has_more_bounties, false)
|> assign(:oauth_url, Github.authorize_url(%{socket_id: socket.id}))
@@ -390,7 +397,7 @@ defmodule AlgoraWeb.Org.DashboardLive do
<.icon name="tabler-circle-number-3 mr-2" class="size-6 text-success-400 shrink-0" />
- Release/withhold escrow end of week
+ Release/withhold escrow as you go
@@ -398,6 +405,7 @@ defmodule AlgoraWeb.Org.DashboardLive do
<.match_card
match={match}
contract_for_user={contract_for_user(@contracts, match.user)}
+ contributions={@contributions[match.user.id]}
current_org={@current_org}
/>
<% end %>
@@ -674,8 +682,7 @@ defmodule AlgoraWeb.Org.DashboardLive do
developer = Enum.find(socket.assigns.developers, &(&1.id == user_id))
match = Enum.find(socket.assigns.matches, &(&1.user.id == user_id))
hourly_rate = match[:hourly_rate]
-
- hours_per_week = developer.hours_per_week || 30
+ hours_per_week = match[:hours_per_week] || developer.hours_per_week || 30
{:noreply,
socket
@@ -691,8 +698,8 @@ defmodule AlgoraWeb.Org.DashboardLive do
hourly_rate: hourly_rate,
contractor_handle: developer.provider_login,
hours_per_week: hours_per_week,
- title: "#{socket.assigns.current_org.name} OSS Development",
- description: "Open source contribution to #{socket.assigns.current_org.name} for a week"
+ title: "#{socket.assigns.current_org.name} Development",
+ description: "Contribution to #{socket.assigns.current_org.name} for #{hours_per_week} hours"
})
|> to_form()
)}
@@ -1330,7 +1337,7 @@ defmodule AlgoraWeb.Org.DashboardLive do
defp match_card(assigns) do
~H"""
-
+
@@ -1405,7 +1412,54 @@ defmodule AlgoraWeb.Org.DashboardLive do
)}
-
+
+ <%= for {owner, contributions} <- aggregate_contributions(@contributions) |> Enum.take(3) do %>
+ <.link
+ href={"https://github.com/#{owner.provider_login}/#{List.first(contributions).repository.name}/pulls?q=author%3A#{@match.user.provider_login}+is%3Amerged+"}
+ target="_blank"
+ rel="noopener"
+ class="flex items-center gap-3 rounded-xl pr-2 bg-card/50 border border-border/50 hover:border-border transition-all"
+ >
+

+
+
+
+ {if owner.type == :organization do
+ owner.name
+ else
+ List.first(contributions).repository.name
+ end}
+
+ <%= if tech = List.first(List.first(contributions).repository.tech_stack) do %>
+
+
{tech}
+
+ <% end %>
+
+
+
+ <.icon name="tabler-star-filled" class="h-4 w-4 mr-1" />
+ {Algora.Util.format_number_compact(
+ max(owner.stargazers_count, total_stars(contributions))
+ )}
+
+
+ <.icon name="tabler-git-pull-request" class="h-4 w-4 mr-1" />
+ {Algora.Util.format_number_compact(total_contributions(contributions))}
+
+
+
+
+ <% end %>
+
+ <%!--
<%= for {project, total_earned} <- @match.projects |> Enum.take(2) do %>
<.link
navigate={User.url(project)}
@@ -1438,18 +1492,20 @@ defmodule AlgoraWeb.Org.DashboardLive do
<% end %>
-
+
--%>
-
- Total payment for {@match.user.hours_per_week || 30}
- hours
-
- (includes all platform and payment processing fees)
-
+ Minimum payment to collaborate:
+
+ {@match[:hourly_rate]
+ |> Money.mult!(@match.hours_per_week || 30)
+ |> Money.to_string!()}
+
+ ({@match.hours_per_week || 30} hours booked)
<.button
@@ -1463,12 +1519,12 @@ defmodule AlgoraWeb.Org.DashboardLive do
>
Offer contract
-
-
- {@match[:hourly_rate]
- |> Money.mult!(@match.user.hours_per_week || 30)
- |> Bounties.calculate_contract_amount()
- |> Money.to_string!(no_fraction_if_integer: false)} / week
+
-
+ {@match[:hourly_rate]}/hr
+
+ (includes all fees)
+
@@ -2070,4 +2126,24 @@ defmodule AlgoraWeb.Org.DashboardLive do
defp format_number(n) when n >= 1_000_000, do: "#{Float.round(n / 1_000_000, 1)}M"
defp format_number(n) when n >= 1_000, do: "#{Float.round(n / 1_000, 1)}K"
defp format_number(n), do: to_string(n)
+
+ defp aggregate_contributions(contributions) do
+ groups = Enum.group_by(contributions, fn c -> c.repository.user end)
+
+ contributions
+ |> Enum.map(fn c -> {c.repository.user, groups[c.repository.user]} end)
+ |> Enum.uniq_by(fn {owner, _} -> owner.id end)
+ end
+
+ defp total_stars(contributions) do
+ contributions
+ |> Enum.map(& &1.repository.stargazers_count)
+ |> Enum.sum()
+ end
+
+ defp total_contributions(contributions) do
+ contributions
+ |> Enum.map(& &1.contribution_count)
+ |> Enum.sum()
+ end
end
diff --git a/lib/algora_web/live/org/nav.ex b/lib/algora_web/live/org/nav.ex
index e1bbbb9ae..0e16a40c3 100644
--- a/lib/algora_web/live/org/nav.ex
+++ b/lib/algora_web/live/org/nav.ex
@@ -132,11 +132,7 @@ defmodule AlgoraWeb.Org.Nav do
bounty_res =
Bounties.create_bounty(
%{
- amount:
- case data.contract_type do
- :marketplace -> Bounties.calculate_contract_amount(amount)
- :bring_your_own -> amount
- end,
+ amount: amount,
creator: socket.assigns.current_user,
owner: socket.assigns.current_org,
title: data.title,