fix feedback widget display
This commit is contained in:
parent
383f675d33
commit
08cb99615f
9 changed files with 73 additions and 74 deletions
32
app/app.vue
32
app/app.vue
|
|
@ -1,5 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
// Site-wide feedback widget. It lives here (outside NuxtLayout) so it renders
|
||||
// on every layout — public, admin and auth. It stays opted out by default and
|
||||
// surfaces only when the visitor opts in: via ?feedback=true or by logging in.
|
||||
// Both set the component's `show-feedback-widget` localStorage flag (login is
|
||||
// wired in useAuth). The per-page map widgets are separate (FeedbackWidgetSlot,
|
||||
// anchored inside each map).
|
||||
useFeedbackScript()
|
||||
const siteFeedbackConfig = JSON.stringify({
|
||||
profile: 'chat-bubble',
|
||||
apiBase: 'https://support.gospelambition.org',
|
||||
enabled: true,
|
||||
showByDefault: false,
|
||||
instanceId: 'fb-site',
|
||||
projectId: '3c0e8534-f593-4222-8315-31dda4514760'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
<ClientOnly>
|
||||
<div class="site-feedback-widget">
|
||||
<feedback-web-component :profile-config="siteFeedbackConfig" />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.site-feedback-widget {
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
<template>
|
||||
<div class="feedback-widget-slot">
|
||||
<feedback-web-component :key="String(isLoggedIn)" :profile-config="profileConfig" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { public: pub } = useRuntimeConfig()
|
||||
const { isLoggedIn } = useAuth()
|
||||
|
||||
const profileConfig = computed(() => JSON.stringify({
|
||||
profile: 'chat-bubble',
|
||||
apiBase: pub.feedbackApiBase,
|
||||
enabled: true,
|
||||
showByDefault: isLoggedIn.value,
|
||||
instanceId: 'fb-doxa-life-parent',
|
||||
projectId: pub.feedbackProjectId
|
||||
}))
|
||||
|
||||
// The feedback widget is a ~95 KB third-party script that is not needed for
|
||||
// first paint. Load it once the browser is idle so it stays off the initial
|
||||
// load critical path. The <feedback-web-component> below upgrades in place
|
||||
// when the definition arrives.
|
||||
const FEEDBACK_SCRIPT = 'https://support.gospelambition.org/js/feedback-web-component.iife.js'
|
||||
|
||||
function loadFeedbackScript() {
|
||||
if (document.querySelector(`script[src="${FEEDBACK_SCRIPT}"]`)) return
|
||||
const script = document.createElement('script')
|
||||
script.src = FEEDBACK_SCRIPT
|
||||
script.async = true
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if ('requestIdleCallback' in window) {
|
||||
requestIdleCallback(loadFeedbackScript, { timeout: 3000 })
|
||||
} else {
|
||||
setTimeout(loadFeedbackScript, 2000)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="feedback-widget-slot">
|
||||
<feedback-web-component :profile-config="profileConfig" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.feedback-widget-slot {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
z-index: 2147483000;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -26,6 +26,17 @@ const clearCache = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// Opt this browser into the feedback widget — the same `show-feedback-widget`
|
||||
// flag that ?feedback=true sets. Lets logged-in users see the widget on public,
|
||||
// edge-cached pages without a /api/auth/me check (we don't run one there).
|
||||
const enableFeedbackWidget = () => {
|
||||
if (import.meta.client) {
|
||||
try {
|
||||
localStorage.setItem('show-feedback-widget', 'true')
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
export const useAuth = () => {
|
||||
const user = useState('auth.user', () => null as any)
|
||||
const authReady = useState('auth.ready', () => false)
|
||||
|
|
@ -47,6 +58,7 @@ export const useAuth = () => {
|
|||
if (response.success) {
|
||||
user.value = response.user
|
||||
saveToCache(response.user)
|
||||
enableFeedbackWidget()
|
||||
|
||||
const route = useRoute()
|
||||
const redirectTo = route.query.redirect as string
|
||||
|
|
@ -112,6 +124,7 @@ export const useAuth = () => {
|
|||
const response = await $fetch('/api/auth/me') as { user: any }
|
||||
user.value = response.user
|
||||
saveToCache(response.user)
|
||||
enableFeedbackWidget()
|
||||
return response.user
|
||||
} catch {
|
||||
user.value = null
|
||||
|
|
|
|||
24
app/composables/useFeedbackScript.ts
Normal file
24
app/composables/useFeedbackScript.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Idle-loads the third-party feedback web-component bundle. It's a ~95 KB
|
||||
// script not needed for first paint, so we defer it until the browser is idle
|
||||
// to keep it off the initial load critical path. Call this from any layout
|
||||
// that renders a <feedback-web-component>; the in-DOM guard means multiple
|
||||
// callers still load the bundle only once.
|
||||
const FEEDBACK_SCRIPT = 'https://support.gospelambition.org/js/feedback-web-component.iife.js'
|
||||
|
||||
function loadFeedbackScript() {
|
||||
if (document.querySelector(`script[src="${FEEDBACK_SCRIPT}"]`)) return
|
||||
const script = document.createElement('script')
|
||||
script.src = FEEDBACK_SCRIPT
|
||||
script.async = true
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
|
||||
export function useFeedbackScript() {
|
||||
onMounted(() => {
|
||||
if ('requestIdleCallback' in window) {
|
||||
requestIdleCallback(loadFeedbackScript, { timeout: 3000 })
|
||||
} else {
|
||||
setTimeout(loadFeedbackScript, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -24,13 +24,6 @@ const preconnectOrigins = computed(() => {
|
|||
})
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const siteFeedbackConfig = JSON.stringify({
|
||||
profile: 'chat-bubble',
|
||||
apiBase: 'https://support.gospelambition.org',
|
||||
enabled: true,
|
||||
instanceId: 'fb-site',
|
||||
projectId: '3c0e8534-f593-4222-8315-31dda4514760'
|
||||
})
|
||||
|
||||
// Direction attribute per locale (Arabic = rtl)
|
||||
const currentLocale = computed(() =>
|
||||
|
|
@ -77,23 +70,12 @@ const { isLoading } = useLoadingIndicator()
|
|||
<slot />
|
||||
</main>
|
||||
<TheFooter />
|
||||
<ClientOnly>
|
||||
<div class="site-feedback-widget">
|
||||
<feedback-web-component :profile-config="siteFeedbackConfig" />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" src="~/assets/styles/main.scss"></style>
|
||||
|
||||
<style scoped>
|
||||
.site-feedback-widget {
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
.site-main {
|
||||
transition: opacity 150ms ease-out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const adoptFeedbackConfig = JSON.stringify({
|
|||
profile: 'chat-bubble',
|
||||
apiBase: 'https://support.gospelambition.org',
|
||||
enabled: true,
|
||||
showByDefault: false,
|
||||
instanceId: 'fb-adopt-map',
|
||||
projectId: 'dd1d9144-3da9-4a3b-87e8-7c17d9e94af0'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ const homeFeedbackConfig = JSON.stringify({
|
|||
profile: 'chat-bubble',
|
||||
apiBase: 'https://support.gospelambition.org',
|
||||
enabled: true,
|
||||
showByDefault: false,
|
||||
instanceId: 'fb-home-map',
|
||||
projectId: '7bb8f5ba-eb45-4933-89de-bc93fcda09b2'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const prayFeedbackConfig = JSON.stringify({
|
|||
profile: 'chat-bubble',
|
||||
apiBase: 'https://support.gospelambition.org',
|
||||
enabled: true,
|
||||
showByDefault: false,
|
||||
instanceId: 'fb-pray-map',
|
||||
projectId: '809ee16b-46e2-4bcd-a93d-b7ea0879d93d'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ const researchFeedbackConfig = JSON.stringify({
|
|||
profile: 'chat-bubble',
|
||||
apiBase: 'https://support.gospelambition.org',
|
||||
enabled: true,
|
||||
showByDefault: false,
|
||||
instanceId: 'fb-research-map',
|
||||
projectId: '1be56abd-60fd-4366-ad4f-178dddef657d'
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue