remove the feedback widget
- delete the bundle loader composable and the unused slot component - strip the site-wide embed from app.vue, leaving the layout shell - drop the runtime config keys, custom element tag and env entries - remove the login opt-in and the preconnect to the feedback host
This commit is contained in:
parent
0262bb4219
commit
87b835e312
8 changed files with 5 additions and 111 deletions
|
|
@ -35,10 +35,6 @@ NUXT_PUBLIC_MAPBOX_TOKEN=your-mapbox-public-token
|
|||
NUXT_TURNSTILE_SITE_KEY=your-turnstile-site-key
|
||||
NUXT_TURNSTILE_SECRET_KEY=your-turnstile-secret-key
|
||||
|
||||
# Feedback widget (site-wide chat bubble). No PROJECT_ID = widget not rendered.
|
||||
NUXT_PUBLIC_FEEDBACK_API_BASE=https://support.example.org
|
||||
NUXT_PUBLIC_FEEDBACK_PROJECT_ID=your-feedback-project-id
|
||||
|
||||
# Statinator analytics (self-hosted tracking-server)
|
||||
# Project must exist on the tracking-server with this site's hostname in allowed_domains.
|
||||
# Set NUXT_PUBLIC_STATINATOR_ENABLED=false (or unset) to disable tracking entirely.
|
||||
|
|
|
|||
40
app/app.vue
40
app/app.vue
|
|
@ -1,45 +1,5 @@
|
|||
<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). This is the only feedback widget on the site.
|
||||
// Destination comes from NUXT_PUBLIC_FEEDBACK_API_BASE / _PROJECT_ID. With no
|
||||
// project id there is nowhere to post, so the widget and its bundle are skipped.
|
||||
const { public: pub } = useRuntimeConfig()
|
||||
const feedbackEnabled = Boolean(pub.feedbackProjectId)
|
||||
|
||||
if (feedbackEnabled) useFeedbackScript()
|
||||
|
||||
const siteFeedbackConfig = JSON.stringify({
|
||||
profile: 'chat-bubble',
|
||||
apiBase: pub.feedbackApiBase,
|
||||
enabled: true,
|
||||
showByDefault: false,
|
||||
instanceId: 'fb-site',
|
||||
projectId: pub.feedbackProjectId
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
<ClientOnly>
|
||||
<div
|
||||
v-if="feedbackEnabled"
|
||||
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,22 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
interface Props {
|
||||
profileConfig: string
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="feedback-widget-slot">
|
||||
<feedback-web-component :profile-config="profileConfig" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.feedback-widget-slot {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -26,17 +26,6 @@ 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)
|
||||
|
|
@ -58,7 +47,6 @@ export const useAuth = () => {
|
|||
if (response.success) {
|
||||
user.value = response.user
|
||||
saveToCache(response.user)
|
||||
enableFeedbackWidget()
|
||||
|
||||
const route = useRoute()
|
||||
const redirectTo = route.query.redirect as string
|
||||
|
|
@ -124,7 +112,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
// window.mapboxgl / window.MapboxGeocoder BEFORE map-app.iife.js runs
|
||||
// customElements.define('doxa-map', …) — otherwise the custom-element upgrade's
|
||||
// connectedCallback calls `new mapboxgl.Map(…)` before the global exists.
|
||||
// The <feedback-widget> bundle is loaded globally via nuxt.config.ts.
|
||||
|
||||
const MAPBOX_JS = 'https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.js'
|
||||
const MAPBOX_GEOCODER_JS = 'https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js'
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
// 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -8,11 +8,11 @@ const { locale, locales } = useI18n()
|
|||
const { public: pub } = useRuntimeConfig()
|
||||
|
||||
// Warm DNS+TCP+TLS for the cross-origin services these pages hit: the prayer
|
||||
// data API (people-group components) and the idle-loaded analytics + feedback
|
||||
// widget scripts. Deriving from runtime config keeps these correct per env.
|
||||
// data API (people-group components) and the idle-loaded analytics script.
|
||||
// Deriving from runtime config keeps these correct per env.
|
||||
const preconnectOrigins = computed(() => {
|
||||
const origins = new Set<string>()
|
||||
for (const url of [pub.prayBaseUrl, pub.statinatorUrl, pub.feedbackApiBase]) {
|
||||
for (const url of [pub.prayBaseUrl, pub.statinatorUrl]) {
|
||||
if (!url) continue
|
||||
try {
|
||||
origins.add(new URL(String(url)).origin)
|
||||
|
|
|
|||
|
|
@ -277,8 +277,6 @@ export default defineNuxtConfig({
|
|||
siteUrl: process.env.NUXT_PUBLIC_SITE_URL || '',
|
||||
prayBaseUrl: process.env.NUXT_PUBLIC_PRAY_BASE_URL || 'https://pray.doxa.life',
|
||||
mapboxToken: process.env.NUXT_PUBLIC_MAPBOX_TOKEN || '',
|
||||
feedbackApiBase: process.env.NUXT_PUBLIC_FEEDBACK_API_BASE || 'https://support.gospelambition.org',
|
||||
feedbackProjectId: process.env.NUXT_PUBLIC_FEEDBACK_PROJECT_ID || '',
|
||||
statinatorUrl: process.env.NUXT_PUBLIC_STATINATOR_URL || 'https://statinator.doxa.life',
|
||||
statinatorProjectId: process.env.NUXT_PUBLIC_STATINATOR_PROJECT_ID || 'doxa',
|
||||
statinatorEnabled: process.env.NUXT_PUBLIC_STATINATOR_ENABLED === 'true',
|
||||
|
|
@ -299,7 +297,7 @@ export default defineNuxtConfig({
|
|||
|
||||
vue: {
|
||||
compilerOptions: {
|
||||
isCustomElement: (tag: string) => ['doxa-map', 'doxa-research-map', 'feedback-web-component'].includes(tag)
|
||||
isCustomElement: (tag: string) => ['doxa-map', 'doxa-research-map'].includes(tag)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -313,7 +311,7 @@ export default defineNuxtConfig({
|
|||
vue: {
|
||||
template: {
|
||||
compilerOptions: {
|
||||
isCustomElement: (tag: string) => ['doxa-map', 'doxa-research-map', 'feedback-web-component'].includes(tag)
|
||||
isCustomElement: (tag: string) => ['doxa-map', 'doxa-research-map'].includes(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue