diff --git a/app/app.vue b/app/app.vue
index f8eacfa7..ca2ace15 100644
--- a/app/app.vue
+++ b/app/app.vue
@@ -1,5 +1,37 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/components/FeedbackWidget.vue b/app/components/FeedbackWidget.vue
deleted file mode 100644
index d5418bcb..00000000
--- a/app/components/FeedbackWidget.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/composables/useAuth.ts b/app/composables/useAuth.ts
index d7084010..aebd8bbb 100644
--- a/app/composables/useAuth.ts
+++ b/app/composables/useAuth.ts
@@ -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
diff --git a/app/composables/useFeedbackScript.ts b/app/composables/useFeedbackScript.ts
new file mode 100644
index 00000000..56b78200
--- /dev/null
+++ b/app/composables/useFeedbackScript.ts
@@ -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 ; 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)
+ }
+ })
+}
diff --git a/app/layouts/default.vue b/app/layouts/default.vue
index d0b3e8a4..dcf12c1e 100644
--- a/app/layouts/default.vue
+++ b/app/layouts/default.vue
@@ -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()
-
-
-
-
-