Mock Haggly agent for now. No API key needed.
diff --git a/src/features/dashboard/ConversationDashboard.jsx b/src/features/dashboard/ConversationDashboard.jsx
new file mode 100644
index 0000000..b59583a
--- /dev/null
+++ b/src/features/dashboard/ConversationDashboard.jsx
@@ -0,0 +1,76 @@
+import { Clock, Trash2 } from 'lucide-react'
+import Button from '../../components/ui/Button'
+import Surface from '../../components/ui/Surface'
+
+const statusLabels = {
+ active: 'Active',
+ accepted: 'Accepted',
+ declined: 'Declined',
+ expired: 'Expired',
+}
+
+function formatUpdatedAt(updatedAt) {
+ if (!updatedAt) {
+ return 'New'
+ }
+
+ return new Intl.DateTimeFormat(undefined, {
+ month: 'short',
+ day: 'numeric',
+ hour: 'numeric',
+ minute: '2-digit',
+ }).format(new Date(updatedAt))
+}
+
+function ConversationDashboard({ conversations, onOpenConversation, onClearHistory }) {
+ return (
+
+
+
+
Local dashboard
+
Saved in this browser only. No login or cloud sync.
+
+ {conversations.length > 0 && (
+
+ )}
+
+
+ {conversations.length === 0 ? (
+
+ Start a buyer or seller chat. Your local sessions will appear here.
+
+ ) : (
+
+ {conversations.slice(0, 5).map((conversation) => (
+
+ ))}
+
+ )}
+
+ )
+}
+
+export default ConversationDashboard
diff --git a/src/lib/storage/conversationStorage.js b/src/lib/storage/conversationStorage.js
new file mode 100644
index 0000000..3f2c19a
--- /dev/null
+++ b/src/lib/storage/conversationStorage.js
@@ -0,0 +1,63 @@
+const STORAGE_KEY = 'haggly:v2:conversations'
+const ALLOWED_STATUSES = new Set(['active', 'accepted', 'declined', 'expired'])
+
+function isBrowserStorageAvailable() {
+ return typeof window !== 'undefined' && Boolean(window.localStorage)
+}
+
+function parseConversations(rawValue) {
+ if (!rawValue) {
+ return []
+ }
+
+ try {
+ const parsed = JSON.parse(rawValue)
+ return Array.isArray(parsed) ? parsed : []
+ } catch {
+ return []
+ }
+}
+
+function readConversations() {
+ if (!isBrowserStorageAvailable()) {
+ return []
+ }
+
+ return parseConversations(window.localStorage.getItem(STORAGE_KEY))
+}
+
+function writeConversations(conversations) {
+ if (!isBrowserStorageAvailable()) {
+ return
+ }
+
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(conversations))
+}
+
+export function getStoredConversations() {
+ return readConversations()
+ .filter((conversation) => conversation?.id && conversation?.mode && Array.isArray(conversation?.messages))
+ .sort((a, b) => b.updatedAt - a.updatedAt)
+}
+
+export function saveConversation(conversation) {
+ const existingConversations = readConversations()
+ const nextConversation = {
+ ...conversation,
+ status: ALLOWED_STATUSES.has(conversation.status) ? conversation.status : 'active',
+ updatedAt: Date.now(),
+ }
+
+ const withoutCurrent = existingConversations.filter((item) => item.id !== nextConversation.id)
+ writeConversations([nextConversation, ...withoutCurrent])
+
+ return nextConversation
+}
+
+export function clearStoredConversations() {
+ if (!isBrowserStorageAvailable()) {
+ return
+ }
+
+ window.localStorage.removeItem(STORAGE_KEY)
+}
diff --git a/src/pages/BuyerPage.jsx b/src/pages/BuyerPage.jsx
index 9c5a8a6..7e20f12 100644
--- a/src/pages/BuyerPage.jsx
+++ b/src/pages/BuyerPage.jsx
@@ -3,7 +3,7 @@ import BrandMark from '../components/BrandMark'
import Button from '../components/ui/Button'
import ChatPanel from '../features/chat/ChatPanel'
-function BuyerPage({ onBack, onCopy }) {
+function BuyerPage({ conversation, onBack, onConversationChange, onCopy }) {
const upcomingTools = [
{ icon: Search, label: 'Question builder' },
{ icon: MessageSquareText, label: 'Response scripts' },
@@ -45,7 +45,12 @@ function BuyerPage({ onBack, onCopy }) {