feat(leads+verification): wire Leads & Lead Verification to be-crm data door
Integrates the Leads and Lead Verification screens with the live be-crm backend (crm.lead.* / crm.leadVerification.* / crm.media.*) behind a mode-agnostic data layer that still falls back to the local mock when the Shell isn't configured. Data layer (new) - src/lib/leads-api.ts — crm.lead.search/get/stats/create/update/ updateStatus/assign/sendForVerification + media (presign upload/download) - src/lib/verify-api.ts — crm.leadVerification.search/get/stats/verify/ markUnverified/assign/reassign/moveToPending Backend → FE wiring - Assignee / creator names: read the resolved DTO fields and, as a safety net, resolve member ids → real names against crm.team.member.search (be-crm currently echoes the raw principalId as the name). - Created By: read the createdBy object the backend returns (was blank). - Site photos: upload via crm.media.presignUpload → PUT, persist through crm.lead.attachment.add (per photo, after create), render in the detail popup via crm.media.presignDownload. - Duplicate guard: surface the backend's real error (detail / duplicate_lead) instead of the SDK's opaque "data command failed: 400". UX - Leads detail: Property Photos gallery + edit-mode photo add/remove. - Verification: "Change Assignee" now opens a searchable, scrollable popup instead of a long inline dropdown. - Removed the static "Storm Zone" tag from lead cards/detail; storm banner only renders when the lead carries storm data. Reference / follow-ups - leads.http, leads.postman_collection.json — be-crm data-door requests. - LEADS_BACKEND_CHANGES.md — required be-crm changes (name resolution, assignee carry-over on sendForVerification) verified against :4010. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1278,8 +1278,23 @@
|
||||
.dash-root .nl-photos-s { font-size: 11px; }
|
||||
.dash-root .nl-photo-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
|
||||
.dash-root .nl-photo-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 600; padding: 5px 10px; border-radius: 99px; background: color-mix(in srgb, var(--green) 15%, transparent); color: var(--green); }
|
||||
.dash-root .nl-photo-chip-x { display: inline-flex; align-items: center; justify-content: center; margin-left: 2px; padding: 0; border: none; background: none; color: inherit; opacity: 0.65; cursor: pointer; }
|
||||
.dash-root .nl-photo-chip-x:hover { opacity: 1; }
|
||||
.dash-root .ds-select.is-placeholder { color: var(--faint, var(--muted)); }
|
||||
|
||||
/* Detail popup — property photo gallery */
|
||||
.dash-root .ld-photo-block { margin-bottom: 14px; }
|
||||
.dash-root .ld-photo-block .ld-section-head { margin-bottom: 8px; }
|
||||
.dash-root .ld-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 8px; }
|
||||
.dash-root .ld-photo { position: relative; display: block; aspect-ratio: 1; border-radius: 10px; overflow: hidden; border: 1px solid var(--border-2); background: var(--panel-2); cursor: pointer; }
|
||||
.dash-root .ld-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.dash-root .ld-photo-ph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--muted); }
|
||||
/* Edit mode — photo tile with a remove badge */
|
||||
.dash-root .nl-edit-photos { margin-bottom: 8px; }
|
||||
.dash-root .ld-photo-edit { position: relative; }
|
||||
.dash-root .ld-photo-x { position: absolute; top: 4px; right: 4px; display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border: none; border-radius: 99px; background: rgba(0,0,0,0.6); color: #fff; cursor: pointer; }
|
||||
.dash-root .ld-photo-x:hover { background: var(--red, #e5484d); }
|
||||
|
||||
/* Canvasser search (Door Knock source) */
|
||||
.dash-root .nl-canvasser { position: relative; }
|
||||
.dash-root .nl-canvasser-menu { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30; max-height: 220px; overflow-y: auto; border: 1px solid var(--border-2); border-radius: 12px; background: var(--panel); box-shadow: 0 12px 32px rgba(0,0,0,0.28); padding: 5px; }
|
||||
@@ -1358,6 +1373,21 @@
|
||||
.lv-menu-item svg { color: var(--muted, #8c8c8c); flex: 0 0 auto; }
|
||||
.lv-menu-item:hover svg { color: var(--orange, #fda913); }
|
||||
|
||||
/* ---- change-assignee popup ---- */
|
||||
.dash-root .lv-assign { display: flex; flex-direction: column; gap: 12px; }
|
||||
.dash-root .lv-assign-search { display: flex; align-items: center; gap: 8px; padding: 9px 11px; border-radius: 11px; border: 1px solid var(--border); background: var(--panel-2); }
|
||||
.dash-root .lv-assign-search svg { color: var(--muted); flex: 0 0 auto; }
|
||||
.dash-root .lv-assign-search input { flex: 1; min-width: 0; border: 0; background: none; color: var(--text); font-family: inherit; font-size: 13px; outline: none; }
|
||||
.dash-root .lv-assign-x { display: inline-flex; border: 0; background: none; color: var(--muted); cursor: pointer; padding: 0; }
|
||||
.dash-root .lv-assign-x:hover { color: var(--text); }
|
||||
.dash-root .lv-assign-list { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; margin: -4px; padding: 4px; }
|
||||
.dash-root .lv-assign-opt { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px; border: 0; border-radius: 10px; background: none; color: var(--text-2); font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer; text-align: left; }
|
||||
.dash-root .lv-assign-opt:hover { background: var(--panel-3, #1b1b22); color: var(--text); }
|
||||
.dash-root .lv-assign-opt.current { background: color-mix(in srgb, var(--orange) 12%, transparent); }
|
||||
.dash-root .lv-assign-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.dash-root .lv-assign-opt.current > svg { color: var(--orange); flex: 0 0 auto; }
|
||||
.dash-root .lv-assign-empty { padding: 20px 10px; text-align: center; color: var(--muted); font-size: 12.5px; }
|
||||
|
||||
/* ---- verification detail popup ---- */
|
||||
.dash-root .lv-detail { display: flex; flex-direction: column; gap: 16px; }
|
||||
.dash-root .lv-d-identity { display: flex; align-items: center; gap: 14px; }
|
||||
|
||||
Reference in New Issue
Block a user