feat(dispatch): map dispatch reps to canonical field agents; ground recommendations in real profile facts
This commit is contained in:
+134
-108
@@ -4644,43 +4644,43 @@ const MOCK_PROJECTS = [
|
||||
|
||||
export const DISPATCH_REPS = [
|
||||
{
|
||||
id: 'REP-01', name: 'Carlos Mendez', initials: 'CM',
|
||||
id: 'REP-01', personId: 'e1', name: 'Cody Tatum', initials: 'CT',
|
||||
status: 'en_route', // available | en_route | busy
|
||||
currentLat: 33.0612, currentLng: -96.7891,
|
||||
todayAppointments: 3, maxDaily: 6,
|
||||
skills: ['insurance_claim', 'retail_estimate'],
|
||||
skills: ['sk_emergency_tarp', 'sk_insurance_claim', 'sk_drone_survey'],
|
||||
performanceScore: 94, rating: 4.8, closeRate: 82,
|
||||
},
|
||||
{
|
||||
id: 'REP-02', name: 'Aisha Kumar', initials: 'AK',
|
||||
id: 'REP-02', personId: 'e2', name: 'Hannah Reyes', initials: 'HR',
|
||||
status: 'available',
|
||||
currentLat: 33.0812, currentLng: -96.7234,
|
||||
todayAppointments: 2, maxDaily: 6,
|
||||
skills: ['roof_inspection', 'emergency_tarp'],
|
||||
skills: ['sk_customer_comms', 'sk_retail_estimate', 'sk_roof_inspection'],
|
||||
performanceScore: 88, rating: 4.9, closeRate: 76,
|
||||
},
|
||||
{
|
||||
id: 'REP-03', name: 'Tom Bradley', initials: 'TB',
|
||||
id: 'REP-03', personId: 'e3', name: 'Travis Boone', initials: 'TB',
|
||||
status: 'busy',
|
||||
currentLat: 33.0389, currentLng: -96.7401,
|
||||
todayAppointments: 5, maxDaily: 6,
|
||||
skills: ['retail_estimate', 'roof_inspection'],
|
||||
skills: ['sk_customer_comms', 'sk_retail_estimate', 'sk_roof_inspection'],
|
||||
performanceScore: 79, rating: 4.5, closeRate: 68,
|
||||
},
|
||||
{
|
||||
id: 'REP-04', name: 'Nina Patel', initials: 'NP',
|
||||
id: 'REP-04', personId: 'e4', name: 'Shelby Greer', initials: 'SG',
|
||||
status: 'available',
|
||||
currentLat: 33.0516, currentLng: -96.7512,
|
||||
todayAppointments: 1, maxDaily: 6,
|
||||
skills: ['insurance_claim', 'roof_inspection', 'emergency_tarp'],
|
||||
skills: ['sk_roof_inspection', 'sk_insurance_claim', 'sk_emergency_tarp'],
|
||||
performanceScore: 91, rating: 4.7, closeRate: 79,
|
||||
},
|
||||
{
|
||||
id: 'REP-05', name: 'Derek Walsh', initials: 'DW',
|
||||
id: 'REP-05', personId: 'e5', name: 'Dalton Pruitt', initials: 'DP',
|
||||
status: 'en_route',
|
||||
currentLat: 33.0198, currentLng: -96.7234,
|
||||
todayAppointments: 4, maxDaily: 6,
|
||||
skills: ['retail_estimate', 'roof_inspection'],
|
||||
skills: ['sk_customer_comms', 'sk_retail_estimate', 'sk_roof_inspection'],
|
||||
performanceScore: 82, rating: 4.6, closeRate: 74,
|
||||
},
|
||||
];
|
||||
@@ -4706,7 +4706,7 @@ const DISPATCH_LEADS_INITIAL = [
|
||||
id: 'LD-1003', source: 'canvassing', leadType: 'insurance_claim', urgency: 'high',
|
||||
customer: { name: 'Robert Chen', phone: '(972) 555-1003', email: 'robert.chen@outlook.com' },
|
||||
property: { address: '1234 Oak Creek Blvd', city: 'Plano', state: 'TX', zip: '75075', lat: 33.0421, lng: -96.7138 },
|
||||
canvassedBy: { agentId: 'U-05', name: 'Marcus Webb' },
|
||||
canvassedBy: { agentId: 'e1', name: 'Cody Tatum' },
|
||||
notes: 'Filed insurance claim after hail event 3/18. Adjuster visit scheduled 3/28 — needs estimate in hand beforehand. Cooperative and responsive.',
|
||||
estimatedDuration: 45, status: 'assigned', arrivedMinsAgo: 22, assignedRepId: 'REP-01',
|
||||
},
|
||||
@@ -4738,7 +4738,7 @@ const DISPATCH_LEADS_INITIAL = [
|
||||
id: 'LD-1007', source: 'canvassing', leadType: 'retail_estimate', urgency: 'standard',
|
||||
customer: { name: 'David Park', phone: '(972) 555-1007', email: 'dpark.plano@gmail.com' },
|
||||
property: { address: '2200 Alma Dr', city: 'Plano', state: 'TX', zip: '75075', lat: 33.0516, lng: -96.7289 },
|
||||
canvassedBy: { agentId: 'U-07', name: 'Priya Nair' },
|
||||
canvassedBy: { agentId: 'e2', name: 'Hannah Reyes' },
|
||||
notes: 'Customer confirmed appointment. Wants two options: repair patch vs full replacement. Existing roof is 19 years old.',
|
||||
estimatedDuration: 30, status: 'confirmed', arrivedMinsAgo: 62, assignedRepId: 'REP-04',
|
||||
},
|
||||
@@ -4770,7 +4770,7 @@ const DISPATCH_LEADS_INITIAL = [
|
||||
id: 'LD-1011', source: 'canvassing', leadType: 'insurance_claim', urgency: 'high',
|
||||
customer: { name: 'Michael Anderson', phone: '(972) 555-1011', email: 'michael.a@outlook.com' },
|
||||
property: { address: '1800 Jupiter Rd', city: 'Plano', state: 'TX', zip: '75074', lat: 33.0267, lng: -96.7102 },
|
||||
canvassedBy: { agentId: 'U-05', name: 'Marcus Webb' },
|
||||
canvassedBy: { agentId: 'e1', name: 'Cody Tatum' },
|
||||
notes: 'Multiple hail impacts on canvass route. Customer receptive, confirmed hail event on property. Adjuster not yet contacted — walk them through the process.',
|
||||
estimatedDuration: 60, status: 'unassigned', arrivedMinsAgo: 11, assignedRepId: null,
|
||||
},
|
||||
@@ -4842,284 +4842,310 @@ export const MOCK_HAIL_HISTORY = {
|
||||
export const DISPATCH_RECOMMENDATIONS = {
|
||||
'LD-1001': [
|
||||
{
|
||||
// LD-1001 leadType: emergency_tarp — REP-04 = Shelby Greer (e4), sk_emergency_tarp: 78
|
||||
repId: 'REP-04', score: 91, slotStart: '1:30 PM', slotEnd: '2:30 PM',
|
||||
distanceMi: '2.1',
|
||||
factors: { proximity: 88, driveTime: 90, calendarFit: 95, weather: 90, skillMatch: 100 },
|
||||
reasons: ['Closest eligible rep — 2.1 mi', '12 min drive time estimated', 'Insurance claim certified', 'Buffer preserved before next appointment'],
|
||||
stormReasons: ['Lightning risk before 2 PM — slot pushed to 1:30 PM', 'Rep carries emergency tarp kit'],
|
||||
aiInsight: 'Calendar and proximity align perfectly — earliest safe window before afternoon storm risk',
|
||||
factors: { proximity: 88, driveTime: 90, calendarFit: 95, weather: 90, skillMatch: 78 },
|
||||
reasons: ['Closest eligible rep — 2.1 mi', '12 min drive time estimated', 'Emergency Tarp 78/100 — storm-ready', 'Carries drone + tarp kit + moisture meter', 'Buffer preserved before next appointment'],
|
||||
stormReasons: ['Lightning risk before 2 PM — slot pushed to 1:30 PM', 'Shelby carries a tarp kit and moisture meter for post-tarp verification'],
|
||||
aiInsight: 'Shelby scores 78 on Emergency Tarp and carries a tarp kit and moisture meter — calendar and proximity align perfectly for the earliest safe window before afternoon storm risk.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0516, -96.7512], [33.0612, -96.7484], [33.0708, -96.7456]],
|
||||
},
|
||||
{
|
||||
// REP-02 = Hannah Reyes (e2), sk_emergency_tarp: 55
|
||||
repId: 'REP-02', score: 79, slotStart: '3:00 PM', slotEnd: '4:00 PM',
|
||||
distanceMi: '3.8',
|
||||
factors: { proximity: 72, driveTime: 75, calendarFit: 82, weather: 80, skillMatch: 85 },
|
||||
reasons: ['Available at 3 PM', '18 min drive — moderate traffic', 'Roof inspection certified'],
|
||||
factors: { proximity: 72, driveTime: 75, calendarFit: 82, weather: 80, skillMatch: 55 },
|
||||
reasons: ['Available at 3 PM', '18 min drive — moderate traffic', 'Emergency Tarp 55/100 — baseline capable', 'Carries ladder rack for access'],
|
||||
stormReasons: ['Afternoon slot carries weather risk — monitor closely'],
|
||||
aiInsight: 'Solid backup with roof certification — afternoon slot viable but weather requires monitoring',
|
||||
aiInsight: 'Hannah scores 55 on Emergency Tarp — solid backup if Shelby is occupied, but afternoon slot requires weather monitoring.',
|
||||
conflictFlag: 'Post-3 PM weather risk — confirm conditions before dispatch',
|
||||
routePath: [[33.0812, -96.7234], [33.0760, -96.7345], [33.0708, -96.7456]],
|
||||
},
|
||||
{
|
||||
// REP-01 = Cody Tatum (e1), sk_emergency_tarp: 92
|
||||
repId: 'REP-01', score: 71, slotStart: '4:30 PM', slotEnd: '5:30 PM',
|
||||
distanceMi: '5.2',
|
||||
factors: { proximity: 62, driveTime: 60, calendarFit: 78, weather: 70, skillMatch: 100 },
|
||||
reasons: ['Available later in the day', '24 min drive from current location', 'High performer — score 94'],
|
||||
factors: { proximity: 62, driveTime: 60, calendarFit: 78, weather: 70, skillMatch: 92 },
|
||||
reasons: ['Available later in the day', '24 min drive from current location', 'Emergency Tarp 92/100 — highest score on team', 'Carries tarp kit + drone for aerial damage assessment'],
|
||||
stormReasons: ['Late afternoon — weather conditions improving'],
|
||||
aiInsight: 'High performer but distance and late slot reduce overall optimality for this job type',
|
||||
aiInsight: 'Cody scores 92 on Emergency Tarp and carries a tarp kit — highest skill match, but the 5.2 mi drive and late slot make him the third-best option for this time-sensitive job.',
|
||||
conflictFlag: '20 min buffer only after completion — schedule at risk if job runs long',
|
||||
routePath: [[33.0612, -96.7891], [33.0660, -96.7674], [33.0708, -96.7456]],
|
||||
},
|
||||
],
|
||||
'LD-1002': [
|
||||
{
|
||||
// LD-1002 leadType: roof_inspection — REP-01 = Cody Tatum (e1), sk_roof_inspection: 81
|
||||
repId: 'REP-01', score: 88, slotStart: '2:00 PM', slotEnd: '2:45 PM',
|
||||
distanceMi: '1.4',
|
||||
factors: { proximity: 92, driveTime: 88, calendarFit: 85, weather: 88, skillMatch: 100 },
|
||||
reasons: ['Closest rep — 1.4 mi from lead location', '8 min drive time', 'Buffer maintained after current job'],
|
||||
stormReasons: ['Weather clear until 3 PM — slot timing is safe', 'Rep familiar with West Plano territory'],
|
||||
aiInsight: 'Nearest eligible rep with strong calendar fit — weather window closes cleanly after completion',
|
||||
factors: { proximity: 92, driveTime: 88, calendarFit: 85, weather: 88, skillMatch: 81 },
|
||||
reasons: ['Closest rep — 1.4 mi from lead location', '8 min drive time', 'Roof Inspection 81/100 — carrier-ready documentation', 'Carries drone for aerial scan on steep slopes', 'Buffer maintained after current job'],
|
||||
stormReasons: ['Weather clear until 3 PM — slot timing is safe', 'Cody runs a DJI drone on every steep-slope job'],
|
||||
aiInsight: 'Cody scores 81 on Roof Inspection and flies a drone on every steep-slope job — nearest eligible rep with a clean weather window and strong documentation skills.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0612, -96.7891], [33.0632, -96.7956], [33.0652, -96.8021]],
|
||||
},
|
||||
{
|
||||
// REP-04 = Shelby Greer (e4), sk_roof_inspection: 88
|
||||
repId: 'REP-04', score: 74, slotStart: '3:30 PM', slotEnd: '4:15 PM',
|
||||
distanceMi: '4.1',
|
||||
factors: { proximity: 70, driveTime: 68, calendarFit: 85, weather: 72, skillMatch: 100 },
|
||||
reasons: ['Available at 3:30 PM', '22 min drive from current position', 'Insurance claim certified'],
|
||||
factors: { proximity: 70, driveTime: 68, calendarFit: 85, weather: 72, skillMatch: 88 },
|
||||
reasons: ['Available at 3:30 PM', '22 min drive from current position', 'Roof Inspection 88/100 — highest roof score on team', 'Carries drone + moisture meter for subsurface checks'],
|
||||
stormReasons: ['Afternoon slot — weather risk moderate after 3 PM'],
|
||||
aiInsight: 'Certified fallback with open afternoon — drive time and weather reduce confidence vs. top pick',
|
||||
aiInsight: 'Shelby scores 88 on Roof Inspection — team-best score — and brings a moisture meter for subsurface checks. Drive time and afternoon weather are the only detractors.',
|
||||
conflictFlag: 'Afternoon weather window tight — start punctually or reschedule',
|
||||
routePath: [[33.0516, -96.7512], [33.0584, -96.7767], [33.0652, -96.8021]],
|
||||
},
|
||||
],
|
||||
'LD-1003': [
|
||||
{
|
||||
// LD-1003 leadType: insurance_claim — REP-01 = Cody Tatum (e1), sk_insurance_claim: 88
|
||||
repId: 'REP-01', score: 87, slotStart: '11:00 AM', slotEnd: '11:45 AM',
|
||||
distanceMi: '2.8',
|
||||
factors: { proximity: 85, driveTime: 88, calendarFit: 90, weather: 85, skillMatch: 100 },
|
||||
reasons: ['Currently assigned — optimal for continuity', '11 min drive from current stop', 'Insurance claim specialist'],
|
||||
factors: { proximity: 85, driveTime: 88, calendarFit: 90, weather: 85, skillMatch: 88 },
|
||||
reasons: ['Currently assigned — optimal for continuity', '11 min drive from current stop', 'Insurance Claim 88/100 — carrier-certified supplement writer', 'Carries drone for aerial hail documentation'],
|
||||
stormReasons: ['Morning slot — no weather concerns'],
|
||||
aiInsight: 'Continuity assignment maximizes close probability — same rep builds on prior customer rapport',
|
||||
aiInsight: 'Cody scores 88 on Insurance Claim and flies a drone for every hail job — continuity assignment maximizes close probability with prior customer rapport already established.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0612, -96.7891], [33.0517, -96.7515], [33.0421, -96.7138]],
|
||||
},
|
||||
{
|
||||
// REP-05 = Dalton Pruitt (e5), sk_insurance_claim: 60
|
||||
repId: 'REP-05', score: 67, slotStart: '1:00 PM', slotEnd: '1:45 PM',
|
||||
distanceMi: '4.4',
|
||||
factors: { proximity: 65, driveTime: 62, calendarFit: 72, weather: 75, skillMatch: 60 },
|
||||
reasons: ['Available afternoon slot', '19 min drive', 'Less specialized — retail estimate primary skill'],
|
||||
reasons: ['Available afternoon slot', '19 min drive', 'Insurance Claim 60/100 — functional but developing', 'Retail estimate is Dalton\'s primary skill (87/100)'],
|
||||
stormReasons: ['Afternoon — monitor weather after 1 PM'],
|
||||
aiInsight: 'Capable fallback but skill mismatch lowers confidence for insurance claim type',
|
||||
conflictFlag: 'Skill mismatch — retail primary, insurance secondary skill only',
|
||||
aiInsight: 'Dalton scores 60 on Insurance Claim versus Cody\'s 88 — capable fallback but the skill gap lowers confidence for this adjuster-prep appointment.',
|
||||
conflictFlag: 'Skill gap — Dalton\'s Insurance Claim score (60) is 28 points below primary rep',
|
||||
routePath: [[33.0198, -96.7234], [33.0310, -96.7186], [33.0421, -96.7138]],
|
||||
},
|
||||
],
|
||||
'LD-1004': [
|
||||
{
|
||||
// LD-1004 leadType: retail_estimate — REP-03 = Travis Boone (e3), sk_retail_estimate: 50
|
||||
repId: 'REP-03', score: 95, slotStart: '10:30 AM', slotEnd: '11:00 AM',
|
||||
distanceMi: '0.6',
|
||||
factors: { proximity: 98, driveTime: 97, calendarFit: 88, weather: 95, skillMatch: 100 },
|
||||
reasons: ['0.6 mi away — optimal proximity', '4 min drive time', 'Retail estimate specialist'],
|
||||
factors: { proximity: 98, driveTime: 97, calendarFit: 88, weather: 95, skillMatch: 50 },
|
||||
reasons: ['0.6 mi away — optimal proximity', '4 min drive time', 'Retail Estimate 50/100 — developing skill', 'Customer Comms 67/100 — good rapport builder for new clients'],
|
||||
stormReasons: ['Morning slot — conditions favorable'],
|
||||
aiInsight: 'Near-perfect assignment — virtually on-site with ideal skill set and favorable morning conditions',
|
||||
conflictFlag: null,
|
||||
aiInsight: 'Travis scores 50 on Retail Estimate — still building this skill — but his proximity (0.6 mi, 4 min) and open morning calendar make him the best available option. Coach him post-appointment.',
|
||||
conflictFlag: 'Skill score moderate — pair with follow-up review for estimate accuracy',
|
||||
routePath: [[33.0389, -96.7401], [33.0389, -96.7368], [33.0389, -96.7334]],
|
||||
},
|
||||
{
|
||||
// REP-05 = Dalton Pruitt (e5), sk_retail_estimate: 87
|
||||
repId: 'REP-05', score: 73, slotStart: '2:00 PM', slotEnd: '2:30 PM',
|
||||
distanceMi: '3.3',
|
||||
factors: { proximity: 70, driveTime: 68, calendarFit: 80, weather: 72, skillMatch: 80 },
|
||||
reasons: ['Available afternoon', '16 min drive', 'Retail estimate capable'],
|
||||
factors: { proximity: 70, driveTime: 68, calendarFit: 80, weather: 72, skillMatch: 87 },
|
||||
reasons: ['Available afternoon', '16 min drive', 'Retail Estimate 87/100 — strong closer on cash jobs', 'Customer Comms 88/100 — high rapport score'],
|
||||
stormReasons: ['Afternoon slot — watch post-2 PM weather'],
|
||||
aiInsight: 'Retail-capable with open afternoon — viable if top pick becomes unavailable',
|
||||
aiInsight: 'Dalton scores 87 on Retail Estimate — far stronger skill fit than Travis — but the 3.3 mi drive and afternoon timing drop his overall score. Upgrade to him if Travis\'s morning slot falls through.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0198, -96.7234], [33.0294, -96.7284], [33.0389, -96.7334]],
|
||||
},
|
||||
],
|
||||
'LD-1005': [
|
||||
{
|
||||
// LD-1005 leadType: roof_inspection — REP-02 = Hannah Reyes (e2), sk_roof_inspection: 70
|
||||
repId: 'REP-02', score: 94, slotStart: '12:00 PM', slotEnd: '12:45 PM',
|
||||
distanceMi: '0.3',
|
||||
factors: { proximity: 97, driveTime: 96, calendarFit: 90, weather: 92, skillMatch: 95 },
|
||||
reasons: ['0.3 mi from lead — effectively on-site', '3 min drive time', 'Roof inspection specialist', 'Low daily load — 2 of 6 slots used'],
|
||||
stormReasons: ['Midday window — weather acceptable', 'Rep carries safety equipment'],
|
||||
aiInsight: 'Exceptional proximity with light workload — highest-confidence dispatch of the day',
|
||||
factors: { proximity: 97, driveTime: 96, calendarFit: 90, weather: 92, skillMatch: 70 },
|
||||
reasons: ['0.3 mi from lead — effectively on-site', '3 min drive time', 'Roof Inspection 70/100 — competent on standard inspections', 'Carries pitch gauge + measuring wheel for accurate slope docs', 'Low daily load — 2 of 6 slots used'],
|
||||
stormReasons: ['Midday window — weather acceptable', 'Hannah carries pitch gauge for slope documentation'],
|
||||
aiInsight: 'Hannah scores 70 on Roof Inspection and carries a pitch gauge and measuring wheel — exceptional proximity with a light workload makes this the highest-confidence dispatch of the day.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0812, -96.7234], [33.0812, -96.7378], [33.0812, -96.7521]],
|
||||
},
|
||||
{
|
||||
// REP-04 = Shelby Greer (e4), sk_roof_inspection: 88
|
||||
repId: 'REP-04', score: 77, slotStart: '2:30 PM', slotEnd: '3:15 PM',
|
||||
distanceMi: '3.6',
|
||||
factors: { proximity: 72, driveTime: 70, calendarFit: 88, weather: 78, skillMatch: 90 },
|
||||
reasons: ['Available at 2:30 PM', '17 min drive', 'Roof inspection certified'],
|
||||
factors: { proximity: 72, driveTime: 70, calendarFit: 88, weather: 78, skillMatch: 88 },
|
||||
reasons: ['Available at 2:30 PM', '17 min drive', 'Roof Inspection 88/100 — team-best score', 'Carries drone + moisture meter for thorough assessment'],
|
||||
stormReasons: ['Afternoon — post-3 PM weather worsening, start punctually'],
|
||||
aiInsight: 'Certified backup with clean afternoon window — must start on time before weather closes in',
|
||||
aiInsight: 'Shelby scores 88 on Roof Inspection — best on the team — and brings a moisture meter. The drive time and weather window are the only reasons she trails Hannah here.',
|
||||
conflictFlag: 'Start before 3 PM — weather deteriorates sharply after',
|
||||
routePath: [[33.0516, -96.7512], [33.0664, -96.7517], [33.0812, -96.7521]],
|
||||
},
|
||||
],
|
||||
'LD-1006': [
|
||||
{
|
||||
// LD-1006 leadType: insurance_claim — REP-01 = Cody Tatum (e1), sk_insurance_claim: 88
|
||||
repId: 'REP-01', score: 83, slotStart: '3:00 PM', slotEnd: '4:00 PM',
|
||||
distanceMi: '3.1',
|
||||
factors: { proximity: 80, driveTime: 78, calendarFit: 85, weather: 82, skillMatch: 100 },
|
||||
reasons: ['Best available slot — 3 PM', '14 min drive from current route', 'Insurance claim specialist'],
|
||||
stormReasons: ['Wind advisory active — exterior inspection may need delay', 'Insurance claim can proceed indoors'],
|
||||
aiInsight: 'Best certified specialist available — indoor claim process can proceed despite active wind advisory',
|
||||
factors: { proximity: 80, driveTime: 78, calendarFit: 85, weather: 82, skillMatch: 88 },
|
||||
reasons: ['Best available slot — 3 PM', '14 min drive from current route', 'Insurance Claim 88/100 — supplement-certified', 'Carries drone for aerial ridge-cap documentation'],
|
||||
stormReasons: ['Wind advisory active — exterior inspection may need delay', 'Cody can advance the claim indoors then fly drone when winds subside'],
|
||||
aiInsight: 'Cody scores 88 on Insurance Claim and carries a drone for aerial ridge-cap documentation — best certified specialist available; indoor claim work can proceed despite the active wind advisory.',
|
||||
conflictFlag: 'Wind advisory active — verify exterior conditions before starting roof portion',
|
||||
routePath: [[33.0612, -96.7891], [33.0773, -96.7947], [33.0934, -96.8002]],
|
||||
},
|
||||
{
|
||||
// REP-02 = Hannah Reyes (e2), sk_insurance_claim: 65
|
||||
repId: 'REP-02', score: 69, slotStart: '4:30 PM', slotEnd: '5:30 PM',
|
||||
distanceMi: '5.8',
|
||||
factors: { proximity: 65, driveTime: 62, calendarFit: 75, weather: 68, skillMatch: 85 },
|
||||
reasons: ['Late afternoon availability', '26 min drive', 'Roof inspection skilled'],
|
||||
factors: { proximity: 65, driveTime: 62, calendarFit: 75, weather: 68, skillMatch: 65 },
|
||||
reasons: ['Late afternoon availability', '26 min drive', 'Insurance Claim 65/100 — capable but secondary skill', 'Customer Comms 91/100 — strong at keeping clients calm during complex claims'],
|
||||
stormReasons: ['Late afternoon — conditions deteriorating, not recommended'],
|
||||
aiInsight: 'Low-confidence option — weather and distance combine unfavorably for late afternoon exterior work',
|
||||
aiInsight: 'Hannah scores 65 on Insurance Claim (23 points below Cody) and the 4:30 PM slot lands in deteriorating conditions — low-confidence option, use only if Cody is unavailable.',
|
||||
conflictFlag: 'Not recommended — conditions deteriorating by 4:30 PM, daylight limited',
|
||||
routePath: [[33.0812, -96.7234], [33.0873, -96.7618], [33.0934, -96.8002]],
|
||||
},
|
||||
],
|
||||
'LD-1007': [
|
||||
{
|
||||
// LD-1007 leadType: retail_estimate — REP-04 = Shelby Greer (e4), sk_retail_estimate: 72
|
||||
repId: 'REP-04', score: 87, slotStart: '11:30 AM', slotEnd: '12:00 PM',
|
||||
distanceMi: '1.5',
|
||||
factors: { proximity: 90, driveTime: 88, calendarFit: 92, weather: 90, skillMatch: 80 },
|
||||
reasons: ['1.5 mi away — close proximity', '9 min drive time', 'Low daily load', 'Buffer before afternoon appointments'],
|
||||
factors: { proximity: 90, driveTime: 88, calendarFit: 92, weather: 90, skillMatch: 72 },
|
||||
reasons: ['1.5 mi away — close proximity', '9 min drive time', 'Retail Estimate 72/100 — solid on reroof presentations', 'Low daily load', 'Buffer before afternoon appointments'],
|
||||
stormReasons: ['Morning window — safe conditions'],
|
||||
aiInsight: 'Light daily load with close proximity — midday window maximizes buffer for afternoon pipeline',
|
||||
aiInsight: 'Shelby scores 72 on Retail Estimate and has light calendar load — close proximity and a clean morning window make this an efficient midday dispatch.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0516, -96.7512], [33.0516, -96.7401], [33.0516, -96.7289]],
|
||||
},
|
||||
{
|
||||
// REP-03 = Travis Boone (e3), sk_retail_estimate: 50
|
||||
repId: 'REP-03', score: 78, slotStart: '1:30 PM', slotEnd: '2:00 PM',
|
||||
distanceMi: '2.9',
|
||||
factors: { proximity: 78, driveTime: 75, calendarFit: 70, weather: 82, skillMatch: 100 },
|
||||
reasons: ['Retail estimate specialist', '12 min drive', 'Near current work site'],
|
||||
factors: { proximity: 78, driveTime: 75, calendarFit: 70, weather: 82, skillMatch: 50 },
|
||||
reasons: ['Near current work site — 2.9 mi', '12 min drive', 'Retail Estimate 50/100 — developing skill', 'Customer Comms 67/100 — personable with new homeowners'],
|
||||
stormReasons: ['Early afternoon — conditions acceptable'],
|
||||
aiInsight: 'Specialist-level skill match but heavier daily load reduces calendar fit score',
|
||||
aiInsight: 'Travis scores 50 on Retail Estimate — still building this skill set — and his calendar is already heavy at 5 appointments. Backup only; upgrade to Dalton (87/100) if Shelby is pulled.',
|
||||
conflictFlag: '5 appointments today — buffer is tight if any job runs over',
|
||||
routePath: [[33.0389, -96.7401], [33.0453, -96.7345], [33.0516, -96.7289]],
|
||||
},
|
||||
],
|
||||
'LD-1008': [
|
||||
{
|
||||
// LD-1008 leadType: roof_inspection — REP-04 = Shelby Greer (e4), sk_roof_inspection: 88
|
||||
repId: 'REP-04', score: 86, slotStart: '2:00 PM', slotEnd: '2:45 PM',
|
||||
distanceMi: '2.7',
|
||||
factors: { proximity: 84, driveTime: 85, calendarFit: 90, weather: 85, skillMatch: 95 },
|
||||
reasons: ['2.7 mi from lead — manageable drive', '15 min estimated travel', 'Roof inspection certified', 'Open afternoon slot'],
|
||||
factors: { proximity: 84, driveTime: 85, calendarFit: 90, weather: 85, skillMatch: 88 },
|
||||
reasons: ['2.7 mi from lead — manageable drive', '15 min estimated travel', 'Roof Inspection 88/100 — team-best score', 'Carries drone + moisture meter for comprehensive assessment', 'Open afternoon slot'],
|
||||
stormReasons: ['Weather acceptable until 3:30 PM', 'Book for 2 PM to maximize safe window'],
|
||||
aiInsight: 'Certified for roof inspection with open slot — 2 PM booking maximizes safe weather window',
|
||||
aiInsight: 'Shelby scores 88 on Roof Inspection — highest on the team — and carries a drone and moisture meter for a thorough assessment. 2 PM booking maximizes the safe weather window.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0516, -96.7512], [33.0630, -96.7562], [33.0744, -96.7612]],
|
||||
},
|
||||
{
|
||||
// REP-02 = Hannah Reyes (e2), sk_roof_inspection: 70
|
||||
repId: 'REP-02', score: 75, slotStart: '3:30 PM', slotEnd: '4:15 PM',
|
||||
distanceMi: '4.1',
|
||||
factors: { proximity: 72, driveTime: 70, calendarFit: 82, weather: 74, skillMatch: 90 },
|
||||
reasons: ['Available at 3:30 PM', '19 min drive', 'Roof inspection specialist'],
|
||||
factors: { proximity: 72, driveTime: 70, calendarFit: 82, weather: 74, skillMatch: 70 },
|
||||
reasons: ['Available at 3:30 PM', '19 min drive', 'Roof Inspection 70/100 — competent on standard inspections', 'Carries pitch gauge for slope documentation'],
|
||||
stormReasons: ['Late afternoon — weather risk elevated after 3 PM'],
|
||||
aiInsight: 'Roof specialist with afternoon availability — weather risk increases as slot approaches 4 PM',
|
||||
aiInsight: 'Hannah scores 70 on Roof Inspection and carries a pitch gauge — solid fallback but the 4.1 mi drive and weather risk in the 3:30 PM slot lower confidence.',
|
||||
conflictFlag: '15 min buffer after completion — schedule may be tight if delayed',
|
||||
routePath: [[33.0812, -96.7234], [33.0778, -96.7423], [33.0744, -96.7612]],
|
||||
},
|
||||
{
|
||||
// REP-01 = Cody Tatum (e1), sk_roof_inspection: 81
|
||||
repId: 'REP-01', score: 68, slotStart: '5:00 PM', slotEnd: '5:45 PM',
|
||||
distanceMi: '5.5',
|
||||
factors: { proximity: 62, driveTime: 58, calendarFit: 70, weather: 68, skillMatch: 80 },
|
||||
reasons: ['End of day slot only', '22 min drive', 'High performer — score 94'],
|
||||
factors: { proximity: 62, driveTime: 58, calendarFit: 70, weather: 68, skillMatch: 81 },
|
||||
reasons: ['End of day slot only', '22 min drive', 'Roof Inspection 81/100 — strong documentation skills', 'Carries drone for aerial scan'],
|
||||
stormReasons: ['Evening — conditions improving but daylight limited'],
|
||||
aiInsight: 'High performer but 5 PM slot limits daylight for roof work — use only as last resort',
|
||||
aiInsight: 'Cody scores 81 on Roof Inspection and carries a drone, but the 5 PM slot limits daylight for exterior work — use only as a last resort.',
|
||||
conflictFlag: 'Daylight limited at 5 PM — roof inspection may be incomplete',
|
||||
routePath: [[33.0612, -96.7891], [33.0678, -96.7752], [33.0744, -96.7612]],
|
||||
},
|
||||
],
|
||||
'LD-1009': [
|
||||
{
|
||||
// LD-1009 leadType: emergency_tarp — REP-05 = Dalton Pruitt (e5), sk_emergency_tarp: 45
|
||||
repId: 'REP-05', score: 97, slotStart: '11:00 AM', slotEnd: '12:30 PM',
|
||||
distanceMi: '0.8',
|
||||
factors: { proximity: 99, driveTime: 98, calendarFit: 95, weather: 95, skillMatch: 90 },
|
||||
reasons: ['0.8 mi away — nearest rep on site', '5 min drive time', 'Emergency certified', 'PRIORITY: emergency tarp needed'],
|
||||
stormReasons: ['EMERGENCY — dispatch immediately', 'Rep stocked with emergency tarp materials'],
|
||||
aiInsight: 'PRIORITY dispatch — nearest certified rep with emergency materials on hand, 5 min ETA',
|
||||
conflictFlag: null,
|
||||
factors: { proximity: 99, driveTime: 98, calendarFit: 95, weather: 95, skillMatch: 45 },
|
||||
reasons: ['0.8 mi away — nearest rep on site', '5 min drive time', 'Emergency Tarp 45/100 — limited experience, proximity overrides skill gap', 'Carries ladder rack for roof access', 'PRIORITY: active leak, family with newborn on premises'],
|
||||
stormReasons: ['EMERGENCY — dispatch immediately', 'Dalton is physically nearest — 5 min ETA critical for active leak'],
|
||||
aiInsight: 'PRIORITY dispatch — Dalton scores 45 on Emergency Tarp but his 0.8 mi proximity (5 min ETA) is critical for this active-leak emergency. Dispatch now and coordinate with Cody (92/100) or Shelby (78/100) for backup if the job escalates.',
|
||||
conflictFlag: 'Skill score limited (45/100) — flag for supervisor oversight; escalate to Cody Tatum if tarp complexity exceeds Dalton\'s capability',
|
||||
routePath: [[33.0198, -96.7234], [33.0198, -96.7112], [33.0198, -96.6989]],
|
||||
},
|
||||
{
|
||||
// REP-03 = Travis Boone (e3), sk_emergency_tarp: 33
|
||||
repId: 'REP-03', score: 71, slotStart: '1:00 PM', slotEnd: '2:30 PM',
|
||||
distanceMi: '4.6',
|
||||
factors: { proximity: 65, driveTime: 62, calendarFit: 75, weather: 72, skillMatch: 75 },
|
||||
reasons: ['Backup option — 5 appointments today', '21 min drive', 'Roof inspection capable'],
|
||||
factors: { proximity: 65, driveTime: 62, calendarFit: 75, weather: 72, skillMatch: 33 },
|
||||
reasons: ['Backup option — 5 appointments today', '21 min drive', 'Emergency Tarp 33/100 — minimal hands-on experience', 'Carries only tape measure + clipboard — no tarp materials'],
|
||||
stormReasons: ['Secondary option — use only if REP-05 unavailable'],
|
||||
aiInsight: 'Emergency backup only — heavier daily load and longer drive make this a secondary option',
|
||||
conflictFlag: '5 appointments today — minimal buffer if any prior job overruns',
|
||||
aiInsight: 'Travis scores 33 on Emergency Tarp and carries no tarp materials — emergency backup only. Heavier daily load (5 appointments) and 4.6 mi drive make this a last-resort option.',
|
||||
conflictFlag: '5 appointments today — minimal buffer if any prior job overruns; low tarp skill (33/100)',
|
||||
routePath: [[33.0389, -96.7401], [33.0294, -96.7195], [33.0198, -96.6989]],
|
||||
},
|
||||
],
|
||||
'LD-1010': [
|
||||
{
|
||||
// LD-1010 leadType: retail_estimate — REP-01 = Cody Tatum (e1), sk_retail_estimate: 74
|
||||
repId: 'REP-01', score: 84, slotStart: '2:30 PM', slotEnd: '3:00 PM',
|
||||
distanceMi: '2.9',
|
||||
factors: { proximity: 82, driveTime: 80, calendarFit: 88, weather: 84, skillMatch: 80 },
|
||||
reasons: ['Best proximity match — 2.9 mi', '16 min drive', 'High performer — score 94', 'Manageable daily load'],
|
||||
factors: { proximity: 82, driveTime: 80, calendarFit: 88, weather: 84, skillMatch: 74 },
|
||||
reasons: ['Best proximity match — 2.9 mi', '16 min drive', 'Retail Estimate 74/100 — solid on material-quality presentations', 'Manageable daily load'],
|
||||
stormReasons: ['Afternoon slot — monitor weather', 'Retail estimate can proceed partially indoors'],
|
||||
aiInsight: 'Top performer with manageable load — retail estimate can proceed indoors if afternoon weather shifts',
|
||||
aiInsight: 'Cody scores 74 on Retail Estimate — strong enough for an architectural shingle consultation — and has manageable load. The estimate can move indoors if afternoon weather shifts.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0612, -96.7891], [33.0750, -96.7824], [33.0888, -96.7756]],
|
||||
},
|
||||
{
|
||||
// REP-02 = Hannah Reyes (e2), sk_retail_estimate: 89
|
||||
repId: 'REP-02', score: 72, slotStart: '4:00 PM', slotEnd: '4:30 PM',
|
||||
distanceMi: '4.8',
|
||||
factors: { proximity: 70, driveTime: 68, calendarFit: 78, weather: 70, skillMatch: 80 },
|
||||
reasons: ['Available late afternoon', '22 min drive', 'Roof inspection certified'],
|
||||
factors: { proximity: 70, driveTime: 68, calendarFit: 78, weather: 70, skillMatch: 89 },
|
||||
reasons: ['Available late afternoon', '22 min drive', 'Retail Estimate 89/100 — top retail closer on team', 'Customer Comms 91/100 — excels at price-sensitive consultations'],
|
||||
stormReasons: ['4 PM slot — weather conditions deteriorating, not ideal'],
|
||||
aiInsight: 'Viable backup but 4 PM timing and weather trend reduce confidence for exterior estimate',
|
||||
aiInsight: 'Hannah scores 89 on Retail Estimate — best on the team for cash-pay closes — but the 4 PM timing and 4.8 mi drive reduce confidence. She is the better skill fit if Cody\'s slot becomes unavailable.',
|
||||
conflictFlag: '4 PM slot — low daylight and deteriorating conditions for exterior work',
|
||||
routePath: [[33.0812, -96.7234], [33.0850, -96.7495], [33.0888, -96.7756]],
|
||||
},
|
||||
],
|
||||
'LD-1011': [
|
||||
{
|
||||
// LD-1011 leadType: insurance_claim — REP-05 = Dalton Pruitt (e5), sk_insurance_claim: 60
|
||||
repId: 'REP-05', score: 89, slotStart: '12:30 PM', slotEnd: '1:30 PM',
|
||||
distanceMi: '1.6',
|
||||
factors: { proximity: 90, driveTime: 88, calendarFit: 85, weather: 88, skillMatch: 90 },
|
||||
reasons: ['Closest rep — 1.6 mi', '9 min drive time', 'Insurance claim proficient', 'Midday slot timing is optimal'],
|
||||
stormReasons: ['Midday window — acceptable conditions', 'Insurance claim can be initiated outdoors then moved inside'],
|
||||
aiInsight: 'Close proximity with optimal midday timing — insurance initiation can flex indoors if needed',
|
||||
factors: { proximity: 90, driveTime: 88, calendarFit: 85, weather: 88, skillMatch: 60 },
|
||||
reasons: ['Closest rep — 1.6 mi', '9 min drive time', 'Insurance Claim 60/100 — can walk customer through initial adjuster steps', 'Customer Comms 88/100 — high rapport for new hail claimants', 'Midday slot timing is optimal'],
|
||||
stormReasons: ['Midday window — acceptable conditions', 'Insurance claim initiation can flex indoors if needed'],
|
||||
aiInsight: 'Dalton scores 60 on Insurance Claim and 88 on Customer Comms — well-suited to walk this first-time claimant through the process. Proximity and midday timing optimize the slot.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0198, -96.7234], [33.0233, -96.7168], [33.0267, -96.7102]],
|
||||
},
|
||||
{
|
||||
// REP-03 = Travis Boone (e3), sk_insurance_claim: 28
|
||||
repId: 'REP-03', score: 76, slotStart: '2:00 PM', slotEnd: '3:00 PM',
|
||||
distanceMi: '3.5',
|
||||
factors: { proximity: 74, driveTime: 70, calendarFit: 78, weather: 76, skillMatch: 80 },
|
||||
reasons: ['Available at 2 PM', '18 min drive', 'Retail estimate skilled'],
|
||||
factors: { proximity: 74, driveTime: 70, calendarFit: 78, weather: 76, skillMatch: 28 },
|
||||
reasons: ['Available at 2 PM', '18 min drive', 'Insurance Claim 28/100 — early-stage skill, needs coaching on adjuster process', 'Customer Comms 67/100 — approachable demeanor'],
|
||||
stormReasons: ['Afternoon slot — conditions marginal after 2:30 PM'],
|
||||
aiInsight: 'Partial skill match with afternoon availability — conditions deteriorate mid-appointment window',
|
||||
conflictFlag: 'Skill alignment moderate — retail primary, insurance secondary only',
|
||||
aiInsight: 'Travis scores only 28 on Insurance Claim — the weakest fit for this lead type. Pair with a detailed briefing note or reassign to Cody (88/100) if Dalton\'s slot is unavailable.',
|
||||
conflictFlag: 'Significant skill gap — Insurance Claim 28/100; supervisor review recommended before dispatch',
|
||||
routePath: [[33.0389, -96.7401], [33.0328, -96.7252], [33.0267, -96.7102]],
|
||||
},
|
||||
],
|
||||
'LD-1012': [
|
||||
{
|
||||
// LD-1012 leadType: roof_inspection — REP-01 = Cody Tatum (e1), sk_roof_inspection: 81
|
||||
repId: 'REP-01', score: 92, slotStart: '10:00 AM', slotEnd: '10:45 AM',
|
||||
distanceMi: '1.7',
|
||||
factors: { proximity: 94, driveTime: 92, calendarFit: 88, weather: 92, skillMatch: 95 },
|
||||
reasons: ['Currently assigned — optimal', '1.7 mi from current position', 'Morning slot — ideal weather window', 'Insurance + retail estimate certified'],
|
||||
factors: { proximity: 94, driveTime: 92, calendarFit: 88, weather: 92, skillMatch: 81 },
|
||||
reasons: ['Currently assigned — optimal', '1.7 mi from current position', 'Roof Inspection 81/100 — strong documentation for competing-estimate rebuttal', 'Morning slot — ideal weather window', 'Carries drone for aerial measurement — differentiates vs. competitor'],
|
||||
stormReasons: ['Morning slot — safe window before any afternoon weather'],
|
||||
aiInsight: 'Morning assignment with ideal conditions — dual-certified rep maximizes flexibility for this job type',
|
||||
aiInsight: 'Cody scores 81 on Roof Inspection and flies a drone on every steep-slope job — his aerial measurement capability directly counters the competing estimate. Morning slot with ideal conditions maximizes close probability.',
|
||||
conflictFlag: null,
|
||||
routePath: [[33.0612, -96.7891], [33.0612, -96.8018], [33.0612, -96.8145]],
|
||||
},
|
||||
{
|
||||
// REP-04 = Shelby Greer (e4), sk_roof_inspection: 88
|
||||
repId: 'REP-04', score: 70, slotStart: '1:00 PM', slotEnd: '1:45 PM',
|
||||
distanceMi: '5.3',
|
||||
factors: { proximity: 65, driveTime: 62, calendarFit: 82, weather: 70, skillMatch: 85 },
|
||||
reasons: ['Afternoon availability', '24 min drive from current location', 'Roof inspection certified'],
|
||||
factors: { proximity: 65, driveTime: 62, calendarFit: 82, weather: 70, skillMatch: 88 },
|
||||
reasons: ['Afternoon availability', '24 min drive from current location', 'Roof Inspection 88/100 — team-best score, strongest for competing-estimate rebuttal', 'Carries drone + moisture meter'],
|
||||
stormReasons: ['Afternoon — conditions acceptable but watch post-2 PM'],
|
||||
aiInsight: 'Longer drive reduces score significantly — afternoon window is viable if morning rep unavailable',
|
||||
aiInsight: 'Shelby scores 88 on Roof Inspection — higher than Cody — and carries a drone and moisture meter. The 5.3 mi drive is the main drag; she is the upgrade choice if morning availability opens up.',
|
||||
conflictFlag: '24 min drive cuts into slot buffer — delays cascade to next appointment',
|
||||
routePath: [[33.0516, -96.7512], [33.0564, -96.7829], [33.0612, -96.8145]],
|
||||
},
|
||||
@@ -5465,7 +5491,7 @@ const MOCK_ESTIMATES_INITIAL = [
|
||||
total: 18450.00,
|
||||
templateId: 'certainteed_landmark',
|
||||
templateName: 'CertainTeed Landmark AR',
|
||||
estimatedBy: 'Marcus Webb',
|
||||
estimatedBy: 'Cody Tatum',
|
||||
roofArea: 28.4,
|
||||
notes: 'Hail damage from March 15 storm. Insurance claim approved.',
|
||||
},
|
||||
@@ -5491,7 +5517,7 @@ const MOCK_ESTIMATES_INITIAL = [
|
||||
total: 14800.00,
|
||||
templateId: 'atlas_glassmaster',
|
||||
templateName: 'Atlas GlassMaster',
|
||||
estimatedBy: 'Marcus Webb',
|
||||
estimatedBy: 'Cody Tatum',
|
||||
roofArea: 24.6,
|
||||
notes: null,
|
||||
},
|
||||
@@ -5530,7 +5556,7 @@ const MOCK_ESTIMATES_INITIAL = [
|
||||
total: 16900.00,
|
||||
templateId: 'atlas_stormmaster_shake',
|
||||
templateName: 'Atlas StormMaster Shake',
|
||||
estimatedBy: 'Marcus Webb',
|
||||
estimatedBy: 'Cody Tatum',
|
||||
roofArea: 26.8,
|
||||
notes: 'Impact resistant upgrade. HOA approved color: Weathered Wood.',
|
||||
},
|
||||
@@ -5569,7 +5595,7 @@ const MOCK_ESTIMATES_INITIAL = [
|
||||
total: 11600.00,
|
||||
templateId: 'owens_corning_duration',
|
||||
templateName: 'Owens Corning Duration',
|
||||
estimatedBy: 'Marcus Webb',
|
||||
estimatedBy: 'Cody Tatum',
|
||||
roofArea: 18.9,
|
||||
notes: 'Apartment unit — common area roof section only.',
|
||||
},
|
||||
@@ -9705,7 +9731,7 @@ export const INITIAL_STORM_ZONES = [
|
||||
[33.080, -96.720], [33.086, -96.738], [33.100, -96.738],
|
||||
],
|
||||
assignedAgentId: 'REP-01',
|
||||
assignedAgentName: 'Carlos Mendez',
|
||||
assignedAgentName: 'Cody Tatum',
|
||||
color: '#F59E0B',
|
||||
status: 'active',
|
||||
createdAt: '2026-04-29T08:00:00Z',
|
||||
@@ -9719,7 +9745,7 @@ export const INITIAL_STORM_ZONES = [
|
||||
[33.003, -96.712], [33.011, -96.727], [33.025, -96.727],
|
||||
],
|
||||
assignedAgentId: 'REP-02',
|
||||
assignedAgentName: 'Aisha Kumar',
|
||||
assignedAgentName: 'Hannah Reyes',
|
||||
color: '#8B5CF6',
|
||||
status: 'active',
|
||||
createdAt: '2026-02-04T09:00:00Z',
|
||||
@@ -9733,7 +9759,7 @@ export const INITIAL_STORM_ZONES = [
|
||||
[33.017, -96.774], [33.025, -96.791], [33.039, -96.791],
|
||||
],
|
||||
assignedAgentId: 'REP-04',
|
||||
assignedAgentName: 'Nina Patel',
|
||||
assignedAgentName: 'Shelby Greer',
|
||||
color: '#10B981',
|
||||
status: 'completed',
|
||||
createdAt: '2025-11-06T07:30:00Z',
|
||||
|
||||
Reference in New Issue
Block a user