mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-05 19:20:12 +08:00
Formbricks (#157)
add quest feedback and bug report form using Formbricks
This commit is contained in:
11 files changed
+2642
-1293
No files matched your search
@@ -10,6 +10,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formbricks/js": "^2.1.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||
|
||||
@@ -9,9 +9,11 @@ import CompleteAnimation from '../../img/complete-animation.json'
|
||||
const showModal = ref(true) // Controls whether the modal is visible or not
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
|
||||
const closeModal = () => {
|
||||
showModal.value = false
|
||||
}
|
||||
|
||||
const defineComponent = () => ({
|
||||
components: {
|
||||
Vue3Lottie,
|
||||
@@ -22,6 +24,7 @@ const defineComponent = () => ({
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const backtoMap = async () => {
|
||||
try {
|
||||
router.push({ name: 'map' })
|
||||
@@ -67,6 +70,21 @@ setTimeout(() => {
|
||||
>回到地圖</a
|
||||
>
|
||||
</div>
|
||||
<div style="position: relative; height: 100vh; overflow: auto">
|
||||
<iframe
|
||||
src="https://app.formbricks.com/s/clyffdm0c0be2wh6335clle0l"
|
||||
frameborder="0"
|
||||
style="
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import useSession from '../../store/session'
|
||||
import { surveyUrl } from '../../config'
|
||||
import { openBugReport, openQuestSurvey } from '../../utils/formbricks'
|
||||
|
||||
const router = useRouter()
|
||||
const sessionStore = useSession()
|
||||
@@ -21,31 +21,39 @@ const continuePlay = async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
class="h-fit w-fit px-1 py-1 grid grid-cols-4 gap-2 place-content-between"
|
||||
>
|
||||
<button id="survey" class="bg-bg-secondary rounded-lg p-2">
|
||||
<a title="Survey" :href="surveyUrl" target="_blank" class="h-5 w-5">
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'file-invoice']"
|
||||
class="text-text-primary px-1"
|
||||
/>
|
||||
<p class="text-text-primary inline ml-1 md:flex">問卷</p>
|
||||
</a>
|
||||
<section class="mt-2 flex flex-row gap-3 justify-center">
|
||||
<button
|
||||
id="survey"
|
||||
class="bg-bg-secondary rounded-lg p-2"
|
||||
@click="openQuestSurvey"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'file-invoice']"
|
||||
class="text-text-primary px-1"
|
||||
/>
|
||||
<p class="text-text-primary inline md:flex">問卷</p>
|
||||
</button>
|
||||
<button disabled id="solution" class="bg-bg-disabled rounded-lg p-2">
|
||||
<button
|
||||
title="Bug Report"
|
||||
@click="openBugReport"
|
||||
class="bg-bg-secondary rounded-lg p-2"
|
||||
>
|
||||
<font-awesome-icon :icon="['fas', 'bug']" class="text-text-primary" />
|
||||
<p class="text-text-primary inline ml-1 md:flex">回報</p>
|
||||
</button>
|
||||
<!-- <button disabled id="solution" class="bg-bg-disabled rounded-lg p-2">
|
||||
<font-awesome-icon
|
||||
:icon="['far', 'circle-question']"
|
||||
class="text-text-disabled px-1"
|
||||
/>
|
||||
<p class="text-text-disabled inline ml-1 md:flex">解答</p>
|
||||
</button>
|
||||
</button> -->
|
||||
<button id="reset" class="bg-bg-secondary rounded-lg p-2" @click="reset">
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'arrow-rotate-left']"
|
||||
class="text-text-primary px-1"
|
||||
/>
|
||||
<p class="text-text-primary inline ml-1 hidden md:flex">重來</p>
|
||||
<p class="text-text-primary inline ml-1 md:flex">重來</p>
|
||||
</button>
|
||||
<button
|
||||
id="continue"
|
||||
@@ -56,7 +64,7 @@ const continuePlay = async () => {
|
||||
:icon="['far', 'circle-right']"
|
||||
class="text-text-primary px-1"
|
||||
/>
|
||||
<p class="text-text-primary inline ml-1 hidden md:flex">繼續</p>
|
||||
<p class="text-text-primary inline ml-1 md:flex">繼續</p>
|
||||
</button>
|
||||
</section>
|
||||
</template>
|
||||
@@ -3,7 +3,8 @@ import { onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import { logout } from '../../utils/auth'
|
||||
import { bugReportUrl, surveyUrl } from '../../config'
|
||||
import { surveyUrl } from '../../config'
|
||||
import { openBugReport } from '../../utils/formbricks'
|
||||
import useSession from '../../store/session'
|
||||
import useUserProfile from '../../store/userProfile'
|
||||
|
||||
@@ -84,15 +85,14 @@ onMounted(async () => {
|
||||
<font-awesome-icon :icon="['fas', 'map']" class="text-text-primary" />
|
||||
<span class="text-text sm:hidden px-2">Map</span>
|
||||
</RouterLink>
|
||||
<a
|
||||
<button
|
||||
title="Bug Report"
|
||||
:href="bugReportUrl"
|
||||
target="_blank"
|
||||
@click="openBugReport"
|
||||
class="md:h-5 md:w-5 px-1.5 w-auto"
|
||||
>
|
||||
<font-awesome-icon :icon="['fas', 'bug']" class="text-text-primary" />
|
||||
<span class="text-text sm:hidden px-2">Bug Report</span>
|
||||
</a>
|
||||
</button>
|
||||
<button
|
||||
title="Sign Out"
|
||||
@click="handleLogout"
|
||||
|
||||
+7
-1
@@ -10,9 +10,9 @@ import Toast, { POSITION } from 'vue-toastification'
|
||||
/* import Vue Lottie */
|
||||
import Vue3Lottie from 'vue3-lottie'
|
||||
import 'vue-toastification/dist/index.css'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import formbricks from './utils/formbricks'
|
||||
|
||||
const app = createApp(App)
|
||||
const pinia = createPinia()
|
||||
@@ -22,6 +22,12 @@ app.component('font-awesome-icon', FontAwesomeIcon)
|
||||
app.use(pinia)
|
||||
app.use(router)
|
||||
|
||||
router.afterEach(() => {
|
||||
if (typeof formbricks !== 'undefined') {
|
||||
formbricks.registerRouteChange()
|
||||
}
|
||||
})
|
||||
|
||||
const options = {
|
||||
position: POSITION.TOP_RIGHT,
|
||||
}
|
||||
|
||||
@@ -61,8 +61,15 @@ const useSession = defineStore('session', {
|
||||
if (response.tasks) {
|
||||
this.session.tasks = response.tasks
|
||||
}
|
||||
if (
|
||||
response.status === 'finished' &&
|
||||
this.session.status !== 'finished'
|
||||
) {
|
||||
this.finish()
|
||||
}
|
||||
this.session.status = response.status
|
||||
},
|
||||
finish() {},
|
||||
reset() {
|
||||
socket.reset()
|
||||
term.reset()
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import formbricks from '@formbricks/js/website'
|
||||
import useSession from '../store/session'
|
||||
import useUserProfile from '../store/userProfile'
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
formbricks.init({
|
||||
environmentId: 'clzcdqqn0000kadvtqykdo0pc',
|
||||
apiHost: 'https://app.formbricks.com',
|
||||
})
|
||||
}
|
||||
|
||||
export function openQuestSurvey() {
|
||||
const sessionStore = useSession()
|
||||
const userStore = useUserProfile()
|
||||
|
||||
formbricks.track('quest_completed', {
|
||||
hiddenFields: {
|
||||
quest: sessionStore.questId,
|
||||
session: sessionStore.session?._id,
|
||||
username: userStore.username,
|
||||
email: userStore.email,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function openBugReport() {
|
||||
const sessionStore = useSession()
|
||||
const userStore = useUserProfile()
|
||||
|
||||
formbricks.track('bug_report', {
|
||||
hiddenFields: {
|
||||
quest: sessionStore.questId,
|
||||
session: sessionStore.session?._id,
|
||||
username: userStore.username,
|
||||
email: userStore.email,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default formbricks
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import useSession from '../store/session'
|
||||
import useUserProfile from '../store/userProfile'
|
||||
import HeaderPart from '../components/header/HeaderPart.vue'
|
||||
import GameHeaderComponents from '../components/header/GameHeaderComponents.vue'
|
||||
import DescriptionPart from '../components/game/DescriptionPart.vue'
|
||||
@@ -10,13 +11,22 @@ import VisualizationPart from '../components/game/VisualizationPart.vue'
|
||||
import ControlPalette from '../components/game/ControlPalette.vue'
|
||||
import CompleteModal from '../components/game/CompleteModal.vue'
|
||||
import StartButton from '../components/game/StartButton.vue'
|
||||
import { openQuestSurvey } from '../utils/formbricks'
|
||||
|
||||
const sessionStore = useSession()
|
||||
const userStore = useUserProfile()
|
||||
|
||||
const completed = computed(() => {
|
||||
return sessionStore.session?.status === 'finished'
|
||||
})
|
||||
|
||||
watch(completed, (newValue, oldValue) => {
|
||||
if (newValue && !oldValue) {
|
||||
console.log('finish', userStore)
|
||||
openQuestSurvey()
|
||||
}
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
questId: {
|
||||
type: String,
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
},
|
||||
},
|
||||
backgroundImage: {
|
||||
catelogbg: "url('./catelogbg.svg')",
|
||||
catelogbg: "url('/catelogbg.svg')",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"latest": "^0.2.0",
|
||||
"typescript-eslint": "^7.4.0"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user