Nasaq

LeadsInbox

Inquiries from your forms with where each came from (UTM, referrer, Google click id), a stage pipeline with counts, a detail panel with reply and canned replies, and conversion into a CRM contact.

PreviewOpen ↗

Code

<LeadsInbox  leads={leads}  canned={snippets}  onStatusChange={async (lead, status) => setStatus(lead.id, status)}  onConvert={async (lead, conversion) => convert(lead.id, conversion)}  onReply={async (lead, message) => reply(lead.id, message)}/>

CRM · beta

Live examples and controls: LeadsInbox in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/leads-inbox.json

What a marketing site collects, made workable: every inquiry with its source, a pipeline you can filter by stage, a side panel to read, reply and move it along, and a convert step that turns it into a contact (and optionally a company and a deal).

When to use

  • Triage of form submissions before they become CRM records.

When not to use

Import

import { LeadsInbox } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"

Quick start

<LeadsInbox
  leads={leads}
  canned={snippets}
  onStatusChange={async (lead, status) => setStatus(lead.id, status)}
  onConvert={async (lead, conversion) => convert(lead.id, conversion)}
  onReply={async (lead, message) => reply(lead.id, message)}
/>

Anatomy

  • Pipeline strip: All, New, Contacted, Qualified, Converted, Spam, each with a count, filtering the list.
  • EntityList: lead, source, stage, score (ScoreBadge), received. Row actions open from a context-click.
  • Detail sheet: stage stepper, actions, message, attribution list (click id and landing page are copyable), reply composer with the canned picker.
  • Convert dialog: contact name, optional company, optional deal.

Source is classified as Paid (a click id is always paid search), Organic, Social, Email, Referral or Direct.

API

PropTypeDescription
leadsLead[]{ id, name, email?, phone?, company?, message?, budget?, status, receivedAt, form?, attribution?, score?, contact?, companyRef?, deal? }.
cannedCannedSnippet[]Saved replies for the composer.
onStatusChange(lead, status) => Promise<...>Never called with converted.
onConvert(lead, { contactName, company?, deal? }) => Promise<...>Return the lead as converted afterwards.
onReply(lead, message) => Promise<...>Omit to hide the composer.
defaultOpenIdstringStart with a lead open.
labelsPartial<LeadsInboxLabels>Override any string.

Also EntityList props such as loading, error, empty, view. Small parts: LeadSourceBadge, LeadStatusBadge, LeadAttributionList. Pure helpers: classifyLeadSource, leadAttributionEntries, leadStatusCounts, canMoveLead, canConvertLead, leadPipelineStates.

Examples

Spam cannot be converted and a converted lead cannot be moved back, so its links to the contact and deal stay true.

Accessibility

The pipeline is a group of toggle buttons with counts. The stepper marks the current step. Source and stage are words. The sheet traps focus.

RTL & i18n

English and Arabic ship. Emails, phones, UTM values and URLs stay left-to-right. Stepper arrows mirror.

Styling & tokens

Semantic tokens only.

Do / Don't

  • Do keep the raw UTM values visible, marketers check them.
  • Don't convert spam.

Lab

https://docs.nasaqui.com/?path=/docs/components-crm-leads-inbox--docs

On this page