8bb321e1f7
- CreateLeadPage.jsx: full page shell with Quick Capture / Full Form toggle, Barlow Condensed header, breadcrumb nav, GSAP progress bar stub, mobile sticky save footer - LeadSectionWrapper.jsx: collapsible section component with Framer Motion height animation, spring chevron rotation, completion dot, dual light/dark header design matching GlassPanel language - 5 sections wired up: Contact (blue), Property (emerald), Job Details (amber), Insurance (violet), Assignment (cyan) — Quick Capture shows first 3, Full Form shows all 5 - Section indicator pills in header dim gracefully when hidden in Quick Capture mode - LEAD_FORM_OPTIONS added to mockStore: lead types, sources, work types, trade types, urgency/priority levels, insurance companies, claim statuses, phone/email types, US states - Route /emp/fa/leads/new added (FIELD_AGENT, ADMIN, OWNER) - New Lead nav item added to sidebar for all 3 roles
2932 lines
131 KiB
React
2932 lines
131 KiB
React
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||
import { toast } from 'sonner';
|
||
import { logger } from '../utils/logger';
|
||
|
||
// --- DATA CONSTANTS (Extracted from old App.jsx) ---
|
||
|
||
const RAW_LOCATIONS = [
|
||
// Residential
|
||
{ address: "2612 Dunwick Dr, Plano, TX 75023", lat: 33.07084060970922, lng: -96.74558398435258, type: "Residential" },
|
||
{ address: "2608 Dunwick Dr, Plano, TX 75023", lat: 33.070834939506284, lng: -96.74532009555337, type: "Residential" },
|
||
{ address: "2604 Dunwick Dr, Plano, TX 75023", lat: 33.07081036862272, lng: -96.74507199497292, type: "Residential" },
|
||
{ address: "2600 Dunwick Dr, Plano, TX 75023", lat: 33.07083115937081, lng: -96.74483066077192, type: "Residential" },
|
||
{ address: "2516 Dunwick Dr, Plano, TX 75023", lat: 33.070770677180924, lng: -96.74459158203076, type: "Residential" },
|
||
{ address: "2637 Rothland Ln, Plano, TX 75023", lat: 33.070426683935366, lng: -96.74557721797312, type: "Residential" },
|
||
{ address: "2633 Rothland Ln, Plano, TX 75023", lat: 33.07042290378234, lng: -96.74534265015158, type: "Residential" },
|
||
{ address: "2629 Rothland Ln, Plano, TX 75023", lat: 33.07042857401182, lng: -96.74508552773183, type: "Residential" },
|
||
{ address: "2617 Rothland Ln, Plano, TX 75023", lat: 33.070432354164595, lng: -96.74435024782977, type: "Residential" },
|
||
{ address: "2513 Rothland Ln, Plano, TX 75023", lat: 33.07016207283135, lng: -96.74304208113281, type: "Residential" },
|
||
// New Residential Data
|
||
{ address: "6613 Phoenix Pl, Plano, TX 75023, USA", lat: 33.063266298016536, lng: -96.76932248857813, type: "Residential" },
|
||
{ address: "6609 Phoenix Pl, Plano, TX 75023, USA", lat: 33.063141994627365, lng: -96.76932089372718, type: "Residential" },
|
||
{ address: "6605 Phoenix Pl, Plano, TX 75023, USA", lat: 33.06302437405446, lng: -96.76933365253466, type: "Residential" },
|
||
{ address: "6601 Phoenix Pl, Plano, TX 75023, USA", lat: 33.06290541672423, lng: -96.7693424242148, type: "Residential" },
|
||
{ address: "6617 Phoenix Pl, Plano, TX 75023, USA", lat: 33.063379067434504, lng: -96.7693376006764, type: "Residential" },
|
||
{ address: "3913 Arizona Pl, Plano, TX 75023, USA", lat: 33.06318117622371, lng: -96.7698079594919, type: "Residential" },
|
||
{ address: "3917 Arizona Pl, Plano, TX 75023, USA", lat: 33.063193097393324, lng: -96.76997201609075, type: "Residential" },
|
||
{ address: "3921 Arizona Pl, Plano, TX 75023, USA", lat: 33.0631946868825, lng: -96.77014555573001, type: "Residential" },
|
||
{ address: "3920 Arizona Pl, Plano, TX 75023, USA", lat: 33.06252788822516, lng: -96.77010020638036, type: "Residential" },
|
||
{ address: "3916 Arizona Pl, Plano, TX 75023, USA", lat: 33.06254219373469, lng: -96.76993520147747, type: "Residential" },
|
||
{ address: "3912 Arizona Pl, Plano, TX 75023, USA", lat: 33.06254378323562, lng: -96.76975502370993, type: "Residential" },
|
||
{ address: "3908 Arizona Pl, Plano, TX 75023, USA", lat: 33.06253583573075, lng: -96.76959191541512, type: "Residential" },
|
||
{ address: "3904 Arizona Pl, Plano, TX 75023, USA", lat: 33.062526298723945, lng: -96.769445876593, type: "Residential" },
|
||
{ address: "3900 Arizona Pl, Plano, TX 75023, USA", lat: 33.06252153022017, lng: -96.76928656151433, type: "Residential" },
|
||
{ address: "3917 Sailmaker Ln, Plano, TX 75023, USA", lat: 33.0622004503711, lng: -96.76993899469362, type: "Residential" },
|
||
{ address: "3913 Sailmaker Ln, Plano, TX 75023, USA", lat: 33.06218773431336, lng: -96.76979295587151, type: "Residential" },
|
||
{ address: "3909 Sailmaker Ln, Plano, TX 75023, USA", lat: 33.06220362938525, lng: -96.76961846792823, type: "Residential" },
|
||
{ address: "3905 Sailmaker Ln, Plano, TX 75023, USA", lat: 33.06221157692012, lng: -96.76945725624147, type: "Residential" },
|
||
{ address: "3901 Sailmaker Ln, Plano, TX 75023, USA", lat: 33.06219091332797, lng: -96.7692808716901, type: "Residential" },
|
||
|
||
// Commercial
|
||
{ address: "6909 Custer Rd, Plano, TX 75023", lat: 33.07020596727293, lng: -96.7390826077087, type: "Commercial" },
|
||
{ address: "2112 Winslow Dr, Plano, TX 75023", lat: 33.069360828751016, lng: -96.73770127012321, type: "Commercial" },
|
||
{ address: "7224 Independence Pkwy, Plano, TX 75025", lat: 33.07506839285908, lng: -96.74984052259599, type: "Commercial" },
|
||
// New Commercial Data
|
||
{ address: "Dallas/Plano Marriott at Legacy Town Center, 7121 Bishop Rd, Plano, TX 75024, United States", lat: 33.074457402913424, lng: -96.8222322519585, type: "Commercial" },
|
||
{ address: "Legacy Town Center Plano, 5760 Daniel Rd, Plano, TX 75024, United States", lat: 33.07360554164325, lng: -96.82142050370054, type: "Commercial" },
|
||
{ address: "WeWork Office Space & Coworking, 6900 Dallas Pkwy Suite 300, Plano, TX 75024, United States", lat: 33.07281088750022, lng: -96.8235902233433, type: "Commercial" },
|
||
{ address: "Truluck's Ocean's Finest Seafood and Crab, 7161 Bishop Rd, Plano, TX 75024, United States", lat: 33.07535565705897, lng: -96.82174939646889, type: "Commercial" },
|
||
{ address: "Del Frisco's Grille, 7200 Bishop Rd Suite D9, Plano, TX 75024, United States", lat: 33.07630819707901, lng: -96.82124417346868, type: "Commercial" },
|
||
{ address: "Scruffy Duffies, 5865 Kincaid Rd E8, Plano, TX 75024, United States", lat: 33.07601336437884, lng: -96.82257940570773, type: "Commercial" },
|
||
{ address: "Half Shells, 7201 Bishop Rd #E4, Plano, TX 75024, United States", lat: 33.07635733578195, lng: -96.82171330913596, type: "Commercial" },
|
||
{ address: "Mi Cocina, 5760 Legacy Dr #B7, Plano, TX 75024, United States", lat: 33.07743082031222, lng: -96.82109531315771, type: "Commercial" },
|
||
{ address: "Leasing Office space and The Kincaid at Legacy Apartment, 7200 Dallas Pkwy, Plano, TX 75024, United States", lat: 33.07619102009707, lng: -96.82340039310428, type: "Commercial" },
|
||
{ address: "Issil Beauty Spa, 7140 Bishop Rd #F4, Plano, TX 75024, United States", lat: 33.07550110630488, lng: -96.82122287598153, type: "Commercial" },
|
||
|
||
// Apartments
|
||
{ address: "2100 Legacy Dr, Plano, TX 75023", lat: 33.07035321131275, lng: -96.73493675556306, type: "Apartments" },
|
||
{ address: "2401 Brown Deer Trail, Plano, TX 75023", lat: 33.06897509321587, lng: -96.7419549494157, type: "Residential" },
|
||
];
|
||
|
||
const PROPERTY_STYLES = [
|
||
{
|
||
label: "Luxury Estate",
|
||
canvassingStatus: "Customer",
|
||
photos: [
|
||
{ id: 'le_1', url: "/assets/images/properties/Luxury_Driveway_Residence.jpg", caption: "Front Exterior" },
|
||
{ id: 'le_2', url: "/assets/images/properties/Sunny_Suburban_House.jpg", caption: "Side Elevation" },
|
||
{ id: 'le_3', url: "/assets/images/properties/Residential_Roof_Texture.jpg", caption: "Roof Quality" }
|
||
],
|
||
baseValue: 850000,
|
||
areaBase: 4200,
|
||
beds: 5,
|
||
baths: 4.5,
|
||
yearBase: 2010,
|
||
desc: "Luxury estate with custom finishes throughout.",
|
||
condition: 5
|
||
},
|
||
{
|
||
label: "Standard Family Home",
|
||
canvassingStatus: "Neutral",
|
||
photos: [
|
||
{ id: 'sf_1', url: "/assets/images/properties/Modern_White_Suburban_Home.jpg", caption: "Front View" },
|
||
{ id: 'sf_2', url: "/assets/images/properties/Brick_Front_Porch_Home.jpg", caption: "Entryway" },
|
||
{ id: 'sf_3', url: "/assets/images/properties/Overlapping_Roof_Shingles.jpg", caption: "Roof Condition" },
|
||
{ id: 'sf_4', url: "/assets/images/properties/Red_Shingle_Cottage.jpg", caption: "Cottage Style" }
|
||
],
|
||
baseValue: 450000,
|
||
areaBase: 2800,
|
||
beds: 4,
|
||
baths: 3,
|
||
yearBase: 1995,
|
||
desc: "Well-maintained family home in established neighborhood.",
|
||
condition: 4
|
||
},
|
||
{
|
||
label: "Fixer Upper",
|
||
canvassingStatus: "Hot Lead",
|
||
photos: [
|
||
{ id: 'fu_1', url: "/assets/images/properties/Beige_Two_Story_House.jpg", caption: "Street View" },
|
||
{ id: 'fu_2', url: "/assets/images/properties/Hail_Damaged_Shingles.jpg", caption: "Hail Damage" },
|
||
{ id: 'fu_3', url: "/assets/images/properties/Broken_Roof_Surface.jpg", caption: "Critical Repairs Needed" },
|
||
{ id: 'fu_4', url: "/assets/images/properties/Cracked_Storm_Shingles.jpg", caption: "Storm Damage" },
|
||
{ id: 'fu_5', url: "/assets/images/properties/Storm_Worn_Roof.jpg", caption: "Worn Roof" }
|
||
],
|
||
baseValue: 320000,
|
||
areaBase: 2400,
|
||
beds: 3,
|
||
baths: 2,
|
||
yearBase: 1980,
|
||
desc: "Great potential, needs cosmetic updates.",
|
||
condition: 2
|
||
},
|
||
{
|
||
label: "Renovated Modern",
|
||
canvassingStatus: "Renovated",
|
||
photos: [
|
||
{ id: 'rm_1', url: "/assets/images/properties/Minimal_Flat_Roof_House.jpg", caption: "Modern Facade" },
|
||
{ id: 'rm_2', url: "/assets/images/properties/Red_Tiled_Roof_House.jpg", caption: "New Roof" },
|
||
{ id: 'rm_3', url: "/assets/images/properties/Roof_Inspection_Angle.jpg", caption: "Drone Inspection" },
|
||
{ id: 'rm_4', url: "/assets/images/properties/Red_Metal_Roof_Home.jpg", caption: "Metal Roof Upgrade" }
|
||
],
|
||
baseValue: 580000,
|
||
areaBase: 3200,
|
||
beds: 4,
|
||
baths: 3.5,
|
||
yearBase: 1990,
|
||
desc: "Recently renovated with modern aesthetics.",
|
||
condition: 5
|
||
}
|
||
];
|
||
|
||
const COMMERCIAL_VARIANTS = [
|
||
{ name: "Legacy Retail Group", type: "Retail Mix", email: "leasing@legacyretail.com" },
|
||
{ name: "Custer Office Park LLC", type: "Office Space", email: "mgmt@custeroffice.com" },
|
||
{ name: "Plano Investments Inc", type: "Mixed Use", email: "contact@planoinvest.com" },
|
||
{ name: "North Texas Prop Co", type: "Service Center", email: "info@ntxprops.com" }
|
||
];
|
||
|
||
const REAL_NAMES = [
|
||
"James Beauford", "Sarah Miller", "Robert Henderson", "Karen Smith", "Michael Chang",
|
||
"Patricia O'Neil", "Dr. Anish Patel", "Marcus Johnson", "Elena Rodriguez", "Greg Alston",
|
||
"Linda Grey", "Bill Thompson", "Jennifer Wu", "David Kowalski", "Omar Farooq",
|
||
"Lisa Chen", "Tom Baker", "Rachel Green", "Steve Martin", "Angela White"
|
||
];
|
||
|
||
const OCCUPATIONS = [
|
||
"Software Engineer", "Petroleum Engineer", "Teacher", "Nurse Practitioner",
|
||
"Small Business Owner", "Accountant", "Marketing Director", "retired",
|
||
"Attorney", "Real Estate Agent", "Sales Manager", "Consultant"
|
||
];
|
||
|
||
const EMPLOYERS_BY_OCCUPATION = {
|
||
"Software Engineer": ["Google", "Microsoft", "Toyota Connected", "Capital One", "Intuit"],
|
||
"Petroleum Engineer": ["ExxonMobil", "Chevron", "Pioneer Natural Resources", "Denbury"],
|
||
"Teacher": ["Plano ISD", "Frisco ISD", "Dallas ISD", "Richardson ISD"],
|
||
"Nurse Practitioner": ["Baylor Scott & White", "Medical City Plano", "Texas Health Resources"],
|
||
"Small Business Owner": ["Self Employed", "Local Boutique", "Consultancy Firm"],
|
||
"Accountant": ["Deloitte", "PwC", "EY", "KPMG", "Local CPA Firm"],
|
||
"Marketing Director": ["PepsiCo", "Toyota", "Frito-Lay", "Yum! Brands"],
|
||
"retired": ["N/A"],
|
||
"Attorney": ["Jones Day", "Baker Botts", "Norton Rose Fulbright", "Local Law Firm"],
|
||
"Real Estate Agent": ["Keller Williams", "Ebby Halliday", "Compass", "Remax"],
|
||
"Sales Manager": ["Oracle", "Salesforce", "AT&T", "Samsung"],
|
||
"Consultant": ["McKinsey", "BCG", "Accenture", "Freelance"]
|
||
};
|
||
|
||
// --- NEW INSURANCE SCHEMA CONSTANTS ---
|
||
const INSURANCE_COMPANIES = [
|
||
"State Farm", "Allstate", "Liberty Mutual", "Farmers", "Nationwide",
|
||
"USAA", "Chubb", "Travelers", "Progressive", "American Family"
|
||
];
|
||
|
||
const ADJUSTER_TYPES = ["Staff Adjuster", "Independent Adjuster", "Public Adjuster"];
|
||
|
||
// --- DATA GENERATION HELPERS ---
|
||
|
||
function generatePolygon(lat, lng) {
|
||
const dLat = 0.0001; // ~11 meters
|
||
const dLng = 0.0001; // ~11 meters
|
||
return [
|
||
[lat + dLat, lng - dLng], // Top Left
|
||
[lat + dLat, lng + dLng], // Top Right
|
||
[lat - dLat, lng + dLng], // Bottom Right
|
||
[lat - dLat, lng - dLng], // Bottom Left
|
||
];
|
||
}
|
||
|
||
function generateEmail(name, company = null) {
|
||
if (company) return company;
|
||
const domains = ["gmail.com", "yahoo.com", "outlook.com", "icloud.com"];
|
||
const domain = domains[Math.floor(Math.random() * domains.length)];
|
||
const parts = name.toLowerCase().split(' ');
|
||
const last = parts[parts.length - 1].replace(/[^a-z]/g, '');
|
||
const first = parts[0].replace(/[^a-z]/g, '');
|
||
return `${first}.${last}@${domain}`;
|
||
}
|
||
|
||
// Weighted Random Helper
|
||
function getWeightedRandom(items, weights) {
|
||
const totalWeight = weights.reduce((a, b) => a + b, 0);
|
||
const random = Math.random() * totalWeight;
|
||
let weightSum = 0;
|
||
|
||
for (let i = 0; i < items.length; i++) {
|
||
weightSum += weights[i];
|
||
if (random <= weightSum) {
|
||
return items[i];
|
||
}
|
||
}
|
||
return items[items.length - 1]; // Fallback
|
||
}
|
||
|
||
function generateProperties() {
|
||
// 1. Generate Base Properties
|
||
const allProperties = RAW_LOCATIONS.map((loc, index) => {
|
||
const isCommercial = loc.type === "Commercial" || loc.type === "Apartments";
|
||
|
||
// Shuffle styles slightly differently than index-based to avoid repeating patterns
|
||
const styleIndex = Math.floor(Math.random() * PROPERTY_STYLES.length);
|
||
const style = isCommercial ? null : PROPERTY_STYLES[styleIndex];
|
||
|
||
let ownerName, ownerEmail, occupation, income, employerName;
|
||
|
||
if (isCommercial) {
|
||
const commVariant = COMMERCIAL_VARIANTS[index % COMMERCIAL_VARIANTS.length];
|
||
ownerName = commVariant.name;
|
||
ownerEmail = commVariant.email;
|
||
occupation = "Commercial Owner";
|
||
income = "$1M+";
|
||
employerName = "Self";
|
||
} else {
|
||
ownerName = REAL_NAMES[index % REAL_NAMES.length];
|
||
ownerEmail = generateEmail(ownerName);
|
||
occupation = OCCUPATIONS[index % OCCUPATIONS.length];
|
||
|
||
const potentialEmployers = EMPLOYERS_BY_OCCUPATION[occupation] || ["Self Employed"];
|
||
employerName = potentialEmployers[index % potentialEmployers.length];
|
||
income = ["$80k - $120k", "$120k - $180k", "$200k+", "$60k - $90k"][index % 4];
|
||
}
|
||
|
||
// Randomize Year and Value to break lines
|
||
const yearOffset = Math.floor(Math.random() * 20) - 10; // +/- 10 years
|
||
const builtYear = isCommercial ? 1995 + (index % 10) : style.yearBase + yearOffset;
|
||
|
||
const valueVariance = (Math.random() * 0.4) - 0.2; // +/- 20%
|
||
const baseSqft = isCommercial ? 12000 + (index * 500) : style.areaBase;
|
||
const sqft = Math.floor(baseSqft * (1 + (valueVariance / 2))); // Size correlates with value but not perfectly
|
||
|
||
const baseVal = isCommercial ? 2500000 + (index * 100000) : style.baseValue;
|
||
const value = Math.floor(baseVal * (1 + valueVariance));
|
||
|
||
// Rental Logic: Target ~10-15 rented (approx 40-50% chance given ~30 props)
|
||
const isRented = Math.random() > 0.55;
|
||
|
||
let tenantData = {};
|
||
if (isRented) {
|
||
const tName = isCommercial ? "Global Corp Inc." : REAL_NAMES[(index + 5) % REAL_NAMES.length];
|
||
const tOcc = isCommercial ? "Retail/Office Mix" : OCCUPATIONS[(index + 3) % OCCUPATIONS.length];
|
||
const tPhone = `469-555-${2000 + index}`;
|
||
const tEmail = generateEmail(tName.split(' ')[0] || "tenant", isCommercial ? "tenant.com" : null);
|
||
const tEmployer = isCommercial ? "N/A" : (EMPLOYERS_BY_OCCUPATION[tOcc]?.[0] || "Self");
|
||
const tIncome = isCommercial ? "$5M+" : ["$60k", "$85k", "$110k", "$140k"][index % 4];
|
||
const tFamily = isCommercial ? "N/A" : (Math.random() > 0.4 ? "Family" : "Single");
|
||
const tLeaseType = isCommercial ? "Commercial NNN" : "Residential Standard";
|
||
|
||
tenantData = {
|
||
currentlyRented: true,
|
||
currentTenantName: tName,
|
||
tenantPhone: tPhone,
|
||
tenantEmail: tEmail,
|
||
tenantOccupation: tOcc,
|
||
tenantEmployer: tEmployer,
|
||
tenantAnnualIncome: tIncome,
|
||
livingStatus: tFamily,
|
||
leaseType: tLeaseType,
|
||
currentMonthlyRentAmount: Math.floor(value * 0.008 / 100) * 100,
|
||
leaseStartDate: "2023-01-01",
|
||
leaseEndDate: "2025-01-01",
|
||
leaseSignedDate: "2022-12-15",
|
||
ownerWillingToRent: false // Already rented
|
||
};
|
||
} else {
|
||
tenantData = {
|
||
currentlyRented: false,
|
||
currentTenantName: null,
|
||
tenantPhone: null,
|
||
tenantEmail: null,
|
||
tenantOccupation: null,
|
||
tenantEmployer: null,
|
||
tenantAnnualIncome: null,
|
||
livingStatus: null,
|
||
leaseType: null,
|
||
currentMonthlyRentAmount: null,
|
||
leaseStartDate: null,
|
||
leaseEndDate: null,
|
||
leaseSignedDate: null,
|
||
ownerWillingToRent: Math.random() > 0.6
|
||
};
|
||
}
|
||
|
||
const rentAmount = tenantData.currentMonthlyRentAmount; // For use below if needed, though mapped in tenantData now
|
||
|
||
// Weighted Roof Condition
|
||
const roofCondition = getWeightedRandom(
|
||
["Good", "Fair", "Excellent", "Needs Repair"],
|
||
[0.4, 0.3, 0.2, 0.1]
|
||
);
|
||
|
||
// Neighborhood Rating
|
||
const neighRating = getWeightedRandom([7, 8, 9, 10, 6, 5], [0.3, 0.3, 0.2, 0.1, 0.05, 0.05]);
|
||
|
||
return {
|
||
id: index + 1,
|
||
center: [loc.lat, loc.lng],
|
||
polygon: generatePolygon(loc.lat, loc.lng),
|
||
// Placeholder status, will be overwritten
|
||
canvassingStatus: "Neutral",
|
||
photos: isCommercial ? [
|
||
{ id: `com_${index}_1`, url: "/assets/images/properties/Apartment_Complex.jpg", caption: "Exterior View" },
|
||
{ id: `com_${index}_2`, url: "/assets/images/properties/Mall_Rooftop_HVAC_Units.jpg", caption: "HVAC Systems" }
|
||
] : style.photos,
|
||
|
||
// --- NEW FIELDS FOR ADMIN ACTION CENTER ---
|
||
assignedAgentId: null, // Default unassigned
|
||
lastContactDate: null,
|
||
pendingSignature: false,
|
||
proposalSentDate: null,
|
||
proposalValue: 0,
|
||
// ------------------------------------------
|
||
|
||
propertyData: {
|
||
propertyId: `P-${2600 + index}`,
|
||
propertyAddress: loc.address,
|
||
propertyType: loc.type,
|
||
totalBuiltUpArea: sqft,
|
||
yearBuilt: builtYear,
|
||
numberOfBedrooms: isCommercial ? 0 : style.beds,
|
||
numberOfBathrooms: isCommercial ? 4 : style.baths,
|
||
numberOfParkingSpaces: isCommercial ? 25 : 2,
|
||
currentEstimatedMarketValue: value,
|
||
propertyTaxAssessmentValue: Math.floor(value * 0.85),
|
||
roofCondition: roofCondition,
|
||
renovationDescription: isCommercial ? "Commercial Maintenance" : style.desc,
|
||
renovationCost: Math.floor(value * (Math.random() * 0.05 + 0.01)),
|
||
lastMajorRenovationDate: "2020-05-15",
|
||
lastRoofRepairReplacementDate: "2018-02-10",
|
||
recentMajorRepairs: "Routine Maintenance",
|
||
|
||
// Spread new robust tenant data
|
||
...tenantData,
|
||
|
||
expectedMonthlyRentAmount: Math.floor(value * 0.008 / 100) * 100,
|
||
rentalAvailabilityDate: null,
|
||
rentalTermsPreference: null,
|
||
schoolDistrict: "Plano ISD",
|
||
neighborhoodRating: neighRating,
|
||
crimeRateIndex: "Low",
|
||
publicTransportationAccess: "Bus Line 204",
|
||
propertyConditionRating: isCommercial ? 4 : style.condition,
|
||
furnishingStatus: "Unfurnished",
|
||
notes: isCommercial ? "Prime commercial location" : style.desc,
|
||
latestPurchasePrice: Math.floor(value * 0.6),
|
||
latestPurchaseDate: "2015-06-20",
|
||
latestSaleListingDate: null,
|
||
latestSaleAskingPrice: null,
|
||
lotPlotSize: isCommercial ? "1.5 Acres" : "0.22 Acres",
|
||
// New Fields for Chatbot
|
||
pendingSignature: Math.random() > 0.9, // 10% chance
|
||
closedDate: Math.random() > 0.8 ? "2026-01-15" : null // Simple mock for revenue queries
|
||
},
|
||
ownerData: {
|
||
ownerId: `OWN-${200 + index}`,
|
||
fullName: ownerName,
|
||
primaryPhoneNumber: `972-555-${1000 + index}`,
|
||
secondaryPhoneNumber: null,
|
||
emailAddress: ownerEmail,
|
||
mailingAddress: loc.address,
|
||
occupation: occupation,
|
||
employerName: employerName,
|
||
annualIncomeRange: income,
|
||
creditScoreRange: "720+",
|
||
ownershipType: isCommercial ? "Corporate" : "Individual",
|
||
ownershipPercentage: "100%",
|
||
willingToRentProperty: Math.random() > 0.8,
|
||
desiredMonthlyRentalPrice: null,
|
||
rentalConditions: null,
|
||
willingToSellProperty: Math.random() > 0.85,
|
||
desiredSellingPrice: Math.floor(value * 1.1),
|
||
minimumAcceptableSellingPrice: Math.floor(value * 1.05)
|
||
},
|
||
// New Insurance Data Schema
|
||
insuranceData: (() => {
|
||
const claimFiled = Math.random() > 0.8; // 20% likely
|
||
if (!claimFiled) {
|
||
return {
|
||
insurance_company: getWeightedRandom(INSURANCE_COMPANIES, Array(10).fill(0.1)),
|
||
insurance_company_not_listed: false,
|
||
damage_location: null,
|
||
date_of_loss: null,
|
||
claim_filed: false,
|
||
claim_number: null,
|
||
has_paperwork: false,
|
||
adjuster_name: null,
|
||
adjuster_phone: null,
|
||
adjuster_ext: null,
|
||
adjuster_type: null,
|
||
adjuster_fax: null,
|
||
adjuster_email: null,
|
||
met_with_adjuster: false,
|
||
claim_approved: false
|
||
};
|
||
}
|
||
|
||
// If claim filed, populate detailed data
|
||
const lossDate = new Date();
|
||
lossDate.setDate(lossDate.getDate() - Math.floor(Math.random() * 60)); // Last 60 days
|
||
|
||
return {
|
||
insurance_company: getWeightedRandom(INSURANCE_COMPANIES, Array(10).fill(0.1)),
|
||
insurance_company_not_listed: false,
|
||
damage_location: "Roof, Gutters, Fence",
|
||
date_of_loss: lossDate.toISOString().split('T')[0],
|
||
claim_filed: true,
|
||
claim_number: `CLM-${Math.floor(Math.random() * 1000000)}`,
|
||
has_paperwork: Math.random() > 0.3,
|
||
adjuster_name: REAL_NAMES[Math.floor(Math.random() * REAL_NAMES.length)],
|
||
adjuster_phone: `214-555-${Math.floor(Math.random() * 9000) + 1000}`,
|
||
adjuster_ext: `${Math.floor(Math.random() * 900) + 100}`,
|
||
adjuster_type: ADJUSTER_TYPES[Math.floor(Math.random() * ADJUSTER_TYPES.length)],
|
||
adjuster_fax: `214-555-${Math.floor(Math.random() * 9000) + 1000}`,
|
||
adjuster_email: `adjuster.${Math.floor(Math.random() * 100)}@insurance.com`,
|
||
met_with_adjuster: Math.random() > 0.5,
|
||
claim_approved: Math.random() > 0.7
|
||
};
|
||
})()
|
||
};
|
||
});
|
||
|
||
// 2. Assign Statuses with Strict Counts
|
||
// User Request: 4-9 Hot Leads, 15-20 Customers
|
||
const countHotLeads = Math.floor(Math.random() * (9 - 4 + 1)) + 4; // 4 to 9
|
||
const countCustomers = Math.floor(Math.random() * (20 - 15 + 1)) + 15; // 15 to 20
|
||
|
||
// Create indices array and shuffle it
|
||
const indices = allProperties.map((_, i) => i);
|
||
for (let i = indices.length - 1; i > 0; i--) {
|
||
const j = Math.floor(Math.random() * (i + 1));
|
||
[indices[i], indices[j]] = [indices[j], indices[i]];
|
||
}
|
||
|
||
// Assign based on shuffled indices
|
||
indices.forEach((propIndex, i) => {
|
||
if (i < countHotLeads) {
|
||
allProperties[propIndex].canvassingStatus = "Hot Lead";
|
||
} else if (i < countHotLeads + countCustomers) {
|
||
allProperties[propIndex].canvassingStatus = "Customer";
|
||
} else {
|
||
// Remaining are Neutral, Renovated, or Not Interested
|
||
// Weighted: 70% Neutral, 20% Not Interested, 10% Renovated
|
||
allProperties[propIndex].canvassingStatus = getWeightedRandom(
|
||
["Neutral", "Not Interested", "Renovated"],
|
||
[0.7, 0.2, 0.1]
|
||
);
|
||
}
|
||
});
|
||
|
||
// --- INJECT REQUIRED MOCK DATA FOR ACTION CENTER ---
|
||
// A. Unassigned Leads (assignedAgentId: null, canvassingStatus: "Lead")
|
||
// Target addresses: 2600 Dunwick Dr, 3900 Arizona Pl, 2112 Winslow Dr, Dallas/Plano Marriott, Legacy Town Center
|
||
const unassignedTargets = [
|
||
"2600 Dunwick Dr, Plano, TX 75023",
|
||
"3900 Arizona Pl, Plano, TX 75023, USA", // Note: original data has USA
|
||
"2112 Winslow Dr, Plano, TX 75023",
|
||
"Dallas/Plano Marriott at Legacy Town Center, 7121 Bishop Rd, Plano, TX 75024, United States",
|
||
"Legacy Town Center Plano, 5760 Daniel Rd, Plano, TX 75024, United States"
|
||
];
|
||
|
||
const unassignedValues = {
|
||
"2600 Dunwick Dr, Plano, TX 75023": 53173,
|
||
"3900 Arizona Pl, Plano, TX 75023, USA": 11608,
|
||
"2112 Winslow Dr, Plano, TX 75023": 40669,
|
||
"Dallas/Plano Marriott at Legacy Town Center, 7121 Bishop Rd, Plano, TX 75024, United States": 15766,
|
||
"Legacy Town Center Plano, 5760 Daniel Rd, Plano, TX 75024, United States": 12792
|
||
};
|
||
|
||
allProperties.forEach(p => {
|
||
const addr = p.propertyData.propertyAddress;
|
||
if (unassignedTargets.includes(addr)) {
|
||
p.canvassingStatus = "Lead"; // "Lead" = Unassigned basically in this context, or just "Neutral" but we track assignments
|
||
p.assignedAgentId = null;
|
||
p.propertyData.currentEstimatedMarketValue = unassignedValues[addr];
|
||
} else {
|
||
// Default random assignment for others if not unassigned
|
||
if (p.canvassingStatus !== "Hot Lead") { // Keep Hot Leads potentially unassigned or specific
|
||
// p.assignedAgentId = "e1"; // Optional: assign everything else
|
||
}
|
||
}
|
||
});
|
||
|
||
// B. Hot Leads Not Contacted
|
||
// Data: 2629 Rothland Ln (2026-02-08), 3920 Arizona Pl (2026-02-08), 3912 Arizona Pl (Never), 3909 Sailmaker Ln (Never)
|
||
const hotLeadTargets = {
|
||
"2629 Rothland Ln, Plano, TX 75023": "2026-02-08T10:00:00Z",
|
||
"3920 Arizona Pl, Plano, TX 75023, USA": "2026-02-08T14:30:00Z",
|
||
"3912 Arizona Pl, Plano, TX 75023, USA": null,
|
||
"3909 Sailmaker Ln, Plano, TX 75023, USA": null
|
||
};
|
||
|
||
allProperties.forEach(p => {
|
||
if (hotLeadTargets.hasOwnProperty(p.propertyData.propertyAddress)) {
|
||
p.canvassingStatus = "Hot Lead";
|
||
p.lastContactDate = hotLeadTargets[p.propertyData.propertyAddress];
|
||
|
||
// Set values if needed match User Data?
|
||
// The prompt gave values: 2629 ($20,298), 3920 ($84,288), 3912 ($73,307), 3909 ($72,563)
|
||
if (p.propertyData.propertyAddress.includes("2629 Rothland")) p.propertyData.currentEstimatedMarketValue = 20298;
|
||
if (p.propertyData.propertyAddress.includes("3920 Arizona")) p.propertyData.currentEstimatedMarketValue = 84288;
|
||
if (p.propertyData.propertyAddress.includes("3912 Arizona")) p.propertyData.currentEstimatedMarketValue = 73307;
|
||
if (p.propertyData.propertyAddress.includes("3909 Sailmaker")) p.propertyData.currentEstimatedMarketValue = 72563;
|
||
}
|
||
});
|
||
|
||
// C. Pending Signatures
|
||
// Data: Client 1 (2612 Dunwick), Client 2 (2608 Dunwick), Client 9 (2617 Rothland), Client 12 (6609 Phoenix)
|
||
const signatureTargets = {
|
||
"2612 Dunwick Dr, Plano, TX 75023": { date: "2026-02-05", val: 8521 },
|
||
"2608 Dunwick Dr, Plano, TX 75023": { date: "2026-02-09", val: 16468 },
|
||
"2617 Rothland Ln, Plano, TX 75023": { date: "2026-02-08", val: 18392 },
|
||
"6609 Phoenix Pl, Plano, TX 75023, USA": { date: "2026-02-06", val: 31768 }
|
||
};
|
||
|
||
allProperties.forEach(p => {
|
||
if (signatureTargets.hasOwnProperty(p.propertyData.propertyAddress)) {
|
||
p.pendingSignature = true;
|
||
p.proposalSentDate = signatureTargets[p.propertyData.propertyAddress].date;
|
||
p.proposalValue = signatureTargets[p.propertyData.propertyAddress].val;
|
||
p.propertyData.pendingSignature = true; // Sync with inner object if needed, but we extended outer
|
||
} else {
|
||
p.pendingSignature = false;
|
||
}
|
||
});
|
||
|
||
// -------------------------------------------------------
|
||
|
||
// 3. Assign Tenants (Strict Counts & Data Depth)
|
||
// User Request: 10-15 Total Rented. 5-8 with "Complete" info, rest "Sparse" (Mandatory only).
|
||
// Current Date Context: Feb 5, 2026.
|
||
|
||
const totalRented = Math.floor(Math.random() * (15 - 10 + 1)) + 10; // 10 to 15
|
||
const fullDetailCount = Math.floor(Math.random() * (8 - 5 + 1)) + 5; // 5 to 8
|
||
const sparseDetailCount = totalRented - fullDetailCount;
|
||
|
||
// Reshuffle for tenant assignment (independent of status)
|
||
const tenantIndices = allProperties.map((_, i) => i);
|
||
for (let i = tenantIndices.length - 1; i > 0; i--) {
|
||
const j = Math.floor(Math.random() * (i + 1));
|
||
[tenantIndices[i], tenantIndices[j]] = [tenantIndices[j], tenantIndices[i]];
|
||
}
|
||
|
||
tenantIndices.forEach((propIndex, i) => {
|
||
if (i < totalRented) {
|
||
const prop = allProperties[propIndex];
|
||
const isFullDetail = i < fullDetailCount;
|
||
const isCommercial = prop.propertyData.propertyType === "Commercial" || prop.propertyData.propertyType === "Apartments";
|
||
const val = prop.propertyData.currentEstimatedMarketValue;
|
||
|
||
// Generate Base Data (Mandatory)
|
||
const tName = isCommercial ? "Global Corp Inc." : REAL_NAMES[(propIndex + 5) % REAL_NAMES.length];
|
||
const tPhone = `469-555-${3000 + propIndex}`;
|
||
|
||
// Optional Data (Full vs Sparse)
|
||
const tEmail = isFullDetail ? generateEmail(tName.split(' ')[0], isCommercial ? "enterprises.com" : null) : "";
|
||
const tOcc = isFullDetail ? (isCommercial ? "Retail/Office Mix" : OCCUPATIONS[(propIndex + 3) % OCCUPATIONS.length]) : "";
|
||
const tEmployer = isFullDetail ? (isCommercial ? "N/A" : (EMPLOYERS_BY_OCCUPATION[tOcc]?.[0] || "Self")) : "";
|
||
const tIncome = isFullDetail ? (isCommercial ? "$5M+" : ["$60k", "$85k", "$110k", "$140k"][propIndex % 4]) : "";
|
||
const tFamily = isFullDetail ? (isCommercial ? "N/A" : (Math.random() > 0.4 ? "Family" : "Single")) : "Single";
|
||
const tLeaseType = isFullDetail ? (isCommercial ? "Commercial NNN" : "Residential Standard") : "Residential Standard";
|
||
|
||
// Dates (Relative to Feb 2026)
|
||
// Start: Jan 2025 - Jan 2026
|
||
const startYear = Math.random() > 0.5 ? 2025 : 2026;
|
||
const tStart = `${startYear}-01-15`;
|
||
|
||
// Signed: 1 month before start
|
||
const tSigned = `${startYear - 1}-12-15`;
|
||
|
||
// End: 1 year after start (2026 or 2027)
|
||
const tEnd = `${startYear + 1}-01-14`;
|
||
|
||
const tRent = Math.floor(val * 0.008 / 100) * 100;
|
||
|
||
// Apply updates
|
||
allProperties[propIndex].propertyData = {
|
||
...allProperties[propIndex].propertyData,
|
||
currentlyRented: true,
|
||
currentTenantName: tName,
|
||
tenantPhone: tPhone,
|
||
|
||
// Optional / Detail Dependent
|
||
tenantEmail: tEmail,
|
||
tenantOccupation: tOcc,
|
||
tenantEmployer: tEmployer,
|
||
tenantAnnualIncome: tIncome,
|
||
livingStatus: tFamily,
|
||
leaseType: tLeaseType,
|
||
|
||
// Dates & Financials (Assign sparse ones too if needed, or leave blank? User said sparse has MANDATORY only. But Rent amount is needed to be "Rented" usually. I'll add Rent/Dates to Full, and maybe just Rent to Sparse?)
|
||
// Re-reading: "The remaining entries may include only the mandatory fields."
|
||
// I will add rent/dates to ALL rented properties because otherwise the map might look broken for "Rented" status without a lease end date. But strictly, I could leave them empty.
|
||
// Let's populate Dates/Rent for ALL, but Personal Info (Email/Job/Income) only for Full.
|
||
|
||
currentMonthlyRentAmount: tRent,
|
||
leaseStartDate: tStart,
|
||
leaseEndDate: tEnd,
|
||
leaseSignedDate: tSigned,
|
||
|
||
ownerWillingToRent: false
|
||
};
|
||
}
|
||
});
|
||
|
||
// 4. Refine Renovation Dates (Recent for 'Renovated' status)
|
||
// User Request: Not older than 6 months from Feb 2026 (Aug 2025 - Feb 2026)
|
||
allProperties.forEach(prop => {
|
||
if (prop.canvassingStatus === "Renovated") {
|
||
const monthsBack = Math.floor(Math.random() * 6); // 0 to 5 months ago
|
||
// Base date: Feb 2026.
|
||
// 0 months ago = Feb 2026. 1 = Jan 2026... 5 = Sep 2025.
|
||
// Let's pick a random day.
|
||
const year = monthsBack <= 1 ? 2026 : 2025;
|
||
let month = 2 - monthsBack; // Feb(2) - 0 = 2. Feb(2) - 5 = -3.
|
||
if (month <= 0) month += 12; // Wrap around to previous year
|
||
|
||
const day = Math.floor(Math.random() * 28) + 1;
|
||
const monthStr = month.toString().padStart(2, '0');
|
||
const dayStr = day.toString().padStart(2, '0');
|
||
|
||
prop.propertyData.lastMajorRenovationDate = `${year}-${monthStr}-${dayStr}`;
|
||
prop.propertyData.recentMajorRepairs = "Full Interior & Exterior Renovation";
|
||
prop.propertyData.renovationDescription = "Modernized kitchen, new flooring, fresh paint, roof inspection";
|
||
}
|
||
});
|
||
|
||
return allProperties;
|
||
}
|
||
|
||
// --- NEW DATA (Users & Meetings) ---
|
||
|
||
const MOCK_USERS = [
|
||
// Customers
|
||
{ id: 'c1', type: 'customer', username: 'alice', email: 'alice@example.com', password: 'password', name: 'Alice Customer', propertyId: 'P-2600' },
|
||
{ id: 'c2', type: 'customer', username: 'bob', email: 'bob@example.com', password: 'password', name: 'Bob Buyer' },
|
||
{ id: 'c3', type: 'customer', username: 'charlie', email: 'charlie@example.com', password: 'password', name: 'Charlie Client' },
|
||
|
||
// Field Agents (5 Agents)
|
||
{ id: 'e1', type: 'employee', empId: 'FA001', email: 'agent1@plano.com', password: 'password', role: 'FIELD_AGENT', name: 'Frank Agent', xp: 12450, doorsKnocked: 342, leadsGained: 45, appointmentsSet: 18, streakDays: 5, achievements: ['Hot Spot Hunter', 'Storm Chaser'] },
|
||
{ id: 'e2', type: 'employee', empId: 'FA002', email: 'agent2@plano.com', password: 'password', role: 'FIELD_AGENT', name: 'Fiona Field', xp: 8200, doorsKnocked: 215, leadsGained: 30, appointmentsSet: 12, streakDays: 2, achievements: ['Star Closer'] },
|
||
{ id: 'e3', type: 'employee', empId: 'FA003', email: 'agent3@plano.com', password: 'password', role: 'FIELD_AGENT', name: 'Fred Flyer', xp: 2100, doorsKnocked: 85, leadsGained: 5, appointmentsSet: 2, streakDays: 0, achievements: [] },
|
||
{ id: 'e4', type: 'employee', empId: 'FA004', email: 'agent4@plano.com', password: 'password', role: 'FIELD_AGENT', name: 'Felicity Fast', xp: 15600, doorsKnocked: 410, leadsGained: 65, appointmentsSet: 24, streakDays: 8, achievements: ['Map Master', 'Hot Spot Hunter', 'Storm Chaser'] },
|
||
{ id: 'e5', type: 'employee', empId: 'FA005', email: 'agent5@plano.com', password: 'password', role: 'FIELD_AGENT', name: 'Felix Fixer', xp: 5400, doorsKnocked: 156, leadsGained: 20, appointmentsSet: 8, streakDays: 1, achievements: ['First Knock'] },
|
||
|
||
// Admins (3 Admins)
|
||
{ id: 'a1', type: 'employee', empId: 'ADM01', email: 'admin@plano.com', password: 'password', role: 'ADMIN', name: 'Adam Admin' },
|
||
{ id: 'a2', type: 'employee', empId: 'ADM02', email: 'admin2@plano.com', password: 'password', role: 'ADMIN', name: 'Amanda Manager' },
|
||
{ id: 'a3', type: 'employee', empId: 'ADM03', email: 'admin3@plano.com', password: 'password', role: 'ADMIN', name: 'Arthur Director' },
|
||
|
||
// --- NEW ROLES (Owners Box) ---
|
||
// Owner 1 — Active, strong financials, one project under dispute
|
||
{
|
||
id: 'own_001',
|
||
type: 'owner',
|
||
username: 'justin',
|
||
email: 'justin@johnsondev.com',
|
||
password: 'password',
|
||
role: 'OWNER',
|
||
name: 'Justin Johnson',
|
||
companyName: 'Johnson Development Group',
|
||
phone: '972-555-1234'
|
||
},
|
||
// Owner 2 — High Risk, vendor payment delays, over-budget project
|
||
{
|
||
id: 'own_002',
|
||
type: 'owner',
|
||
username: 'diana',
|
||
email: 'diana@reevesconstruction.com',
|
||
password: 'password',
|
||
role: 'OWNER',
|
||
name: 'Diana Reeves',
|
||
companyName: 'Reeves Construction Partners',
|
||
phone: '214-555-5678'
|
||
},
|
||
// Contractor
|
||
{
|
||
id: 'con_001',
|
||
type: 'contractor',
|
||
username: 'mike',
|
||
email: 'mike@texasbuilders.com',
|
||
password: 'password',
|
||
role: 'CONTRACTOR',
|
||
name: 'Mike Contractor',
|
||
companyName: 'Texas Builders LLC',
|
||
licenseNumber: 'TX-GC-123456',
|
||
phone: '214-555-4567'
|
||
},
|
||
// Subcontractor
|
||
{
|
||
id: 'sub_001',
|
||
type: 'subcontractor',
|
||
username: 'carlos',
|
||
email: 'carlos@electricpro.com',
|
||
password: 'password',
|
||
role: 'SUBCONTRACTOR',
|
||
name: 'Carlos Subcontractor',
|
||
companyName: 'Electric Pro Services',
|
||
tradeType: 'electrical',
|
||
phone: '469-555-9012'
|
||
},
|
||
// Vendor (Supplier)
|
||
{
|
||
id: 'ven_001',
|
||
type: 'vendor',
|
||
username: 'abc_supply',
|
||
email: 'sales@abcsupply.com',
|
||
password: 'password',
|
||
role: 'VENDOR',
|
||
name: 'ABC Supply Co.',
|
||
companyName: 'ABC Supply',
|
||
tradeType: 'materials',
|
||
phone: '972-555-8888'
|
||
}
|
||
];
|
||
|
||
// --- NEW MOCK SALES HISTORY FOR LEADERBOARD ---
|
||
const MOCK_SALES_HISTORY = [
|
||
// Frank Agent (High Revenue, Low Volume - "The Sniper")
|
||
{ id: 'tx_1', agentId: 'e1', date: '2026-02-10', amount: 450000, status: 'closed_won' },
|
||
{ id: 'tx_2', agentId: 'e1', date: '2026-02-05', amount: 520000, status: 'closed_won' },
|
||
{ id: 'tx_3', agentId: 'e1', date: '2026-01-28', amount: 380000, status: 'closed_won' },
|
||
{ id: 'tx_4', agentId: 'e1', date: '2026-02-01', amount: 0, status: 'closed_lost' }, // Lost deal
|
||
|
||
// Fiona Field (High Volume, Mid Revenue - "The Grinder")
|
||
{ id: 'tx_5', agentId: 'e2', date: '2026-02-09', amount: 250000, status: 'closed_won' },
|
||
{ id: 'tx_6', agentId: 'e2', date: '2026-02-08', amount: 240000, status: 'closed_won' },
|
||
{ id: 'tx_7', agentId: 'e2', date: '2026-02-06', amount: 260000, status: 'closed_won' },
|
||
{ id: 'tx_8', agentId: 'e2', date: '2026-01-30', amount: 230000, status: 'closed_won' },
|
||
{ id: 'tx_9', agentId: 'e2', date: '2026-02-02', amount: 255000, status: 'closed_won' },
|
||
{ id: 'tx_10', agentId: 'e2', date: '2026-01-25', amount: 0, status: 'closed_lost' },
|
||
{ id: 'tx_11', agentId: 'e2', date: '2026-01-20', amount: 0, status: 'closed_lost' },
|
||
|
||
// Fred Flyer (New/Low Performance)
|
||
{ id: 'tx_12', agentId: 'e3', date: '2026-02-07', amount: 180000, status: 'closed_won' },
|
||
{ id: 'tx_13', agentId: 'e3', date: '2026-02-03', amount: 0, status: 'closed_lost' },
|
||
{ id: 'tx_14', agentId: 'e3', date: '2026-01-29', amount: 0, status: 'closed_lost' },
|
||
|
||
// Felicity Fast (Consistent)
|
||
{ id: 'tx_15', agentId: 'e4', date: '2026-02-10', amount: 310000, status: 'closed_won' },
|
||
{ id: 'tx_16', agentId: 'e4', date: '2026-02-04', amount: 305000, status: 'closed_won' },
|
||
{ id: 'tx_17', agentId: 'e4', date: '2026-01-27', amount: 295000, status: 'closed_won' },
|
||
|
||
// Felix Fixer (Closer - High Win Rate)
|
||
{ id: 'tx_18', agentId: 'e5', date: '2026-02-08', amount: 410000, status: 'closed_won' },
|
||
{ id: 'tx_19', agentId: 'e5', date: '2026-02-01', amount: 390000, status: 'closed_won' },
|
||
];
|
||
|
||
// Helper to generate meetings
|
||
function generateMockMeetings() {
|
||
const agents = ['e1', 'e2', 'e3', 'e4', 'e5'];
|
||
const statuses = ['Scheduled', 'Rescheduled', 'Completed', 'Converted', 'Cancelled'];
|
||
const meetings = [];
|
||
let meetingIdCounter = 1;
|
||
|
||
agents.forEach(agentId => {
|
||
// Generate ~7 meetings per agent
|
||
for (let i = 0; i < 7; i++) {
|
||
const isPast = i < 4; // First 4 are past/completed/converted
|
||
const status = isPast
|
||
? (Math.random() > 0.3 ? 'Completed' : (Math.random() > 0.5 ? 'Converted' : 'Cancelled')) // Past mix
|
||
: (Math.random() > 0.3 ? 'Scheduled' : 'Rescheduled'); // Future mix
|
||
|
||
// Date Logic
|
||
const date = new Date();
|
||
date.setDate(date.getDate() + (isPast ? -1 * (i + 1) * 2 : (i + 1) * 2)); // Spread out days
|
||
|
||
// Deal Value (only for relevant statuses)
|
||
let dealValue = null;
|
||
if (['Completed', 'Converted'].includes(status)) {
|
||
dealValue = Math.floor(Math.random() * (50000 - 5000) + 5000); // 5k to 50k
|
||
}
|
||
|
||
// Time Logic (09:00 to 16:00)
|
||
const hour = 9 + (i % 8);
|
||
const timeString = `${hour.toString().padStart(2, '0')}:00`;
|
||
|
||
// New Data Fields for Chatbot Context
|
||
const issues = [
|
||
"Leaking skylight in master bath",
|
||
"Missing shingles after recent storm",
|
||
"Water spots on ceiling",
|
||
"Gutter detachment on north side",
|
||
"General roof inspection requested"
|
||
];
|
||
const comments = [
|
||
"Customer is worried about upcoming rain.",
|
||
"Insurance adjuster already visited.",
|
||
"Prefer morning appointments.",
|
||
"Dog in backyard, please knock front door.",
|
||
"Previous contractor did poor work."
|
||
];
|
||
|
||
meetings.push({
|
||
id: `m${meetingIdCounter++}`,
|
||
agentId: agentId,
|
||
customerName: REAL_NAMES[(meetingIdCounter * 3) % REAL_NAMES.length], // Pick random names
|
||
propertyId: `P-${2600 + (meetingIdCounter * 2)}`,
|
||
date: date.toISOString().split('T')[0],
|
||
time: timeString,
|
||
status: status,
|
||
dealValue: dealValue,
|
||
notes: status === 'Converted' ? 'Contract signed for full roof replacement.' :
|
||
status === 'Rescheduled' ? 'Client verified availability.' : 'Standard consultation.',
|
||
// New Fields
|
||
issueDescription: issues[i % issues.length],
|
||
customerComments: comments[i % comments.length],
|
||
outcome: status === 'Converted' ? 'Signed Contract' : status === 'Completed' ? 'Quote Sent' : 'Pending'
|
||
});
|
||
}
|
||
});
|
||
|
||
// Generate Alice's Demo Meetings
|
||
const aliceMeetings = [
|
||
// Upcoming
|
||
{
|
||
id: `m-alice-1`,
|
||
agentId: 'e1',
|
||
customerName: 'Alice Customer',
|
||
customerId: 'c1', // Explicit ID link
|
||
propertyId: 'P-Alice-1',
|
||
date: new Date(Date.now() + 86400000 * 2).toISOString().split('T')[0], // 2 days from now
|
||
time: '14:00',
|
||
status: 'Scheduled',
|
||
agentName: 'Frank Agent',
|
||
notes: 'Initial Roof Inspection',
|
||
issueDescription: 'Noticed missing shingles after last storm.',
|
||
customerComments: 'Gate code is 1234.',
|
||
outcome: 'Pending'
|
||
},
|
||
// History
|
||
{
|
||
id: `m-alice-2`,
|
||
agentId: 'e2',
|
||
customerName: 'Alice Customer',
|
||
customerId: 'c1',
|
||
propertyId: 'P-Alice-1',
|
||
date: new Date(Date.now() - 86400000 * 15).toISOString().split('T')[0], // 15 days ago
|
||
time: '10:00',
|
||
status: 'Completed',
|
||
agentName: 'Fiona Field',
|
||
dealValue: 1500,
|
||
notes: 'Minor repairs completed. Payment received.',
|
||
issueDescription: 'Leak in garage.',
|
||
customerComments: 'Please call before arriving.',
|
||
outcome: 'Repairs Completed'
|
||
},
|
||
{
|
||
id: `m-alice-3`,
|
||
agentId: 'e1',
|
||
customerName: 'Alice Customer',
|
||
customerId: 'c1',
|
||
propertyId: 'P-Alice-1',
|
||
date: new Date(Date.now() - 86400000 * 45).toISOString().split('T')[0], // 45 days ago
|
||
time: '11:00',
|
||
status: 'Completed',
|
||
agentName: 'Frank Agent',
|
||
dealValue: 0,
|
||
notes: 'Consultation - Quote provided.',
|
||
issueDescription: 'General inspection.',
|
||
customerComments: '',
|
||
outcome: 'Quote Sent'
|
||
}
|
||
];
|
||
|
||
meetings.push(...aliceMeetings);
|
||
|
||
return meetings;
|
||
}
|
||
|
||
const MOCK_MEETINGS = generateMockMeetings();
|
||
|
||
// --- OWNER PROFILES ---
|
||
|
||
const MOCK_OWNERS = [
|
||
{
|
||
id: 'own_001',
|
||
companyName: 'Johnson Development Group',
|
||
primaryContact: 'Justin Johnson',
|
||
email: 'justin@johnsondev.com',
|
||
phone: '972-555-1234',
|
||
companyType: 'Real Estate Developer',
|
||
portfolioSize: 6,
|
||
activeProjects: 4,
|
||
completedProjects: 1,
|
||
onHoldProjects: 1,
|
||
totalInvestmentValue: 187000,
|
||
riskScore: 28,
|
||
status: 'Active',
|
||
location: { city: 'Plano', state: 'TX' },
|
||
memberSince: '2023-06-15',
|
||
lastActivityDate: '2026-02-15',
|
||
dashboardSummary: {
|
||
totalBudget: 187000,
|
||
committedCost: 156200,
|
||
actualSpent: 131500,
|
||
roiProjection: 12.4,
|
||
pendingApprovals: 3,
|
||
openChangeOrders: 2,
|
||
openRFIs: 1,
|
||
disputes: 1,
|
||
upcomingMilestones: [
|
||
{ name: 'Shingle Install Complete', project: '2604 Dunwick Dr', dueDate: '2026-02-14', projectId: 'proj_001' },
|
||
{ name: 'Electrical Hookup', project: '6613 Phoenix Pl', dueDate: '2026-02-14', projectId: 'proj_003' },
|
||
{ name: 'Flooring and Trim', project: '2612 Dunwick Dr', dueDate: '2026-02-18', projectId: 'proj_004' },
|
||
{ name: 'Panel Replacement', project: '3913 Arizona Pl', dueDate: '2026-02-20', projectId: 'proj_006' }
|
||
],
|
||
cashFlowForecast: [
|
||
{ month: 'Mar 2026', inflow: 45000, outflow: 38000 },
|
||
{ month: 'Apr 2026', inflow: 32000, outflow: 28000 },
|
||
{ month: 'May 2026', inflow: 18000, outflow: 15000 },
|
||
{ month: 'Jun 2026', inflow: 12000, outflow: 8000 },
|
||
{ month: 'Jul 2026', inflow: 8000, outflow: 5000 },
|
||
{ month: 'Aug 2026', inflow: 5000, outflow: 3000 }
|
||
],
|
||
monthlySpend: [
|
||
{ month: 'Mar 2025', amount: 0 },
|
||
{ month: 'Apr 2025', amount: 0 },
|
||
{ month: 'May 2025', amount: 0 },
|
||
{ month: 'Jun 2025', amount: 0 },
|
||
{ month: 'Jul 2025', amount: 0 },
|
||
{ month: 'Aug 2025', amount: 0 },
|
||
{ month: 'Sep 2025', amount: 0 },
|
||
{ month: 'Oct 2025', amount: 0 },
|
||
{ month: 'Nov 2025', amount: 8500 },
|
||
{ month: 'Dec 2025', amount: 33200 },
|
||
{ month: 'Jan 2026', amount: 52800 },
|
||
{ month: 'Feb 2026', amount: 37000 }
|
||
]
|
||
}
|
||
},
|
||
{
|
||
id: 'own_002',
|
||
companyName: 'Reeves Construction Partners',
|
||
primaryContact: 'Diana Reeves',
|
||
email: 'diana@reevesconstruction.com',
|
||
phone: '214-555-5678',
|
||
companyType: 'Institutional',
|
||
portfolioSize: 6,
|
||
activeProjects: 3,
|
||
completedProjects: 1,
|
||
onHoldProjects: 2,
|
||
totalInvestmentValue: 430000,
|
||
riskScore: 72,
|
||
status: 'High Risk',
|
||
location: { city: 'Plano', state: 'TX' },
|
||
memberSince: '2024-01-10',
|
||
lastActivityDate: '2026-02-12',
|
||
dashboardSummary: {
|
||
totalBudget: 430000,
|
||
committedCost: 385000,
|
||
actualSpent: 291300,
|
||
roiProjection: 4.8,
|
||
pendingApprovals: 5,
|
||
openChangeOrders: 5,
|
||
openRFIs: 3,
|
||
disputes: 2,
|
||
upcomingMilestones: [
|
||
{ name: 'Section A - TPO Install', project: '6909 Custer Rd', dueDate: '2026-02-28', projectId: 'proj_007' },
|
||
{ name: 'Final Grade and Drainage', project: '2112 Winslow Dr', dueDate: '2026-02-10', projectId: 'proj_008' },
|
||
{ name: 'Floor 2 Installation', project: '7224 Independence Pkwy', dueDate: '2026-02-14', projectId: 'proj_009' },
|
||
{ name: 'Waterproofing Application', project: 'Legacy Town Center', dueDate: '2026-02-12', projectId: 'proj_011' }
|
||
],
|
||
cashFlowForecast: [
|
||
{ month: 'Mar 2026', inflow: 85000, outflow: 92000 },
|
||
{ month: 'Apr 2026', inflow: 72000, outflow: 68000 },
|
||
{ month: 'May 2026', inflow: 55000, outflow: 45000 },
|
||
{ month: 'Jun 2026', inflow: 40000, outflow: 32000 },
|
||
{ month: 'Jul 2026', inflow: 25000, outflow: 18000 },
|
||
{ month: 'Aug 2026', inflow: 15000, outflow: 10000 }
|
||
],
|
||
monthlySpend: [
|
||
{ month: 'Mar 2025', amount: 0 },
|
||
{ month: 'Apr 2025', amount: 0 },
|
||
{ month: 'May 2025', amount: 0 },
|
||
{ month: 'Jun 2025', amount: 0 },
|
||
{ month: 'Jul 2025', amount: 0 },
|
||
{ month: 'Aug 2025', amount: 0 },
|
||
{ month: 'Sep 2025', amount: 14200 },
|
||
{ month: 'Oct 2025', amount: 35000 },
|
||
{ month: 'Nov 2025', amount: 52000 },
|
||
{ month: 'Dec 2025', amount: 68400 },
|
||
{ month: 'Jan 2026', amount: 74200 },
|
||
{ month: 'Feb 2026', amount: 47500 }
|
||
]
|
||
}
|
||
}
|
||
];
|
||
|
||
// --- NEW OWNERS BOX DATA SCHEMAS ---
|
||
|
||
const MOCK_PERSONNEL = [
|
||
{
|
||
id: 'p1',
|
||
name: 'Jesus Gonzales',
|
||
role: 'W2_EMPLOYEE',
|
||
email: 'jesus@lynkeduppro.com',
|
||
phone: '214-555-0101',
|
||
team: 'Sales Team A',
|
||
manager: 'Justin Johnson',
|
||
sensitiveData: {
|
||
ssn: '123-45-6789',
|
||
bankAccount: '9876543210'
|
||
},
|
||
compliance: {
|
||
w9Signed: true,
|
||
payPlanSigned: true,
|
||
driverLicense: {
|
||
uploaded: true,
|
||
expirationDate: '2026-08-15',
|
||
status: 'compliant'
|
||
}
|
||
},
|
||
status: 'active'
|
||
},
|
||
{
|
||
id: 'p2',
|
||
name: 'Sarah Sales',
|
||
role: '1099_SALES_REP',
|
||
email: 'sarah@lynkeduppro.com',
|
||
phone: '214-555-0102',
|
||
team: 'Sales Team A',
|
||
manager: 'Jesus Gonzales',
|
||
sensitiveData: {
|
||
ssn: '987-65-4321',
|
||
bankAccount: '1234567890'
|
||
},
|
||
compliance: {
|
||
w9Signed: true,
|
||
payPlanSigned: false,
|
||
driverLicense: {
|
||
uploaded: true,
|
||
expirationDate: '2025-12-01',
|
||
status: 'expiring'
|
||
}
|
||
},
|
||
status: 'active'
|
||
}
|
||
];
|
||
|
||
const MOCK_VENDORS = [
|
||
{
|
||
id: 'v1',
|
||
vendorName: 'Texas Roofing Crew A',
|
||
vendorType: 'roofing_crew',
|
||
primaryContact: {
|
||
name: 'Juan Perez',
|
||
email: 'juan@texasroofing.com',
|
||
phone: '469-555-0201'
|
||
},
|
||
sensitiveData: {
|
||
ein: '12-3456789',
|
||
bankAccount: '1122334455'
|
||
},
|
||
compliance: {
|
||
w9: { uploaded: true, status: 'approved' },
|
||
subcontractorAgreement: { uploaded: true, status: 'approved' },
|
||
coi: {
|
||
uploaded: true,
|
||
expirationDate: '2026-06-30',
|
||
status: 'compliant'
|
||
}
|
||
},
|
||
spend: {
|
||
totalSpend: 218000,
|
||
lastPayment: { date: '2026-02-08', amount: 18500 },
|
||
ytdSpend: 67000,
|
||
pendingInvoices: 4200
|
||
},
|
||
performance: {
|
||
rating: 4.8,
|
||
onTimeRate: 0.95,
|
||
jobsCompleted: 42,
|
||
activeJobs: 3
|
||
},
|
||
status: 'active'
|
||
},
|
||
{
|
||
id: 'v2',
|
||
vendorName: 'Sparky Electric',
|
||
vendorType: 'electrical',
|
||
primaryContact: {
|
||
name: 'Mike Spark',
|
||
email: 'mike@sparky.com',
|
||
phone: '469-555-0202'
|
||
},
|
||
sensitiveData: {
|
||
ein: '98-7654321',
|
||
bankAccount: '5544332211'
|
||
},
|
||
compliance: {
|
||
w9: { uploaded: true, status: 'approved' },
|
||
subcontractorAgreement: { uploaded: false, status: 'pending' },
|
||
coi: {
|
||
uploaded: true,
|
||
expirationDate: '2026-01-15',
|
||
status: 'expired'
|
||
}
|
||
},
|
||
spend: {
|
||
totalSpend: 9200,
|
||
lastPayment: { date: '2025-12-15', amount: 1800 },
|
||
ytdSpend: 0,
|
||
pendingInvoices: 3400
|
||
},
|
||
performance: {
|
||
rating: 4.2,
|
||
onTimeRate: 0.88,
|
||
jobsCompleted: 8,
|
||
activeJobs: 1
|
||
},
|
||
status: 'non_compliant'
|
||
},
|
||
{
|
||
id: 'v3',
|
||
vendorName: 'ABC Supply Co.',
|
||
vendorType: 'material_supplier',
|
||
primaryContact: {
|
||
name: 'Sales Desk',
|
||
email: 'sales@abcsupply.com',
|
||
phone: '972-555-8888'
|
||
},
|
||
sensitiveData: {
|
||
ein: '55-4433221',
|
||
bankAccount: '9988776655'
|
||
},
|
||
compliance: {
|
||
w9: { uploaded: true, status: 'approved' },
|
||
subcontractorAgreement: { uploaded: true, status: 'approved' },
|
||
coi: { uploaded: true, status: 'compliant', expirationDate: '2027-01-01' }
|
||
},
|
||
spend: {
|
||
totalSpend: 312000,
|
||
lastPayment: { date: '2026-02-12', amount: 22400 },
|
||
ytdSpend: 98000,
|
||
pendingInvoices: 15600
|
||
},
|
||
performance: {
|
||
rating: 5.0,
|
||
onTimeRate: 0.99,
|
||
jobsCompleted: 124,
|
||
activeJobs: 7
|
||
},
|
||
status: 'active'
|
||
},
|
||
{
|
||
id: 'v4',
|
||
vendorName: 'Lone Star Plumbing',
|
||
vendorType: 'plumbing',
|
||
primaryContact: {
|
||
name: 'Ray Gutierrez',
|
||
email: 'ray@lonestarplumbing.com',
|
||
phone: '469-555-0304'
|
||
},
|
||
sensitiveData: {
|
||
ein: '33-2211009',
|
||
bankAccount: '4455667788'
|
||
},
|
||
compliance: {
|
||
w9: { uploaded: true, status: 'approved' },
|
||
subcontractorAgreement: { uploaded: true, status: 'approved' },
|
||
coi: {
|
||
uploaded: true,
|
||
expirationDate: '2026-03-05',
|
||
status: 'compliant'
|
||
}
|
||
},
|
||
spend: {
|
||
totalSpend: 86000,
|
||
lastPayment: { date: '2026-01-20', amount: 7200 },
|
||
ytdSpend: 14500,
|
||
pendingInvoices: 8900
|
||
},
|
||
performance: {
|
||
rating: 4.5,
|
||
onTimeRate: 0.91,
|
||
jobsCompleted: 19,
|
||
activeJobs: 2
|
||
},
|
||
status: 'active'
|
||
},
|
||
{
|
||
id: 'v5',
|
||
vendorName: 'DFW Foundation Pros',
|
||
vendorType: 'foundation',
|
||
primaryContact: {
|
||
name: 'Tom Atkins',
|
||
email: 'tom@dfwfoundation.com',
|
||
phone: '214-555-0405'
|
||
},
|
||
sensitiveData: {
|
||
ein: '44-5566778',
|
||
bankAccount: '7788991100'
|
||
},
|
||
compliance: {
|
||
w9: { uploaded: false, status: 'pending' },
|
||
subcontractorAgreement: { uploaded: true, status: 'approved' },
|
||
coi: {
|
||
uploaded: true,
|
||
expirationDate: '2026-09-15',
|
||
status: 'compliant'
|
||
}
|
||
},
|
||
spend: {
|
||
totalSpend: 142000,
|
||
lastPayment: { date: '2026-01-10', amount: 24000 },
|
||
ytdSpend: 24000,
|
||
pendingInvoices: 18500
|
||
},
|
||
performance: {
|
||
rating: 3.9,
|
||
onTimeRate: 0.82,
|
||
jobsCompleted: 11,
|
||
activeJobs: 2
|
||
},
|
||
status: 'non_compliant'
|
||
},
|
||
{
|
||
id: 'v6',
|
||
vendorName: 'North Texas HVAC Solutions',
|
||
vendorType: 'hvac',
|
||
primaryContact: {
|
||
name: 'Linda Foster',
|
||
email: 'linda@ntxhvac.com',
|
||
phone: '972-555-0506'
|
||
},
|
||
sensitiveData: {
|
||
ein: '66-7788990',
|
||
bankAccount: '2233445566'
|
||
},
|
||
compliance: {
|
||
w9: { uploaded: true, status: 'approved' },
|
||
subcontractorAgreement: { uploaded: true, status: 'approved' },
|
||
coi: {
|
||
uploaded: true,
|
||
expirationDate: '2026-11-20',
|
||
status: 'compliant'
|
||
}
|
||
},
|
||
spend: {
|
||
totalSpend: 178000,
|
||
lastPayment: { date: '2026-02-05', amount: 9800 },
|
||
ytdSpend: 32000,
|
||
pendingInvoices: 6700
|
||
},
|
||
performance: {
|
||
rating: 4.6,
|
||
onTimeRate: 0.93,
|
||
jobsCompleted: 27,
|
||
activeJobs: 3
|
||
},
|
||
status: 'active'
|
||
}
|
||
];
|
||
|
||
const MOCK_ORDERS = [
|
||
{
|
||
id: 'ORD-001',
|
||
vendorId: 'v3',
|
||
projectId: 'proj_001',
|
||
projectAddress: '2604 Dunwick Dr, Plano, TX 75023',
|
||
orderDate: '2026-01-18',
|
||
dueDate: '2026-01-28',
|
||
deliveryDate: '2026-01-27',
|
||
status: 'delivered',
|
||
items: [
|
||
{
|
||
id: 'item_001',
|
||
description: 'Roofing Shingles - Architectural',
|
||
quantity: 50,
|
||
unit: 'bundles',
|
||
unitPrice: 45.00,
|
||
total: 2250.00,
|
||
specifications: 'GAF Timberline HDZ, Charcoal'
|
||
},
|
||
{
|
||
id: 'item_002',
|
||
description: 'Roofing Underlayment',
|
||
quantity: 10,
|
||
unit: 'rolls',
|
||
unitPrice: 85.00,
|
||
total: 850.00,
|
||
specifications: 'Synthetic, 10 sq per roll'
|
||
}
|
||
],
|
||
subtotal: 3100.00,
|
||
tax: 255.75,
|
||
total: 3355.75,
|
||
deliveryAddress: {
|
||
street: '2604 Dunwick Dr',
|
||
city: 'Plano',
|
||
state: 'TX',
|
||
zip: '75023',
|
||
instructions: 'Deliver to side yard, call foreman on arrival'
|
||
},
|
||
timeline: [
|
||
{ date: '2026-01-18', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2026-01-19', event: 'Order Confirmed', status: 'completed' },
|
||
{ date: '2026-01-24', event: 'Shipped', status: 'completed' },
|
||
{ date: '2026-01-27', event: 'Delivered', status: 'completed' }
|
||
],
|
||
documents: [
|
||
{ id: 'odoc_001', type: 'PO', name: 'PO-2604-Dunwick.pdf', url: '#' },
|
||
{ id: 'odoc_002', type: 'Invoice', name: 'INV-ORD001.pdf', url: '#' }
|
||
],
|
||
// TODO: cross-reference — Vendor: ABC Supply Co., Project Contractor: Texas Builders LLC
|
||
notes: 'Rush order for weather window',
|
||
contactPerson: 'Juan Perez',
|
||
contactPhone: '469-555-0201'
|
||
},
|
||
{
|
||
id: 'ORD-002',
|
||
vendorId: 'v3',
|
||
projectId: 'proj_002',
|
||
projectAddress: '2617 Rothland Ln, Plano, TX 75023',
|
||
orderDate: '2025-11-10',
|
||
dueDate: '2025-11-20',
|
||
deliveryDate: '2025-11-19',
|
||
status: 'delivered',
|
||
items: [
|
||
{
|
||
id: 'item_003',
|
||
description: 'Gutter System - Seamless Aluminum',
|
||
quantity: 150,
|
||
unit: 'linear feet',
|
||
unitPrice: 12.50,
|
||
total: 1875.00,
|
||
specifications: 'White, 5-inch K-style'
|
||
},
|
||
{
|
||
id: 'item_004',
|
||
description: 'Downspout Extensions',
|
||
quantity: 8,
|
||
unit: 'pieces',
|
||
unitPrice: 28.00,
|
||
total: 224.00,
|
||
specifications: 'Aluminum, matching white'
|
||
}
|
||
],
|
||
subtotal: 2099.00,
|
||
tax: 173.17,
|
||
total: 2272.17,
|
||
deliveryAddress: {
|
||
street: '2617 Rothland Ln',
|
||
city: 'Plano',
|
||
state: 'TX',
|
||
zip: '75023',
|
||
instructions: 'Leave at garage side'
|
||
},
|
||
timeline: [
|
||
{ date: '2025-11-10', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2025-11-11', event: 'Order Confirmed', status: 'completed' },
|
||
{ date: '2025-11-17', event: 'Shipped', status: 'completed' },
|
||
{ date: '2025-11-19', event: 'Delivered', status: 'completed' }
|
||
],
|
||
documents: [
|
||
{ id: 'odoc_003', type: 'PO', name: 'PO-2617-Rothland.pdf', url: '#' },
|
||
{ id: 'odoc_004', type: 'Delivery Receipt', name: 'DR-ORD002.pdf', url: '#' }
|
||
],
|
||
// TODO: cross-reference — Vendor: ABC Supply Co., Project Contractor: Texas Builders LLC
|
||
notes: 'Completed project delivery - all materials accounted for',
|
||
contactPerson: 'Sales Desk',
|
||
contactPhone: '972-555-8888'
|
||
},
|
||
{
|
||
id: 'ORD-003',
|
||
vendorId: 'v6',
|
||
projectId: 'proj_003',
|
||
projectAddress: '6613 Phoenix Pl, Plano, TX 75023',
|
||
orderDate: '2026-01-25',
|
||
dueDate: '2026-02-08',
|
||
deliveryDate: null,
|
||
status: 'shipped',
|
||
items: [
|
||
{
|
||
id: 'item_005',
|
||
description: 'Commercial HVAC Unit - 5 Ton',
|
||
quantity: 2,
|
||
unit: 'units',
|
||
unitPrice: 4200.00,
|
||
total: 8400.00,
|
||
specifications: 'Carrier 14 SEER2, R-410A'
|
||
},
|
||
{
|
||
id: 'item_006',
|
||
description: 'Ductwork - Flex',
|
||
quantity: 200,
|
||
unit: 'linear feet',
|
||
unitPrice: 6.50,
|
||
total: 1300.00,
|
||
specifications: 'R-8 insulated, 8-inch diameter'
|
||
}
|
||
],
|
||
subtotal: 9700.00,
|
||
tax: 800.25,
|
||
total: 10500.25,
|
||
deliveryAddress: {
|
||
street: '6613 Phoenix Pl',
|
||
city: 'Plano',
|
||
state: 'TX',
|
||
zip: '75023',
|
||
instructions: 'Equipment pad on south side of building'
|
||
},
|
||
timeline: [
|
||
{ date: '2026-01-25', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2026-01-27', event: 'Order Confirmed', status: 'completed' },
|
||
{ date: '2026-02-03', event: 'Shipped', status: 'completed' },
|
||
{ date: '2026-02-08', event: 'Estimated Delivery', status: 'pending' }
|
||
],
|
||
documents: [
|
||
{ id: 'odoc_005', type: 'PO', name: 'PO-6613-Phoenix-HVAC.pdf', url: '#' }
|
||
],
|
||
// TODO: cross-reference — Vendor: North Texas HVAC Solutions, Project Contractor: Texas Builders LLC
|
||
notes: 'HVAC units backordered 5 days, pushed delivery date',
|
||
contactPerson: 'Linda Foster',
|
||
contactPhone: '972-555-0506'
|
||
},
|
||
{
|
||
id: 'ORD-004',
|
||
vendorId: 'v5',
|
||
projectId: 'proj_008',
|
||
projectAddress: '2112 Winslow Dr, Plano, TX 75023',
|
||
orderDate: '2025-12-02',
|
||
dueDate: '2025-12-15',
|
||
deliveryDate: '2025-12-14',
|
||
status: 'delivered',
|
||
items: [
|
||
{
|
||
id: 'item_007',
|
||
description: 'Steel Piers - Foundation',
|
||
quantity: 18,
|
||
unit: 'piers',
|
||
unitPrice: 420.00,
|
||
total: 7560.00,
|
||
specifications: 'Galvanized steel, 12-foot depth rated'
|
||
},
|
||
{
|
||
id: 'item_008',
|
||
description: 'Hydraulic Jacks - Rental',
|
||
quantity: 6,
|
||
unit: 'units',
|
||
unitPrice: 180.00,
|
||
total: 1080.00,
|
||
specifications: '20-ton capacity, 30-day rental'
|
||
}
|
||
],
|
||
subtotal: 8640.00,
|
||
tax: 712.80,
|
||
total: 9352.80,
|
||
deliveryAddress: {
|
||
street: '2112 Winslow Dr',
|
||
city: 'Plano',
|
||
state: 'TX',
|
||
zip: '75023',
|
||
instructions: 'Loading dock access required, heavy equipment'
|
||
},
|
||
timeline: [
|
||
{ date: '2025-12-02', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2025-12-03', event: 'Order Confirmed', status: 'completed' },
|
||
{ date: '2025-12-10', event: 'Shipped', status: 'completed' },
|
||
{ date: '2025-12-14', event: 'Delivered', status: 'completed' }
|
||
],
|
||
documents: [
|
||
{ id: 'odoc_006', type: 'PO', name: 'PO-Winslow-Foundation.pdf', url: '#' },
|
||
{ id: 'odoc_007', type: 'Invoice', name: 'INV-ORD004.pdf', url: '#' },
|
||
{ id: 'odoc_008', type: 'Delivery Receipt', name: 'DR-ORD004.pdf', url: '#' }
|
||
],
|
||
// TODO: cross-reference — Vendor: DFW Foundation Pros, Project Contractor: Texas Builders LLC
|
||
notes: 'Foundation repair materials - additional piers ordered due to scope expansion',
|
||
contactPerson: 'Tom Atkins',
|
||
contactPhone: '214-555-0405'
|
||
},
|
||
{
|
||
id: 'ORD-005',
|
||
vendorId: 'v3',
|
||
projectId: 'proj_007',
|
||
projectAddress: '6909 Custer Rd, Plano, TX 75023',
|
||
orderDate: '2026-02-01',
|
||
dueDate: '2026-02-14',
|
||
deliveryDate: null,
|
||
status: 'confirmed',
|
||
items: [
|
||
{
|
||
id: 'item_009',
|
||
description: 'Commercial TPO Membrane',
|
||
quantity: 120,
|
||
unit: 'rolls',
|
||
unitPrice: 95.00,
|
||
total: 11400.00,
|
||
specifications: '60 mil, white, 10-ft wide'
|
||
},
|
||
{
|
||
id: 'item_010',
|
||
description: 'Roof Insulation Boards',
|
||
quantity: 300,
|
||
unit: 'sheets',
|
||
unitPrice: 18.50,
|
||
total: 5550.00,
|
||
specifications: 'Polyiso, 2-inch, 4x8'
|
||
},
|
||
{
|
||
id: 'item_011',
|
||
description: 'Mechanical Fasteners',
|
||
quantity: 40,
|
||
unit: 'boxes',
|
||
unitPrice: 52.00,
|
||
total: 2080.00,
|
||
specifications: 'FM-approved, #14 x 3-inch'
|
||
}
|
||
],
|
||
subtotal: 19030.00,
|
||
tax: 1569.98,
|
||
total: 20599.98,
|
||
deliveryAddress: {
|
||
street: '6909 Custer Rd',
|
||
city: 'Plano',
|
||
state: 'TX',
|
||
zip: '75023',
|
||
instructions: 'Crane lift to rooftop, coordinate 48hrs in advance'
|
||
},
|
||
timeline: [
|
||
{ date: '2026-02-01', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2026-02-03', event: 'Order Confirmed', status: 'completed' },
|
||
{ date: '2026-02-10', event: 'Estimated Ship Date', status: 'pending' },
|
||
{ date: '2026-02-14', event: 'Estimated Delivery', status: 'pending' }
|
||
],
|
||
documents: [
|
||
{ id: 'odoc_009', type: 'PO', name: 'PO-Custer-Commercial-Roof.pdf', url: '#' }
|
||
],
|
||
// TODO: cross-reference — Vendor: ABC Supply Co., Project Contractor: Texas Builders LLC
|
||
notes: 'Large commercial order - confirm crane availability before ship',
|
||
contactPerson: 'Sales Desk',
|
||
contactPhone: '972-555-8888'
|
||
},
|
||
{
|
||
id: 'ORD-006',
|
||
vendorId: 'v4',
|
||
projectId: 'proj_012',
|
||
projectAddress: 'Dallas/Plano Marriott at Legacy Town Center, 7121 Bishop Rd, Plano, TX 75024',
|
||
orderDate: '2026-01-15',
|
||
dueDate: '2026-01-30',
|
||
deliveryDate: '2026-01-29',
|
||
status: 'delivered',
|
||
items: [
|
||
{
|
||
id: 'item_012',
|
||
description: 'Commercial Grade PVC Pipe - 4 inch',
|
||
quantity: 400,
|
||
unit: 'linear feet',
|
||
unitPrice: 8.75,
|
||
total: 3500.00,
|
||
specifications: 'Schedule 40, SDR-26'
|
||
},
|
||
{
|
||
id: 'item_013',
|
||
description: 'Ball Valves - Brass',
|
||
quantity: 24,
|
||
unit: 'pieces',
|
||
unitPrice: 42.00,
|
||
total: 1008.00,
|
||
specifications: '2-inch, full port, lead-free'
|
||
},
|
||
{
|
||
id: 'item_014',
|
||
description: 'Water Heater - Commercial Tankless',
|
||
quantity: 3,
|
||
unit: 'units',
|
||
unitPrice: 2800.00,
|
||
total: 8400.00,
|
||
specifications: 'Rinnai CU199iN, 199K BTU'
|
||
}
|
||
],
|
||
subtotal: 12908.00,
|
||
tax: 1064.91,
|
||
total: 13972.91,
|
||
deliveryAddress: {
|
||
street: '7121 Bishop Rd',
|
||
city: 'Plano',
|
||
state: 'TX',
|
||
zip: '75024',
|
||
instructions: 'Service entrance, coordinate with building management'
|
||
},
|
||
timeline: [
|
||
{ date: '2026-01-15', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2026-01-16', event: 'Order Confirmed', status: 'completed' },
|
||
{ date: '2026-01-24', event: 'Shipped', status: 'completed' },
|
||
{ date: '2026-01-29', event: 'Delivered', status: 'completed' }
|
||
],
|
||
documents: [
|
||
{ id: 'odoc_010', type: 'PO', name: 'PO-Marriott-Plumbing.pdf', url: '#' },
|
||
{ id: 'odoc_011', type: 'Delivery Receipt', name: 'DR-ORD006.pdf', url: '#' },
|
||
{ id: 'odoc_012', type: 'Invoice', name: 'INV-ORD006.pdf', url: '#' }
|
||
],
|
||
// TODO: cross-reference — Vendor: Lone Star Plumbing, Project Contractor: Texas Builders LLC
|
||
notes: 'Plumbing overhaul materials - project currently on hold pending permit review',
|
||
contactPerson: 'Ray Gutierrez',
|
||
contactPhone: '469-555-0304'
|
||
},
|
||
{
|
||
id: 'ORD-007',
|
||
vendorId: 'v3',
|
||
projectId: 'proj_004',
|
||
projectAddress: '2612 Dunwick Dr, Plano, TX 75023',
|
||
orderDate: '2026-02-15',
|
||
dueDate: '2026-02-28',
|
||
deliveryDate: null,
|
||
status: 'pending',
|
||
items: [
|
||
{ id: 'item_015', description: 'Interior Drywall Sheets', quantity: 80, unit: 'sheets', unitPrice: 14.50, total: 1160.00, specifications: '4x8, 1/2-inch, fire-rated' },
|
||
{ id: 'item_016', description: 'Joint Compound', quantity: 12, unit: 'buckets', unitPrice: 22.00, total: 264.00, specifications: 'All-purpose, 5-gallon' }
|
||
],
|
||
subtotal: 1424.00,
|
||
tax: 117.48,
|
||
total: 1541.48,
|
||
deliveryAddress: { street: '2612 Dunwick Dr', city: 'Plano', state: 'TX', zip: '75023', instructions: 'Front entrance, stack in garage' },
|
||
timeline: [
|
||
{ date: '2026-02-15', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2026-02-28', event: 'Estimated Delivery', status: 'pending' }
|
||
],
|
||
documents: [{ id: 'odoc_013', type: 'PO', name: 'PO-Dunwick-Drywall.pdf', url: '#' }],
|
||
notes: 'Awaiting vendor confirmation',
|
||
contactPerson: 'Sales Desk',
|
||
contactPhone: '972-555-8888'
|
||
},
|
||
{
|
||
id: 'ORD-008',
|
||
vendorId: 'v3',
|
||
projectId: 'proj_009',
|
||
projectAddress: '7224 Independence Pkwy, Plano, TX 75025',
|
||
orderDate: '2026-02-10',
|
||
dueDate: '2026-02-22',
|
||
deliveryDate: null,
|
||
status: 'shipped',
|
||
items: [
|
||
{ id: 'item_017', description: 'Window Sealant - Exterior Grade', quantity: 48, unit: 'tubes', unitPrice: 8.50, total: 408.00, specifications: 'Silicone, clear, UV-resistant' },
|
||
{ id: 'item_018', description: 'Flashing Tape - Self-Adhesive', quantity: 20, unit: 'rolls', unitPrice: 35.00, total: 700.00, specifications: '6-inch, peel-and-stick, 75-ft' }
|
||
],
|
||
subtotal: 1108.00,
|
||
tax: 91.41,
|
||
total: 1199.41,
|
||
deliveryAddress: { street: '7224 Independence Pkwy', city: 'Plano', state: 'TX', zip: '75025', instructions: 'Leave at side entrance' },
|
||
timeline: [
|
||
{ date: '2026-02-10', event: 'Order Placed', status: 'completed' },
|
||
{ date: '2026-02-11', event: 'Order Confirmed', status: 'completed' },
|
||
{ date: '2026-02-17', event: 'Shipped', status: 'completed' },
|
||
{ date: '2026-02-22', event: 'Estimated Delivery', status: 'pending' }
|
||
],
|
||
documents: [{ id: 'odoc_014', type: 'PO', name: 'PO-Independence-Sealant.pdf', url: '#' }],
|
||
notes: 'In transit via FedEx Freight',
|
||
contactPerson: 'Sales Desk',
|
||
contactPhone: '972-555-8888'
|
||
}
|
||
];
|
||
|
||
const MOCK_VENDOR_INVOICES = [
|
||
{
|
||
id: 'INV-2026-001',
|
||
vendorId: 'v3',
|
||
orderId: 'ORD-002',
|
||
projectId: 'proj_002',
|
||
project: '2617 Rothland Ln, Plano, TX 75023',
|
||
invoiceDate: '2025-11-22',
|
||
dueDate: '2025-12-07',
|
||
amount: 2272.17,
|
||
status: 'paid',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Gutter System and Downspout Materials'
|
||
},
|
||
{
|
||
id: 'INV-2026-002',
|
||
vendorId: 'v3',
|
||
orderId: 'ORD-001',
|
||
projectId: 'proj_001',
|
||
project: '2604 Dunwick Dr, Plano, TX 75023',
|
||
invoiceDate: '2026-01-28',
|
||
dueDate: '2026-02-12',
|
||
amount: 3355.75,
|
||
status: 'pending',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Roofing Shingles and Underlayment Delivery'
|
||
},
|
||
{
|
||
id: 'INV-2026-003',
|
||
vendorId: 'v6',
|
||
orderId: 'ORD-003',
|
||
projectId: 'proj_003',
|
||
project: '6613 Phoenix Pl, Plano, TX 75023',
|
||
invoiceDate: '2026-02-04',
|
||
dueDate: '2026-02-19',
|
||
amount: 10500.25,
|
||
status: 'pending',
|
||
paymentTerms: 'Net 15',
|
||
description: 'HVAC Units and Ductwork Delivery'
|
||
},
|
||
{
|
||
id: 'INV-2026-004',
|
||
vendorId: 'v5',
|
||
orderId: 'ORD-004',
|
||
projectId: 'proj_008',
|
||
project: '2112 Winslow Dr, Plano, TX 75023',
|
||
invoiceDate: '2025-12-16',
|
||
dueDate: '2025-12-31',
|
||
amount: 9352.80,
|
||
status: 'paid',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Foundation Steel Piers and Equipment Rental'
|
||
},
|
||
{
|
||
id: 'INV-2026-005',
|
||
vendorId: 'v3',
|
||
orderId: 'ORD-005',
|
||
projectId: 'proj_007',
|
||
project: '6909 Custer Rd, Plano, TX 75023',
|
||
invoiceDate: '2026-02-03',
|
||
dueDate: '2026-02-18',
|
||
amount: 20599.98,
|
||
status: 'pending',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Commercial TPO Roofing Materials'
|
||
},
|
||
{
|
||
id: 'INV-2026-006',
|
||
vendorId: 'v4',
|
||
orderId: 'ORD-006',
|
||
projectId: 'proj_012',
|
||
project: 'Dallas/Plano Marriott, 7121 Bishop Rd, Plano, TX 75024',
|
||
invoiceDate: '2026-01-30',
|
||
dueDate: '2026-02-14',
|
||
amount: 13972.91,
|
||
status: 'pending',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Commercial Plumbing Materials and Water Heaters'
|
||
},
|
||
{
|
||
id: 'INV-2026-007',
|
||
vendorId: 'v1',
|
||
orderId: 'ORD-LABOR-001',
|
||
projectId: 'proj_004',
|
||
project: '2612 Dunwick Dr, Plano, TX 75023',
|
||
invoiceDate: '2026-02-10',
|
||
dueDate: '2026-02-25',
|
||
amount: 8750.00,
|
||
status: 'pending',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Interior Renovation - Roofing Crew Labor Week 3'
|
||
},
|
||
{
|
||
id: 'INV-2026-008',
|
||
vendorId: 'v3',
|
||
orderId: 'ORD-MAT-006',
|
||
projectId: 'proj_006',
|
||
project: '3913 Arizona Pl, Plano, TX 75023',
|
||
invoiceDate: '2026-02-07',
|
||
dueDate: '2026-02-22',
|
||
amount: 2850.00,
|
||
status: 'pending',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Electrical Panel and Circuit Breaker Materials'
|
||
},
|
||
{
|
||
id: 'INV-2025-045',
|
||
vendorId: 'v1',
|
||
orderId: 'ORD-HIST-001',
|
||
projectId: 'proj_010',
|
||
project: '2100 Legacy Dr, Plano, TX 75023',
|
||
invoiceDate: '2025-10-15',
|
||
dueDate: '2025-10-30',
|
||
amount: 14200.00,
|
||
status: 'paid',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Parking Lot Resurfacing Crew Labor'
|
||
},
|
||
{
|
||
id: 'INV-2025-046',
|
||
vendorId: 'v3',
|
||
orderId: 'ORD-HIST-002',
|
||
projectId: 'proj_010',
|
||
project: '2100 Legacy Dr, Plano, TX 75023',
|
||
invoiceDate: '2025-10-02',
|
||
dueDate: '2025-10-17',
|
||
amount: 8400.00,
|
||
status: 'paid',
|
||
paymentTerms: 'Net 15',
|
||
description: 'Asphalt and Sealant Materials'
|
||
}
|
||
];
|
||
|
||
const MOCK_DOCUMENTS = [
|
||
{
|
||
id: 'd1',
|
||
name: 'Jesus Gonzales - Driver License',
|
||
entityId: 'p1',
|
||
entityType: 'personnel',
|
||
entityName: 'Jesus Gonzales',
|
||
vendorId: 'v1',
|
||
documentType: 'DL',
|
||
fileName: 'JG_DriverLicense.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Jesus Gonzales',
|
||
uploadedAt: '2025-08-15',
|
||
expirationDate: '2026-08-15',
|
||
status: 'approved',
|
||
aiConfidence: 0.98,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2025-08-16'
|
||
},
|
||
{
|
||
id: 'd2',
|
||
name: 'Sparky Electric - Certificate of Insurance',
|
||
entityId: 'v2',
|
||
entityType: 'vendor',
|
||
entityName: 'Sparky Electric',
|
||
vendorId: 'v2',
|
||
documentType: 'COI',
|
||
fileName: 'Sparky_COI_2025.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Mike Spark',
|
||
uploadedAt: '2025-01-10',
|
||
expirationDate: '2026-01-15',
|
||
status: 'expired',
|
||
aiConfidence: 0.95,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2025-01-11'
|
||
},
|
||
{
|
||
id: 'd3',
|
||
name: 'Sarah Sales - Pay Plan Agreement',
|
||
entityId: 'p2',
|
||
entityType: 'personnel',
|
||
entityName: 'Sarah Sales',
|
||
vendorId: 'v1',
|
||
documentType: 'PAY_PLAN',
|
||
fileName: 'Sarah_PayPlan_Signed.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Sarah Sales',
|
||
uploadedAt: '2026-02-14',
|
||
expirationDate: '2027-02-14',
|
||
status: 'pending_review',
|
||
aiConfidence: 0.88,
|
||
reviewedBy: null,
|
||
reviewedAt: null
|
||
},
|
||
{
|
||
id: 'd4',
|
||
name: 'Lone Star Plumbing - Certificate of Insurance',
|
||
entityId: 'v4',
|
||
entityType: 'vendor',
|
||
entityName: 'Lone Star Plumbing',
|
||
vendorId: 'v4',
|
||
documentType: 'COI',
|
||
fileName: 'LoneStarPlumbing_COI_2026.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Ray Gutierrez',
|
||
uploadedAt: '2025-03-10',
|
||
expirationDate: '2026-03-05',
|
||
status: 'approved',
|
||
aiConfidence: 0.96,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2025-03-11'
|
||
},
|
||
{
|
||
id: 'd5',
|
||
name: 'DFW Foundation Pros - W9 Form',
|
||
entityId: 'v5',
|
||
entityType: 'vendor',
|
||
entityName: 'DFW Foundation Pros',
|
||
vendorId: 'v5',
|
||
documentType: 'W9',
|
||
fileName: 'DFW_Foundation_W9.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Tom Atkins',
|
||
uploadedAt: '2026-01-20',
|
||
expirationDate: '2027-01-20',
|
||
status: 'pending_review',
|
||
aiConfidence: 0.82,
|
||
reviewedBy: null,
|
||
reviewedAt: null
|
||
},
|
||
{
|
||
id: 'd6',
|
||
name: 'Texas Roofing Crew A - Subcontractor Agreement',
|
||
entityId: 'v1',
|
||
entityType: 'vendor',
|
||
entityName: 'Texas Roofing Crew A',
|
||
vendorId: 'v1',
|
||
documentType: 'SUB_AGREEMENT',
|
||
fileName: 'TexasRoofing_SubAgreement_2026.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Juan Perez',
|
||
uploadedAt: '2025-12-01',
|
||
expirationDate: '2026-12-01',
|
||
status: 'approved',
|
||
aiConfidence: 0.97,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2025-12-02'
|
||
},
|
||
{
|
||
id: 'd7',
|
||
name: 'North Texas HVAC - Certificate of Insurance',
|
||
entityId: 'v6',
|
||
entityType: 'vendor',
|
||
entityName: 'North Texas HVAC Solutions',
|
||
vendorId: 'v6',
|
||
documentType: 'COI',
|
||
fileName: 'NTXHVAC_COI_2026.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Linda Foster',
|
||
uploadedAt: '2025-11-25',
|
||
expirationDate: '2026-11-20',
|
||
status: 'approved',
|
||
aiConfidence: 0.94,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2025-11-26'
|
||
},
|
||
{
|
||
id: 'd8',
|
||
name: 'ABC Supply Co. - Certificate of Insurance',
|
||
entityId: 'v3',
|
||
entityType: 'vendor',
|
||
entityName: 'ABC Supply Co.',
|
||
vendorId: 'v3',
|
||
documentType: 'COI',
|
||
fileName: 'ABCSupply_COI_2027.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Sales Desk',
|
||
uploadedAt: '2026-01-05',
|
||
expirationDate: '2027-01-01',
|
||
status: 'approved',
|
||
aiConfidence: 0.99,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2026-01-06'
|
||
},
|
||
{
|
||
id: 'd9',
|
||
name: 'Sparky Electric - W9 Form',
|
||
entityId: 'v2',
|
||
entityType: 'vendor',
|
||
entityName: 'Sparky Electric',
|
||
vendorId: 'v2',
|
||
documentType: 'W9',
|
||
fileName: 'Sparky_W9_2026.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Mike Spark',
|
||
uploadedAt: '2026-02-01',
|
||
expirationDate: '2027-02-01',
|
||
status: 'approved',
|
||
aiConfidence: 0.91,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2026-02-02'
|
||
},
|
||
{
|
||
id: 'd10',
|
||
name: 'DFW Foundation Pros - Certificate of Insurance',
|
||
entityId: 'v5',
|
||
entityType: 'vendor',
|
||
entityName: 'DFW Foundation Pros',
|
||
vendorId: 'v5',
|
||
documentType: 'COI',
|
||
fileName: 'DFW_Foundation_COI_2026.pdf',
|
||
fileUrl: '#',
|
||
uploadedBy: 'Tom Atkins',
|
||
uploadedAt: '2025-09-20',
|
||
expirationDate: '2026-09-15',
|
||
status: 'approved',
|
||
aiConfidence: 0.93,
|
||
reviewedBy: 'Admin',
|
||
reviewedAt: '2025-09-21'
|
||
}
|
||
];
|
||
|
||
const MOCK_PROJECTS = [
|
||
// =====================================================================
|
||
// OWNER 1: Marcus Whitfield (own_001) — 6 Projects
|
||
// Active owner, strong financials, one project under dispute
|
||
// =====================================================================
|
||
|
||
// Project 1: Active, on track, healthy budget
|
||
{
|
||
id: 'proj_001',
|
||
ownerId: 'own_001',
|
||
propertyId: 'P-2602',
|
||
address: '2604 Dunwick Dr, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: ['sub_001'],
|
||
projectType: 'Roof Replacement',
|
||
status: 'active',
|
||
phase: 'Structural',
|
||
budget: 45000,
|
||
approvedBudget: 45000,
|
||
committedCost: 38500,
|
||
actualCost: 22500,
|
||
spent: 22500,
|
||
variancePercent: -50.0,
|
||
margin: 0.40,
|
||
startDate: '2026-01-20',
|
||
endDate: '2026-03-05',
|
||
completionPercentage: 55,
|
||
healthScore: 82,
|
||
openRFIs: 0,
|
||
changeOrderCount: 0,
|
||
pendingInvoiceCount: 2,
|
||
budgetBreakdown: [
|
||
{ category: 'Materials - Shingles', allocated: 15000, committed: 14200, actual: 8500 },
|
||
{ category: 'Materials - Underlayment', allocated: 3500, committed: 3355, actual: 3355 },
|
||
{ category: 'Labor - Tear Off', allocated: 8000, committed: 8000, actual: 8000 },
|
||
{ category: 'Labor - Install', allocated: 12000, committed: 7200, actual: 0 },
|
||
{ category: 'Permits & Inspection', allocated: 2500, committed: 2500, actual: 2645 },
|
||
{ category: 'Cleanup & Haul-Away', allocated: 4000, committed: 3245, actual: 0 }
|
||
],
|
||
changeOrders: [],
|
||
rfis: [],
|
||
riskLog: [
|
||
{ id: 'risk_001_1', description: 'Weather delay risk during February', severity: 'Medium', likelihood: 'Likely', mitigation: 'Monitor 10-day forecast, flex schedule for rain days', status: 'monitoring' },
|
||
{ id: 'risk_001_2', description: 'Material price increase from supplier', severity: 'Low', likelihood: 'Unlikely', mitigation: 'Price locked with PO', status: 'mitigated' }
|
||
],
|
||
issueLog: [],
|
||
paymentSchedule: [
|
||
{ id: 'ps_001_1', milestone: 'Mobilization (20%)', amount: 9000, dueDate: '2026-01-22', status: 'paid' },
|
||
{ id: 'ps_001_2', milestone: 'Tear-off Complete (30%)', amount: 13500, dueDate: '2026-02-01', status: 'paid' },
|
||
{ id: 'ps_001_3', milestone: 'Install Complete (30%)', amount: 13500, dueDate: '2026-02-20', status: 'pending' },
|
||
{ id: 'ps_001_4', milestone: 'Final Inspection (20%)', amount: 9000, dueDate: '2026-03-05', status: 'pending' }
|
||
],
|
||
activityTimeline: [
|
||
{ date: '2026-02-12', action: 'Invoice Submitted', user: 'ABC Supply Co.', details: 'INV-001-2 for roofing materials - $3,355.75' },
|
||
{ date: '2026-02-08', action: 'Milestone Completed', user: 'Texas Roofing Crew A', details: 'Dry-In Inspection passed' },
|
||
{ date: '2026-02-01', action: 'Payment Released', user: 'Justin Johnson', details: 'Tear-off milestone payment - $12,000' },
|
||
{ date: '2026-01-27', action: 'Material Delivered', user: 'ABC Supply Co.', details: 'Shingles and underlayment delivered to site' },
|
||
{ date: '2026-01-20', action: 'Project Started', user: 'Texas Builders LLC', details: 'Roof replacement project kicked off' }
|
||
],
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: ABC Supply Co., Texas Roofing Crew A
|
||
milestones: [
|
||
{ id: 'ms_001_1', name: 'Material Delivery', dueDate: '2026-01-25', status: 'completed', assignedTo: 'v3' },
|
||
{ id: 'ms_001_2', name: 'Roof Tear-off', dueDate: '2026-01-30', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_001_3', name: 'Dry-In Inspection', dueDate: '2026-02-03', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_001_4', name: 'Shingle Install', dueDate: '2026-02-14', status: 'in_progress', assignedTo: 'v1' },
|
||
{ id: 'ms_001_5', name: 'Final Inspection', dueDate: '2026-03-01', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_001_1', amount: 12000, submittedBy: 'con_001', status: 'paid', dueDate: '2026-02-01', datePaid: '2026-02-02' },
|
||
{ id: 'inv_001_2', amount: 3355.75, submittedBy: 'v3', status: 'pending', dueDate: '2026-02-12' },
|
||
{ id: 'inv_001_3', amount: 7200, submittedBy: 'v1', status: 'pending', dueDate: '2026-02-20' }
|
||
],
|
||
documents: [
|
||
{ name: 'Scope of Work - Roof Replacement', url: '#', type: 'contract' },
|
||
{ name: 'Permit #26-0401', url: '#', type: 'permit' },
|
||
{ name: 'Material Order PO-2604', url: '#', type: 'invoice' }
|
||
]
|
||
},
|
||
|
||
// Project 2: Completed, zero variance (perfectly on budget)
|
||
{
|
||
id: 'proj_002',
|
||
ownerId: 'own_001',
|
||
propertyId: 'P-2608',
|
||
address: '2617 Rothland Ln, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: [],
|
||
projectType: 'Gutter Replacement',
|
||
status: 'completed',
|
||
phase: 'Handover',
|
||
budget: 8500,
|
||
approvedBudget: 8500,
|
||
committedCost: 8500,
|
||
actualCost: 8500,
|
||
spent: 8500,
|
||
variancePercent: 0,
|
||
margin: 0.35,
|
||
startDate: '2025-11-15',
|
||
endDate: '2025-12-10',
|
||
completionPercentage: 100,
|
||
healthScore: 100,
|
||
openRFIs: 0,
|
||
changeOrderCount: 0,
|
||
pendingInvoiceCount: 0,
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: ABC Supply Co.
|
||
milestones: [
|
||
{ id: 'ms_002_1', name: 'Old Gutter Removal', dueDate: '2025-11-18', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_002_2', name: 'Material Delivery', dueDate: '2025-11-20', status: 'completed', assignedTo: 'v3' },
|
||
{ id: 'ms_002_3', name: 'Seamless Gutter Install', dueDate: '2025-11-28', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_002_4', name: 'Downspout Routing', dueDate: '2025-12-03', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_002_5', name: 'Final Walkthrough', dueDate: '2025-12-08', status: 'completed', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_002_1', amount: 2272.17, submittedBy: 'v3', status: 'paid', dueDate: '2025-11-25', datePaid: '2025-11-26' },
|
||
{ id: 'inv_002_2', amount: 4200, submittedBy: 'con_001', status: 'paid', dueDate: '2025-12-05', datePaid: '2025-12-06' },
|
||
{ id: 'inv_002_3', amount: 2027.83, submittedBy: 'con_001', status: 'paid', dueDate: '2025-12-10', datePaid: '2025-12-10' }
|
||
],
|
||
documents: [
|
||
{ name: 'Scope of Work - Gutter', url: '#', type: 'contract' },
|
||
{ name: 'Completion Certificate', url: '#', type: 'certificate' },
|
||
{ name: 'Final Invoice Package', url: '#', type: 'invoice' },
|
||
{ name: 'Warranty Registration', url: '#', type: 'warranty' }
|
||
]
|
||
},
|
||
|
||
// Project 3: Delayed with missed milestone
|
||
{
|
||
id: 'proj_003',
|
||
ownerId: 'own_001',
|
||
propertyId: 'P-2610',
|
||
address: '6613 Phoenix Pl, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: ['sub_001'],
|
||
projectType: 'HVAC Installation',
|
||
status: 'active',
|
||
phase: 'MEP',
|
||
budget: 32000,
|
||
approvedBudget: 32000,
|
||
committedCost: 28200,
|
||
actualCost: 18400,
|
||
spent: 18400,
|
||
variancePercent: -42.5,
|
||
margin: 0.30,
|
||
startDate: '2026-01-06',
|
||
endDate: '2026-02-28',
|
||
completionPercentage: 42,
|
||
healthScore: 58,
|
||
openRFIs: 1,
|
||
changeOrderCount: 2,
|
||
pendingInvoiceCount: 2,
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: North Texas HVAC Solutions, ABC Supply Co.
|
||
milestones: [
|
||
{ id: 'ms_003_1', name: 'Site Preparation', dueDate: '2026-01-10', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_003_2', name: 'Ductwork Rough-In', dueDate: '2026-01-20', status: 'completed', assignedTo: 'v6' },
|
||
{ id: 'ms_003_3', name: 'Equipment Delivery', dueDate: '2026-01-30', status: 'completed', assignedTo: 'v6' },
|
||
{ id: 'ms_003_4', name: 'Unit Installation', dueDate: '2026-02-07', status: 'in_progress', assignedTo: 'v6' },
|
||
{ id: 'ms_003_5', name: 'Electrical Hookup', dueDate: '2026-02-14', status: 'pending', assignedTo: 'sub_001' },
|
||
{ id: 'ms_003_6', name: 'System Test and Commissioning', dueDate: '2026-02-25', status: 'pending', assignedTo: 'v6' }
|
||
],
|
||
budgetBreakdown: [
|
||
{ category: 'Equipment & Materials', allocated: 15000, committed: 15000, actual: 12500 },
|
||
{ category: 'Labor - HVAC', allocated: 8000, committed: 8000, actual: 4000 },
|
||
{ category: 'Labor - Electrical', allocated: 3000, committed: 3000, actual: 0 },
|
||
{ category: 'Permits & Fees', allocated: 1000, committed: 1000, actual: 950 },
|
||
{ category: 'Contingency', allocated: 5000, committed: 1200, actual: 950 }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_003_1', amount: 8200, submittedBy: 'con_001', status: 'paid', dueDate: '2026-01-15', datePaid: '2026-01-16' },
|
||
{ id: 'inv_003_2', amount: 10500.25, submittedBy: 'v6', status: 'pending', dueDate: '2026-02-19' },
|
||
{ id: 'inv_003_3', amount: 3400, submittedBy: 'v2', status: 'pending', dueDate: '2026-02-22' }
|
||
],
|
||
changeOrders: [
|
||
{ id: 'CO-003-01', title: 'Upsize Return Ducts', amount: 1200, status: 'approved', dateSubmitted: '2026-01-22', description: 'Increase return duct size for better airflow in master bedroom.' },
|
||
{ id: 'CO-003-02', title: 'Smart Thermostat Upgrade', amount: 450, status: 'pending', dateSubmitted: '2026-02-18', description: 'Upgrade to Ecobee Premium thermostats per owner request.' }
|
||
],
|
||
rfis: [
|
||
{ id: 'RFI-003-01', subject: 'Condenser Pad Location', status: 'closed', submittedBy: 'North Texas HVAC', dateOpened: '2026-01-12', dateClosed: '2026-01-14' },
|
||
{ id: 'RFI-003-02', subject: 'Duct Routing Conflict in Attic', status: 'open', submittedBy: 'Texas Builders LLC', dateOpened: '2026-02-15' }
|
||
],
|
||
riskLog: [
|
||
{ id: 'risk_003_1', description: 'Equipment backorder from manufacturer', severity: 'High', likelihood: 'Likely', mitigation: 'Source equivalent unit from secondary distributor', status: 'open' }
|
||
],
|
||
issueLog: [
|
||
{ id: 'issue_003_1', title: 'Failed framing inspection for duct clearance', priority: 'High', status: 'open', assignedTo: 'Texas Builders LLC', dateReported: '2026-02-14' }
|
||
],
|
||
activityTimeline: [
|
||
{ date: '2026-02-15', action: 'RFI Submitted', user: 'Site Supervisor', details: 'Duct routing conflict in attic' },
|
||
{ date: '2026-02-14', action: 'Inspection Failed', user: 'City Inspector', details: 'Framing clearance insufficient for 12" ducts' },
|
||
{ date: '2026-01-30', action: 'Milestone Completed', user: 'North Texas HVAC', details: 'Equipment Delivery phase finished' }
|
||
],
|
||
documents: [
|
||
{ name: 'HVAC Design Plans', url: '#', type: 'plans' },
|
||
{ name: 'Mechanical Permit #26-0187', url: '#', type: 'permit' },
|
||
{ name: 'Equipment Spec Sheets', url: '#', type: 'specification' }
|
||
]
|
||
},
|
||
|
||
// Project 4: Active, over budget (spent > budget)
|
||
{
|
||
id: 'proj_004',
|
||
ownerId: 'own_001',
|
||
propertyId: 'P-2600',
|
||
address: '2612 Dunwick Dr, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: ['sub_001'],
|
||
projectType: 'Interior Renovation',
|
||
status: 'active',
|
||
phase: 'Finishing',
|
||
budget: 55000,
|
||
approvedBudget: 55000,
|
||
committedCost: 62300,
|
||
actualCost: 62300,
|
||
spent: 62300,
|
||
variancePercent: 13.3,
|
||
margin: -0.13,
|
||
startDate: '2025-12-01',
|
||
endDate: '2026-02-28',
|
||
completionPercentage: 78,
|
||
healthScore: 35,
|
||
openRFIs: 1,
|
||
changeOrderCount: 2,
|
||
pendingInvoiceCount: 2,
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: ABC Supply Co., Texas Roofing Crew A, Sparky Electric
|
||
milestones: [
|
||
{ id: 'ms_004_1', name: 'Demo and Abatement', dueDate: '2025-12-10', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_004_2', name: 'Framing and Structural', dueDate: '2025-12-22', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_004_3', name: 'Electrical Rough-In', dueDate: '2026-01-08', status: 'completed', assignedTo: 'sub_001' },
|
||
{ id: 'ms_004_4', name: 'Plumbing Rough-In', dueDate: '2026-01-15', status: 'completed', assignedTo: 'v4' },
|
||
{ id: 'ms_004_5', name: 'Drywall and Paint', dueDate: '2026-02-05', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_004_6', name: 'Flooring and Trim', dueDate: '2026-02-18', status: 'in_progress', assignedTo: 'con_001' },
|
||
{ id: 'ms_004_7', name: 'Final Punch List', dueDate: '2026-02-25', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
budgetBreakdown: [
|
||
{ category: 'Demolition', allocated: 5000, committed: 5500, actual: 5500 },
|
||
{ category: 'Framing & Structural', allocated: 8000, committed: 8500, actual: 8500 },
|
||
{ category: 'Electrical', allocated: 7000, committed: 7000, actual: 4800 },
|
||
{ category: 'Plumbing', allocated: 6000, committed: 6500, actual: 6500 },
|
||
{ category: 'Drywall & Paint', allocated: 9000, committed: 10000, actual: 10000 },
|
||
{ category: 'Flooring & Trim', allocated: 12000, committed: 15500, actual: 15500 },
|
||
{ category: 'Contingency', allocated: 8000, committed: 9300, actual: 11500 }
|
||
],
|
||
changeOrders: [
|
||
{ id: 'CO-004-01', title: 'Scope Expansion - Kitchen Island', amount: 4500, status: 'approved', dateSubmitted: '2026-01-10', description: 'Add a custom 6ft island with quartz countertop and built-in microwave.' },
|
||
{ id: 'CO-004-02', title: 'Hardwood Flooring Upgrade', amount: 2800, status: 'approved', dateSubmitted: '2026-01-25', description: 'Upgrade from LVP to engineered hardwood in living areas.' }
|
||
],
|
||
rfis: [
|
||
{ id: 'RFI-004-01', subject: 'Load-bearing wall clarification', status: 'closed', submittedBy: 'Texas Builders LLC', dateOpened: '2025-12-15', dateClosed: '2025-12-16' },
|
||
{ id: 'RFI-004-02', subject: 'Paint finish in bathrooms', status: 'open', submittedBy: 'Texas Builders LLC', dateOpened: '2026-02-02' }
|
||
],
|
||
riskLog: [
|
||
{ id: 'risk_004_1', description: 'Flooring shipment delayed at port', severity: 'High', likelihood: 'Likely', mitigation: 'Source alternative matching material from local distributor', status: 'open' },
|
||
{ id: 'risk_004_2', description: 'Paint color mismatch between batches', severity: 'Medium', likelihood: 'Possible', mitigation: 'Verify batch numbers before final coat', status: 'mitigated' }
|
||
],
|
||
issueLog: [
|
||
{ id: 'issue_004_1', title: 'Drywall texturing inconsistent in hallway', priority: 'Medium', status: 'open', assignedTo: 'Texas Builders LLC', dateReported: '2026-02-16' },
|
||
{ id: 'issue_004_2', title: 'Plumbing rough-in failed initial inspection', priority: 'High', status: 'resolved', assignedTo: 'Lone Star Plumbing', dateReported: '2026-01-16' }
|
||
],
|
||
activityTimeline: [
|
||
{ date: '2026-02-16', action: 'Issue Reported', user: 'Site Supervisor', details: 'Drywall texture inconsistent in main hallway' },
|
||
{ date: '2026-02-05', action: 'Milestone Completed', user: 'Texas Builders LLC', details: 'Drywall and Paint phase finished' },
|
||
{ date: '2026-01-22', action: 'Payment Released', user: 'Marcus Whitfield', details: 'Truss and framing payment - $12,800' },
|
||
{ date: '2026-01-18', action: 'Inspection Passed', user: 'City Inspector', details: 'Plumbing rough-in re-inspection passed' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_004_1', amount: 18000, submittedBy: 'con_001', status: 'paid', dueDate: '2025-12-15', datePaid: '2025-12-16' },
|
||
{ id: 'inv_004_2', amount: 15500, submittedBy: 'con_001', status: 'paid', dueDate: '2026-01-10', datePaid: '2026-01-12' },
|
||
{ id: 'inv_004_3', amount: 12800, submittedBy: 'v3', status: 'paid', dueDate: '2026-01-20', datePaid: '2026-01-22' },
|
||
{ id: 'inv_004_3b', amount: 4800, submittedBy: 'sub_001', status: 'paid', dueDate: '2026-01-12', datePaid: '2026-01-14' },
|
||
{ id: 'inv_004_4', amount: 8750, submittedBy: 'v1', status: 'pending', dueDate: '2026-02-25' },
|
||
{ id: 'inv_004_5', amount: 7250, submittedBy: 'con_001', status: 'pending', dueDate: '2026-02-28' }
|
||
],
|
||
documents: [
|
||
{ name: 'Interior Renovation Contract', url: '#', type: 'contract' },
|
||
{ name: 'Building Permit #25-1892', url: '#', type: 'permit' },
|
||
{ name: 'Change Order #1 - Scope Expansion', url: '#', type: 'change_order' },
|
||
{ name: 'Change Order #2 - Material Upgrade', url: '#', type: 'change_order' },
|
||
{ name: 'Asbestos Abatement Report', url: '#', type: 'report' }
|
||
]
|
||
},
|
||
|
||
// Project 5: On Hold with pending dispute
|
||
{
|
||
id: 'proj_005',
|
||
ownerId: 'own_001',
|
||
propertyId: 'P-2601',
|
||
address: '2608 Dunwick Dr, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: [],
|
||
projectType: 'Siding Replacement',
|
||
status: 'on_hold',
|
||
phase: 'Structural',
|
||
budget: 28000,
|
||
approvedBudget: 28000,
|
||
committedCost: 20700,
|
||
actualCost: 14200,
|
||
spent: 14200,
|
||
variancePercent: -49.3,
|
||
margin: 0.25,
|
||
startDate: '2026-01-06',
|
||
endDate: '2026-02-20',
|
||
completionPercentage: 38,
|
||
healthScore: 42,
|
||
openRFIs: 0,
|
||
changeOrderCount: 1,
|
||
pendingInvoiceCount: 1,
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: ABC Supply Co.
|
||
milestones: [
|
||
{ id: 'ms_005_1', name: 'Scaffolding Setup', dueDate: '2026-01-08', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_005_2', name: 'Old Siding Removal', dueDate: '2026-01-15', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_005_3', name: 'Moisture Barrier Install', dueDate: '2026-01-22', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_005_4', name: 'New Siding Install', dueDate: '2026-02-05', status: 'pending', assignedTo: 'con_001' },
|
||
{ id: 'ms_005_5', name: 'Trim and Caulking', dueDate: '2026-02-15', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
budgetBreakdown: [
|
||
{ category: 'Materials - Siding', allocated: 12000, committed: 12000, actual: 8000 },
|
||
{ category: 'Labor - Prep & Install', allocated: 9000, committed: 9000, actual: 3500 },
|
||
{ category: 'Equipment Rental', allocated: 2000, committed: 2000, actual: 1500 },
|
||
{ category: 'Structural Repairs (CO)', allocated: 0, committed: 850, actual: 850 },
|
||
{ category: 'Contingency', allocated: 5000, committed: 5000, actual: 350 }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_005_1', amount: 8400, submittedBy: 'con_001', status: 'paid', dueDate: '2026-01-12', datePaid: '2026-01-13' },
|
||
{ id: 'inv_005_2', amount: 5800, submittedBy: 'v3', status: 'paid', dueDate: '2026-01-20', datePaid: '2026-01-21' },
|
||
{ id: 'inv_005_3', amount: 6500, submittedBy: 'con_001', status: 'pending', dueDate: '2026-02-10' }
|
||
],
|
||
changeOrders: [
|
||
{ id: 'CO-005-01', title: 'Rotten Fascia Board Replacement', amount: 850, status: 'approved', dateSubmitted: '2026-01-18', description: 'Replace 40 linear feet of rotted fascia discovered during tear-off.' }
|
||
],
|
||
rfis: [
|
||
{ id: 'RFI-005-01', subject: 'Vapor Barrier Specification', status: 'closed', submittedBy: 'Texas Builders LLC', dateOpened: '2026-01-20', dateClosed: '2026-01-21' }
|
||
],
|
||
riskLog: [
|
||
{ id: 'risk_005_1', description: 'Water damage hidden behind existing siding', severity: 'High', likelihood: 'Certain', mitigation: 'Halt work, assess rot, submit change order for structural repair.', status: 'realized' }
|
||
],
|
||
issueLog: [
|
||
{ id: 'issue_005_1', title: 'Defective siding panels delivered', priority: 'Critical', status: 'open', assignedTo: 'ABC Supply Co.', dateReported: '2026-02-04' }
|
||
],
|
||
activityTimeline: [
|
||
{ date: '2026-02-06', action: 'Project Paused', user: 'System', details: 'Status changed to On Hold due to material dispute' },
|
||
{ date: '2026-02-04', action: 'Issue Reported', user: 'Site Supervisor', details: 'Batch of siding panels showed unacceptable warping' },
|
||
{ date: '2026-01-22', action: 'Milestone Completed', user: 'Texas Builders LLC', details: 'Moisture Barrier Install finished' }
|
||
],
|
||
documents: [
|
||
{ name: 'Siding Replacement Contract', url: '#', type: 'contract' },
|
||
{ name: 'Dispute Notice - Material Defect', url: '#', type: 'dispute' },
|
||
{ name: 'Manufacturer Warranty Claim', url: '#', type: 'warranty' },
|
||
{ name: 'Site Photos - Defective Panels', url: '#', type: 'photos' }
|
||
]
|
||
},
|
||
|
||
// Project 6: Active, on track, early stage
|
||
{
|
||
id: 'proj_006',
|
||
ownerId: 'own_001',
|
||
propertyId: 'P-2625',
|
||
address: '3913 Arizona Pl, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: ['sub_001'],
|
||
projectType: 'Electrical Upgrade',
|
||
status: 'active',
|
||
phase: 'MEP',
|
||
budget: 18500,
|
||
approvedBudget: 18500,
|
||
committedCost: 12400,
|
||
actualCost: 5600,
|
||
spent: 5600,
|
||
variancePercent: -69.7,
|
||
margin: 0.38,
|
||
startDate: '2026-02-03',
|
||
endDate: '2026-03-15',
|
||
completionPercentage: 22,
|
||
healthScore: 88,
|
||
openRFIs: 0,
|
||
changeOrderCount: 0,
|
||
pendingInvoiceCount: 1,
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: Sparky Electric
|
||
milestones: [
|
||
{ id: 'ms_006_1', name: 'Panel Assessment', dueDate: '2026-02-05', status: 'completed', assignedTo: 'sub_001' },
|
||
{ id: 'ms_006_2', name: 'Permit Approval', dueDate: '2026-02-10', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_006_3', name: 'Panel Replacement', dueDate: '2026-02-20', status: 'in_progress', assignedTo: 'sub_001' },
|
||
{ id: 'ms_006_4', name: 'Circuit Re-routing', dueDate: '2026-03-01', status: 'pending', assignedTo: 'sub_001' },
|
||
{ id: 'ms_006_5', name: 'City Inspection', dueDate: '2026-03-12', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_006_1', amount: 2200, submittedBy: 'sub_001', status: 'paid', dueDate: '2026-02-08', datePaid: '2026-02-09' },
|
||
{ id: 'inv_006_2', amount: 3400, submittedBy: 'sub_001', status: 'pending', dueDate: '2026-02-22' }
|
||
],
|
||
documents: [
|
||
{ name: 'Electrical Upgrade Proposal', url: '#', type: 'contract' },
|
||
{ name: 'Electrical Permit #26-0223', url: '#', type: 'permit' },
|
||
{ name: 'Load Calculation Report', url: '#', type: 'report' }
|
||
]
|
||
},
|
||
|
||
// =====================================================================
|
||
// OWNER 2: Diana Reeves (own_002) — 6 Projects
|
||
// High risk owner, vendor payment delays, over-budget project
|
||
// =====================================================================
|
||
|
||
// Project 7: Active, on track, healthy budget (commercial)
|
||
{
|
||
id: 'proj_007',
|
||
ownerId: 'own_002',
|
||
propertyId: 'P-2640',
|
||
address: '6909 Custer Rd, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: ['sub_001'],
|
||
projectType: 'Commercial Roof Replacement',
|
||
status: 'active',
|
||
phase: 'Structural',
|
||
budget: 125000,
|
||
approvedBudget: 125000,
|
||
committedCost: 98000,
|
||
actualCost: 48000,
|
||
spent: 48000,
|
||
variancePercent: -61.6,
|
||
margin: 0.35,
|
||
startDate: '2026-01-27',
|
||
endDate: '2026-04-15',
|
||
completionPercentage: 32,
|
||
healthScore: 78,
|
||
openRFIs: 0,
|
||
changeOrderCount: 0,
|
||
pendingInvoiceCount: 2,
|
||
budgetBreakdown: [
|
||
{ category: 'Materials - TPO Membrane', allocated: 38000, committed: 35400, actual: 11400 },
|
||
{ category: 'Materials - Insulation', allocated: 18000, committed: 16800, actual: 5550 },
|
||
{ category: 'Materials - Fasteners/Adhesive', allocated: 8000, committed: 7200, actual: 2080 },
|
||
{ category: 'Labor - Section A', allocated: 22000, committed: 18500, actual: 18500 },
|
||
{ category: 'Labor - Section B', allocated: 22000, committed: 8000, actual: 0 },
|
||
{ category: 'Crane Rental', allocated: 8000, committed: 5600, actual: 4200 },
|
||
{ category: 'Permits & Inspection', allocated: 4000, committed: 3500, actual: 3270 },
|
||
{ category: 'Safety Equipment', allocated: 5000, committed: 3000, actual: 3000 }
|
||
],
|
||
changeOrders: [
|
||
{ id: 'CO-007-1', title: 'Additional Drainage Scuppers', amount: 4200, status: 'pending', dateSubmitted: '2026-02-10', description: 'Building management requested 4 additional scuppers on east elevation for improved water management' }
|
||
],
|
||
rfis: [
|
||
{ id: 'RFI-007-1', subject: 'Deck Condition Under Section B', status: 'open', submittedBy: 'Texas Roofing Crew A', dateOpened: '2026-02-14', dateClosed: null },
|
||
{ id: 'RFI-007-2', subject: 'Flashing Detail at Parapet Wall', status: 'closed', submittedBy: 'Texas Builders LLC', dateOpened: '2026-02-03', dateClosed: '2026-02-06' }
|
||
],
|
||
riskLog: [
|
||
{ id: 'risk_007_1', description: 'Roof deck deterioration may require additional repairs', severity: 'High', likelihood: 'Possible', mitigation: 'Structural assessment scheduled before Section B tear-off', status: 'open' },
|
||
{ id: 'risk_007_2', description: 'High winds could delay membrane installation', severity: 'Medium', likelihood: 'Likely', mitigation: 'Schedule membrane work on low-wind days, use mechanical fasteners as backup', status: 'monitoring' },
|
||
{ id: 'risk_007_3', description: 'Supply chain delay on TPO rolls', severity: 'Low', likelihood: 'Unlikely', mitigation: 'Full order confirmed and 60% already delivered', status: 'mitigated' }
|
||
],
|
||
issueLog: [
|
||
{ id: 'issue_007_1', title: 'Crane access blocked by tenant parking', priority: 'Medium', status: 'resolved', assignedTo: 'Texas Builders LLC', dateReported: '2026-02-01' },
|
||
{ id: 'issue_007_2', title: 'Section A tear-off revealed wet insulation', priority: 'High', status: 'open', assignedTo: 'Texas Roofing Crew A', dateReported: '2026-02-14' }
|
||
],
|
||
paymentSchedule: [
|
||
{ id: 'ps_007_1', milestone: 'Mobilization (20%)', amount: 25000, dueDate: '2026-01-30', status: 'paid' },
|
||
{ id: 'ps_007_2', milestone: 'Section A Complete (25%)', amount: 31250, dueDate: '2026-03-01', status: 'pending' },
|
||
{ id: 'ps_007_3', milestone: 'Section B Complete (25%)', amount: 31250, dueDate: '2026-03-30', status: 'pending' },
|
||
{ id: 'ps_007_4', milestone: 'Final Inspection (20%)', amount: 25000, dueDate: '2026-04-10', status: 'pending' },
|
||
{ id: 'ps_007_5', milestone: 'Warranty Registration (10%)', amount: 12500, dueDate: '2026-04-15', status: 'pending' }
|
||
],
|
||
activityTimeline: [
|
||
{ date: '2026-02-14', action: 'RFI Submitted', user: 'Texas Roofing Crew A', details: 'RFI-007-1: Deck condition under Section B needs assessment' },
|
||
{ date: '2026-02-14', action: 'Issue Reported', user: 'Texas Roofing Crew A', details: 'Wet insulation found during Section A tear-off' },
|
||
{ date: '2026-02-10', action: 'Change Order Submitted', user: 'Texas Builders LLC', details: 'CO-007-1: Additional drainage scuppers requested - $4,200' },
|
||
{ date: '2026-02-06', action: 'RFI Closed', user: 'Texas Builders LLC', details: 'RFI-007-2: Flashing detail resolved per manufacturer spec' },
|
||
{ date: '2026-02-03', action: 'Milestone Completed', user: 'ABC Supply Co.', details: 'Material procurement complete - all TPO delivered' },
|
||
{ date: '2026-01-30', action: 'Payment Released', user: 'Diana Reeves', details: 'Mobilization payment - $25,000' },
|
||
{ date: '2026-01-27', action: 'Project Started', user: 'Texas Builders LLC', details: 'Commercial roof replacement kicked off' }
|
||
],
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: ABC Supply Co., Texas Roofing Crew A
|
||
milestones: [
|
||
{ id: 'ms_007_1', name: 'Roof Survey and Assessment', dueDate: '2026-01-30', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_007_2', name: 'Material Procurement', dueDate: '2026-02-07', status: 'completed', assignedTo: 'v3' },
|
||
{ id: 'ms_007_3', name: 'Section A - Tear Off', dueDate: '2026-02-14', status: 'completed', assignedTo: 'v1' },
|
||
{ id: 'ms_007_4', name: 'Section A - TPO Install', dueDate: '2026-02-28', status: 'in_progress', assignedTo: 'v1' },
|
||
{ id: 'ms_007_5', name: 'Section B - Tear Off', dueDate: '2026-03-15', status: 'pending', assignedTo: 'v1' },
|
||
{ id: 'ms_007_6', name: 'Section B - TPO Install', dueDate: '2026-03-30', status: 'pending', assignedTo: 'v1' },
|
||
{ id: 'ms_007_7', name: 'Final Inspection and Warranty', dueDate: '2026-04-10', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_007_1', amount: 25000, submittedBy: 'con_001', status: 'paid', dueDate: '2026-02-05', datePaid: '2026-02-06' },
|
||
{ id: 'inv_007_2', amount: 20599.98, submittedBy: 'v3', status: 'pending', dueDate: '2026-02-18' },
|
||
{ id: 'inv_007_3', amount: 18500, submittedBy: 'v1', status: 'pending', dueDate: '2026-02-28' }
|
||
],
|
||
documents: [
|
||
{ name: 'Commercial Roofing Contract', url: '#', type: 'contract' },
|
||
{ name: 'Commercial Building Permit #26-0312', url: '#', type: 'permit' },
|
||
{ name: 'TPO Manufacturer Spec', url: '#', type: 'specification' },
|
||
{ name: 'Roof Survey Report', url: '#', type: 'report' },
|
||
{ name: 'Safety Plan - Fall Protection', url: '#', type: 'safety' }
|
||
]
|
||
},
|
||
|
||
// Project 8: Active, over budget (spent > budget)
|
||
{
|
||
id: 'proj_008',
|
||
ownerId: 'own_002',
|
||
propertyId: 'P-2641',
|
||
address: '2112 Winslow Dr, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: [],
|
||
projectType: 'Foundation Repair',
|
||
status: 'active',
|
||
phase: 'Finishing',
|
||
budget: 75000,
|
||
approvedBudget: 75000,
|
||
committedCost: 91500,
|
||
actualCost: 91500,
|
||
spent: 91500,
|
||
variancePercent: 22.0,
|
||
margin: -0.22,
|
||
startDate: '2025-11-18',
|
||
endDate: '2026-02-28',
|
||
completionPercentage: 88,
|
||
healthScore: 25,
|
||
openRFIs: 0,
|
||
changeOrderCount: 2,
|
||
pendingInvoiceCount: 2,
|
||
// TODO: cross-reference — Contractor: Texas Builders LLC, Vendors: DFW Foundation Pros, ABC Supply Co.
|
||
milestones: [
|
||
{ id: 'ms_008_1', name: 'Structural Engineering Report', dueDate: '2025-11-22', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_008_2', name: 'Pier Installation - East', dueDate: '2025-12-06', status: 'completed', assignedTo: 'v5' },
|
||
{ id: 'ms_008_3', name: 'Pier Installation - West', dueDate: '2025-12-20', status: 'completed', assignedTo: 'v5' },
|
||
{ id: 'ms_008_4', name: 'Slab Lifting', dueDate: '2026-01-10', status: 'completed', assignedTo: 'v5' },
|
||
{ id: 'ms_008_5', name: 'Plumbing Re-test', dueDate: '2026-01-25', status: 'completed', assignedTo: 'v4' },
|
||
{ id: 'ms_008_6', name: 'Final Grade and Drainage', dueDate: '2026-02-10', status: 'in_progress', assignedTo: 'con_001' },
|
||
{ id: 'ms_008_7', name: 'Engineering Re-certification', dueDate: '2026-02-25', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_008_1', amount: 30000, submittedBy: 'con_001', status: 'paid', dueDate: '2025-12-01', datePaid: '2025-12-03' },
|
||
{ id: 'inv_008_2', amount: 9352.80, submittedBy: 'v5', status: 'paid', dueDate: '2025-12-20', datePaid: '2025-12-22' },
|
||
{ id: 'inv_008_3', amount: 24000, submittedBy: 'v5', status: 'paid', dueDate: '2026-01-15', datePaid: '2026-01-18' },
|
||
{ id: 'inv_008_4', amount: 18500, submittedBy: 'v5', status: 'pending', dueDate: '2026-02-15' },
|
||
{ id: 'inv_008_5', amount: 9647.20, submittedBy: 'con_001', status: 'pending', dueDate: '2026-02-28' }
|
||
],
|
||
documents: [
|
||
{ name: 'Foundation Repair Contract', url: '#', type: 'contract' },
|
||
{ name: 'Structural Engineering Report', url: '#', type: 'report' },
|
||
{ name: 'Pier Layout Diagram', url: '#', type: 'plans' },
|
||
{ name: 'Change Order #1 - Additional Piers', url: '#', type: 'change_order' },
|
||
{ name: 'Change Order #2 - Plumbing Reroute', url: '#', type: 'change_order' },
|
||
{ name: 'Soil Analysis Report', url: '#', type: 'report' }
|
||
]
|
||
},
|
||
|
||
// Project 9: Delayed with missed milestone
|
||
{
|
||
id: 'proj_009',
|
||
ownerId: 'own_002',
|
||
propertyId: 'P-2642',
|
||
address: '7224 Independence Pkwy, Plano, TX 75025',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: ['sub_001'],
|
||
projectType: 'Window Replacement',
|
||
status: 'active',
|
||
budget: 42000,
|
||
spent: 25800,
|
||
margin: 0.28,
|
||
startDate: '2026-01-13',
|
||
endDate: '2026-03-10',
|
||
completionPercentage: 50,
|
||
phase: 'Finishing',
|
||
approvedBudget: 42000,
|
||
committedCost: 32000,
|
||
actualCost: 25800,
|
||
variancePercent: -38.6,
|
||
healthScore: 55,
|
||
openRFIs: 0,
|
||
changeOrderCount: 0,
|
||
pendingInvoiceCount: 1,
|
||
milestones: [
|
||
{ id: 'ms_009_1', name: 'Window Measurements', dueDate: '2026-01-16', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_009_2', name: 'Custom Window Fabrication', dueDate: '2026-01-30', status: 'completed', assignedTo: 'v3' },
|
||
{ id: 'ms_009_3', name: 'Floor 1 Installation', dueDate: '2026-02-07', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_009_4', name: 'Floor 2 Installation', dueDate: '2026-02-14', status: 'in_progress', assignedTo: 'con_001' },
|
||
{ id: 'ms_009_5', name: 'Exterior Trim and Sealant', dueDate: '2026-02-25', status: 'pending', assignedTo: 'con_001' },
|
||
{ id: 'ms_009_6', name: 'Energy Audit Verification', dueDate: '2026-03-05', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_009_1', amount: 14000, submittedBy: 'v3', status: 'paid', dueDate: '2026-02-01', datePaid: '2026-02-03' },
|
||
{ id: 'inv_009_2', amount: 8200, submittedBy: 'con_001', status: 'paid', dueDate: '2026-02-10', datePaid: '2026-02-11' },
|
||
{ id: 'inv_009_3', amount: 9800, submittedBy: 'con_001', status: 'pending', dueDate: '2026-02-25' }
|
||
],
|
||
documents: [
|
||
{ name: 'Window Replacement Agreement', url: '#', type: 'contract' },
|
||
{ name: 'Custom Window Order Confirmation', url: '#', type: 'purchase_order' },
|
||
{ name: 'Energy Rating Certificates', url: '#', type: 'certificate' }
|
||
]
|
||
},
|
||
|
||
// Project 10: Completed, zero variance
|
||
{
|
||
id: 'proj_010',
|
||
ownerId: 'own_002',
|
||
propertyId: 'P-2656',
|
||
address: '2100 Legacy Dr, Plano, TX 75023',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: [],
|
||
projectType: 'Parking Lot Resurface',
|
||
status: 'completed',
|
||
budget: 35000,
|
||
spent: 35000,
|
||
margin: 0.30,
|
||
startDate: '2025-09-15',
|
||
endDate: '2025-10-28',
|
||
completionPercentage: 100,
|
||
phase: 'Handover',
|
||
approvedBudget: 35000,
|
||
committedCost: 35000,
|
||
actualCost: 35000,
|
||
variancePercent: 0.0,
|
||
healthScore: 100,
|
||
openRFIs: 0,
|
||
changeOrderCount: 0,
|
||
pendingInvoiceCount: 0,
|
||
milestones: [
|
||
{ id: 'ms_010_1', name: 'Surface Milling', dueDate: '2025-09-20', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_010_2', name: 'Base Repair', dueDate: '2025-09-28', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_010_3', name: 'Asphalt Paving', dueDate: '2025-10-08', status: 'completed', assignedTo: 'v1' },
|
||
{ id: 'ms_010_4', name: 'Sealcoat Application', dueDate: '2025-10-18', status: 'completed', assignedTo: 'v1' },
|
||
{ id: 'ms_010_5', name: 'Striping and Signage', dueDate: '2025-10-25', status: 'completed', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_010_1', amount: 8400, submittedBy: 'v3', status: 'paid', dueDate: '2025-09-25', datePaid: '2025-09-26' },
|
||
{ id: 'inv_010_2', amount: 14200, submittedBy: 'v1', status: 'paid', dueDate: '2025-10-12', datePaid: '2025-10-13' },
|
||
{ id: 'inv_010_3', amount: 12400, submittedBy: 'con_001', status: 'paid', dueDate: '2025-10-28', datePaid: '2025-10-28' }
|
||
],
|
||
documents: [
|
||
{ name: 'Paving Contract', url: '#', type: 'contract' },
|
||
{ name: 'Completion Certificate', url: '#', type: 'certificate' },
|
||
{ name: 'ADA Compliance Verification', url: '#', type: 'report' },
|
||
{ name: 'Final Payment Release', url: '#', type: 'invoice' }
|
||
]
|
||
},
|
||
|
||
// Project 11: Disputed with open change orders and unresolved issues
|
||
{
|
||
id: 'proj_011',
|
||
ownerId: 'own_002',
|
||
propertyId: 'P-2645',
|
||
address: 'Legacy Town Center, 5760 Daniel Rd, Plano, TX 75024',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: ['sub_001'],
|
||
projectType: 'Exterior Facade Restoration',
|
||
status: 'disputed',
|
||
budget: 95000,
|
||
spent: 68400,
|
||
margin: 0.20,
|
||
startDate: '2025-12-08',
|
||
endDate: '2026-03-20',
|
||
completionPercentage: 62,
|
||
phase: 'MEP',
|
||
approvedBudget: 95000,
|
||
committedCost: 88000,
|
||
actualCost: 68400,
|
||
variancePercent: -28.0,
|
||
healthScore: 30,
|
||
openRFIs: 2,
|
||
changeOrderCount: 3,
|
||
pendingInvoiceCount: 2,
|
||
milestones: [
|
||
{ id: 'ms_011_1', name: 'Scaffolding and Protection', dueDate: '2025-12-12', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_011_2', name: 'Surface Cleaning and Prep', dueDate: '2025-12-22', status: 'completed', assignedTo: 'con_001' },
|
||
{ id: 'ms_011_3', name: 'Masonry Repair - Phase 1', dueDate: '2026-01-10', status: 'completed', assignedTo: 'v1' },
|
||
{ id: 'ms_011_4', name: 'Masonry Repair - Phase 2', dueDate: '2026-01-28', status: 'completed', assignedTo: 'v1' },
|
||
{ id: 'ms_011_5', name: 'Waterproofing Application', dueDate: '2026-02-12', status: 'in_progress', assignedTo: 'con_001' },
|
||
{ id: 'ms_011_6', name: 'Window Sealant Replacement', dueDate: '2026-02-28', status: 'pending', assignedTo: 'v4' },
|
||
{ id: 'ms_011_7', name: 'Final Restoration and Paint', dueDate: '2026-03-15', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_011_1', amount: 22000, submittedBy: 'con_001', status: 'paid', dueDate: '2025-12-18', datePaid: '2025-12-20' },
|
||
{ id: 'inv_011_2', amount: 18400, submittedBy: 'v1', status: 'paid', dueDate: '2026-01-15', datePaid: '2026-01-18' },
|
||
{ id: 'inv_011_3', amount: 15200, submittedBy: 'v3', status: 'paid', dueDate: '2026-01-30', datePaid: '2026-02-02' },
|
||
{ id: 'inv_011_4', amount: 12800, submittedBy: 'con_001', status: 'pending', dueDate: '2026-02-20' },
|
||
{ id: 'inv_011_5', amount: 8900, submittedBy: 'v4', status: 'pending', dueDate: '2026-03-05' }
|
||
],
|
||
documents: [
|
||
{ name: 'Facade Restoration Master Contract', url: '#', type: 'contract' },
|
||
{ name: 'Building Permit #25-2101', url: '#', type: 'permit' },
|
||
{ name: 'Change Order #1 - Hidden Water Damage', url: '#', type: 'change_order' },
|
||
{ name: 'Change Order #2 - Additional Masonry', url: '#', type: 'change_order' },
|
||
{ name: 'Change Order #3 - Structural Reinforcement', url: '#', type: 'change_order' },
|
||
{ name: 'Dispute Filing - Scope Disagreement', url: '#', type: 'dispute' },
|
||
{ name: 'RFI #1 - Original vs Current Scope', url: '#', type: 'rfi' },
|
||
{ name: 'RFI #2 - Waterproofing Method', url: '#', type: 'rfi' }
|
||
]
|
||
},
|
||
|
||
// Project 12: On Hold
|
||
{
|
||
id: 'proj_012',
|
||
ownerId: 'own_002',
|
||
propertyId: 'P-2644',
|
||
address: 'Dallas/Plano Marriott at Legacy Town Center, 7121 Bishop Rd, Plano, TX 75024',
|
||
contractorId: 'con_001',
|
||
subcontractorIds: [],
|
||
projectType: 'Plumbing Overhaul',
|
||
status: 'on_hold',
|
||
budget: 58000,
|
||
spent: 22600,
|
||
margin: 0.32,
|
||
startDate: '2026-01-13',
|
||
endDate: '2026-04-01',
|
||
completionPercentage: 28,
|
||
phase: 'Foundation',
|
||
approvedBudget: 58000,
|
||
committedCost: 34000,
|
||
actualCost: 22600,
|
||
variancePercent: -61.0,
|
||
healthScore: 45,
|
||
openRFIs: 0,
|
||
changeOrderCount: 0,
|
||
pendingInvoiceCount: 2,
|
||
milestones: [
|
||
{ id: 'ms_012_1', name: 'Plumbing Assessment', dueDate: '2026-01-17', status: 'completed', assignedTo: 'v4' },
|
||
{ id: 'ms_012_2', name: 'Material Procurement', dueDate: '2026-01-25', status: 'completed', assignedTo: 'v4' },
|
||
{ id: 'ms_012_3', name: 'Main Line Replacement', dueDate: '2026-02-05', status: 'completed', assignedTo: 'v4' },
|
||
{ id: 'ms_012_4', name: 'Water Heater Installation', dueDate: '2026-02-18', status: 'pending', assignedTo: 'v4' },
|
||
{ id: 'ms_012_5', name: 'Branch Line Reroute', dueDate: '2026-03-05', status: 'pending', assignedTo: 'v4' },
|
||
{ id: 'ms_012_6', name: 'Pressure Testing', dueDate: '2026-03-20', status: 'pending', assignedTo: 'v4' },
|
||
{ id: 'ms_012_7', name: 'City Inspection', dueDate: '2026-03-28', status: 'pending', assignedTo: 'con_001' }
|
||
],
|
||
invoices: [
|
||
{ id: 'inv_012_1', amount: 8600, submittedBy: 'v4', status: 'paid', dueDate: '2026-01-22', datePaid: '2026-01-24' },
|
||
{ id: 'inv_012_2', amount: 13972.91, submittedBy: 'v4', status: 'pending', dueDate: '2026-02-14' },
|
||
{ id: 'inv_012_3', amount: 12000, submittedBy: 'con_001', status: 'pending', dueDate: '2026-02-28' }
|
||
],
|
||
documents: [
|
||
{ name: 'Plumbing Overhaul Contract', url: '#', type: 'contract' },
|
||
{ name: 'Plumbing Permit #26-0156', url: '#', type: 'permit' },
|
||
{ name: 'Scope Hold Notice - Permit Review', url: '#', type: 'notice' },
|
||
{ name: 'Material Delivery Receipt', url: '#', type: 'receipt' }
|
||
]
|
||
}
|
||
];
|
||
|
||
// --- CONTEXT SETUP ---
|
||
|
||
const MockStoreContext = createContext();
|
||
|
||
export const MockStoreProvider = ({ children }) => {
|
||
const [properties, setProperties] = useState([]);
|
||
const [users, setUsers] = useState(MOCK_USERS);
|
||
const [meetings, setMeetings] = useState(MOCK_MEETINGS);
|
||
const [salesHistory, setSalesHistory] = useState(MOCK_SALES_HISTORY);
|
||
|
||
// New Data States
|
||
const [owners, setOwners] = useState(MOCK_OWNERS);
|
||
const [personnel, setPersonnel] = useState(MOCK_PERSONNEL);
|
||
const [vendors, setVendors] = useState(MOCK_VENDORS);
|
||
const [documents, setDocuments] = useState(MOCK_DOCUMENTS);
|
||
const [projects, setProjects] = useState(MOCK_PROJECTS);
|
||
const [orders, setOrders] = useState(MOCK_ORDERS);
|
||
const [vendorInvoices, setVendorInvoices] = useState(MOCK_VENDOR_INVOICES);
|
||
|
||
// Initialize properties once
|
||
useEffect(() => {
|
||
const data = generateProperties();
|
||
setProperties(data);
|
||
}, []);
|
||
|
||
const updatePropertyStatus = (id, newStatus) => {
|
||
setProperties(prev => prev.map(p =>
|
||
p.id === id ? { ...p, canvassingStatus: newStatus } : p
|
||
));
|
||
};
|
||
|
||
const addMeeting = (meeting) => {
|
||
setMeetings(prev => [...prev, { ...meeting, id: `m${prev.length + 1}` }]);
|
||
};
|
||
|
||
// --- NEW ACTIONS for ADMIN CENTER ---
|
||
|
||
const assignAgent = (propertyId, agentId) => {
|
||
let found = false;
|
||
setProperties(prev => prev.map(p => {
|
||
if (p.id === propertyId || p.propertyData.propertyId === propertyId) {
|
||
found = true;
|
||
return { ...p, assignedAgentId: agentId, canvassingStatus: "Assigned" };
|
||
}
|
||
return p;
|
||
}));
|
||
|
||
if (!found) {
|
||
toast.error("Failed to assign agent: Property not found.");
|
||
return false;
|
||
}
|
||
|
||
const agent = users.find(u => u.id === agentId);
|
||
toast.success(`Agent ${agent ? agent.name : 'assigned'} linked to property.`);
|
||
logger.info(`Property ${propertyId} assigned to Agent ${agentId}`);
|
||
return true;
|
||
};
|
||
|
||
const markLeadContacted = (propertyId) => {
|
||
let found = false;
|
||
setProperties(prev => prev.map(p => {
|
||
if (p.id === propertyId || p.propertyData.propertyId === propertyId) {
|
||
found = true;
|
||
return { ...p, lastContactDate: new Date().toISOString() };
|
||
}
|
||
return p;
|
||
}));
|
||
|
||
if (!found) {
|
||
toast.error("Action failed: Property not found.");
|
||
return false;
|
||
}
|
||
|
||
toast.success("Lead marked as contacted.");
|
||
return true;
|
||
};
|
||
|
||
const sendReminder = (propertyId) => {
|
||
const prop = properties.find(p => p.id === propertyId || p.propertyData.propertyId === propertyId);
|
||
if (!prop) {
|
||
toast.error("Failed to send reminder: Client not found.");
|
||
return false;
|
||
}
|
||
|
||
const name = prop?.ownerData?.fullName || "Client";
|
||
toast.success(`Reminder sent to ${name}`);
|
||
logger.info(`Reminder sent to property ${propertyId}`);
|
||
return true;
|
||
};
|
||
|
||
return (
|
||
<MockStoreContext.Provider value={{
|
||
properties,
|
||
users,
|
||
meetings,
|
||
salesHistory, // Exported for Leaderboard
|
||
|
||
// New Owners Box Data
|
||
owners,
|
||
personnel,
|
||
vendors,
|
||
documents,
|
||
projects,
|
||
orders,
|
||
vendorInvoices,
|
||
|
||
updatePropertyStatus,
|
||
addMeeting,
|
||
updateUser: (updatedUser) => {
|
||
setUsers(prev => prev.map(u => u.id === updatedUser.id ? updatedUser : u));
|
||
},
|
||
// Export new actions
|
||
assignAgent,
|
||
markLeadContacted,
|
||
sendReminder
|
||
}}>
|
||
{children}
|
||
</MockStoreContext.Provider>
|
||
);
|
||
};
|
||
|
||
export const useMockStore = () => useContext(MockStoreContext);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Lead Creation Form Options
|
||
// ---------------------------------------------------------------------------
|
||
export const LEAD_FORM_OPTIONS = {
|
||
leadTypes: [
|
||
'Residential',
|
||
'Commercial',
|
||
'Multi-Family',
|
||
'Industrial',
|
||
'HOA / Community',
|
||
],
|
||
leadSources: [
|
||
'Door Knock',
|
||
'Referral',
|
||
'Storm Chase',
|
||
'Online / Web',
|
||
'Mailer / Postcard',
|
||
'Sign Call',
|
||
'Insurance Agent Referral',
|
||
'Repeat Customer',
|
||
'Social Media',
|
||
'Other',
|
||
],
|
||
workTypes: [
|
||
'Roof Replacement',
|
||
'Roof Repair',
|
||
'Gutters',
|
||
'Siding',
|
||
'Windows',
|
||
'Solar',
|
||
'Inspection Only',
|
||
'Emergency Tarping',
|
||
'Other',
|
||
],
|
||
tradeTypes: [
|
||
'Roofing',
|
||
'Gutter',
|
||
'Siding',
|
||
'Windows',
|
||
'Solar',
|
||
'General Contractor',
|
||
],
|
||
urgencyLevels: [
|
||
{ label: 'Standard', value: 'standard', color: '#6B7280' },
|
||
{ label: 'High', value: 'high', color: '#F59E0B' },
|
||
{ label: 'Emergency', value: 'emergency', color: '#EF4444' },
|
||
],
|
||
priorityLevels: [
|
||
{ label: 'Low', value: 'low', color: '#6B7280' },
|
||
{ label: 'Medium', value: 'medium', color: '#3B82F6' },
|
||
{ label: 'High', value: 'high', color: '#F59E0B' },
|
||
{ label: 'Critical', value: 'critical', color: '#EF4444' },
|
||
],
|
||
insuranceCompanies: [
|
||
'State Farm',
|
||
'Allstate',
|
||
'USAA',
|
||
'Farmers Insurance',
|
||
'Liberty Mutual',
|
||
'Progressive',
|
||
'Nationwide',
|
||
'American Family',
|
||
'Travelers',
|
||
'GEICO',
|
||
'Chubb',
|
||
'Erie Insurance',
|
||
'Auto-Owners',
|
||
'Other',
|
||
],
|
||
claimStatuses: [
|
||
'Not Filed',
|
||
'Filed – Pending Adjuster',
|
||
'Adjuster Scheduled',
|
||
'Adjuster Completed',
|
||
'Approved',
|
||
'Denied',
|
||
'Supplement In Progress',
|
||
'Closed',
|
||
],
|
||
phoneTypes: ['Mobile', 'Home', 'Work', 'Other'],
|
||
emailTypes: ['Personal', 'Work', 'Other'],
|
||
usStates: [
|
||
'AL','AK','AZ','AR','CA','CO','CT','DE','FL','GA',
|
||
'HI','ID','IL','IN','IA','KS','KY','LA','ME','MD',
|
||
'MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ',
|
||
'NM','NY','NC','ND','OH','OK','OR','PA','RI','SC',
|
||
'SD','TN','TX','UT','VT','VA','WA','WV','WI','WY',
|
||
],
|
||
};
|