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 @@