import React, { useState, useEffect } from 'react';
import { ChevronLeft, ChevronRight, Calculator, TrendingUp, Home, DollarSign, FileText, BarChart3, PieChart } from 'lucide-react';
const FloridaRealEstateAnalyzer = () => {
const [currentStep, setCurrentStep] = useState(1);
const [propertyData, setPropertyData] = useState({
// General Information
address: '',
city: '',
state: 'Florida',
zipCode: '',
propertyType: 'Residential',
constructionYear: 2000,
lastRenovation: 2020,
// Surface Area
buildingArea: 0,
landArea: 0,
// Physical Attributes
bedrooms: 1,
bathrooms: 1,
parkingType: 'None',
// Amenities
amenities: {
pool: false,
gym: false,
elevator: false,
security: false,
ac: false,
heating: false,
dishwasher: false,
laundry: false,
balcony: false,
garden: false
},
// Initial Investment
purchasePrice: 0,
closingCosts: 0,
makeReadyCosts: 0,
// Income
monthlyRent: 0,
vacancyRate: 5.0,
// Operating Expenses
propertyTaxes: 0,
landlordInsurance: 0,
maintenance: 0,
propertyManagement: 0.0,
utilities: 0,
hoaFees: 0,
specialAssessments: 0,
// Risk Provision
capexFund: 0,
// Qualitative Checklist
checklist: {
reserveStudy: false,
delinquencyRate: false,
rentalCaps: false,
lawsRestrictions: false
},
// Analysis Parameters
desiredCapRate: 5.0,
projectionYears: 10,
annualAppreciation: 2.0,
propertyAppreciationRate: 2.0,
annualRentIncrease: 2.0,
sp500Return: 8.0,
bondsReturn: 4.0
});
// Calculated metrics
const [metrics, setMetrics] = useState({
totalCashOutlay: 0,
totalOpex: 0,
grossIncome: 0,
noi: 0,
annualCashFlow: 0,
capRate: 0,
cashOnCashReturn: 0,
grm: 0,
paybackPeriod: 0,
maxPurchasePrice: 0
});
// Calculate metrics whenever propertyData changes
useEffect(() => {
calculateMetrics();
}, [propertyData]);
const calculateMetrics = () => {
const totalCashOutlay = propertyData.purchasePrice + propertyData.closingCosts + propertyData.makeReadyCosts;
const grossIncome = propertyData.monthlyRent * 12 * (1 - propertyData.vacancyRate / 100);
const totalOpex = propertyData.propertyTaxes + propertyData.landlordInsurance +
propertyData.maintenance + (propertyData.propertyManagement / 100 * grossIncome) +
propertyData.utilities + propertyData.hoaFees + propertyData.specialAssessments +
propertyData.capexFund;
const noi = grossIncome - totalOpex;
const annualCashFlow = noi;
const capRate = propertyData.purchasePrice > 0 ? (noi / propertyData.purchasePrice) * 100 : 0;
const cashOnCashReturn = totalCashOutlay > 0 ? (annualCashFlow / totalCashOutlay) * 100 : 0;
const grm = propertyData.monthlyRent > 0 ? propertyData.purchasePrice / (propertyData.monthlyRent * 12) : 0;
const paybackPeriod = annualCashFlow > 0 ? totalCashOutlay / annualCashFlow : 0;
const maxPurchasePrice = propertyData.desiredCapRate > 0 ? noi / (propertyData.desiredCapRate / 100) : 0;
setMetrics({
totalCashOutlay,
totalOpex,
grossIncome,
noi,
annualCashFlow,
capRate,
cashOnCashReturn,
grm,
paybackPeriod,
maxPurchasePrice
});
};
const updatePropertyData = (field, value) => {
if (field.includes('.')) {
const [parent, child] = field.split('.');
setPropertyData(prev => ({
...prev,
[parent]: {
...prev[parent],
[child]: value
}
}));
} else {
setPropertyData(prev => ({
...prev,
[field]: value
}));
}
};
const formatCurrency = (amount) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(amount);
};
const formatPercentage = (value) => {
return `${value.toFixed(2)}%`;
};
const steps = [
{ id: 1, title: 'Pillar 1', subtitle: 'General Info' },
{ id: 2, title: 'Pillar 2', subtitle: 'Property Details' },
{ id: 3, title: 'Pillar 3', subtitle: 'Financial Analysis' },
{ id: 4, title: 'Pillar 4', subtitle: 'Projections' }
];
const renderGeneralInfo = () => (
Property Type
{['Residential', 'Multifamily', 'Commercial', 'Industrial', 'Mixed Use'].map((type) => (
updatePropertyData('propertyType', type)}
className={`p-3 rounded-lg border-2 transition-colors ${
propertyData.propertyType === type
? 'border-blue-500 bg-blue-500/20 text-blue-400'
: 'border-gray-600 text-gray-400 hover:border-gray-500'
}`}
>
{type === 'Residential' && }
{type === 'Multifamily' && }
{type === 'Commercial' && }
{type === 'Industrial' && }
{type === 'Mixed Use' && }
{type}
))}
);
const renderPropertyDetails = () => (
Physical Attributes
Bedrooms
updatePropertyData('bedrooms', Math.max(0, propertyData.bedrooms - 1))}
className="w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center hover:bg-blue-700"
>
-
{propertyData.bedrooms}
updatePropertyData('bedrooms', propertyData.bedrooms + 1)}
className="w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center hover:bg-blue-700"
>
+
Bathrooms
updatePropertyData('bathrooms', Math.max(0, propertyData.bathrooms - 1))}
className="w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center hover:bg-blue-700"
>
-
{propertyData.bathrooms}
updatePropertyData('bathrooms', propertyData.bathrooms + 1)}
className="w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center hover:bg-blue-700"
>
+
Parking Type
{['None', 'Street', 'Driveway', 'Garage', 'Carport', 'Assigned'].map((type) => (
updatePropertyData('parkingType', type)}
className={`p-2 rounded-lg border text-sm transition-colors ${
propertyData.parkingType === type
? 'border-blue-500 bg-blue-500/20 text-blue-400'
: 'border-gray-600 text-gray-400 hover:border-gray-500'
}`}
>
{type}
))}
);
const renderFinancialAnalysis = () => (
Initial Investment
Purchase Price
$
updatePropertyData('purchasePrice', parseFloat(e.target.value) || 0)}
className="w-full bg-gray-700 text-white rounded-lg pl-8 pr-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
{propertyData.purchasePrice === 0 && (
Purchase price cannot be zero.
)}
Total Cash Outlay
{formatCurrency(metrics.totalCashOutlay)}
Income
Projected Monthly Rent
$
updatePropertyData('monthlyRent', parseFloat(e.target.value) || 0)}
className="w-full bg-gray-700 text-white rounded-lg pl-8 pr-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
{propertyData.monthlyRent === 0 && (
Projected monthly rent cannot be zero.
)}
Gross Income (Annual)
{formatCurrency(metrics.grossIncome)}
Operating Expenses (OPEX - Annual)
{[
{ key: 'propertyTaxes', label: 'Property Taxes' },
{ key: 'landlordInsurance', label: 'Landlord Insurance' },
{ key: 'maintenance', label: 'Maintenance & Repairs' },
{ key: 'utilities', label: 'Utilities' },
{ key: 'hoaFees', label: 'Monthly HOA Fees' },
{ key: 'specialAssessments', label: 'Known Special Assessments (Annual)' },
{ key: 'capexFund', label: 'CapEx & Assessment Fund' }
].map((expense) => (
))}
Key Metrics
{[
{ label: 'Total Cash Outlay', value: formatCurrency(metrics.totalCashOutlay) },
{ label: 'Total OPEX Annual', value: formatCurrency(metrics.totalOpex) },
{ label: 'Net Operating Income (NOI)', value: formatCurrency(metrics.noi) },
{ label: 'Annual Cash Flow', value: formatCurrency(metrics.annualCashFlow) },
{ label: 'Cap Rate', value: formatPercentage(metrics.capRate) },
{ label: 'Cash-on-Cash Return', value: formatPercentage(metrics.cashOnCashReturn) }
].map((metric, index) => (
{metric.label}
{metric.value}
))}
Maximum Purchase Price
Cap Rate measures annual return before financing. Adjust your target rate to know
the maximum price you should pay based on the calculated NOI.
Annual NOI (USD)
{formatCurrency(metrics.noi)}
{metrics.noi <= 0 && (
Make sure the NOI is greater than zero to calculate the maximum price
)}
{metrics.noi > 0 && (
Maximum Purchase Price
{formatCurrency(metrics.maxPurchasePrice)}
)}
);
const renderProjections = () => {
const projectedValue = propertyData.purchasePrice * Math.pow(1 + propertyData.propertyAppreciationRate / 100, propertyData.projectionYears);
const appreciationGain = projectedValue - propertyData.purchasePrice;
return (
Reference Metrics
Cap Rate
{formatPercentage(metrics.capRate)}
GRM
{metrics.grm.toFixed(2)} BIEN
Payback Period (Years)
{metrics.paybackPeriod.toFixed(1)}
Sensitivity Analysis
Property Value Appreciation Impact
Payback Period vs Appreciation
1%
3%
5%
7%
9%
10%
Payback Period
Years to Break Even
Without Appreciation
{metrics.paybackPeriod.toFixed(1)}
With Appreciation
{(metrics.paybackPeriod * 0.8).toFixed(1)}
Future Value Projection
Projection Years
updatePropertyData('projectionYears', Math.max(1, propertyData.projectionYears - 1))}
className="w-8 h-8 bg-gray-600 text-white rounded flex items-center justify-center hover:bg-gray-500"
>
-
{propertyData.projectionYears} years
updatePropertyData('projectionYears', propertyData.projectionYears + 1)}
className="w-8 h-8 bg-gray-600 text-white rounded flex items-center justify-center hover:bg-gray-500"
>
+
Projected Value in {propertyData.projectionYears} Years
{formatCurrency(projectedValue)}
Appreciation Gain
{formatCurrency(appreciationGain)}
Opportunity Cost Analysis
Projected Cap Rate Analysis
Projection Year
updatePropertyData('projectionYears', Math.max(1, propertyData.projectionYears - 1))}
className="w-8 h-8 bg-gray-600 text-white rounded flex items-center justify-center hover:bg-gray-500"
>
-
Year {Math.min(propertyData.projectionYears, 5)}
updatePropertyData('projectionYears', Math.min(10, propertyData.projectionYears + 1))}
className="w-8 h-8 bg-gray-600 text-white rounded flex items-center justify-center hover:bg-gray-500"
>
+
Cap Rate Projection (1-10 Years)
{[...Array(10)].map((_, i) => (
))}
1
5
10
Year {Math.min(propertyData.projectionYears, 5)} Projection
Property Value
{formatCurrency(projectedValue)}
Annual Rent
{formatCurrency(propertyData.monthlyRent * 12 * Math.pow(1 + propertyData.annualRentIncrease / 100, Math.min(propertyData.projectionYears, 5)))}
Net Operating Income
{formatCurrency(metrics.noi * Math.pow(1 + propertyData.annualRentIncrease / 100, Math.min(propertyData.projectionYears, 5)))}
Projected Cap Rate
{formatPercentage(metrics.capRate)}
vs Current Cap Rate
{formatPercentage(metrics.capRate)} → {formatPercentage(metrics.capRate)}
i
Note:
The projected Cap Rate may decrease over time if the property's value
appreciates faster than the rental income increases. This is a normal market
behavior and indicates that the asset is gaining value at a higher rate than its
income potential. It's common in strong real estate markets where property
appreciation outpaces rent growth.
);
};
const exportToPDF = () => {
// Simulate PDF export
alert('PDF Export functionality would be implemented here with a library like jsPDF or Puppeteer');
};
return (
{/* Header */}
Florida Real Estate
Investment Analyzer
Export PDF
{/* Step Navigation */}
{steps.map((step) => (
setCurrentStep(step.id)}
className={`flex-1 text-center py-2 px-4 rounded-lg mx-1 transition-colors ${
currentStep === step.id
? 'bg-blue-600 text-white'
: 'text-gray-400 hover:text-white hover:bg-gray-700'
}`}
>
{step.id}
{step.title}
{step.subtitle}
))}
{/* Content */}
{currentStep === 1 && renderGeneralInfo()}
{currentStep === 2 && renderPropertyDetails()}
{currentStep === 3 && renderFinancialAnalysis()}
{currentStep === 4 && renderProjections()}
{/* Navigation Buttons */}
setCurrentStep(Math.max(1, currentStep - 1))}
disabled={currentStep === 1}
className="flex items-center space-x-2 px-4 py-2 bg-gray-600 hover:bg-gray-500 disabled:opacity-50 disabled:cursor-not-allowed rounded-lg transition-colors"
>
Previous
setCurrentStep(Math.min(4, currentStep + 1))}
disabled={currentStep === 4}
className="flex items-center space-x-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed rounded-lg transition-colors"
>
Next
);
};
export default FloridaRealEstateAnalyzer;