diff --git a/apps/frontend/src/pages/[type]/[id]/settings/index.vue b/apps/frontend/src/pages/[type]/[id]/settings/index.vue index e78a94564d..7ef1319512 100644 --- a/apps/frontend/src/pages/[type]/[id]/settings/index.vue +++ b/apps/frontend/src/pages/[type]/[id]/settings/index.vue @@ -273,6 +273,60 @@ + +
+
+ + +
+
+
+
+ + + + +
+
@@ -311,6 +365,7 @@ import { CheckIcon, ImageIcon, IssuesIcon, + ScaleIcon, TrashIcon, TriangleAlertIcon, UploadIcon, @@ -319,6 +374,7 @@ import { import { MIN_SUMMARY_CHARS } from '@modrinth/moderation' import { Avatar, + ButtonStyled, Combobox, ConfirmLeaveModal, ConfirmModal, @@ -326,14 +382,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, @@ -364,6 +424,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) @@ -378,6 +454,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 @@ -450,6 +528,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 }) @@ -468,6 +553,7 @@ const original = computed(() => ({ deletedIcon: false, bannerFile: null, deletedBanner: false, + monetizationEnabled: project.value.monetization_status === 'monetized', })) const modified = computed(() => ({ @@ -481,6 +567,7 @@ const modified = computed(() => ({ deletedIcon: deletedIcon.value, bannerFile: bannerFile.value, deletedBanner: deletedBanner.value, + monetizationEnabled: monetizationEnabled.value, })) const hasChanges = computed(() => @@ -504,6 +591,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 = () => {