Onsidian Help
Lead System

UI Architecture

Components, hooks, and data flow in the leads frontend

Page structure

The leads page lives at /agent/leads (route: app/(nav)/(private)/agent/leads/page.tsx). It renders the LeadsPage component which has a split layout: lead table on the left, detail panel on the right.

Tabs

The page has tabs that vary by role:

TabWho sees itComponent
LeadsEveryoneLead table with filters
FeedEveryoneActivity feed across all leads
Referrals (Old)EveryoneLegacy referrals view
DistributeAdmins/managersBulk lead assignment
ExportAdmins/managersCSV export with history

Key components

leads-page.tsx

The main container. Manages:

  • Active tab state
  • Selected lead ID
  • Filter state (stages, types, states, search query)
  • Modal visibility

Renders the lead table, detail panel (when a lead is selected), and tab content.

Lead table (in leads-page.tsx)

Uses the design system Table component. Columns: Name, Stage (color-coded badge), Type, State, Contact (phone/email icons), Created, Last Activity (via LiveTimeSince).

lead-details.tsx

The detail panel for a single lead. Tabbed interface:

TabWhat it shows
ActionsStage-aware action buttons (call, schedule, present, resolve)
DemographicsPrimary/secondary insured info
OutcomeSale details table (ALP/AHP summary + product breakdown)
AppointmentsAppointment history with status badges
ActivityFull timeline of every action
AdminField editing (admin only)
DebugRaw JSON dump

The Actions tab adapts based on the lead's current stage — different buttons appear for new vs scheduled vs no_show.

Action modals

ModalFileWhen used
outgoing-contact-modal.tsxAgent initiates contactShows method (call/text/email), outcome options, optional appointment picker
received-message-modal.tsxLead contacts agentSimilar to outgoing but for inbound
appointment-modal.tsxDirect appointment managementSchedule, cancel, no-show, reschedule
resolve-modal.tsxTerminal outcomesRefused, Wrong Number, Unresponsive, DNC
note-modal.tsxAdd a noteSimple text input
presentation-start-modal.tsxConfirm presentation startCounts toward metrics
create-lead-modal.tsxCreate a new leadName, phone, state, type, etc.

Supporting detail components

FilePurpose
lead-details-overview.tsxContact info, status, type cards
lead-details-activity.tsxActivity timeline table
lead-details-demographics.tsxPrimary/secondary insured details
lead-details-outcome.tsxSale summary and product breakdown
lead-details-appointments.tsxAppointment history
lead-details-admin.tsxAdmin field editing
lead-details-debug.tsxRaw JSON

Hooks

useLead(user, leadId)

File: src/components/leads/use-lead.ts

The core hook for a single lead. Fetches the lead, its referral parent, activity history, appointments, and sale details in parallel.

Data returned:

  • lead — the lead with source image
  • referralLead — parent lead if this is a referral
  • leadActivity[] — all activities with agent names
  • appointments[] — calendar events of type lead_appointment
  • saleDetails[] — individual policy records

Methods returned:

  • addActivity(type, note) — log a simple activity
  • addActivityWithAppointment(outcome, note, date) — calls manage_appointment RPC
  • logContactWithOutcome(method, result, metadata) — calls log_contact_with_outcome RPC
  • logIncomingContact(method, result, metadata) — calls log_incoming_contact RPC
  • startPresentation() — opens the presentation pop-out window
  • fetchLead() — manual refresh

Auto-refreshes on window focus (so data updates after returning from the presentation window).

useLeads(user, options)

File: src/components/leads/use-leads.ts

Lists and filters leads with pagination (30 per page).

Filter options: agentIds, agencyId, stages, types, states, searchQuery, unassigned

Search is case-insensitive across first_name, last_name, phone, and email.

Methods: fetchLeads(), loadMore(), createLead(data)

useLeadExports(agencyId, filterTypes, filterStates)

File: src/components/leads/use-lead-exports.ts

Manages CSV exports. Tracks which leads have been exported to avoid duplicates.

Methods: exportFiltered(), redownloadExport(record), createExport(leadIds, filters, filename)

useLeadTeamUsers(user, isAdmin)

File: src/components/leads/use-lead-team-users.ts

Fetches team members for the distribution view. Admins get all agency profiles; non-admins use get_users_under_profile RPC.


Utility files

FileExportPurpose
get-lead-source-img.tsgetLeadSourceImage()Maps source to icon ('onsidian'/images/xp.svg)
is-terminal-status.tsisTerminalStatus()Returns true if status === 'resolved'
is-contacted-status.tsisContactedStage()Returns true if stage !== 'new'
lead-filters-dropdown.tsxLeadFiltersDropdownMulti-select filter UI for type and state

Presentation flow

When an agent starts a presentation from a lead:

  1. startPresentation() in useLead checks that lead.appt_at exists
  2. openPresentationFromLead(lead) builds a BasePresentation object with lead data
  3. Checks local storage for an existing presentation (resume vs. new)
  4. Opens a pop-out browser window with the presentation controls
  5. The presentation window calls the /api/leads/log-presentation-activity endpoint to log presentation_started or presentation_resumed
  6. On completion, the presentation window calls submit_lead_presentation RPC directly
  7. When the agent returns to the main window, useLead auto-refreshes via the window focus listener

Stage colors

Used consistently across the table and detail panel for visual status:

StageColor variable
new--primary-blue
attempted--yellow
callback--yellow
scheduled--green
no_show--red
sale--green
no_sale--red
refused--red
wrong_number--red
bad_number--red
unresponsive--red
duplicate--secondary-text-color
dnc--red

On this page