You've already forked AstralRinth
forked from xxxOFFxxx/AstralRinth
Provide more specific payout method names on frontend (#4977)
* Provide more specific payout method names on frontend Been getting a lot of confused tickets recently of people withdrawing to PayPal but then not recognizing what "Tremendous" means. This should clarify things. * feat: improve icons + names for withdrawals * Update apps/frontend/src/components/ui/dashboard/RevenueTransaction.vue Co-authored-by: Emma Alexia <emma@modrinth.com> Signed-off-by: Calum H. <hendersoncal117@gmail.com> * fix: icons * fix: object cover * feat: icons for crypto + bank * fix: remove empty null * fix: qa --------- Signed-off-by: Calum H. <hendersoncal117@gmail.com> Co-authored-by: Calum H. <contact@cal.engineer>
This commit is contained in:
@@ -1,17 +1,28 @@
|
||||
<template>
|
||||
<div class="flex flex-row gap-2 md:gap-3">
|
||||
<div
|
||||
class="flex h-10 min-h-10 w-10 min-w-10 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"
|
||||
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"
|
||||
>
|
||||
<ArrowDownIcon v-if="isIncome" class="my-auto size-6 text-secondary md:size-8" />
|
||||
<ArrowUpIcon v-else class="my-auto size-6 text-secondary md:size-8" />
|
||||
<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)
|
||||
: 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'">
|
||||
@@ -33,8 +44,8 @@
|
||||
<div class="my-auto flex flex-row items-center gap-2">
|
||||
<span
|
||||
class="text-base font-semibold md:text-lg"
|
||||
:class="transaction.type === 'payout_available' ? 'text-green' : 'text-contrast'"
|
||||
>{{ formatMoney(transaction.amount) }}</span
|
||||
: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" :triggers="['hover', 'focus']" no-auto-focus>
|
||||
@@ -55,12 +66,27 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ArrowDownIcon, ArrowUpIcon, XIcon } from '@modrinth/assets'
|
||||
import { BulletDivider, ButtonStyled, injectNotificationManager } from '@modrinth/ui'
|
||||
import {
|
||||
ArrowDownIcon,
|
||||
ArrowUpIcon,
|
||||
LandmarkIcon,
|
||||
PayPalColorIcon,
|
||||
VenmoColorIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
BulletDivider,
|
||||
ButtonStyled,
|
||||
getCurrencyIcon,
|
||||
injectNotificationManager,
|
||||
} from '@modrinth/ui'
|
||||
import { capitalizeString, formatMoney } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { Tooltip } from 'floating-vue'
|
||||
|
||||
import { useGeneratedState } from '~/composables/generated'
|
||||
import { findRail } from '~/utils/muralpay-rails'
|
||||
|
||||
type PayoutStatus = 'in-transit' | 'cancelling' | 'cancelled' | 'success' | 'failed'
|
||||
type PayoutMethodType = 'paypal' | 'venmo' | 'tremendous' | 'muralpay'
|
||||
type PayoutSource = 'creator_rewards' | 'affilites'
|
||||
@@ -96,15 +122,73 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const generatedState = useGeneratedState()
|
||||
|
||||
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 = generatedState.value.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 = generatedState.value.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)
|
||||
}
|
||||
|
||||
function formatMethodName(method: string | undefined): string {
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
function formatMethodName(method: string | undefined, method_id: string | undefined): string {
|
||||
if (!method) return 'Unknown'
|
||||
switch (method) {
|
||||
case 'paypal':
|
||||
@@ -112,9 +196,19 @@ function formatMethodName(method: string | undefined): string {
|
||||
case 'venmo':
|
||||
return 'Venmo'
|
||||
case 'tremendous':
|
||||
if (method_id) {
|
||||
const info = generatedState.value.tremendousIdMap?.[method_id]
|
||||
if (info) return `${info.name}`
|
||||
}
|
||||
return 'Tremendous'
|
||||
case 'muralpay':
|
||||
return 'Muralpay'
|
||||
if (method_id) {
|
||||
const rail = findRail(method_id)
|
||||
if (rail) {
|
||||
return formatMessage(rail.name)
|
||||
}
|
||||
}
|
||||
return 'Mural Pay (Unknown)'
|
||||
default:
|
||||
return capitalizeString(method)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ export const useGeneratedState = () =>
|
||||
muralBankDetails: generatedState.muralBankDetails as
|
||||
| Record<string, { bankNames: string[] }>
|
||||
| undefined,
|
||||
tremendousIdMap: generatedState.tremendousIdMap as
|
||||
| Record<string, { name: string; image_url: string | null }>
|
||||
| undefined,
|
||||
countries: (generatedState.countries ?? []) as ISO3166.Country[],
|
||||
subdivisions: (generatedState.subdivisions ?? {}) as Record<string, ISO3166.Subdivision[]>,
|
||||
|
||||
|
||||
@@ -95,8 +95,11 @@ import { formatMoney } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import RevenueTransaction from '~/components/ui/dashboard/RevenueTransaction.vue'
|
||||
import { useGeneratedState } from '~/composables/generated'
|
||||
import { findRail } from '~/utils/muralpay-rails'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const generatedState = useGeneratedState()
|
||||
|
||||
useHead({
|
||||
title: 'Transaction history - Modrinth',
|
||||
@@ -216,10 +219,24 @@ function transactionsToCSV() {
|
||||
methodOrSource = 'Venmo'
|
||||
break
|
||||
case 'tremendous':
|
||||
if (txn.method_id) {
|
||||
const info = generatedState.value.tremendousIdMap?.[txn.method_id]
|
||||
if (info) {
|
||||
methodOrSource = `Tremendous (${info.name})`
|
||||
break
|
||||
}
|
||||
}
|
||||
methodOrSource = 'Tremendous'
|
||||
break
|
||||
case 'muralpay':
|
||||
methodOrSource = 'Muralpay'
|
||||
if (txn.method_id) {
|
||||
const rail = findRail(txn.method_id)
|
||||
if (rail) {
|
||||
methodOrSource = `${rail.name.defaultMessage}`
|
||||
break
|
||||
}
|
||||
}
|
||||
methodOrSource = 'Mural Pay (Unknown)'
|
||||
break
|
||||
default:
|
||||
methodOrSource = method.charAt(0).toUpperCase() + method.slice(1)
|
||||
|
||||
@@ -855,6 +855,7 @@ export const MURALPAY_RAILS: Record<string, RailConfig> = {
|
||||
currency: 'USDC',
|
||||
type: 'crypto',
|
||||
fee: '≈ 1%',
|
||||
railCode: 'blockchain-usdc-polygon',
|
||||
blockchain: 'POLYGON',
|
||||
warningMessage: defineMessage({
|
||||
id: 'muralpay.warning.wallet-address',
|
||||
@@ -888,6 +889,7 @@ export const MURALPAY_RAILS: Record<string, RailConfig> = {
|
||||
currency: 'USDC',
|
||||
type: 'crypto',
|
||||
fee: '≈ 1%',
|
||||
railCode: 'blockchain-usdc-base',
|
||||
blockchain: 'BASE',
|
||||
warningMessage: defineMessage({
|
||||
id: 'muralpay.warning.wallet-address',
|
||||
@@ -924,6 +926,7 @@ export const MURALPAY_RAILS: Record<string, RailConfig> = {
|
||||
currency: 'USDC',
|
||||
type: 'crypto',
|
||||
fee: '≈ 1%',
|
||||
railCode: 'blockchain-usdc-ethereum',
|
||||
blockchain: 'ETHEREUM',
|
||||
warningMessage: defineMessage({
|
||||
id: 'muralpay.warning.wallet-address',
|
||||
@@ -957,6 +960,7 @@ export const MURALPAY_RAILS: Record<string, RailConfig> = {
|
||||
currency: 'USDC',
|
||||
type: 'crypto',
|
||||
fee: '≈ 1%',
|
||||
railCode: 'blockchain-usdc-celo',
|
||||
blockchain: 'CELO',
|
||||
warningMessage: defineMessage({
|
||||
id: 'muralpay.warning.wallet-address',
|
||||
@@ -996,3 +1000,7 @@ export function getRailsByType(type: 'fiat' | 'crypto'): RailConfig[] {
|
||||
export function getRailConfig(railId: string): RailConfig | undefined {
|
||||
return MURALPAY_RAILS[railId]
|
||||
}
|
||||
|
||||
export function findRail(railCode: string): RailConfig | undefined {
|
||||
return Object.values(MURALPAY_RAILS).find((rail) => rail.railCode === railCode)
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ export class LabrinthStateModule extends AbstractModule {
|
||||
products,
|
||||
muralBankDetails,
|
||||
iso3166Data,
|
||||
payoutMethods,
|
||||
] = await Promise.all([
|
||||
// Tag endpoints
|
||||
this.client
|
||||
@@ -114,8 +115,23 @@ export class LabrinthStateModule extends AbstractModule {
|
||||
this.client.iso3166.data
|
||||
.build()
|
||||
.catch((err) => handleError(err, { countries: [], subdivisions: {} })),
|
||||
|
||||
// Payout methods for tremendous ID mapping
|
||||
this.client
|
||||
.request<Labrinth.State.PayoutMethodInfo[]>('/payout/methods', {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
})
|
||||
.catch((err) => handleError(err, [])),
|
||||
])
|
||||
|
||||
const tremendousIdMap = Object.fromEntries(
|
||||
(payoutMethods as Labrinth.State.PayoutMethodInfo[])
|
||||
.filter((m) => m.type === 'tremendous')
|
||||
.map((m) => [m.id, { name: m.name, image_url: m.image_logo_url }]),
|
||||
)
|
||||
|
||||
return {
|
||||
categories,
|
||||
loaders,
|
||||
@@ -127,6 +143,7 @@ export class LabrinthStateModule extends AbstractModule {
|
||||
homePageNotifs,
|
||||
products,
|
||||
muralBankDetails: muralBankDetails?.bankDetails,
|
||||
tremendousIdMap,
|
||||
countries: iso3166Data.countries,
|
||||
subdivisions: iso3166Data.subdivisions,
|
||||
errors,
|
||||
|
||||
@@ -699,6 +699,13 @@ export namespace Labrinth {
|
||||
}
|
||||
|
||||
export namespace State {
|
||||
export interface PayoutMethodInfo {
|
||||
id: string
|
||||
type: string
|
||||
name: string
|
||||
image_logo_url: string | null
|
||||
}
|
||||
|
||||
export interface GeneratedState {
|
||||
categories: Tags.v2.Category[]
|
||||
loaders: Tags.v2.Loader[]
|
||||
@@ -711,6 +718,13 @@ export namespace Labrinth {
|
||||
bankNames: string[]
|
||||
}
|
||||
>
|
||||
tremendousIdMap?: Record<
|
||||
string,
|
||||
{
|
||||
name: string
|
||||
image_url: string | null
|
||||
}
|
||||
>
|
||||
|
||||
homePageProjects?: Projects.v2.Project[]
|
||||
homePageSearch?: Search.v2.SearchResults
|
||||
|
||||
Reference in New Issue
Block a user