diff --git a/src/data/mockStore.jsx b/src/data/mockStore.jsx index 95f92f0..75f21c9 100644 --- a/src/data/mockStore.jsx +++ b/src/data/mockStore.jsx @@ -219,10 +219,56 @@ function generateProperties() { const baseVal = isCommercial ? 2500000 + (index * 100000) : style.baseValue; const value = Math.floor(baseVal * (1 + valueVariance)); - const isRented = Math.random() > 0.7; // 30% rented - const tenantName = isRented ? (isCommercial ? "Multiple Commercial Tenants" : REAL_NAMES[(index + 5) % REAL_NAMES.length]) : null; - const tenantOcc = isRented ? (isCommercial ? "Retail/Office Mix" : OCCUPATIONS[(index + 3) % OCCUPATIONS.length]) : null; - const rentAmount = isRented ? Math.floor(value * 0.008 / 100) * 100 : null; + // 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( @@ -257,14 +303,10 @@ function generateProperties() { lastMajorRenovationDate: "2020-05-15", lastRoofRepairReplacementDate: "2018-02-10", recentMajorRepairs: "Routine Maintenance", - currentlyRented: isRented, - currentTenantName: tenantName, - tenantOccupation: tenantOcc, - tenantAnnualIncome: isRented ? "$100k - $150k" : null, - currentMonthlyRentAmount: rentAmount, - leaseStartDate: isRented ? "2023-01-01" : null, - leaseEndDate: isRented ? "2025-01-01" : null, - ownerWillingToRent: !isRented && Math.random() > 0.6, + + // Spread new robust tenant data + ...tenantData, + expectedMonthlyRentAmount: Math.floor(value * 0.008 / 100) * 100, rentalAvailabilityDate: null, rentalTermsPreference: null, @@ -332,6 +374,85 @@ function generateProperties() { } }); + + + // 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 + }; + } + }); + return allProperties; } diff --git a/src/pages/Maps.jsx b/src/pages/Maps.jsx index 06d6dc4..0c21f68 100644 --- a/src/pages/Maps.jsx +++ b/src/pages/Maps.jsx @@ -405,11 +405,29 @@ const Drawer = ({ isOpen, onClose, data, newLocation, onUpdateStatus, onSave, lo {formData.isRented === 'Yes' ? (
- +

Tenant Profile

+
- - + +
+
+ + +
+
+ + +
+ +

Lease Details

+ +
+ + + +
+
) : (
@@ -603,13 +621,24 @@ function Maps() { roofCondition: formData.roofCondition, lastRenovationDate: formData.lastRenovationDate, - // Rental Status - isRented: formData.isRented, - tenantName: formData.tenantName, - currentRent: formData.currentRent, - leaseEnd: formData.leaseEnd, - ownerWillingToRent: formData.ownerWillingToRent, - expectedRent: formData.expectedRent, + // Rental Status (Enhanced) + isRented: formData.isRented === 'Yes', + currentlyRented: formData.isRented === 'Yes', // Sync both just in case + currentTenantName: formData.tenantName, + tenantPhone: formData.tenantPhone, + tenantEmail: formData.tenantEmail, + tenantOccupation: formData.tenantOccupation, + tenantEmployer: formData.tenantEmployer, + tenantAnnualIncome: formData.tenantIncome, + livingStatus: formData.livingStatus, + leaseType: formData.leaseType, + leaseSignedDate: formData.leaseSigned, + leaseStartDate: formData.leaseStart, + leaseEndDate: formData.leaseEnd, + currentMonthlyRentAmount: formData.currentRent, + + ownerWillingToRent: formData.ownerWillingToRent === 'Yes', + expectedMonthlyRentAmount: formData.expectedRent, // Location (can be expanded) schoolDistrict: formData.schoolDistrict,