diff --git a/apps/frontend/src/pages/[type]/[id].vue b/apps/frontend/src/pages/[type]/[id].vue index c5e680927..b41727d5b 100644 --- a/apps/frontend/src/pages/[type]/[id].vue +++ b/apps/frontend/src/pages/[type]/[id].vue @@ -2465,9 +2465,16 @@ provideProjectPageContext({ right: 1rem; overflow-y: auto; z-index: 50; + transition: bottom 0.25s ease-in-out; > div { box-shadow: 0 0 15px rgba(0, 0, 0, 0.3); } } + + diff --git a/apps/labrinth/src/routes/v3/payouts.rs b/apps/labrinth/src/routes/v3/payouts.rs index 667c32dda..d0a2dbdb3 100644 --- a/apps/labrinth/src/routes/v3/payouts.rs +++ b/apps/labrinth/src/routes/v3/payouts.rs @@ -499,15 +499,19 @@ pub async fn create_payout( .await .wrap_internal_err("failed to calculate user balance")?; - // Note: We only check for negative amounts here. The full balance validation - // happens later in payout_flow.validate() which correctly handles currency - // conversion (body.amount may be in local currency for gift cards, not USD). if body.amount < Decimal::ZERO { return Err(ApiError::InvalidInput( "Amount must be positive!".to_string(), )); } + // Create the payout flow first so we can use the resolved USD amount + // for tax threshold checks. body.amount may be in local currency for + // gift cards (e.g. INR), so we must not compare it directly against + // USD thresholds. + let payout_flow = payouts_queue.create_payout_flow(body.0).await?; + let amount_usd = payout_flow.net_usd.get(); + let requires_manual_review; if let Some(threshold) = tax_compliance_payout_threshold() { @@ -533,7 +537,7 @@ pub async fn create_payout( }; if !(tin_matched && signed) - && balance.withdrawn_ytd + body.amount >= threshold + && balance.withdrawn_ytd + amount_usd >= threshold { // We propagate the error this way because we don't want to block payouts // that would be acceptable regardless of the tax form submission status @@ -570,7 +574,6 @@ pub async fn create_payout( )); } - let payout_flow = payouts_queue.create_payout_flow(body.0).await?; let payout_flow = match payout_flow.validate(balance.available) { Ok(flow) => flow, Err(err) => return Err(ApiError::InvalidInput(err.to_string())), diff --git a/packages/ui/src/components/base/FloatingActionBar.vue b/packages/ui/src/components/base/FloatingActionBar.vue index 3585aa939..693ec01b9 100644 --- a/packages/ui/src/components/base/FloatingActionBar.vue +++ b/packages/ui/src/components/base/FloatingActionBar.vue @@ -1,7 +1,21 @@