You've already forked AstralRinth
forked from didirus/AstralRinth
feat: 2nd batch of withdraw QA changes (#4724)
* polish: increase gap between svg and text in empty state * fix: use ts & change cancel btn style * fix: btn style * polish: new transaction page design * fix: navstack match nested + csv download * fix: lint & i18n * Add tooltip to CSV download button + standard btn style Signed-off-by: Calum H. <contact@cal.engineer> * fix: lint & i18n --------- Signed-off-by: Calum H. <contact@cal.engineer>
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
v-else-if="item.link ?? item.to"
|
||||
:to="(item.link ?? item.to) as string"
|
||||
class="nav-item inline-flex w-full cursor-pointer items-center gap-2 text-nowrap rounded-xl border-none bg-transparent px-4 py-2.5 text-left text-base font-semibold leading-tight text-button-text transition-all hover:bg-button-bg hover:text-contrast active:scale-[0.97]"
|
||||
:class="{ 'is-active': isActive(item as NavStackLinkItem) }"
|
||||
>
|
||||
<component
|
||||
:is="item.icon"
|
||||
@@ -80,6 +81,7 @@ type NavStackLinkItem = NavStackBaseItem & {
|
||||
link?: string | null
|
||||
to?: string | null
|
||||
action?: (() => void) | null
|
||||
matchNested?: boolean
|
||||
}
|
||||
|
||||
type NavStackSeparator = { type: 'separator' }
|
||||
@@ -96,6 +98,8 @@ const props = defineProps<{
|
||||
|
||||
const ariaLabel = computed(() => props.ariaLabel ?? 'Section navigation')
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const slots = useSlots()
|
||||
const hasSlotContent = computed(() => {
|
||||
const content = slots.default?.()
|
||||
@@ -117,6 +121,19 @@ function getKey(item: NavStackEntry, idx: number) {
|
||||
return link ? `link-${link}` : `action-${(item as NavStackLinkItem).label}-${idx}`
|
||||
}
|
||||
|
||||
function isActive(item: NavStackLinkItem): boolean {
|
||||
const link = item.link ?? item.to
|
||||
if (!link) return false
|
||||
|
||||
const currentPath = route.path
|
||||
|
||||
if (item.matchNested) {
|
||||
return currentPath.startsWith(link)
|
||||
}
|
||||
|
||||
return currentPath === link
|
||||
}
|
||||
|
||||
const filteredItems = computed(() => props.items?.filter((x) => x.shown === undefined || x.shown))
|
||||
</script>
|
||||
|
||||
@@ -124,11 +141,13 @@ const filteredItems = computed(() => props.items?.filter((x) => x.shown === unde
|
||||
li {
|
||||
text-align: unset;
|
||||
}
|
||||
.router-link-exact-active.nav-item {
|
||||
.router-link-exact-active.nav-item,
|
||||
.nav-item.is-active {
|
||||
background: var(--color-button-bg-selected);
|
||||
color: var(--color-button-text-selected);
|
||||
}
|
||||
.router-link-exact-active.nav-item .text-contrast {
|
||||
.router-link-exact-active.nav-item .text-contrast,
|
||||
.nav-item.is-active .text-contrast {
|
||||
color: var(--color-button-text-selected);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
<div class="flex w-full flex-row justify-between">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-base font-semibold text-contrast md:text-lg">{{
|
||||
isIncome
|
||||
transaction.type === 'payout_available'
|
||||
? formatPayoutSource(transaction.payout_source)
|
||||
: formatMethodName(transaction.method_type || transaction.method)
|
||||
}}</span>
|
||||
<span class="text-xs text-secondary md:text-sm">
|
||||
<template v-if="!isIncome">
|
||||
<template v-if="transaction.type === 'withdrawal'">
|
||||
<span
|
||||
:class="[
|
||||
transaction.status === 'cancelling' || transaction.status === 'cancelled'
|
||||
@@ -24,8 +24,8 @@
|
||||
>{{ formatTransactionStatus(transaction.status) }} <BulletDivider
|
||||
/></span>
|
||||
</template>
|
||||
{{ $dayjs(transaction.created).format('MMM DD YYYY') }}
|
||||
<template v-if="!isIncome && transaction.fee">
|
||||
{{ dayjs(transaction.created).format('MMM DD YYYY') }}
|
||||
<template v-if="transaction.type === 'withdrawal' && transaction.fee">
|
||||
<BulletDivider /> Fee {{ formatMoney(transaction.fee) }}
|
||||
</template>
|
||||
</span>
|
||||
@@ -33,13 +33,13 @@
|
||||
<div class="my-auto flex flex-row items-center gap-2">
|
||||
<span
|
||||
class="text-base font-semibold md:text-lg"
|
||||
:class="isIncome ? 'text-green' : 'text-contrast'"
|
||||
:class="transaction.type === 'payout_available' ? 'text-green' : 'text-contrast'"
|
||||
>{{ formatMoney(transaction.amount) }}</span
|
||||
>
|
||||
<template v-if="!isIncome && transaction.status === 'in-transit'">
|
||||
<template v-if="transaction.type === 'withdrawal' && transaction.status === 'in-transit'">
|
||||
<Tooltip theme="dismissable-prompt" :triggers="['hover', 'focus']" no-auto-focus>
|
||||
<span class="my-auto align-middle"
|
||||
><ButtonStyled circular size="small">
|
||||
><ButtonStyled circular type="outlined" size="small">
|
||||
<button class="align-middle" @click="cancelPayout">
|
||||
<XIcon />
|
||||
</button> </ButtonStyled
|
||||
@@ -54,32 +54,57 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { ArrowDownIcon, ArrowUpIcon, XIcon } from '@modrinth/assets'
|
||||
import { BulletDivider, ButtonStyled, injectNotificationManager } from '@modrinth/ui'
|
||||
import { capitalizeString, formatMoney } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { Tooltip } from 'floating-vue'
|
||||
|
||||
const props = defineProps({
|
||||
transaction: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
type PayoutStatus = 'in-transit' | 'cancelling' | 'cancelled' | 'success' | 'failed'
|
||||
type PayoutMethodType = 'paypal' | 'venmo' | 'tremendous' | 'muralpay'
|
||||
type PayoutSource = 'creator_rewards' | 'affilites'
|
||||
|
||||
const emit = defineEmits(['cancelled'])
|
||||
type WithdrawalTransaction = {
|
||||
type: 'withdrawal'
|
||||
id: string
|
||||
status: PayoutStatus
|
||||
created: string
|
||||
amount: number
|
||||
fee?: number | null
|
||||
method_type?: PayoutMethodType | null
|
||||
method?: string
|
||||
method_id?: string
|
||||
method_address?: string | null
|
||||
}
|
||||
|
||||
type PayoutAvailableTransaction = {
|
||||
type: 'payout_available'
|
||||
created: string
|
||||
payout_source: PayoutSource
|
||||
amount: number
|
||||
}
|
||||
|
||||
type Transaction = WithdrawalTransaction | PayoutAvailableTransaction
|
||||
|
||||
const props = defineProps<{
|
||||
transaction: Transaction
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancelled'): void
|
||||
}>()
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const auth = await useAuth()
|
||||
|
||||
const isIncome = computed(() => props.transaction.type === 'payout_available')
|
||||
|
||||
function formatTransactionStatus(status) {
|
||||
function formatTransactionStatus(status: string): string {
|
||||
if (status === 'in-transit') return 'In Transit'
|
||||
return capitalizeString(status)
|
||||
}
|
||||
|
||||
function formatMethodName(method) {
|
||||
function formatMethodName(method: string | undefined): string {
|
||||
if (!method) return 'Unknown'
|
||||
switch (method) {
|
||||
case 'paypal':
|
||||
@@ -95,24 +120,27 @@ function formatMethodName(method) {
|
||||
}
|
||||
}
|
||||
|
||||
function formatPayoutSource(source) {
|
||||
function formatPayoutSource(source: string | undefined): string {
|
||||
if (!source) return 'Income'
|
||||
return source
|
||||
.split('_')
|
||||
.map((word) => capitalizeString(word))
|
||||
.map((word: string) => capitalizeString(word))
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
async function cancelPayout() {
|
||||
async function cancelPayout(): Promise<void> {
|
||||
startLoading()
|
||||
try {
|
||||
await useBaseFetch(`payout/${props.transaction.id}`, {
|
||||
const transaction = props.transaction
|
||||
if (transaction.type !== 'withdrawal') return
|
||||
|
||||
await useBaseFetch(`payout/${transaction.id}`, {
|
||||
method: 'DELETE',
|
||||
apiVersion: 3,
|
||||
})
|
||||
await useAuth(auth.value.token)
|
||||
await useAuth()
|
||||
emit('cancelled')
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
addNotification({
|
||||
title: 'Failed to cancel transaction',
|
||||
text: err.data ? err.data.description : err,
|
||||
|
||||
Reference in New Issue
Block a user