feat: add monetization toggle for projects (#5961)
* Add monetization toggle for projects * add flag for monetization toggle * remove feature flag toggle
This commit is contained in:
@@ -271,6 +271,60 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!isServerProject" class="mt-4 flex flex-col gap-2">
|
||||
<div class="grid grid-cols-[1fr_auto] items-center gap-6">
|
||||
<label for="project-monetization-toggle">
|
||||
<span class="mb-1 block text-lg font-semibold text-contrast">Monetization</span>
|
||||
<span class="block">
|
||||
When enabled, this project can earn revenue through Modrinth's
|
||||
<nuxt-link to="/legal/cmp-info" target="_blank" class="text-link"
|
||||
>Rewards Program</nuxt-link
|
||||
>. If you don't want to (or can't for legal reasons) earn revenue from this project,
|
||||
you can turn it off here.
|
||||
</span>
|
||||
</label>
|
||||
<Toggle
|
||||
id="project-monetization-toggle"
|
||||
v-model="monetizationEnabled"
|
||||
:disabled="monetizationToggleDisabled"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isForceDemonetized" class="mt-2 flex flex-wrap items-center gap-2 text-orange">
|
||||
<TriangleAlertIcon aria-hidden="true" />
|
||||
<span>
|
||||
Your project is not eligible for monetization. If you think this is a mistake, please
|
||||
<a
|
||||
class="text-orange underline hover:brightness-110"
|
||||
href="https://support.modrinth.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
contact support</a
|
||||
>.
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="isStaff" class="mt-2">
|
||||
<ButtonStyled color="orange">
|
||||
<button
|
||||
v-if="!isForceDemonetized"
|
||||
:disabled="loadingModeratorMonetization"
|
||||
@click="updateMonetizationStatus('force-demonetized')"
|
||||
>
|
||||
<ScaleIcon aria-hidden="true" />
|
||||
Disable monetization
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
:disabled="loadingModeratorMonetization"
|
||||
@click="updateMonetizationStatus('monetized')"
|
||||
>
|
||||
<ScaleIcon aria-hidden="true" />
|
||||
Allow monetization
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="universal-card">
|
||||
@@ -306,6 +360,7 @@ import {
|
||||
CheckIcon,
|
||||
ImageIcon,
|
||||
IssuesIcon,
|
||||
ScaleIcon,
|
||||
TrashIcon,
|
||||
TriangleAlertIcon,
|
||||
UploadIcon,
|
||||
@@ -322,14 +377,18 @@ import {
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
UnsavedChangesPopup,
|
||||
usePageLeaveSafety,
|
||||
} from '@modrinth/ui'
|
||||
import { fileIsValid, formatProjectStatus, formatProjectType } from '@modrinth/utils'
|
||||
|
||||
import FileInput from '~/components/ui/FileInput.vue'
|
||||
import { useAuth } from '~/composables/auth.js'
|
||||
import { useFeatureFlags } from '~/composables/featureFlags.ts'
|
||||
|
||||
const auth = await useAuth()
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const {
|
||||
projectV2: project,
|
||||
@@ -360,6 +419,22 @@ const visibility = ref(
|
||||
: project.value.requested_status,
|
||||
)
|
||||
|
||||
const monetizationEnabled = ref(project.value.monetization_status === 'monetized')
|
||||
const loadingModeratorMonetization = ref(false)
|
||||
|
||||
watch(
|
||||
() => project.value.monetization_status,
|
||||
() => {
|
||||
monetizationEnabled.value = project.value.monetization_status === 'monetized'
|
||||
},
|
||||
)
|
||||
|
||||
const isStaff = computed(
|
||||
() => !!auth.value.user && tags.value.staffRoles.includes(auth.value.user.role),
|
||||
)
|
||||
|
||||
const isForceDemonetized = computed(() => project.value.monetization_status === 'force-demonetized')
|
||||
|
||||
// Server project specific refs
|
||||
const MC_SERVER_BANNER_NAME = '__mc_server_banner__'
|
||||
const isServerProject = computed(() => projectV3.value?.minecraft_server != null)
|
||||
@@ -374,6 +449,8 @@ const hasPermission = computed(() => {
|
||||
return ((currentMember.value?.permissions ?? 0) & EDIT_DETAILS) === EDIT_DETAILS
|
||||
})
|
||||
|
||||
const monetizationToggleDisabled = computed(() => !hasPermission.value || isForceDemonetized.value)
|
||||
|
||||
const hasDeletePermission = computed(() => {
|
||||
const DELETE_PROJECT = 1 << 7
|
||||
return ((currentMember.value?.permissions ?? 0) & DELETE_PROJECT) === DELETE_PROJECT
|
||||
@@ -446,6 +523,13 @@ const basePatchData = computed(() => {
|
||||
data.requested_status = visibility.value
|
||||
}
|
||||
|
||||
if (project.value.monetization_status !== 'force-demonetized') {
|
||||
const wasMonetized = project.value.monetization_status === 'monetized'
|
||||
if (monetizationEnabled.value !== wasMonetized) {
|
||||
data.monetization_status = monetizationEnabled.value ? 'monetized' : 'demonetized'
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
})
|
||||
|
||||
@@ -464,6 +548,7 @@ const original = computed(() => ({
|
||||
deletedIcon: false,
|
||||
bannerFile: null,
|
||||
deletedBanner: false,
|
||||
monetizationEnabled: project.value.monetization_status === 'monetized',
|
||||
}))
|
||||
|
||||
const modified = computed(() => ({
|
||||
@@ -477,6 +562,7 @@ const modified = computed(() => ({
|
||||
deletedIcon: deletedIcon.value,
|
||||
bannerFile: bannerFile.value,
|
||||
deletedBanner: deletedBanner.value,
|
||||
monetizationEnabled: monetizationEnabled.value,
|
||||
}))
|
||||
|
||||
const hasChanges = computed(() =>
|
||||
@@ -500,6 +586,16 @@ function resetChanges() {
|
||||
bannerFile.value = null
|
||||
bannerPreview.value = null
|
||||
deletedBanner.value = false
|
||||
monetizationEnabled.value = project.value.monetization_status === 'monetized'
|
||||
}
|
||||
|
||||
async function updateMonetizationStatus(status) {
|
||||
loadingModeratorMonetization.value = true
|
||||
try {
|
||||
await patchProject({ monetization_status: status })
|
||||
} finally {
|
||||
loadingModeratorMonetization.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const hasModifiedVisibility = () => {
|
||||
|
||||
Reference in New Issue
Block a user