Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ async function continueForm() {
}
} catch (error) {
console.error('Error occurred while continuing tax form:', error)
handleCancel()
} finally {
manualLoading.value = false
}
Expand Down
54 changes: 24 additions & 30 deletions apps/frontend/src/pages/dashboard/revenue/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,17 @@
</div>
</div>
<div class="input-group mt-4">
<span
:class="{
'disabled-cursor-wrapper': userBalance.available < minWithdraw || blockedByTax,
}"
>
<ButtonStyled color="brand">
<nuxt-link
:aria-disabled="
userBalance.available < minWithdraw || blockedByTax ? 'true' : 'false'
"
:class="{ 'disabled-link': userBalance.available < minWithdraw || blockedByTax }"
:disabled="!!(userBalance.available < minWithdraw || blockedByTax) || null"
:tabindex="userBalance.available < minWithdraw || blockedByTax ? -1 : undefined"
to="/dashboard/revenue/withdraw"
>
<TransferIcon /> Withdraw
</nuxt-link>
</ButtonStyled>
</span>
<ButtonStyled color="brand">
<nuxt-link
v-if="!(userBalance.available < minWithdraw || blockedByTax)"
to="/dashboard/revenue/withdraw"
>
<TransferIcon /> Withdraw
</nuxt-link>
<span v-else class="disabled">
<TransferIcon /> Withdraw
</span>
</ButtonStyled>
<ButtonStyled>
<NuxtLink to="/dashboard/revenue/transfers">
<HistoryIcon />
Expand Down Expand Up @@ -176,9 +168,19 @@ const { addNotification, handleError } = injectNotificationManager()
const auth = await useAuth()
const minWithdraw = ref(0.01)

const { data: userBalance } = await useAsyncData(`payout/balance`, () =>
useBaseFetch(`payout/balance`, { apiVersion: 3 }),
)
const { data: userBalance } = await useAsyncData(`payout/balance`, async () => {
const response = await useBaseFetch(`payout/balance`, { apiVersion: 3 })
return {
...response,
available: parseFloat(response.available),
withdrawn_lifetime: parseFloat(response.withdrawn_lifetime),
withdrawn_ytd: parseFloat(response.withdrawn_ytd),
pending: parseFloat(response.pending),
dates: Object.fromEntries(
Object.entries(response.dates).map(([date, value]) => [date, parseFloat(value)]),
),
}
})

const blockedByTax = computed(() => {
const status = userBalance.value?.form_completion_status ?? 'unknown'
Expand Down Expand Up @@ -250,14 +252,6 @@ strong {
font-weight: 500;
}

.disabled-cursor-wrapper {
cursor: not-allowed;
}

.disabled-link {
pointer-events: none;
}

.grid-display {
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
Expand Down
70 changes: 69 additions & 1 deletion apps/frontend/src/pages/dashboard/revenue/withdraw.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<template>
<CreatorTaxFormModal
ref="taxFormModalRef"
@success="onTaxFormSuccess"
@cancelled="onTaxFormCancelled"
/>
<section class="universal-card">
<Breadcrumbs
current-title="Withdraw"
Expand Down Expand Up @@ -135,6 +140,10 @@
</template>
</div>

<p v-if="willTriggerTaxForm" class="font-bold text-orange">
This withdrawal will exceed $600 for the year. You will be prompted to complete a tax form before proceeding.
</p>

<p v-if="blockedByTax" class="font-bold text-orange">
You have withdrawn over $600 this year. To continue withdrawing, you must complete a tax form.
</p>
Expand Down Expand Up @@ -207,6 +216,7 @@ import { all } from 'iso-3166-1'
import { Multiselect } from 'vue-multiselect'

import VenmoIcon from '~/assets/images/external/venmo.svg?component'
import CreatorTaxFormModal from '~/components/ui/dashboard/CreatorTaxFormModal.vue'

const { addNotification } = injectNotificationManager()
const auth = await useAuth()
Expand All @@ -227,7 +237,19 @@ const country = ref(

const [{ data: userBalance }, { data: payoutMethods, refresh: refreshPayoutMethods }] =
await Promise.all([
useAsyncData(`payout/balance`, () => useBaseFetch(`payout/balance`, { apiVersion: 3 })),
useAsyncData(`payout/balance`, async () => {
const response = await useBaseFetch(`payout/balance`, { apiVersion: 3 })
return {
...response,
available: parseFloat(response.available),
withdrawn_lifetime: parseFloat(response.withdrawn_lifetime),
withdrawn_ytd: parseFloat(response.withdrawn_ytd),
pending: parseFloat(response.pending),
dates: Object.fromEntries(
Object.entries(response.dates).map(([date, value]) => [date, parseFloat(value)]),
),
}
}),
useAsyncData(`payout/methods?country=${country.value.id}`, () =>
useBaseFetch(`payout/methods?country=${country.value.id}`, { apiVersion: 3 }),
),
Expand Down Expand Up @@ -334,6 +356,13 @@ const blockedByTax = computed(() => {
return thresholdMet && status !== 'complete'
})

const willTriggerTaxForm = computed(() => {
const status = userBalance.value?.form_completion_status ?? 'unknown'
const currentWithdrawn = userBalance.value?.withdrawn_ytd ?? 0
const wouldExceedThreshold = currentWithdrawn + parsedAmount.value >= 600
return wouldExceedThreshold && status !== 'complete' && !blockedByTax.value
})

watch(country, async () => {
await refreshPayoutMethods()
if (payoutMethods.value && payoutMethods.value[0]) {
Expand All @@ -353,7 +382,19 @@ watch(selectedMethod, () => {
agreedTerms.value = false
})

const taxFormModalRef = ref(null)
const taxFormCancelled = ref(false)

async function withdraw() {
// Check if withdrawal will trigger tax form
if (willTriggerTaxForm.value) {
taxFormCancelled.value = false
if (taxFormModalRef.value && taxFormModalRef.value.startTaxForm) {
await taxFormModalRef.value.startTaxForm(new MouseEvent('click'))
}
return
}

startLoading()
try {
const auth = await useAuth()
Expand Down Expand Up @@ -386,6 +427,33 @@ async function withdraw() {
}
stopLoading()
}

async function onTaxFormSuccess() {
// Refresh user balance to get updated form completion status
const updatedBalance = await useBaseFetch(`payout/balance`, { apiVersion: 3 })
userBalance.value = updatedBalance

// Check if the form was actually completed
if (updatedBalance?.form_completion_status === 'complete') {
// Now proceed with the withdrawal
await withdraw()
} else {
addNotification({
title: 'Tax form incomplete',
text: 'You must complete a tax form for this withdrawal.',
type: 'error',
})
}
}

function onTaxFormCancelled() {
taxFormCancelled.value = true
addNotification({
title: 'Withdrawal canceled',
text: 'You must complete a tax form for this withdrawal.',
type: 'error',
})
}
</script>

<style lang="scss" scoped>
Expand Down
Loading