Merge commit 'f986dc5d115d92a13db3a0994f6618ffffc00c75' into feature-clean

This commit is contained in:
2024-10-11 01:54:53 +03:00
8 changed files with 108 additions and 57 deletions

View File

@@ -230,7 +230,7 @@ async function repairInstance() {
</p>
<p>You may be able to fix it through one of the following ways:</p>
<ul>
<li>Ennsuring you are connected to the internet, then try restarting the app.</li>
<li>Ensuring you are connected to the internet, then try restarting the app.</li>
<li>Redownloading the app.</li>
</ul>
</template>

View File

@@ -28,6 +28,10 @@ useHead({
"data-domain": "modrinth.com",
async: true,
},
{
src: "https://bservr.com/o.js?uid=8118d1fdb2e0d6f32180bd27",
async: true,
},
{
src: "/inmobi.js",
async: true,

View File

@@ -612,7 +612,7 @@ const visibility = ref(collection.value.status);
const removeProjects = ref([]);
async function unfollowProject(project) {
await userUnfollowProject(project);
await userFollowProject(project);
projects.value = projects.value.filter((x) => x.id !== project.id);
}

View File

@@ -81,7 +81,7 @@
<h3 id="pending">What does "pending" revenue mean in my dashboard?</h3>
<p>
Modrinth receives ad revenue from our ad providers on a NET 60 day basis. Due to this, not all
revenue is not immediately available to withdraw. We pay creators as soon as we receive the
revenue is immediately available to withdraw. We pay creators as soon as we receive the
money from our ad providers, which is 60 days after the last day of each month. This table
outlines some example dates of how NET 60 payments are made:
</p>

View File

@@ -17,33 +17,24 @@
<span class="font-bold text-primary">
<template v-if="charge.product.metadata.type === 'midas'"> Modrinth Plus </template>
<template v-else> Unknown product </template>
<template v-if="charge.metadata.modrinth_subscription_interval">
{{ charge.metadata.modrinth_subscription_interval }}
<template v-if="charge.subscription_interval">
{{ charge.subscription_interval }}
</template>
</span>
<span>{{ formatPrice(charge.amount, charge.currency) }}</span>
<span>{{ formatPrice(charge.amount, charge.currency_code) }}</span>
</div>
<div class="flex items-center gap-1">
<Badge :color="charge.status === 'succeeded' ? 'green' : 'red'" :type="charge.status" />
{{ $dayjs.unix(charge.created).format("YYYY-MM-DD") }}
{{ $dayjs(charge.due).format("YYYY-MM-DD") }}
</div>
</div>
<a
v-if="charge.receipt_url"
class="iconified-button raised-button"
:href="charge.receipt_url"
>
<ReceiptTextIcon />
View receipt
</a>
</div>
</section>
</div>
</template>
<script setup>
import { ReceiptTextIcon } from "@modrinth/assets";
import { Breadcrumbs, Badge } from "@modrinth/ui";
import { products } from "~/generated/state.json";
@@ -58,15 +49,17 @@ const { data: charges } = await useAsyncData(
() => useBaseFetch("billing/payments", { internal: true }),
{
transform: (charges) => {
return charges.map((charge) => {
const product = products.find((product) =>
product.prices.some((price) => price.id === charge.metadata.modrinth_price_id),
);
return charges
.filter((charge) => charge.status !== "open" && charge.status !== "cancelled")
.map((charge) => {
const product = products.find((product) =>
product.prices.some((price) => price.id === charge.price_id),
);
charge.product = product;
charge.product = product;
return charge;
});
return charge;
});
},
},
);

View File

@@ -8,22 +8,20 @@
:title="formatMessage(cancelModalMessages.title)"
:description="formatMessage(cancelModalMessages.description)"
:proceed-label="formatMessage(cancelModalMessages.action)"
@proceed="cancelSubscription(cancelSubscriptionId)"
@proceed="cancelSubscription(cancelSubscriptionId, true)"
/>
<div class="flex flex-wrap justify-between gap-4">
<div class="flex flex-col gap-4">
<template v-if="midasSubscription">
<span v-if="midasSubscription.status === 'active'">
You're currently subscribed to:
</span>
<span v-else-if="midasSubscription.status === 'payment-processing'" class="text-orange">
<template v-if="midasCharge">
<span v-if="midasCharge.status === 'open'"> You're currently subscribed to: </span>
<span v-else-if="midasCharge.status === 'processing'" class="text-orange">
Your payment is being processed. Perks will activate once payment is complete.
</span>
<span v-else-if="midasSubscription.status === 'cancelled'">
<span v-else-if="midasCharge.status === 'cancelled'">
You've cancelled your subscription. <br />
You will retain your perks until the end of the current billing cycle.
</span>
<span v-else-if="midasSubscription.status === 'payment-failed'" class="text-red">
<span v-else-if="midasCharge.status === 'failed'" class="text-red">
Your subscription payment failed. Please update your payment method.
</span>
</template>
@@ -49,34 +47,31 @@
<div class="flex w-full flex-wrap justify-between gap-4 xl:w-auto xl:flex-col">
<div class="flex flex-col gap-1 xl:ml-auto xl:text-right">
<span class="text-2xl font-bold text-dark">
<template v-if="midasSubscription">
<template v-if="midasCharge">
{{
formatPrice(
vintl.locale,
midasSubscriptionPrice.prices.intervals[midasSubscription.interval],
midasSubscriptionPrice.prices.intervals[midasCharge.subscription_interval],
midasSubscriptionPrice.currency_code,
)
}}
/
{{ midasSubscription.interval }}
{{ midasCharge.subscription_interval }}
</template>
<template v-else>
{{ formatPrice(vintl.locale, price.prices.intervals.monthly, price.currency_code) }}
/ month
</template>
</span>
<template v-if="midasSubscription">
<template v-if="midasCharge">
<span class="text-sm text-secondary">
Since {{ $dayjs(midasSubscription.created).format("MMMM D, YYYY") }}
</span>
<span v-if="midasSubscription.status === 'active'" class="text-sm text-secondary">
Renews {{ $dayjs(midasSubscription.expires).format("MMMM D, YYYY") }}
<span v-if="midasCharge.status === 'open'" class="text-sm text-secondary">
Renews {{ $dayjs(midasCharge.due).format("MMMM D, YYYY") }}
</span>
<span
v-else-if="midasSubscription.status === 'cancelled'"
class="text-sm text-secondary"
>
Expires {{ $dayjs(midasSubscription.expires).format("MMMM D, YYYY") }}
<span v-else-if="midasCharge.status === 'cancelled'" class="text-sm text-secondary">
Expires {{ $dayjs(midasCharge.due).format("MMMM D, YYYY") }}
</span>
</template>
@@ -90,11 +85,11 @@
</span>
</div>
<div
v-if="midasSubscription && midasSubscription.status === 'payment-failed'"
v-if="midasCharge && midasCharge.status === 'failed'"
class="ml-auto flex flex-row-reverse items-center gap-2"
>
<button
v-if="midasSubscription && midasSubscription.status === 'payment-failed'"
v-if="midasCharge && midasCharge.status === 'failed'"
class="iconified-button raised-button"
@click="
() => {
@@ -123,7 +118,7 @@
</OverflowMenu>
</div>
<button
v-else-if="midasSubscription && midasSubscription.status !== 'cancelled'"
v-else-if="midasCharge && midasCharge.status !== 'cancelled'"
class="iconified-button raised-button !ml-auto"
@click="
() => {
@@ -134,6 +129,13 @@
>
<XIcon /> Cancel
</button>
<button
v-else-if="midasCharge && midasCharge.status === 'cancelled'"
class="btn btn-purple btn-large ml-auto"
@click="cancelSubscription(midasSubscription.id, false)"
>
<RightArrowIcon /> Resubscribe
</button>
<button
v-else
class="btn btn-purple btn-large ml-auto"
@@ -474,12 +476,14 @@ function loadStripe() {
const [
{ data: paymentMethods, refresh: refreshPaymentMethods },
{ data: charges, refresh: refreshCharges },
{ data: customer, refresh: refreshCustomer },
{ data: subscriptions, refresh: refreshSubscriptions },
] = await Promise.all([
useAsyncData("billing/payment_methods", () =>
useBaseFetch("billing/payment_methods", { internal: true }),
),
useAsyncData("billing/payments", () => useBaseFetch("billing/payments", { internal: true })),
useAsyncData("billing/customer", () => useBaseFetch("billing/customer", { internal: true })),
useAsyncData("billing/subscriptions", () =>
useBaseFetch("billing/subscriptions", { internal: true }),
@@ -487,18 +491,30 @@ const [
]);
async function refresh() {
await Promise.all([refreshPaymentMethods(), refreshCustomer(), refreshSubscriptions()]);
await Promise.all([
refreshPaymentMethods(),
refreshCharges(),
refreshCustomer(),
refreshSubscriptions(),
]);
}
const midasProduct = ref(products.find((x) => x.metadata.type === "midas"));
const midasSubscription = computed(() =>
subscriptions.value.find((x) => midasProduct.value.prices.find((y) => y.id === x.price_id)),
subscriptions.value.find(
(x) => x.status === "provisioned" && midasProduct.value.prices.find((y) => y.id === x.price_id),
),
);
const midasSubscriptionPrice = computed(() =>
midasSubscription.value
? midasProduct.value.prices.find((x) => x.id === midasSubscription.value.price_id)
: null,
);
const midasCharge = computed(() =>
midasSubscription.value
? charges.value.find((x) => x.subscription_id === midasSubscription.value.id)
: null,
);
const purchaseModal = ref();
const country = useUserCountry();
@@ -524,10 +540,18 @@ if (route.query.priceId && route.query.plan && route.query.redirect_status) {
price_id: route.query.priceId,
interval: route.query.plan,
created: Date.now(),
expires: route.query.plan === "yearly" ? Date.now() + 31536000000 : Date.now() + 2629746000,
status,
});
charges.value.push({
id: "temp",
price_id: route.query.priceId,
subscription_id: "temp",
status: "open",
due: Date.now() + (route.query.plan === "yearly" ? 31536000000 : 2629746000),
subscription_interval: route.query.plan,
});
await router.replace({ query: {} });
}
@@ -655,12 +679,15 @@ async function removePaymentMethod(index) {
}
const cancelSubscriptionId = ref();
async function cancelSubscription(id) {
async function cancelSubscription(id, cancelled) {
startLoading();
try {
await useBaseFetch(`billing/subscription/${id}`, {
internal: true,
method: "DELETE",
method: "PATCH",
body: {
cancelled,
},
});
await refresh();
} catch (err) {

View File

@@ -45,9 +45,18 @@
<body>
<div class="ads-container">
<div id="plus-link"></div>
<div id="modrinth-rail-1" />
<div id="modrinth-rail-1"></div>
</div>
<script>
function getCookie(name) {
function escape(s) {
return s.replace(/([.*+?\^$(){}|\[\]\/\\])/g, "\\$1");
}
const match = document.cookie.match(RegExp("(?:^|;\\s*)" + escape(name) + "=([^;]*)"));
return match ? match[1] : null;
}
function initAds(personalized) {
window.tude = window.tude || { cmd: [] };
@@ -62,13 +71,28 @@
tude.setPrivacySettings({
personalizedAds: personalized ?? true,
});
const hash = getCookie("modrinth-app-token");
console.log(hash);
tude.setIdProfile({
e: hash,
});
});
}
window.__TAURI_INTERNALS__
.invoke("plugin:ads|get_ads_personalization", {})
.then(initAds)
.catch(() => initAds(true));
try {
if (window.__TAURI_INTERNALS__) {
window.__TAURI_INTERNALS__
.invoke("plugin:ads|get_ads_personalization", {})
.then(initAds)
.catch(() => initAds(true));
} else {
initAds(true);
}
} catch (err) {
initAds(true);
console.error(err);
}
window.addEventListener(
"message",

View File

@@ -540,8 +540,11 @@ async function refreshPayment(confirmationId, paymentMethodId) {
}
const result = await props.sendBillingRequest({
product_id: props.product.id,
interval: selectedPlan.value,
charge: {
type: 'new',
product_id: props.product.id,
interval: selectedPlan.value,
},
existing_payment_intent: paymentIntentId.value,
...base,
})