diff --git a/src/app/(dashboard)/inbox/page.tsx b/src/app/(dashboard)/inbox/page.tsx index 0750c41..f7e531d 100644 --- a/src/app/(dashboard)/inbox/page.tsx +++ b/src/app/(dashboard)/inbox/page.tsx @@ -10,6 +10,7 @@ import { MessageThread } from "@/components/inbox/message-thread"; import { ContactSidebar } from "@/components/inbox/contact-sidebar"; import { toast } from "sonner"; import { WifiOff } from "lucide-react"; +import { cn } from "@/lib/utils"; export default function InboxPage() { const router = useRouter(); @@ -191,6 +192,19 @@ export default function InboxPage() { [activeConversation?.id, router] ); + // Mobile "back" — deselect the conversation so the list pane comes + // back. Also clears the ?c= param so a refresh lands on the list + // instead of re-opening the thread the user just backed out of. + const handleCloseConversation = useCallback(() => { + setActiveConversation(null); + setActiveContact(null); + setMessages([]); + // Clearing the ref lets the deep-link auto-selector fire again if + // the user later visits /inbox?c= — desirable UX. + autoSelectedForDeepLinkRef.current = null; + router.replace("/inbox", { scroll: false }); + }, [router]); + const handleMessagesLoaded = useCallback((loaded: Message[]) => { setMessages(loaded); @@ -224,8 +238,15 @@ export default function InboxPage() { [activeConversation] ); + // On mobile ( +
{/* WhatsApp connection banner — in the flex column, not absolute, so it pushes the panels down instead of overlapping them. */} {whatsappConnected === false && ( @@ -238,26 +259,46 @@ export default function InboxPage() { )}
- {/* Left panel: Conversation list */} - + {/* Left panel: Conversation list. + Hidden on mobile when a conversation is selected so the + thread can occupy the full width. Always visible on lg+. */} +
+ +
- {/* Center panel: Message thread */} - + {/* Center panel: Message thread. + Hidden on mobile when no conversation is selected so the + list can occupy the full width. Always visible on lg+ + (shows its own empty-state if no thread is picked yet). */} +
+ +
- {/* Right panel: Contact sidebar (hidden on small screens) */} + {/* Right panel: Contact sidebar — desktop only. */}
diff --git a/src/components/inbox/conversation-list.tsx b/src/components/inbox/conversation-list.tsx index c13e137..fe9ae48 100644 --- a/src/components/inbox/conversation-list.tsx +++ b/src/components/inbox/conversation-list.tsx @@ -110,7 +110,10 @@ export function ConversationList({ const activeFilter = FILTER_OPTIONS.find((o) => o.value === filter); return ( -
+ // w-full on mobile so the list occupies the whole viewport when it's + // the single pane showing; fixed 320px on desktop where it shares the + // row with the thread + contact sidebar. +
{/* Search + Filter */}
diff --git a/src/components/inbox/message-thread.tsx b/src/components/inbox/message-thread.tsx index a4a402e..984b7dd 100644 --- a/src/components/inbox/message-thread.tsx +++ b/src/components/inbox/message-thread.tsx @@ -9,6 +9,7 @@ import { ChevronDown, UserPlus, Clock, + ArrowLeft, } from "lucide-react"; import { format, isToday, isYesterday, differenceInHours } from "date-fns"; import { Badge } from "@/components/ui/badge"; @@ -32,6 +33,13 @@ interface MessageThreadProps { onNewMessage: (message: Message) => void; onUpdateMessage: (id: string, updates: Partial) => void; onStatusChange: (conversationId: string, status: ConversationStatus) => void; + /** + * On mobile, the thread is shown full-screen with the conversation list + * hidden. This callback lets the page deselect the active conversation + * and reveal the list again. Rendered as a back-arrow in the header on + * mobile only. + */ + onBack?: () => void; } function formatDateSeparator(dateStr: string): string { @@ -72,6 +80,7 @@ export function MessageThread({ onNewMessage, onUpdateMessage, onStatusChange, + onBack, }: MessageThreadProps) { const [loading, setLoading] = useState(false); const scrollRef = useRef(null); @@ -278,20 +287,33 @@ export function MessageThread({ return (
{/* Header */} -
-
-
+
+
+ {/* Back-to-list button — mobile only. Hidden on lg+ where the + conversation list is always visible next to the thread. */} + {onBack && ( + + )} +
{displayName.charAt(0).toUpperCase()}
-
-

{displayName}

-

{contact.phone}

+
+

{displayName}

+

{contact.phone}

- {/* Session timer badge */} + {/* Session timer badge — hidden on the narrowest phones so + the name + back arrow keep their room. */}