[object Object]

← back to Dear Bubbe Nextjs

feat(bubbe.ai): free chat — 3 messages before Google sign-in (mobile-first)

c7ca51c24d9c4cce76edb2a80ca5444824a322c2 · 2026-07-16 16:53:14 -0700 · Steve Abrams

- page.tsx: render chat for guests instead of hard-redirecting to /auth/signin
- MobileBubbe/DesktopBubbe: gate send after 3 free messages (localStorage), then trigger Google sign-in
- restores the intended '3 free messages' onboarding so mobile users can chat immediately

Files touched

Diff

commit c7ca51c24d9c4cce76edb2a80ca5444824a322c2
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 16 16:53:14 2026 -0700

    feat(bubbe.ai): free chat — 3 messages before Google sign-in (mobile-first)
    
    - page.tsx: render chat for guests instead of hard-redirecting to /auth/signin
    - MobileBubbe/DesktopBubbe: gate send after 3 free messages (localStorage), then trigger Google sign-in
    - restores the intended '3 free messages' onboarding so mobile users can chat immediately
---
 app/page.tsx                | 26 +++++++++-----------------
 components/DesktopBubbe.tsx | 21 +++++++++++++++++++--
 components/MobileBubbe.tsx  | 22 +++++++++++++++++++---
 3 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/app/page.tsx b/app/page.tsx
index a9aae6e..7987913 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -12,29 +12,21 @@ export default function Home() {
 
   useEffect(() => {
     if (status === 'loading') return
-    
-    // Redirect to sign-in if not authenticated
-    if (!session) {
-      router.push('/auth/signin')
-      return
-    }
-    
-    // Check if profile setup is complete
-    const profileData = localStorage.getItem('bubbeProfile')
-    if (!profileData) {
-      router.push('/auth/profile-setup')
+
+    // Guests chat freely (gated after a few messages inside the chat component).
+    // Only signed-in users without a profile get sent to profile setup.
+    if (session) {
+      const profileData = localStorage.getItem('bubbeProfile')
+      if (!profileData) {
+        router.push('/auth/profile-setup')
+      }
     }
   }, [session, status, router])
 
-  // Show loading while checking auth
+  // Show loading only while auth state is resolving
   if (status === 'loading') {
     return <LoadingScreen />
   }
 
-  // Show loading while redirecting
-  if (!session) {
-    return <LoadingScreen />
-  }
-
   return <BubbeResponsive />
 }
\ No newline at end of file
diff --git a/components/DesktopBubbe.tsx b/components/DesktopBubbe.tsx
index 8271672..6497593 100644
--- a/components/DesktopBubbe.tsx
+++ b/components/DesktopBubbe.tsx
@@ -1,8 +1,10 @@
 'use client'
 
 import { useState, useEffect, useRef } from 'react'
+import { useSession, signIn } from 'next-auth/react'
 
 export default function DesktopBubbe() {
+  const { data: session } = useSession()
   const [messages, setMessages] = useState<Array<{id: string, role: 'user' | 'assistant', content: string}>>([])
   const [textInput, setTextInput] = useState('')
   const [isLoading, setIsLoading] = useState(false)
@@ -165,13 +167,28 @@ export default function DesktopBubbe() {
 
   const handleSendMessage = async (text: string) => {
     if (!text.trim()) return
-    
+
+    // Free-chat gate: guests get 3 free messages, then Google sign-in is required.
+    if (!session) {
+      const used = parseInt(localStorage.getItem('bubbeFreeMessages') || '0', 10)
+      if (used >= 3) {
+        setMessages(prev => [...prev, {
+          id: Date.now().toString(),
+          role: 'assistant' as const,
+          content: "Enough freebies, bubbeleh! Sign in with Google so I remember who you are — then we can really talk. Nu, what are you waiting for?"
+        }])
+        signIn('google')
+        return
+      }
+      localStorage.setItem('bubbeFreeMessages', String(used + 1))
+    }
+
     const userMessage = {
       id: Date.now().toString(),
       role: 'user' as const,
       content: text.trim()
     }
-    
+
     setMessages(prev => [...prev, userMessage])
     setTextInput('')
     setIsLoading(true)
diff --git a/components/MobileBubbe.tsx b/components/MobileBubbe.tsx
index f157e0a..5c160c3 100644
--- a/components/MobileBubbe.tsx
+++ b/components/MobileBubbe.tsx
@@ -1,7 +1,7 @@
 'use client'
 
 import { useState, useEffect, useRef } from 'react'
-import { useSession, signOut } from 'next-auth/react'
+import { useSession, signOut, signIn } from 'next-auth/react'
 
 export default function MobileBubbe() {
   // Start with welcome screen
@@ -151,13 +151,29 @@ export default function MobileBubbe() {
 
   const handleSendMessage = async (text: string) => {
     if (!text.trim()) return
-    
+
+    // Free-chat gate: guests get 3 free messages, then Google sign-in is required
+    // (keeps memory/profiles for signed-in users without blocking the first hello).
+    if (!session) {
+      const used = parseInt(localStorage.getItem('bubbeFreeMessages') || '0', 10)
+      if (used >= 3) {
+        setMessages(prev => [...prev, {
+          id: Date.now().toString(),
+          role: 'assistant' as const,
+          content: "Enough freebies, bubbeleh! Sign in with Google so I remember who you are — then we can really talk. Nu, what are you waiting for?"
+        }])
+        signIn('google')
+        return
+      }
+      localStorage.setItem('bubbeFreeMessages', String(used + 1))
+    }
+
     const userMessage = {
       id: Date.now().toString(),
       role: 'user' as const,
       content: text.trim()
     }
-    
+
     setMessages(prev => [...prev, userMessage])
     setTextInput('')
     setIsLoading(true)

← 242ce89 deploy(bubbe.ai): OpenAI-primary chat, drop standalone for n  ·  back to Dear Bubbe Nextjs  ·  auto-save: 2026-07-16T17:13:50 (2 files) — components/Deskto bffe4c6 →