diff --git a/web/app/(app)/dashboard/layout.tsx b/web/app/(app)/dashboard/layout.tsx
index 0ea977a..d212fa6 100644
--- a/web/app/(app)/dashboard/layout.tsx
+++ b/web/app/(app)/dashboard/layout.tsx
@@ -6,6 +6,7 @@ import { usePathname } from 'next/navigation'
import AccountDeletionAlert from './(components)/account-deletion-alert'
import UpgradeToProAlert from './(components)/upgrade-to-pro-alert'
import VerifyEmailAlert from './(components)/verify-email-alert'
+import { SurveyModal } from '@/components/shared/survey-modal'
export default function DashboardLayout({
children,
@@ -88,6 +89,8 @@ export default function DashboardLayout({
{/* Bottom padding for mobile to account for the fixed navigation */}
+
+
)
}
diff --git a/web/components/shared/survey-modal.tsx b/web/components/shared/survey-modal.tsx
new file mode 100644
index 0000000..00b07a7
--- /dev/null
+++ b/web/components/shared/survey-modal.tsx
@@ -0,0 +1,189 @@
+'use client'
+
+import { useState, useEffect } from 'react'
+import { useQuery } from '@tanstack/react-query'
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogFooter,
+} from '@/components/ui/dialog'
+import { Button } from '@/components/ui/button'
+import httpBrowserClient from '@/lib/httpBrowserClient'
+import { ApiEndpoints } from '@/config/api'
+
+const STORAGE_KEYS = {
+ LAST_SHOWN: 'survey_modal_last_shown',
+ HAS_SUBMITTED: 'survey_modal_has_submitted',
+}
+
+const SHOW_INTERVAL = 1 * 60 * 60 * 1000 // 1 hour in milliseconds
+const RANDOM_CHANCE = 0.5 // 50% chance to show when eligible
+
+export const SurveyModal = () => {
+ const [isOpen, setIsOpen] = useState(false)
+
+ const {
+ data: currentUser,
+ isLoading: isLoadingUser,
+ error: currentUserError,
+ } = useQuery({
+ queryKey: ['currentUser'],
+ queryFn: () =>
+ httpBrowserClient
+ .get(ApiEndpoints.auth.whoAmI())
+ .then((res) => res.data?.data),
+ })
+
+ useEffect(() => {
+ const checkAndShowModal = () => {
+ // Don't show if user data is still loading or there's an error
+ if (isLoadingUser || currentUserError) {
+ return
+ }
+
+ // Don't show if no user data
+ if (!currentUser) {
+ return
+ }
+
+ // Check if user has already submitted
+ const hasSubmitted =
+ localStorage.getItem(STORAGE_KEYS.HAS_SUBMITTED) === 'true'
+ if (hasSubmitted) return
+
+ // Check if user account is less than 3 days old
+ if (currentUser?.createdAt) {
+ const createdAt = new Date(currentUser.createdAt)
+ const now = new Date()
+ const daysSinceCreation =
+ (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24)
+
+ if (daysSinceCreation < 3) {
+ return // Don't show modal for new users
+ }
+ }
+
+ const lastShown = localStorage.getItem(STORAGE_KEYS.LAST_SHOWN)
+ const now = Date.now()
+ const lastShownTime = lastShown ? parseInt(lastShown) : 0
+
+
+
+ if (!lastShown || now - lastShownTime >= SHOW_INTERVAL) {
+
+ if (Math.random() < RANDOM_CHANCE) {
+
+ setIsOpen(true)
+ localStorage.setItem(STORAGE_KEYS.LAST_SHOWN, now.toString())
+ }
+ }
+ }
+
+ // Add a small delay to ensure everything is loaded
+ const timer = setTimeout(() => {
+ checkAndShowModal()
+ }, 1000)
+
+ // Also check when tab becomes visible
+ const handleVisibilityChange = () => {
+ if (document.visibilityState === 'visible') {
+ setTimeout(checkAndShowModal, 500)
+ }
+ }
+
+ document.addEventListener('visibilitychange', handleVisibilityChange)
+
+ return () => {
+ clearTimeout(timer)
+ document.removeEventListener('visibilitychange', handleVisibilityChange)
+ }
+ }, [currentUser, currentUserError, isLoadingUser])
+
+ const handleSubmitted = () => {
+ localStorage.setItem(STORAGE_KEYS.HAS_SUBMITTED, 'true')
+ setIsOpen(false)
+ }
+
+ const handleRemindLater = () => {
+ setIsOpen(false)
+ }
+
+ // Generate the Google Form URL with prefilled data
+ const getFormUrl = () => {
+ if (!currentUser) return ''
+
+ const baseUrl =
+ 'https://docs.google.com/forms/d/e/1FAIpQLSe8Vd6bDvJYxwWFaWHyMYrTrrij0cSquteQiYlvggQLzLJxAw/viewform'
+ const nameParam = encodeURIComponent(currentUser.name || '').replace(
+ /%20/g,
+ '+'
+ )
+ const emailParam = encodeURIComponent(currentUser.email || '').replace(
+ /%20/g,
+ '+'
+ )
+
+ return `${baseUrl}?usp=pp_url&entry.2069418346=${nameParam}&entry.292129827=${emailParam}`
+ }
+
+ return (
+
+ )
+}