mirror of
https://github.com/modrinth/code.git
synced 2026-08-26 17:44:50 +00:00
246 lines
6.1 KiB
Vue
246 lines
6.1 KiB
Vue
<script setup lang="ts">
|
|
import { NotepadTextIcon, XIcon } from '@modrinth/assets'
|
|
import { Button, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
|
import { type } from '@tauri-apps/plugin-os'
|
|
import { $fetch } from 'ofetch'
|
|
import { onMounted, onUnmounted, ref } from 'vue'
|
|
|
|
import { release_ads_window_hold, take_ads_window_hold } from '@/helpers/ads.js'
|
|
import { list } from '@/helpers/instance'
|
|
import { get as getCreds } from '@/helpers/mr_auth.ts'
|
|
|
|
let adsWindowHold = false
|
|
|
|
type Survey = {
|
|
id: string
|
|
tally_id: string
|
|
type: string
|
|
condition?: string
|
|
assigned_users?: string[]
|
|
dismissed_users?: string[]
|
|
}
|
|
|
|
type TallyApi = {
|
|
openPopup: (formId: string, options: object) => void
|
|
}
|
|
|
|
const tallyWindow = window as Window & { Tally?: TallyApi }
|
|
|
|
const { formatMessage } = useVIntl()
|
|
const { handleError } = injectNotificationManager()
|
|
|
|
const availableSurvey = ref<Survey | null>(null)
|
|
|
|
const messages = defineMessages({
|
|
surveyTitle: {
|
|
id: 'app.survey.title',
|
|
defaultMessage: 'Hey there Modrinth user!',
|
|
},
|
|
surveyBody: {
|
|
id: 'app.survey.body',
|
|
defaultMessage:
|
|
'Would you mind answering a few questions about your experience with Modrinth App?',
|
|
},
|
|
surveyFooter: {
|
|
id: 'app.survey.footer',
|
|
defaultMessage:
|
|
'This feedback will go directly to the Modrinth team and help guide future updates!',
|
|
},
|
|
takeSurvey: {
|
|
id: 'app.survey.take-survey',
|
|
defaultMessage: 'Take survey',
|
|
},
|
|
surveyNoThanks: {
|
|
id: 'app.survey.no-thanks',
|
|
defaultMessage: 'No thanks',
|
|
},
|
|
})
|
|
|
|
function cleanupOldSurveyDisplayData() {
|
|
const threeWeeksAgo = new Date()
|
|
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21)
|
|
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
const key = localStorage.key(i)
|
|
|
|
if (key?.startsWith('survey-') && key.endsWith('-display')) {
|
|
const dateValue = new Date(localStorage.getItem(key) ?? '')
|
|
if (dateValue < threeWeeksAgo) {
|
|
localStorage.removeItem(key)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function openSurvey() {
|
|
if (!availableSurvey.value) {
|
|
console.error('No survey to open')
|
|
return
|
|
}
|
|
|
|
const creds = await getCreds().catch(handleError)
|
|
const userId = creds?.user_id
|
|
|
|
const formId = availableSurvey.value.tally_id
|
|
|
|
const popupOptions = {
|
|
layout: 'modal',
|
|
width: 700,
|
|
autoClose: 2000,
|
|
hideTitle: true,
|
|
hiddenFields: {
|
|
user_id: userId,
|
|
},
|
|
onOpen: () => console.info('Opened user survey'),
|
|
onClose: () => {
|
|
console.info('Closed user survey')
|
|
if (adsWindowHold) {
|
|
adsWindowHold = false
|
|
release_ads_window_hold()
|
|
}
|
|
},
|
|
onSubmit: () => console.info('Active user survey submitted'),
|
|
}
|
|
|
|
try {
|
|
await take_ads_window_hold()
|
|
adsWindowHold = true
|
|
if (tallyWindow.Tally?.openPopup) {
|
|
console.info(`Opening Tally popup for user survey (form ID: ${formId})`)
|
|
dismissSurvey()
|
|
tallyWindow.Tally.openPopup(formId, popupOptions)
|
|
} else {
|
|
console.warn('Tally script not yet loaded')
|
|
adsWindowHold = false
|
|
await release_ads_window_hold()
|
|
}
|
|
} catch (e) {
|
|
console.error('Error opening Tally popup:', e)
|
|
if (adsWindowHold) {
|
|
adsWindowHold = false
|
|
await release_ads_window_hold()
|
|
}
|
|
}
|
|
|
|
console.info(`Found user survey to show with tally_id: ${formId}`)
|
|
}
|
|
|
|
onUnmounted(() => {
|
|
if (adsWindowHold) {
|
|
adsWindowHold = false
|
|
release_ads_window_hold()
|
|
}
|
|
})
|
|
|
|
function dismissSurvey() {
|
|
if (!availableSurvey.value) return
|
|
localStorage.setItem(`survey-${availableSurvey.value.id}-display`, String(new Date()))
|
|
availableSurvey.value = null
|
|
}
|
|
|
|
async function processPendingSurveys() {
|
|
function isWithinLastTwoWeeks(date: string | Date | null | undefined) {
|
|
if (!date) return false
|
|
const twoWeeksAgo = new Date()
|
|
twoWeeksAgo.setDate(twoWeeksAgo.getDate() - 14)
|
|
return new Date(date) >= twoWeeksAgo
|
|
}
|
|
|
|
cleanupOldSurveyDisplayData()
|
|
|
|
const creds = await getCreds().catch(handleError)
|
|
const userId = creds?.user_id
|
|
|
|
const instances = (await list().catch(handleError)) ?? []
|
|
const isActivePlayer = instances.some(
|
|
(instance) =>
|
|
isWithinLastTwoWeeks(instance.last_played) && !isWithinLastTwoWeeks(instance.created),
|
|
)
|
|
|
|
let surveys: Survey[] = []
|
|
try {
|
|
surveys = await $fetch('https://api.modrinth.com/v2/surveys')
|
|
} catch (e) {
|
|
console.error('Error fetching surveys:', e)
|
|
}
|
|
|
|
const surveyToShow = surveys.find(
|
|
(survey) =>
|
|
!!(
|
|
localStorage.getItem(`survey-${survey.id}-display`) === null &&
|
|
survey.type === 'tally_app' &&
|
|
((survey.condition === 'active_player' && isActivePlayer) ||
|
|
(!!userId &&
|
|
survey.assigned_users?.includes(userId) &&
|
|
!survey.dismissed_users?.includes(userId)))
|
|
),
|
|
)
|
|
|
|
if (surveyToShow) {
|
|
availableSurvey.value = surveyToShow
|
|
} else {
|
|
console.info('No user survey to show')
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
const osType = await type()
|
|
if (osType === 'windows') {
|
|
await processPendingSurveys()
|
|
} else {
|
|
console.info('Skipping user surveys on non-Windows platforms')
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<transition name="popup-survey">
|
|
<div
|
|
v-if="availableSurvey"
|
|
class="w-[400px] z-20 fixed -bottom-12 pb-16 right-[--right-bar-width] mr-4 rounded-t-2xl card-shadow bg-bg-raised border-surface-5 border-[1px] border-solid border-b-0 p-4"
|
|
>
|
|
<h2 class="text-lg font-extrabold mt-0 mb-2">
|
|
{{ formatMessage(messages.surveyTitle) }}
|
|
</h2>
|
|
<p class="m-0 leading-tight">
|
|
{{ formatMessage(messages.surveyBody) }}
|
|
</p>
|
|
<p class="mt-3 mb-4 leading-tight">
|
|
{{ formatMessage(messages.surveyFooter) }}
|
|
</p>
|
|
<div class="flex gap-2">
|
|
<Button type="colored" color="brand" @click="openSurvey">
|
|
<NotepadTextIcon />
|
|
{{ formatMessage(messages.takeSurvey) }}
|
|
</Button>
|
|
<Button @click="dismissSurvey">
|
|
<XIcon />
|
|
{{ formatMessage(messages.surveyNoThanks) }}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.popup-survey-enter-active {
|
|
transition:
|
|
opacity 0.25s ease,
|
|
transform 0.25s cubic-bezier(0.51, 1.08, 0.35, 1.15);
|
|
transform-origin: top center;
|
|
}
|
|
|
|
.popup-survey-leave-active {
|
|
transition:
|
|
opacity 0.25s ease,
|
|
transform 0.25s cubic-bezier(0.68, -0.17, 0.23, 0.11);
|
|
transform-origin: top center;
|
|
}
|
|
|
|
.popup-survey-enter-from,
|
|
.popup-survey-leave-to {
|
|
opacity: 0;
|
|
transform: translateY(10rem) scale(0.8) scaleY(1.6);
|
|
}
|
|
</style>
|