feat: start of cross platform page system (#4731)

* feat: abstract api-client DI into ui package

* feat: cross platform page system

* feat: tanstack as cross platform useAsyncData

* feat: archon servers routes + labrinth billing routes

* fix: dont use partial

* feat: migrate server list page to tanstack + api-client + re-enabled broken features!

* feat: migrate servers manage page to api-client before page system

* feat: migrate manage page to page system

* fix: type issues

* fix: upgrade wrapper bugs

* refactor: move state types into api-client

* feat: disable financial stuff on app frontend

* feat: finalize cross platform page system for now

* fix: lint

* fix: build issues

* feat: remove papaparse

* fix: lint

* fix: interface error

---------

Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
This commit is contained in:
Calum H.
2025-11-14 17:15:09 +00:00
committed by GitHub
parent 26feaf753a
commit 7ccc32675b
79 changed files with 2631 additions and 1259 deletions

View File

@@ -1,23 +1,25 @@
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import { formatPrice } from '@modrinth/utils'
import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, provide } from 'vue'
import { monthsInInterval, type ServerBillingInterval, type ServerPlan } from '../../utils/billing'
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
import OptionGroup from '../base/OptionGroup.vue'
import ModalBasedServerPlan from './ModalBasedServerPlan.vue'
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
const { formatMessage, locale } = useVIntl()
const props = defineProps<{
availableProducts: ServerPlan[]
availableProducts: Labrinth.Billing.Internal.Product[]
currency: string
existingPlan?: ServerPlan
existingPlan?: Labrinth.Billing.Internal.Product
}>()
const availableBillingIntervals = ['monthly', 'quarterly']
const selectedPlan = defineModel<ServerPlan>('plan')
const selectedPlan = defineModel<Labrinth.Billing.Internal.Product>('plan')
const selectedInterval = defineModel<ServerBillingInterval>('interval')
const emit = defineEmits<{
(e: 'choose-custom'): void
@@ -75,7 +77,10 @@ const isSameAsExistingPlan = computed(() => {
})
const plansByRam = computed(() => {
const byName: Record<'small' | 'medium' | 'large', ServerPlan | undefined> = {
const byName: Record<
'small' | 'medium' | 'large',
Labrinth.Billing.Internal.Product | undefined
> = {
small: undefined,
medium: undefined,
large: undefined,
@@ -93,13 +98,11 @@ function handleCustomPlan() {
emit('choose-custom')
}
function pricePerMonth(plan?: ServerPlan) {
if (!plan) return undefined
const total = plan.prices?.find((x) => x.currency_code === props.currency)?.prices?.intervals?.[
selectedInterval.value!
]
function pricePerMonth(plan?: Labrinth.Billing.Internal.Product) {
if (!plan || !selectedInterval.value) return undefined
const total = getPriceForInterval(plan, props.currency, selectedInterval.value)
if (!total) return undefined
return total / monthsInInterval[selectedInterval.value!]
return total / monthsInInterval[selectedInterval.value]
}
const customPricePerGb = computed(() => {
@@ -107,7 +110,9 @@ const customPricePerGb = computed(() => {
let min: number | undefined
for (const p of props.availableProducts) {
const perMonth = pricePerMonth(p)
const ramGb = (p?.metadata?.ram ?? 0) / 1024
const metadata = p?.metadata
if (!metadata || (metadata.type !== 'pyro' && metadata.type !== 'medal')) continue
const ramGb = metadata.ram / 1024
if (perMonth && ramGb > 0) {
const perGb = perMonth / ramGb
if (min === undefined || perGb < min) min = perGb