From 56f6075ceb64c44dc65882b1705c505f8bfb98cf Mon Sep 17 00:00:00 2001 From: Satyam Rastogi Date: Fri, 29 May 2026 21:05:34 +0530 Subject: [PATCH] feat(data): lead-verification queue + mutators (verify pushes a grounded New Lead into the pipeline) --- src/data/mockStore.jsx | 481 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 481 insertions(+) diff --git a/src/data/mockStore.jsx b/src/data/mockStore.jsx index e2ec6fa..0f15f9c 100644 --- a/src/data/mockStore.jsx +++ b/src/data/mockStore.jsx @@ -6899,6 +6899,327 @@ export const SUBCONTRACTOR_FEE_TYPES = [ 'Other', ]; +// --------------------------------------------------------------------------- +// LEAD VERIFICATION QUEUE +// --------------------------------------------------------------------------- +// Admins: a1 Wade Hollis · a2 Darlene Brooks · a3 Roy Schaefer +// DEMO_TODAY = 2026-05-29 + +const MOCK_LEAD_VERIFICATIONS = [ + { + id: 'lv_001', leadId: 'LD-V-001', + customerName: 'Kevin Hartley', + phone: '(972) 413-8902', + email: 'kevin.hartley@gmail.com', + address: '2814 Ravenswood Dr, Plano, TX 75023', + source: 'Door Knock', + status: 'Verified', + verificationStatus: 'Verified', + assigneeId: 'a1', assigneeName: 'Wade Hollis', + urgency: 'standard', + createdAt: '2026-05-14T09:10:00Z', + assignedAt: '2026-05-14T09:40:00Z', + verifiedAt: '2026-05-16T14:25:00Z', + verificationNotes: 'Ownership confirmed via county records. Hail damage from April 28 storm event verified.', + history: [ + { at: '2026-05-14T09:10:00Z', by: 'System', action: 'Lead submitted via door knock intake.' }, + { at: '2026-05-14T09:40:00Z', by: 'Wade Hollis', action: 'Assigned to Wade Hollis.' }, + { at: '2026-05-15T08:30:00Z', by: 'Wade Hollis', action: 'First contact made — homeowner confirmed damage.' }, + { at: '2026-05-16T14:25:00Z', by: 'Wade Hollis', action: 'Verified and pushed to New Leads.' }, + ], + }, + { + id: 'lv_002', leadId: 'LD-V-002', + customerName: 'Sandra Nguyen', + phone: '(469) 551-7034', + email: 'sandra.nguyen@yahoo.com', + address: '4817 Shady Brook Ln, Plano, TX 75093', + source: 'Web Form', + status: 'Verified', + verificationStatus: 'Verified', + assigneeId: 'a2', assigneeName: 'Darlene Brooks', + urgency: 'standard', + createdAt: '2026-05-17T13:45:00Z', + assignedAt: '2026-05-17T14:15:00Z', + verifiedAt: '2026-05-19T11:00:00Z', + verificationNotes: 'Identity and property ownership confirmed. Adjuster appointment already scheduled.', + history: [ + { at: '2026-05-17T13:45:00Z', by: 'System', action: 'Lead submitted via website form.' }, + { at: '2026-05-17T14:15:00Z', by: 'Darlene Brooks', action: 'Assigned to Darlene Brooks.' }, + { at: '2026-05-18T09:00:00Z', by: 'Darlene Brooks', action: 'Marked In Progress — reviewing insurance docs.' }, + { at: '2026-05-19T11:00:00Z', by: 'Darlene Brooks', action: 'Verified and pushed to New Leads.' }, + ], + }, + { + id: 'lv_003', leadId: 'LD-V-003', + customerName: 'Marcus Trevino', + phone: '(214) 837-4561', + email: 'marcus.trevino@outlook.com', + address: '1234 Oak Creek Blvd, Plano, TX 75075', + source: 'Storm Canvass', + status: 'In Progress', + verificationStatus: 'Verifying Identity', + assigneeId: 'a1', assigneeName: 'Wade Hollis', + urgency: 'standard', + createdAt: '2026-05-22T11:20:00Z', + assignedAt: '2026-05-22T12:00:00Z', + verifiedAt: null, + verificationNotes: 'Storm canvass capture. Cross-checking ownership records with county appraisal district.', + history: [ + { at: '2026-05-22T11:20:00Z', by: 'System', action: 'Lead captured during storm canvass.' }, + { at: '2026-05-22T12:00:00Z', by: 'Wade Hollis', action: 'Assigned to Wade Hollis.' }, + { at: '2026-05-23T09:15:00Z', by: 'Wade Hollis', action: 'Marked In Progress — verifying identity via CAD records.' }, + ], + }, + { + id: 'lv_004', leadId: 'LD-V-004', + customerName: 'Brenda Kowalski', + phone: '(972) 604-2817', + email: 'b.kowalski@gmail.com', + address: '890 Custer Rd, Plano, TX 75075', + source: 'Referral', + status: 'In Progress', + verificationStatus: 'Reviewing Insurance', + assigneeId: 'a3', assigneeName: 'Roy Schaefer', + urgency: 'high', + createdAt: '2026-05-20T08:30:00Z', + assignedAt: '2026-05-20T09:00:00Z', + verifiedAt: null, + verificationNotes: 'Referred by existing customer. Adjuster supplement under review — large residential loss.', + history: [ + { at: '2026-05-20T08:30:00Z', by: 'System', action: 'Referral submitted by existing customer.' }, + { at: '2026-05-20T09:00:00Z', by: 'Roy Schaefer', action: 'Assigned to Roy Schaefer.' }, + { at: '2026-05-21T10:45:00Z', by: 'Roy Schaefer', action: 'Marked In Progress — reviewing adjuster supplement.' }, + ], + }, + { + id: 'lv_005', leadId: 'LD-V-005', + customerName: 'Diane Castillo', + phone: '(469) 228-6390', + email: 'diane.castillo@icloud.com', + address: '321 Independence Pkwy, Plano, TX 75023', + source: 'Call Center', + status: 'Assigned', + verificationStatus: 'Pending Outreach', + assigneeId: 'a2', assigneeName: 'Darlene Brooks', + urgency: 'standard', + createdAt: '2026-05-25T14:00:00Z', + assignedAt: '2026-05-25T14:30:00Z', + verifiedAt: null, + verificationNotes: 'Inbound call center lead. First outreach attempt scheduled for tomorrow morning.', + history: [ + { at: '2026-05-25T14:00:00Z', by: 'System', action: 'Lead created from call center intake.' }, + { at: '2026-05-25T14:30:00Z', by: 'Darlene Brooks', action: 'Assigned to Darlene Brooks.' }, + ], + }, + { + id: 'lv_006', leadId: 'LD-V-006', + customerName: 'Gerald Hoffmann', + phone: '(972) 386-9140', + email: 'gerald.hoffmann@yahoo.com', + address: '7654 Preston Rd, Plano, TX 75024', + source: 'Storm Canvass', + status: 'Assigned', + verificationStatus: 'Pending Outreach', + assigneeId: 'a3', assigneeName: 'Roy Schaefer', + urgency: 'standard', + createdAt: '2026-05-26T09:05:00Z', + assignedAt: '2026-05-26T09:40:00Z', + verifiedAt: null, + verificationNotes: 'Storm canvass — visible hail damage on south slope. Assigned for morning call.', + history: [ + { at: '2026-05-26T09:05:00Z', by: 'System', action: 'Lead captured during storm canvass.' }, + { at: '2026-05-26T09:40:00Z', by: 'Roy Schaefer', action: 'Assigned to Roy Schaefer.' }, + ], + }, + { + id: 'lv_007', leadId: 'LD-V-007', + customerName: 'Lucinda Farrar', + phone: '(214) 509-3762', + email: 'lucinda.farrar@gmail.com', + address: '2200 Alma Dr, Plano, TX 75075', + source: 'Door Knock', + status: 'In Progress', + verificationStatus: 'Awaiting Confirmation', + assigneeId: 'a1', assigneeName: 'Wade Hollis', + urgency: 'standard', + createdAt: '2026-05-21T10:00:00Z', + assignedAt: '2026-05-21T10:30:00Z', + verifiedAt: null, + verificationNotes: 'Homeowner reachable. Confirmed damage but waiting on insurance policy number before proceeding.', + history: [ + { at: '2026-05-21T10:00:00Z', by: 'System', action: 'Lead submitted via door knock intake.' }, + { at: '2026-05-21T10:30:00Z', by: 'Wade Hollis', action: 'Assigned to Wade Hollis.' }, + { at: '2026-05-22T08:00:00Z', by: 'Wade Hollis', action: 'First contact made — awaiting homeowner insurance docs.' }, + ], + }, + { + id: 'lv_008', leadId: 'LD-V-008', + customerName: 'Preston Okafor', + phone: '(945) 762-4830', + email: 'p.okafor@outlook.com', + address: '555 Legacy Dr, Plano, TX 75023', + source: 'Referral', + status: 'Pending', + verificationStatus: 'Unassigned', + assigneeId: null, assigneeName: null, + urgency: 'standard', + createdAt: '2026-05-27T08:15:00Z', + assignedAt: null, + verifiedAt: null, + verificationNotes: 'Referral from verified homeowner on Legacy Dr. Needs verifier assignment.', + history: [ + { at: '2026-05-27T08:15:00Z', by: 'System', action: 'Referral submitted by existing customer.' }, + ], + }, + { + id: 'lv_009', leadId: 'LD-V-009', + customerName: 'Tamara Whitfield', + phone: '(469) 334-6017', + email: 'tamara.whitfield@gmail.com', + address: '3301 Avenue K, Plano, TX 75074', + source: 'Call Center', + status: 'Pending', + verificationStatus: 'Unassigned', + assigneeId: null, assigneeName: null, + urgency: 'standard', + createdAt: '2026-05-28T15:30:00Z', + assignedAt: null, + verifiedAt: null, + verificationNotes: 'Inbound call — homeowner reported significant granule loss. Awaiting verifier assignment.', + history: [ + { at: '2026-05-28T15:30:00Z', by: 'System', action: 'Lead created from call center intake.' }, + ], + }, + { + id: 'lv_010', leadId: 'LD-V-010', + customerName: 'Alicia Drummond', + phone: '(972) 817-5429', + email: 'alicia.drummond@yahoo.com', + address: '6711 W Spring Creek Pkwy, Plano, TX 75024', + source: 'Web Form', + status: 'Pending', + verificationStatus: 'Unassigned', + assigneeId: null, assigneeName: null, + urgency: 'standard', + createdAt: '2026-05-29T07:45:00Z', + assignedAt: null, + verifiedAt: null, + verificationNotes: 'Web form submission this morning. No notes from intake yet.', + history: [ + { at: '2026-05-29T07:45:00Z', by: 'System', action: 'Lead submitted via website form.' }, + ], + }, + { + id: 'lv_011', leadId: 'LD-V-011', + customerName: 'Raymond Ostrowski', + phone: '(214) 673-9045', + email: 'r.ostrowski@gmail.com', + address: '1800 Jupiter Rd, Plano, TX 75074', + source: 'Storm Canvass', + status: 'Unverified', + verificationStatus: 'Failed Contact', + assigneeId: 'a2', assigneeName: 'Darlene Brooks', + urgency: 'standard', + createdAt: '2026-05-18T16:10:00Z', + assignedAt: '2026-05-18T16:40:00Z', + verifiedAt: null, + verificationNotes: 'Four callback attempts — number goes straight to voicemail. Email bounced. Marking unverified.', + history: [ + { at: '2026-05-18T16:10:00Z', by: 'System', action: 'Lead captured during storm canvass.' }, + { at: '2026-05-18T16:40:00Z', by: 'Darlene Brooks', action: 'Assigned to Darlene Brooks.' }, + { at: '2026-05-20T09:00:00Z', by: 'Darlene Brooks', action: 'Attempt 1 — voicemail, no response.' }, + { at: '2026-05-21T10:30:00Z', by: 'Darlene Brooks', action: 'Attempt 2 — voicemail.' }, + { at: '2026-05-22T14:00:00Z', by: 'Darlene Brooks', action: 'Attempt 3 — voicemail. Email bounced.' }, + { at: '2026-05-23T11:15:00Z', by: 'Darlene Brooks', action: 'Marked Unverified — no contact after 4 attempts.' }, + ], + }, + { + id: 'lv_012', leadId: 'LD-V-012', + customerName: 'Felicia Granger', + phone: '(469) 490-3156', + email: 'felicia.granger@gmail.com', + address: '4400 W Parker Rd, Plano, TX 75093', + source: 'Door Knock', + status: 'Unverified', + verificationStatus: 'Failed Contact', + assigneeId: 'a3', assigneeName: 'Roy Schaefer', + urgency: 'standard', + createdAt: '2026-05-16T11:00:00Z', + assignedAt: '2026-05-16T11:30:00Z', + verifiedAt: null, + verificationNotes: 'Number disconnected after two attempts. Owner may have moved. Flagged unverified.', + history: [ + { at: '2026-05-16T11:00:00Z', by: 'System', action: 'Lead submitted via door knock intake.' }, + { at: '2026-05-16T11:30:00Z', by: 'Roy Schaefer', action: 'Assigned to Roy Schaefer.' }, + { at: '2026-05-17T09:00:00Z', by: 'Roy Schaefer', action: 'Attempt 1 — number disconnected.' }, + { at: '2026-05-18T10:00:00Z', by: 'Roy Schaefer', action: 'Marked Unverified — number disconnected, no secondary contact.' }, + ], + }, + { + id: 'lv_013', leadId: 'LD-V-013', + customerName: 'Nathaniel Crosby', + phone: '(972) 945-2807', + email: 'n.crosby@icloud.com', + address: '5920 Coit Rd, Plano, TX 75023', + source: 'Storm Canvass', + status: 'Assigned', + verificationStatus: 'Pending Outreach', + assigneeId: 'a1', assigneeName: 'Wade Hollis', + urgency: 'high', + createdAt: '2026-05-28T10:00:00Z', + assignedAt: '2026-05-28T10:35:00Z', + verifiedAt: null, + verificationNotes: 'Significant hail event last night. Homeowner flagged as high priority — visible structural damage on ridge.', + history: [ + { at: '2026-05-28T10:00:00Z', by: 'System', action: 'Lead captured during storm canvass after overnight hail.' }, + { at: '2026-05-28T10:35:00Z', by: 'Wade Hollis', action: 'Assigned to Wade Hollis — high urgency.' }, + ], + }, + { + id: 'lv_014', leadId: 'LD-V-014', + customerName: 'Josephine Aldridge', + phone: '(214) 770-6381', + email: 'jo.aldridge@yahoo.com', + address: '3108 Hedgcoxe Rd, Plano, TX 75025', + source: 'Call Center', + status: 'In Progress', + verificationStatus: 'Reviewing Insurance', + assigneeId: 'a2', assigneeName: 'Darlene Brooks', + urgency: 'high', + createdAt: '2026-05-24T13:00:00Z', + assignedAt: '2026-05-24T13:30:00Z', + verifiedAt: null, + verificationNotes: 'Homeowner has Allstate claim already filed. Reviewing adjuster report for scope accuracy.', + history: [ + { at: '2026-05-24T13:00:00Z', by: 'System', action: 'Lead created from call center intake.' }, + { at: '2026-05-24T13:30:00Z', by: 'Darlene Brooks', action: 'Assigned to Darlene Brooks.' }, + { at: '2026-05-25T09:00:00Z', by: 'Darlene Brooks', action: 'Marked In Progress — reviewing Allstate adjuster report.' }, + ], + }, + { + id: 'lv_015', leadId: 'LD-V-015', + customerName: 'Tyrone Beaumont', + phone: '(945) 381-7024', + email: 'tyrone.beaumont@gmail.com', + address: '4712 Mapleshade Ln, Plano, TX 75093', + source: 'Door Knock', + status: 'In Progress', + verificationStatus: 'Emergency — Awaiting Verifier', + assigneeId: 'a3', assigneeName: 'Roy Schaefer', + urgency: 'emergency', + createdAt: '2026-05-29T06:50:00Z', + assignedAt: '2026-05-29T07:00:00Z', + verifiedAt: null, + verificationNotes: 'Active roof leak with interior water intrusion. Family with young children on site. Emergency verification required immediately.', + history: [ + { at: '2026-05-29T06:50:00Z', by: 'System', action: 'Emergency intake from door knock — active leak reported.' }, + { at: '2026-05-29T07:00:00Z', by: 'Roy Schaefer', action: 'Assigned to Roy Schaefer — emergency priority.' }, + { at: '2026-05-29T07:05:00Z', by: 'Roy Schaefer', action: 'Marked In Progress — emergency verification in progress.' }, + ], + }, +]; + const MOCK_SUBCONTRACTORS = [ { id: 'sub_001', @@ -8678,6 +8999,7 @@ export const MockStoreProvider = ({ children }) => { const [kanbanColumns, setKanbanColumns] = useState(KANBAN_COLUMNS_INITIAL); const [kanbanLeads, setKanbanLeads] = useState(KANBAN_LEADS_INITIAL); const [stormZones, setStormZones] = useState(INITIAL_STORM_ZONES); + const [leadVerifications, setLeadVerifications] = useState(MOCK_LEAD_VERIFICATIONS); // Commission Settings — Org defaults + per-user overrides const [orgCommissionDefaults, setOrgCommissionDefaults] = useState({ @@ -9303,6 +9625,157 @@ export const MockStoreProvider = ({ children }) => { toast.success(`Task reassigned to ${subcontractor.name}`); }; + // ── Lead Verification Workflow ────────────────────────────────────────── + const appendLvHistory = (lv, entry) => ({ + ...lv, + history: [...(lv.history || []), { at: new Date().toISOString(), ...entry }], + }); + + const assignLeadVerification = (id, assigneeId, assigneeName) => { + if (!assigneeId) { + toast.error('Please select an assignee.'); + return; + } + setLeadVerifications(prev => prev.map(lv => { + if (lv.id !== id) return lv; + const wasUnassigned = !lv.assigneeId; + return appendLvHistory({ + ...lv, + assigneeId, + assigneeName, + status: (lv.status === 'Pending' || lv.status === 'Unverified') ? 'Assigned' : lv.status, + verificationStatus: wasUnassigned ? 'Pending Outreach' : lv.verificationStatus, + assignedAt: lv.assignedAt || new Date().toISOString(), + }, { by: assigneeName, action: `${wasUnassigned ? 'Assigned' : 'Reassigned'} to ${assigneeName}.` }); + })); + toast.success(`Lead assigned to ${assigneeName}`); + }; + + const reassignLeadVerification = (id, assigneeId, assigneeName) => { + if (!assigneeId) { + toast.error('Please select an assignee.'); + return; + } + setLeadVerifications(prev => prev.map(lv => { + if (lv.id !== id) return lv; + return appendLvHistory({ + ...lv, + assigneeId, + assigneeName, + }, { by: assigneeName, action: `Reassigned to ${assigneeName}.` }); + })); + toast.success(`Lead reassigned to ${assigneeName}`); + }; + + const setLeadVerificationStatus = (id, newStatus, note = '') => { + setLeadVerifications(prev => prev.map(lv => { + if (lv.id !== id) return lv; + const derivedVerificationStatus = + newStatus === 'In Progress' ? 'Verifying Identity' : + newStatus === 'Assigned' ? 'Pending Outreach' : + newStatus === 'Pending' ? (lv.assigneeId ? 'Pending Outreach' : 'Unassigned') : + newStatus === 'Unverified' ? 'Failed Contact' : + lv.verificationStatus; + return appendLvHistory({ + ...lv, + status: newStatus, + verificationStatus: derivedVerificationStatus, + verificationNotes: note || lv.verificationNotes, + }, { by: lv.assigneeName || 'System', action: `Status changed to ${newStatus}${note ? ` — ${note}` : ''}.` }); + })); + toast.success(`Lead moved to ${newStatus}`); + }; + + const verifyLead = (id) => { + const lv = leadVerifications.find(x => x.id === id); + if (!lv) return; + if (lv.status === 'Verified') { + toast.info('Lead already verified.'); + return; + } + const nowIso = new Date().toISOString(); + setLeadVerifications(prev => prev.map(item => { + if (item.id !== id) return item; + return appendLvHistory({ + ...item, + status: 'Verified', + verificationStatus: 'Verified', + verifiedAt: nowIso, + }, { by: item.assigneeName || 'System', action: 'Verified and pushed to New Leads.' }); + })); + + // Split customerName → firstName / lastName + const nameParts = (lv.customerName || '').trim().split(' '); + const firstName = nameParts[0] || 'Unknown'; + const lastName = nameParts.slice(1).join(' '); + + // Parse city/state from address (e.g. "... Plano, TX 75023") + const addrMatch = (lv.address || '').match(/,\s*([^,]+),\s*([A-Z]{2})\s+\d+\s*$/); + const city = addrMatch ? addrMatch[1].trim() : 'Plano'; + const state = addrMatch ? addrMatch[2].trim() : 'TX'; + + const newLead = { + id: `lead_lv_${Date.now()}`, + firstName, + lastName, + address: lv.address || '', + city, + state, + urgency: lv.urgency || 'standard', + status: 'New', + leadSource: lv.source || 'Lead Verification', + phones: lv.phone ? [{ id: '1', number: lv.phone, type: 'Mobile', isPrimary: true }] : [], + emails: lv.email ? [{ email: lv.email, isPrimary: true }] : [], + createdAt: nowIso, + createdByName: 'Lead Verification', + verificationId: lv.id, + verificationLeadId: lv.leadId, + notes: lv.verificationNotes || '', + // Minimal enriched fields so LeadsListPage doesn't break + canvasserName: lv.assigneeName || '', + assignedTo: '', + priority: lv.urgency === 'emergency' ? 'critical' : lv.urgency === 'high' ? 'high' : 'low', + followUpDate: '', + isQuickCapture: false, + zip: (lv.address || '').match(/\d{5}$/)?.[0] || '', + propertyType: 'Single Family', + propertyPhotos: [], + leadType: 'Insurance', + workType: 'Roof Replacement', + tradeType: 'Roofing', + referralNote: '', + canvasserId: '', + insuranceCompany: '', claimNumber: '', claimStatus: '', + adjusterName: '', adjusterPhone: '', policyNumber: '', + }; + setLeads(prev => [newLead, ...prev]); + toast.success(`${lv.customerName} verified — moved to New Leads`); + }; + + const unverifyLead = (id, note = '') => { + setLeadVerifications(prev => prev.map(lv => { + if (lv.id !== id) return lv; + return appendLvHistory({ + ...lv, + status: 'Unverified', + verificationStatus: 'Failed Contact', + verificationNotes: note || lv.verificationNotes, + }, { by: lv.assigneeName || 'System', action: `Marked Unverified${note ? ` — ${note}` : ''}.` }); + })); + toast.success('Lead marked as Unverified'); + }; + + const addLeadVerificationNote = (id, note) => { + if (!note?.trim()) return; + setLeadVerifications(prev => prev.map(lv => { + if (lv.id !== id) return lv; + return appendLvHistory({ + ...lv, + verificationNotes: note.trim(), + }, { by: lv.assigneeName || 'System', action: `Note added: ${note.trim()}` }); + })); + }; + return ( { resolveProfile, updateOwnProfile, setSkillScore, + // ── Lead Verification Queue ── + leadVerifications, + assignLeadVerification, + reassignLeadVerification, + setLeadVerificationStatus, + verifyLead, + unverifyLead, + addLeadVerificationNote, }}> {children}