Add ability to switch payment interval for Modrinth+ (#3581)

This commit is contained in:
Prospector 2025-05-01 10:36:51 -07:00 committed by GitHub
parent 41543e3af0
commit 4a2605bc1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -64,6 +64,21 @@
</template> </template>
</span> </span>
<template v-if="midasCharge"> <template v-if="midasCharge">
<span
v-if="
midasCharge.status === 'open' && midasCharge.subscription_interval === 'monthly'
"
class="text-sm text-purple"
>
Save
{{
formatPrice(
vintl.locale,
midasCharge.amount * 12 - oppositePrice,
midasCharge.currency_code,
)
}}/year by switching to yearly billing!
</span>
<span class="text-sm text-secondary"> <span class="text-sm text-secondary">
Since {{ $dayjs(midasSubscription.created).format("MMMM D, YYYY") }} Since {{ $dayjs(midasSubscription.created).format("MMMM D, YYYY") }}
</span> </span>
@ -118,9 +133,13 @@
</OverflowMenu> </OverflowMenu>
</ButtonStyled> </ButtonStyled>
</div> </div>
<ButtonStyled v-else-if="midasCharge && midasCharge.status !== 'cancelled'"> <div
v-else-if="midasCharge && midasCharge.status !== 'cancelled'"
class="ml-auto flex gap-2"
>
<ButtonStyled>
<button <button
class="ml-auto" :disabled="changingInterval"
@click=" @click="
() => { () => {
cancelSubscriptionId = midasSubscription.id; cancelSubscriptionId = midasSubscription.id;
@ -131,6 +150,29 @@
<XIcon /> Cancel <XIcon /> Cancel
</button> </button>
</ButtonStyled> </ButtonStyled>
<ButtonStyled
:color="midasCharge.subscription_interval === 'yearly' ? 'standard' : 'purple'"
color-fill="text"
>
<button
v-tooltip="
midasCharge.subscription_interval === 'yearly'
? `Monthly billing will cost you an additional ${formatPrice(
vintl.locale,
oppositePrice * 12 - midasCharge.amount,
midasCharge.currency_code,
)} per year`
: undefined
"
:disabled="changingInterval"
@click="switchMidasInterval(oppositeInterval)"
>
<SpinnerIcon v-if="changingInterval" class="animate-spin" />
<TransferIcon v-else /> {{ changingInterval ? "Switching" : "Switch" }} to
{{ oppositeInterval }}
</button>
</ButtonStyled>
</div>
<ButtonStyled <ButtonStyled
v-else-if="midasCharge && midasCharge.status === 'cancelled'" v-else-if="midasCharge && midasCharge.status === 'cancelled'"
color="purple" color="purple"
@ -551,6 +593,8 @@ import {
} from "@modrinth/ui"; } from "@modrinth/ui";
import { import {
PlusIcon, PlusIcon,
TransferIcon,
SpinnerIcon,
ArrowBigUpDashIcon, ArrowBigUpDashIcon,
XIcon, XIcon,
CardIcon, CardIcon,
@ -754,6 +798,13 @@ const midasCharge = computed(() =>
: null, : null,
); );
const oppositePrice = computed(() =>
midasSubscription.value
? midasProduct.value?.prices?.find((price) => price.id === midasSubscription.value.price_id)
?.prices?.intervals?.[oppositeInterval.value]
: undefined,
);
const pyroSubscriptions = computed(() => { const pyroSubscriptions = computed(() => {
const pyroSubs = subscriptions.value?.filter((s) => s?.metadata?.type === "pyro") || []; const pyroSubs = subscriptions.value?.filter((s) => s?.metadata?.type === "pyro") || [];
const servers = serversData.value?.servers || []; const servers = serversData.value?.servers || [];
@ -851,6 +902,31 @@ async function submit() {
const removePaymentMethodIndex = ref(); const removePaymentMethodIndex = ref();
const changingInterval = ref(false);
const oppositeInterval = computed(() =>
midasCharge.value?.subscription_interval === "yearly" ? "monthly" : "yearly",
);
async function switchMidasInterval(interval) {
changingInterval.value = true;
startLoading();
try {
await useBaseFetch(`billing/subscription/${midasSubscription.value.id}`, {
internal: true,
method: "PATCH",
body: {
interval,
},
});
await refresh();
} catch (error) {
console.error("Error switching Modrinth+ payment interval:", error);
}
stopLoading();
changingInterval.value = false;
}
async function editPaymentMethod(index, primary) { async function editPaymentMethod(index, primary) {
startLoading(); startLoading();
try { try {