Skip to content

Commit 3765a6d

Browse files
IMB11ProspectoraecsocketAlexTMjugador
authored
feat: creator revenue page overhaul (#4204)
* feat: start on tax compliance * feat: avarala1099 composable * fix: shouldShow should be managed on the page itself * refactor: move show logic to revenue page * feat: security practices rather than info * feat: withdraw page lock * fix: empty modal bug & lint issues * feat: hide behind feature flag * Use standard admonition components, make casing consistent * modal title * lint * feat: withdrawal check * feat: tax cap on withdrawals warning * feat: start on revenue page overhaul * feat: segment generation for bar * feat: tooltips and links * fix: tooltip border * feat: finish initial layout, start on withdraw modal * feat: start on withdrawal limit stage * feat: shade support for primary colors * feat: start on withdraw details stage * fix: convert swatches to hex * feat: payout method/region dropdown temporarily using multiselect * feat: fix modal open issues and use teleport dropdowns * feat: hide transactions section if there are no transactions * refactor: NavStack surfaces * feat: new dropdown component * feat: remove teleport dropdown modal in favour of new combobox component * fix: lint * refactor: dashboard sidebar layout * feat: cleanup * fix: niche bugs * fix: ComboBox styling * feat: first part of qa * feat: animate flash rather than tooltip * fix: lint * feat: qa border gradient * fix: seg hover flashes * feat: i18n * feat: i18n and final QA * fix: lint * feat: QA * fix: lint * fix: merge conflicts * fix: intl * fix: blue hover * fix: transfers page * feat: surface variables & gradients * feat: text vars * fix: lint * fix: intl * feat: stages * fix: lint * feat: region selection * feat: method selection btns * fix: flex col on transactions * feat: hook up method selection to ctx * feat: muralpay kyc stage info * wip: muralpay integration * Basic Mural Pay API bindings * Fix clippy * use dotenvy in muralpay example * Refactor payout creation code * wip: muralpay payout requests * Mural Pay payouts work * Fix clippy * feat: progress * fix: broken tax form stage logic * polish: tax form stage and method selection stage layout * add mural pay fees API * Work on payout fee API * Fees API for more payment methods * Fix CI * polish: muralpay qa * refactor: clean up combobox component * polish: change from critical -> warning admonition in MuralpayDetailsStage * Temporarily disable Venmo and PayPal methods from frontend * polish: clean up transaction component & page * polish: navbar qa, text color-contrast in chips type buttonstyled, mb on rev/index.vue page * fix: incorrectly using available balance as tax form withdraw limit after tax forms submitted * wip: counterparties * Start on counterparties and payment methods API * polish: combobox component * polish: fix broken scroll logic using a composable & web:fix * fix: lint * polish: various QA fixes * feat: hook up with backend (wip) * feat: draft muralpay rails dynamic logic * polish: modify rails to support backend changes * Mural Pay multiple methods when fetching * Don't send supported_countries to frontend * Mural Pay multiple methods when fetching * Don't send supported_countries to frontend * feat: fees & methods endpoint hookup * chore: remove duplicates fix * polish: qa changes + figma match * Add countries to muralpay fiat methods * Compile fix * Add exchange rate info to fees endpoint * Add fees to premium Tremendous options * polish: i18n and better document type dropdown -> id input labels * feat: tremendous * fix: lint & i18n * feat: reintroduce tin mismatch logic to index.vue * polish: qa * fix: i18n * feat: remove teleport dropdown menu - combobox should be used * fix: lint * fix: jsdoc * feat: checkbox for reward program terms * Add delivery email field to Tremendous payouts * Add Tremendous product category to payout methods * Add bank details API to muralpay * Fix CI * Fix CI * polish: qa changes * feat: i18n pass * feat: deduplicate methods endpoint & fix i18n issues * chore: deduplicate i18n strings into common-messages.ts * fix: lint * fix: i18n * feat: estimates * polish: more QA * Remove prepaid visa, compute fees properly for Tremendous methods * Add more details to Tremendous errors * feat: withdraw endpoint impl & internals refactor * Add more details to Tremendous errors * feat: completion stage * Add fees to Mural * feat: transactions page match figma * fix: i18n * polish: QA changes * polish: qa * Payout history route and bank details * polish: autofill and requirements checks * fix: i18n + lint * fix: fiat rail fees * polish: move scroll fade stuff into NewModal rather than just CreatorWithdrawModal * feat: simplify action btn logic & tax form error * fix: tax -> Tax form * Re-add legacy PayPal/Venmo options for US * feat: mobile responsiveness fixes for modal * fix: responsiveness issues * feat: navstack responsiveness * fix: responsiveness * move the mural bank details route * fix: generated state cleanup & bank details input * fix: lint & i18n * Add utoipa support to payout endpoints * address some PR comments * polish: qa * add CORS to new utoipa routes * feat: legacy paypal/venmo stage * polish: reset amount on back qa * revert: navstack mr changes * polish: loading indicator on method selection stage * fix: paypal modal doesnt reopen after auth * fix: lint & i18n * fix: paypal flow * polish: qa changes * fix: gitignore * polish: qa fixes * fix: payouts_available in payouts.rs * fix: bug when limit is zero * polish: qa changes * fix: qa stuff & muralpay sub-division fix * Immediately approve mural payouts * Add currency support to Tremendous payouts * Currency forex * add forex to tremendous fee request * polish: qa & currency support for paypal tremendous * polish: fx qa * feat: demo mode flag * fix: i18n & padding issues * polish: qa changes * fix: ml * Add Mural balance to bank balance info * polish: show warning for paypal international USD withdrawals + more currencies * Add more Tremendous currencies support * fix: colors on balance bars * fix: empty states * fix: pl-8 mobile issue * fix: hide see all * Transaction payouts available use the correct date * Address my own review comment * Address PR comments * Change Mural withdrawal limit to 3k * fix: empty state + paypal warning * maybe fix tremendous gift cards * Change how Mural minimum withdrawals are calculated * Tweak min/max withdrawal values * fix: segment brightness * fix: min & max for muralpay & legacy paypal * Fix some icon issues * more issues * fix user menu * fix: remove + network --------- Signed-off-by: Calum H. <contact@cal.engineer> Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com> Co-authored-by: aecsocket <aecsocket@tutanota.com> Co-authored-by: Alejandro González <me@alegon.dev>
1 parent 92698e4 commit 3765a6d

File tree

108 files changed

+9054
-2647
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+9054
-2647
lines changed

.github/instructions/i18n-convert.instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Please follow these rules precisely:
99
1. Identify translatable strings
1010

1111
- Scan the <template> for all user-visible strings (inner text, alt attributes, placeholders, button labels, etc.). Do not extract dynamic expressions (like {{ user.name }}) or HTML tags. Only extract static human-readable text.
12+
- There may be strings within the <script> block, e.g dropdown option labels, notifications etc.
1213

1314
2. Create message definitions
1415

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,6 @@ app-playground-data/*
6565

6666
.astro
6767
.claude
68+
69+
# labrinth demo fixtures
70+
apps/labrinth/fixtures/demo

apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import {
1515
ButtonStyled,
1616
Checkbox,
1717
Chips,
18+
Combobox,
1819
injectNotificationManager,
19-
TeleportDropdownMenu,
2020
} from '@modrinth/ui'
2121
import {
2222
formatCategory,
@@ -158,6 +158,21 @@ const selectableGameVersionNumbers = computed(() => {
158158
.map((x) => x.version)
159159
})
160160
161+
const gameVersionOptions = computed(() =>
162+
(selectableGameVersionNumbers.value ?? []).map((v) => ({ value: v, label: v })),
163+
)
164+
165+
const loaderVersionOptions = computed(() =>
166+
(selectableLoaderVersions.value ?? []).map((opt, index) => ({ value: index, label: opt.id })),
167+
)
168+
169+
const loaderVersionLabel = computed(() => {
170+
const idx = loaderVersionIndex.value
171+
return idx >= 0 && selectableLoaderVersions.value
172+
? selectableLoaderVersions.value[idx]?.id
173+
: 'Select version'
174+
})
175+
161176
const selectableLoaderVersions: ComputedRef<ManifestLoaderVersion[] | undefined> = computed(() => {
162177
if (gameVersion.value) {
163178
if (loader.value === 'fabric') {
@@ -647,11 +662,11 @@ const messages = defineMessages({
647662
{{ formatMessage(messages.gameVersion) }}
648663
</h2>
649664
<div class="flex flex-wrap mt-2 gap-2">
650-
<TeleportDropdownMenu
665+
<Combobox
651666
v-if="selectableGameVersionNumbers !== undefined"
652667
v-model="gameVersion"
653-
:options="selectableGameVersionNumbers"
654-
name="Game Version Dropdown"
668+
:options="gameVersionOptions"
669+
:display-value="gameVersion || formatMessage(messages.unknownVersion)"
655670
/>
656671
<Checkbox
657672
v-if="hasSnapshots"
@@ -663,14 +678,13 @@ const messages = defineMessages({
663678
<h2 class="m-0 mt-4 text-lg font-extrabold text-contrast block">
664679
{{ formatMessage(messages.loaderVersion, { loader: formatCategory(loader) }) }}
665680
</h2>
666-
<TeleportDropdownMenu
681+
<Combobox
667682
v-if="selectableLoaderVersions"
668-
:model-value="selectableLoaderVersions[loaderVersionIndex]"
669-
:options="selectableLoaderVersions"
670-
:display-name="(option: ManifestLoaderVersion) => option?.id"
683+
v-model="loaderVersionIndex"
684+
:options="loaderVersionOptions"
685+
:display-value="loaderVersionLabel"
671686
name="Version selector"
672687
class="mt-2"
673-
@change="(value) => (loaderVersionIndex = value.index)"
674688
/>
675689
<div v-else class="mt-2 text-brand-red flex gap-2 items-center">
676690
<IssuesIcon />

apps/app-frontend/src/components/ui/settings/AppearanceSettings.vue

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { TeleportDropdownMenu, ThemeSelector, Toggle } from '@modrinth/ui'
2+
import { Combobox, ThemeSelector, Toggle } from '@modrinth/ui'
33
import { ref, watch } from 'vue'
44
55
import { get, set } from '@/helpers/settings.ts'
@@ -50,7 +50,7 @@ watch(
5050
:model-value="themeStore.advancedRendering"
5151
@update:model-value="
5252
(e) => {
53-
themeStore.advancedRendering = e
53+
themeStore.advancedRendering = !!e
5454
settings.advanced_rendering = themeStore.advancedRendering
5555
}
5656
"
@@ -86,12 +86,13 @@ watch(
8686
<h2 class="m-0 text-lg font-extrabold text-contrast">Default landing page</h2>
8787
<p class="m-0 mt-1">Change the page to which the launcher opens on.</p>
8888
</div>
89-
<TeleportDropdownMenu
89+
<Combobox
9090
id="opening-page"
9191
v-model="settings.default_page"
9292
name="Opening page dropdown"
9393
class="w-40"
94-
:options="['Home', 'Library']"
94+
:options="['Home', 'Library'].map((v) => ({ value: v, label: v }))"
95+
:display-value="settings.default_page ?? 'Select an option'"
9596
/>
9697
</div>
9798

@@ -122,7 +123,7 @@ watch(
122123
:model-value="settings.toggle_sidebar"
123124
@update:model-value="
124125
(e) => {
125-
settings.toggle_sidebar = e
126+
settings.toggle_sidebar = !!e
126127
themeStore.toggleSidebar = settings.toggle_sidebar
127128
}
128129
"

apps/app-frontend/src/components/ui/world/modal/ServerModalBody.vue

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { TeleportDropdownMenu } from '@modrinth/ui'
2+
import { Combobox } from '@modrinth/ui'
33
import { defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
44
55
import type { ServerPackStatus } from '@/helpers/worlds.ts'
@@ -74,12 +74,19 @@ defineExpose({ resourcePackOptions })
7474
{{ formatMessage(messages.resourcePack) }}
7575
</h2>
7676
<div>
77-
<TeleportDropdownMenu
77+
<Combobox
7878
v-model="resourcePack"
79-
:options="resourcePackOptions"
79+
:options="
80+
resourcePackOptions.map((o) => ({
81+
value: o,
82+
label: formatMessage(resourcePackOptionMessages[o]),
83+
}))
84+
"
8085
name="Server resource pack"
81-
:display-name="
82-
(option: ServerPackStatus) => formatMessage(resourcePackOptionMessages[option])
86+
:display-value="
87+
resourcePack
88+
? formatMessage(resourcePackOptionMessages[resourcePack])
89+
: 'Select an option'
8390
"
8491
/>
8592
</div>

apps/frontend/nuxt.config.ts

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@ import { promises as fs } from 'fs'
77
import { globIterate } from 'glob'
88
import { defineNuxtConfig } from 'nuxt/config'
99
import { $fetch } from 'ofetch'
10+
import Papa from 'papaparse'
1011
import { basename, relative, resolve } from 'pathe'
1112
import svgLoader from 'vite-svg-loader'
1213

14+
import type { GeneratedState } from './src/composables/generated'
15+
1316
const STAGING_API_URL = 'https://staging-api.modrinth.com/v2/'
17+
// ISO 3166 data from https://github.com/ipregistry/iso3166
18+
// Licensed under CC BY-SA 4.0
19+
const ISO3166_REPO = 'https://raw.githubusercontent.com/ipregistry/iso3166/master'
1420

1521
const preloadedFonts = [
1622
'inter/Inter-Regular.woff2',
@@ -133,20 +139,7 @@ export default defineNuxtConfig({
133139
// 30 minutes
134140
const TTL = 30 * 60 * 1000
135141

136-
let state: {
137-
lastGenerated?: string
138-
apiUrl?: string
139-
categories?: any[]
140-
loaders?: any[]
141-
gameVersions?: any[]
142-
donationPlatforms?: any[]
143-
reportTypes?: any[]
144-
homePageProjects?: any[]
145-
homePageSearch?: any[]
146-
homePageNotifs?: any[]
147-
products?: any[]
148-
errors?: number[]
149-
} = {}
142+
let state: Partial<GeneratedState> = {}
150143

151144
try {
152145
state = JSON.parse(await fs.readFile('./src/generated/state.json', 'utf8'))
@@ -200,6 +193,9 @@ export default defineNuxtConfig({
200193
homePageSearch,
201194
homePageNotifs,
202195
products,
196+
muralBankDetails,
197+
countriesCSV,
198+
subdivisionsCSV,
203199
] = await Promise.all([
204200
$fetch(`${API_URL}tag/category`, headers).catch((err) => handleFetchError(err, [])),
205201
$fetch(`${API_URL}tag/loader`, headers).catch((err) => handleFetchError(err, [])),
@@ -220,8 +216,53 @@ export default defineNuxtConfig({
220216
$fetch(`${API_URL.replace('/v2/', '/_internal/')}billing/products`, headers).catch((err) =>
221217
handleFetchError(err, []),
222218
),
219+
$fetch(`${API_URL.replace('/v2/', '/_internal/')}mural/bank-details`, headers).catch(
220+
(err) => handleFetchError(err, null),
221+
),
222+
$fetch<string>(`${ISO3166_REPO}/countries.csv`, {
223+
...headers,
224+
responseType: 'text',
225+
}).catch((err) => handleFetchError(err, '')),
226+
$fetch<string>(`${ISO3166_REPO}/subdivisions.csv`, {
227+
...headers,
228+
responseType: 'text',
229+
}).catch((err) => handleFetchError(err, '')),
223230
])
224231

232+
const countriesData = Papa.parse(countriesCSV, {
233+
header: true,
234+
skipEmptyLines: true,
235+
transformHeader: (header) => (header.startsWith('#') ? header.slice(1) : header),
236+
}).data
237+
const subdivisionsData = Papa.parse(subdivisionsCSV, {
238+
header: true,
239+
skipEmptyLines: true,
240+
transformHeader: (header) => (header.startsWith('#') ? header.slice(1) : header),
241+
}).data
242+
243+
const subdivisionsByCountry = (subdivisionsData as any[]).reduce(
244+
(acc, sub) => {
245+
const countryCode = sub.country_code_alpha2
246+
247+
if (!countryCode || typeof countryCode !== 'string' || countryCode.trim() === '') {
248+
return acc
249+
}
250+
251+
if (!acc[countryCode]) acc[countryCode] = []
252+
253+
acc[countryCode].push({
254+
code: sub['subdivision_code_iso3166-2'],
255+
name: sub.subdivision_name,
256+
localVariant: sub.localVariant || null,
257+
category: sub.category,
258+
parent: sub.parent_subdivision || null,
259+
language: sub.language_code,
260+
})
261+
return acc
262+
},
263+
{} as Record<string, any[]>,
264+
)
265+
225266
state.categories = categories
226267
state.loaders = loaders
227268
state.gameVersions = gameVersions
@@ -231,6 +272,15 @@ export default defineNuxtConfig({
231272
state.homePageSearch = homePageSearch
232273
state.homePageNotifs = homePageNotifs
233274
state.products = products
275+
state.muralBankDetails = muralBankDetails.bankDetails
276+
state.countries = (countriesData as any[]).map((c) => ({
277+
alpha2: c.country_code_alpha2,
278+
alpha3: c.country_code_alpha3,
279+
numeric: c.numeric_code,
280+
nameShort: c.name_short,
281+
nameLong: c.name_long,
282+
}))
283+
state.subdivisions = subdivisionsByCountry
234284
state.errors = [...caughtErrorCodes]
235285

236286
await fs.writeFile('./src/generated/state.json', JSON.stringify(state))
@@ -475,6 +525,12 @@ export default defineNuxtConfig({
475525
'Critical-CH': 'Sec-CH-Prefers-Color-Scheme',
476526
},
477527
},
528+
'/dashboard/revenue/withdraw': {
529+
redirect: {
530+
to: '/dashboard/revenue',
531+
statusCode: 410,
532+
},
533+
},
478534
'/email/**': {
479535
redirect: '/_internal/templates/email/**',
480536
},

apps/frontend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@nuxt/devtools": "^1.3.3",
1919
"@types/dompurify": "^3.0.5",
2020
"@types/node": "^20.1.0",
21+
"@types/papaparse": "^5.3.15",
2122
"@vintl/compact-number": "^2.0.5",
2223
"@vintl/how-ago": "^3.0.1",
2324
"@vintl/nuxt": "^1.9.2",
@@ -56,10 +57,10 @@
5657
"floating-vue": "^5.2.2",
5758
"fuse.js": "^6.6.2",
5859
"highlight.js": "^11.7.0",
59-
"iso-3166-1": "^2.1.1",
6060
"js-yaml": "^4.1.0",
6161
"jszip": "^3.10.1",
6262
"markdown-it": "14.1.0",
63+
"papaparse": "^5.4.1",
6364
"pathe": "^1.1.2",
6465
"pinia": "^2.1.7",
6566
"pinia-plugin-persistedstate": "^4.4.1",

apps/frontend/src/components/brand/TextLogo.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@
5353
</svg>
5454
</template>
5555

56-
<script setup>
56+
<script setup lang="ts">
5757
const loading = useLoading()
5858
5959
const config = useRuntimeConfig()
60+
const flags = useFeatureFlags()
6061
6162
const api = computed(() => {
63+
if (flags.value.demoMode) return 'prod'
64+
6265
const apiUrl = config.public.apiBaseUrl
6366
if (apiUrl.startsWith('https://api.modrinth.com')) {
6467
return 'prod'

apps/frontend/src/components/ui/EnvironmentIndicator.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ defineProps({
9090
},
9191
})
9292
93-
const tags = useTags()
93+
const tags = useGeneratedState()
9494
</script>
9595
<style lang="scss" scoped>
9696
.environment {

0 commit comments

Comments
 (0)