mirror of
https://github.com/modrinth/code.git
synced 2026-08-24 16:44:51 +00:00
* chore: reduce memory usage * feat: worker tracing * fix: eslint * fix: remove compat flag * fix: prettier
236 lines
6.3 KiB
Vue
236 lines
6.3 KiB
Vue
<template>
|
|
<div class="flex flex-row gap-2 md:gap-3">
|
|
<div
|
|
class="flex h-10 min-h-10 w-10 min-w-10 items-center justify-center rounded-full border-[1px] border-solid border-button-bg bg-bg-raised !p-0 shadow-md md:h-12 md:min-h-12 md:w-12 md:min-w-12"
|
|
>
|
|
<img
|
|
v-if="methodIconUrl"
|
|
:src="methodIconUrl"
|
|
alt=""
|
|
class="size-6 rounded-full object-cover md:size-8"
|
|
/>
|
|
<component
|
|
:is="methodIconComponent"
|
|
v-else-if="methodIconComponent"
|
|
class="size-6 md:size-8"
|
|
/>
|
|
<ArrowDownIcon v-else-if="isIncome" class="size-6 text-secondary md:size-8" />
|
|
<ArrowUpIcon v-else class="size-6 text-secondary md:size-8" />
|
|
</div>
|
|
<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">{{
|
|
transaction.type === 'payout_available'
|
|
? formatPayoutSource(transaction.payout_source)
|
|
: formatMethodName(transaction.method_type || transaction.method, transaction.method_id)
|
|
}}</span>
|
|
<span class="text-xs text-secondary md:text-sm">
|
|
<template v-if="transaction.type === 'withdrawal'">
|
|
<span
|
|
:class="[
|
|
transaction.status === 'cancelling' || transaction.status === 'cancelled'
|
|
? 'text-red'
|
|
: '',
|
|
]"
|
|
>{{ formatTransactionStatus(transaction.status) }} <BulletDivider
|
|
/></span>
|
|
</template>
|
|
{{ formatDate(transaction.created) }}
|
|
<template v-if="transaction.type === 'withdrawal' && transaction.fee">
|
|
<BulletDivider /> Fee {{ formatMoney(transaction.fee) }}
|
|
</template>
|
|
</span>
|
|
</div>
|
|
<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'"
|
|
>{{ isIncome ? '' : '-' }}{{ formatMoney(transaction.amount) }}</span
|
|
>
|
|
<template v-if="transaction.type === 'withdrawal' && transaction.status === 'in-transit'">
|
|
<Tooltip
|
|
theme="dismissable-prompt"
|
|
class="inline-flex shrink-0"
|
|
:triggers="['hover', 'focus']"
|
|
no-auto-focus
|
|
>
|
|
<span class="my-auto align-middle"
|
|
><IconButton
|
|
type="outlined"
|
|
size="xs"
|
|
label="Button"
|
|
class="!size-6 align-middle"
|
|
@click="cancelPayout"
|
|
>
|
|
<XIcon /> </IconButton
|
|
></span>
|
|
<template #popper>
|
|
<div class="font-semibold text-contrast">Cancel transaction</div>
|
|
</template>
|
|
</Tooltip>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { Labrinth } from '@modrinth/api-client'
|
|
import {
|
|
ArrowDownIcon,
|
|
ArrowUpIcon,
|
|
LandmarkIcon,
|
|
PayPalColorIcon,
|
|
VenmoColorIcon,
|
|
XIcon,
|
|
} from '@modrinth/assets'
|
|
import {
|
|
BulletDivider,
|
|
getCurrencyIcon,
|
|
IconButton,
|
|
injectNotificationManager,
|
|
useFormatDateTime,
|
|
useFormatMoney,
|
|
useVIntl,
|
|
} from '@modrinth/ui'
|
|
import { capitalizeString } from '@modrinth/utils'
|
|
import { Tooltip } from 'floating-vue'
|
|
|
|
import { tremendousIdMap } from '~/generated/state.json'
|
|
import { findRail } from '~/utils/muralpay-rails'
|
|
|
|
type Transaction = Labrinth.Payout.v3.TransactionItem
|
|
|
|
const props = defineProps<{
|
|
transaction: Transaction
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'cancelled'): void
|
|
}>()
|
|
|
|
const { addNotification } = injectNotificationManager()
|
|
|
|
const isIncome = computed(() => props.transaction.type === 'payout_available')
|
|
|
|
const methodIconUrl = computed(() => {
|
|
if (props.transaction.type !== 'withdrawal') return null
|
|
const method = props.transaction.method_type || props.transaction.method
|
|
const methodId = props.transaction.method_id
|
|
|
|
if (method === 'tremendous' && methodId) {
|
|
const methodInfo = tremendousIdMap?.[methodId]
|
|
if (methodInfo?.name?.toLowerCase()?.includes('paypal')) return null
|
|
return methodInfo?.image_url ?? null
|
|
}
|
|
|
|
return null
|
|
})
|
|
|
|
const methodIconComponent = computed(() => {
|
|
if (props.transaction.type !== 'withdrawal') return null
|
|
const method = props.transaction.method_type || props.transaction.method
|
|
switch (method) {
|
|
case 'paypal':
|
|
return PayPalColorIcon
|
|
case 'tremendous': {
|
|
const methodId = props.transaction.method_id
|
|
if (methodId) {
|
|
const info = tremendousIdMap?.[methodId]
|
|
if (info?.name?.toLowerCase()?.includes('paypal')) {
|
|
return PayPalColorIcon
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
case 'venmo':
|
|
return VenmoColorIcon
|
|
case 'muralpay': {
|
|
const methodId = props.transaction.method_id
|
|
if (methodId) {
|
|
const rail = findRail(methodId)
|
|
if (rail) {
|
|
if (rail.type === 'crypto') {
|
|
const currencyIcon = getCurrencyIcon(rail.currency)
|
|
if (currencyIcon) return currencyIcon
|
|
}
|
|
if (rail.type === 'fiat') {
|
|
const currencyIcon = getCurrencyIcon(rail.currency)
|
|
if (currencyIcon) return currencyIcon
|
|
return LandmarkIcon
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
default:
|
|
return null
|
|
}
|
|
})
|
|
|
|
function formatTransactionStatus(status: string): string {
|
|
if (status === 'in-transit') return 'In Transit'
|
|
return capitalizeString(status)
|
|
}
|
|
|
|
const { formatMessage } = useVIntl()
|
|
const formatMoney = useFormatMoney()
|
|
const formatDate = useFormatDateTime({ dateStyle: 'medium' })
|
|
|
|
function formatMethodName(method: string | undefined, method_id: string | undefined): string {
|
|
if (!method) return 'Unknown'
|
|
switch (method) {
|
|
case 'paypal':
|
|
return 'PayPal'
|
|
case 'venmo':
|
|
return 'Venmo'
|
|
case 'tremendous':
|
|
if (method_id) {
|
|
const info = tremendousIdMap?.[method_id]
|
|
if (info) return `${info.name}`
|
|
}
|
|
return 'Tremendous'
|
|
case 'muralpay':
|
|
if (method_id) {
|
|
const rail = findRail(method_id)
|
|
if (rail) {
|
|
return formatMessage(rail.name)
|
|
}
|
|
}
|
|
return 'Mural Pay (Unknown)'
|
|
default:
|
|
return capitalizeString(method)
|
|
}
|
|
}
|
|
|
|
function formatPayoutSource(source: string | undefined): string {
|
|
if (!source) return 'Income'
|
|
return source
|
|
.split('_')
|
|
.map((word: string) => capitalizeString(word))
|
|
.join(' ')
|
|
}
|
|
|
|
async function cancelPayout(): Promise<void> {
|
|
startLoading()
|
|
try {
|
|
const transaction = props.transaction
|
|
if (transaction.type !== 'withdrawal') return
|
|
|
|
await useBaseFetch(`payout/${transaction.id}`, {
|
|
method: 'DELETE',
|
|
apiVersion: 3,
|
|
})
|
|
await useAuth()
|
|
emit('cancelled')
|
|
} catch (err: any) {
|
|
addNotification({
|
|
title: 'Failed to cancel transaction',
|
|
text: err.data ? err.data.description : err,
|
|
type: 'error',
|
|
})
|
|
}
|
|
stopLoading()
|
|
}
|
|
</script>
|