Tabbed CRM Panel
The CRM panel (right column, 440px) was redesigned from a long vertical scroll of collapsible sections into an organized tabbed layout. Content is grouped into four tabs: Notes, Photos, Contact, and AI.
Layout
The hero section remains at the top showing avatar, name, phone, tags, personality, and bell icon. Below it sits a tab bar with four tabs, and below that the scrollable tab content area.
Tab Structure
Notes Tab (Default)
The default tab when selecting a contact. Contains two sections:
AI Summarise at the top. Click “Summarise conversation…” to generate an AI-powered conversation summary. The summary includes context from the notes field. The backend whereWereWe endpoint accepts an optional notes parameter that gets included in the AI system prompt. After generation, summary displayed in a purple card with token count and response time. “Copy to notes” prepends a dated summary to the notes textarea. “Refresh” re-runs the summary; “Dismiss” hides it.
Notes textarea below. Large scrollable textarea (min-h 320px) for free-form facts about the contact. Auto-saves with debounced updates (1.5 second delay). Saving indicator shown in header.
Photos Tab
- “Browse All Media” button at top navigates to Media Browser filtered to this contact
- 4-column thumbnail grid of synced photos
- Click any photo to open Media Browser
Contact Tab
The old massive edit form split into collapsible “Twisty” sections:
| Section | Default | Fields |
|---|---|---|
| Details | Open | Name, company, email, location met, social handles |
| Dates | Closed | Birthday, anniversary, contact cycle days |
| Detail Tokens | Closed | AI-extracted personal details (Pets, Kids, Work, etc.) |
| Tags | Closed | Tag management with badge showing count |
All fields auto-save via the existing ContactEditForm component.
AI Tab
Combines all AI and action features:
- AnalysePanel – AI analysis of conversation to extract contact details with “Accept All” to save suggestions
- PersonalityPicker – Assign/change/pause AI auto-reply personality. Triggers live refresh of chat list personality emoji via onChanged callback
- Reminders – Create, view, complete actions/reminders with inline add form
Hero Changes
- Avatar – Click opens fullscreen lightbox overlay (was: opened new browser tab)
- Personality – Emoji + name shown next to bell icon
- Bell icon – Amber when actions pending, muted when none
- City widget – Green “Add location” button
Conversation Header Cleanup
Removed redundant elements from the conversation header (column 2):
| Removed | Reason |
|---|---|
| Contact name, pushname, phone | Already in CRM panel (column 3) |
| Personality badge | Shown in chat list and CRM hero |
| Actions count button | Bell icon covers this |
| Sync Media button | Redundant with earlier messages button |
Kept: “Import Chat” button (renamed from “Import”), zoom controls.
Chat List Icon Cleanup
- “ACT” text badge replaced with bell icon (w-4 h-4, amber)
- “action” tag filtered from tags row – bell is the sole indicator
- Bell + personality emoji combined on one line in right column
- Avatar fallback shows initial letter only (no personality emoji)
- All right-column icons standardized to w-4 h-4 (16px)
AI Token Tracking
Backend
AIService singleton tracks cumulative session usage: total tokens, call count, and start timestamp. New endpoint GET /api/ai/token-usage returns the session stats.
Frontend
TopBar polls every 30 seconds, displays compact counter (e.g., “340 tk” or “1.2k tk”). Hover shows call count.
Cross-Component Personality Refresh
When personality changes in CRM panel (column 3), the chat list (column 1) must update. The signal chain: PersonalityPicker calls onChanged, CrmPanel calls onPersonalityChanged, ChatPage increments assignmentRefreshKey, ChatList re-fetches assignments, and ChatListItem updates the personality emoji.
Files Modified
| File | Changes |
|---|---|
| CrmPanel.tsx | Complete rewrite – tabbed layout, AI summary, notes, avatar lightbox |
| ContactEditForm.tsx | Removed reminders, AnalysePanel, notes. Added Twisty collapsibles |
| PersonalityPicker.tsx | Added onChanged callback |
| ChatListItem.tsx | Bell icons, icon sizing, personality on same line |
| ConversationView.tsx | Removed name/phone/personality/Actions/Sync from header |
| ChatList.tsx | assignmentRefreshKey for live personality updates |
| ChatPage.tsx | assignmentRefreshKey state, onPersonalityChanged prop |
| TopBar.tsx | Token counter, brand rename to IPNOELP CRM |
| AIService.ts | Session token tracking |
| aiRoutes.ts | GET /ai/token-usage endpoint |
| aiCrmController.ts | whereWereWe accepts notes parameter |
| api.ts | aiAPI.getTokenUsage, whereWereWe notes param |