Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/offer-analyzer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2672,12 +2672,13 @@ export default function OfferAnalyzerPage() {
e.stopPropagation();
handleDeleteOffer(offer.id);
}}
className="p-1.5 text-red-600 hover:bg-red-50 rounded-md transition-colors"
className="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-red-700 bg-red-50 border border-red-200 rounded-md hover:bg-red-100 hover:border-red-300 transition-all duration-200 shadow-sm"
title="Delete offer"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
Delete
</button>
</div>
</div>
Expand All @@ -2697,6 +2698,7 @@ export default function OfferAnalyzerPage() {
</div>
</div>
)}
{AlertComponent}
</AuthGuard>
);
}
107 changes: 67 additions & 40 deletions components/shared/BuyBoxModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Dialog } from "@headlessui/react";
import { PropertyCountRangeIndicator } from "@/components/ui/PropertyCountRangeIndicator";
import { getPropertyCountStatus, MarketTier, MARKET_TIERS } from "@/lib/marketSizeUtil";


// Utility function for capitalizing words (proper case)
const capitalizeWords = (str: string) =>
str.toLowerCase().replace(/\b\w/g, (c) => c.toUpperCase());
Expand Down Expand Up @@ -745,7 +746,13 @@ export const BuyBoxModal: React.FC<BuyBoxModalProps> = ({ isOpen, onClose, focus

const checkPropertyCount = async (market: Market): Promise<{ count: number; propertyIds: string[]; coordinates?: { lat: number; lng: number } }> => {
try {
const searchPayload: any = {
// SEARCH CRITERIA LOGIC - Updated to use AND logic for better filtering
// CHANGES MADE:
// 1. Changed from OR to AND logic - properties must match ALL specified criteria
// 2. Added support for units_min = 0 to include counties with unknown unit counts
// 3. Confirmed year_built nulls auto-pass by default (no special handling needed)
// 4. All criteria now applied directly to searchPayload for AND behavior
let searchPayload: any = {
size: 8000, // Cap at 8,000 properties for API limit
resultIndex: 0,
count: true,
Expand Down Expand Up @@ -777,44 +784,61 @@ export const BuyBoxModal: React.FC<BuyBoxModalProps> = ({ isOpen, onClose, focus
return { count: 0, propertyIds: [], coordinates: undefined };
}

const orCriteria: any[] = [];

if (market.units_min > 0 || market.units_max > 0) {
const unitsCondition: any = {};
if (market.units_min > 0) unitsCondition.units_min = market.units_min;
if (market.units_max > 0) unitsCondition.units_max = market.units_max;
orCriteria.push(unitsCondition);
}

if (market.assessed_value_min > 0 || market.assessed_value_max > 0) {
const assessedValueCondition: any = {};
if (market.assessed_value_min > 0) assessedValueCondition.assessed_value_min = market.assessed_value_min;
if (market.assessed_value_max > 0) assessedValueCondition.assessed_value_max = market.assessed_value_max;
orCriteria.push(assessedValueCondition);
}

if (market.estimated_value_min > 0 || market.estimated_value_max > 0) {
const estimatedValueCondition: any = {};
if (market.estimated_value_min > 0) estimatedValueCondition.value_min = market.estimated_value_min;
if (market.estimated_value_max > 0) estimatedValueCondition.value_max = market.estimated_value_max;
orCriteria.push(estimatedValueCondition);
}

if (market.year_built_min > 0 || market.year_built_max > 0) {
const yearBuiltCondition: any = {};
if (market.year_built_min > 0) yearBuiltCondition.year_built_min = market.year_built_min;
if (market.year_built_max > 0) yearBuiltCondition.year_built_max = market.year_built_max;
orCriteria.push(yearBuiltCondition);
}

if (orCriteria.length > 0) {
searchPayload.and = [
locationCondition,
{ or: orCriteria }
];
} else {
Object.assign(searchPayload, locationCondition);
}
// OLD OR LOGIC - COMMENTED OUT
// Previously used OR logic where properties matched ANY of the criteria types
// const orCriteria: any[] = [];
// if (market.units_min > 0 || market.units_max > 0) {
// const unitsCondition: any = {};
// if (market.units_min > 0) unitsCondition.units_min = market.units_min;
// if (market.units_max > 0) unitsCondition.units_max = market.units_max;
// orCriteria.push(unitsCondition);
// }
// if (market.assessed_value_min > 0 || market.assessed_value_max > 0) {
// const assessedValueCondition: any = {};
// if (market.assessed_value_min > 0) assessedValueCondition.assessed_value_min = market.assessed_value_min;
// if (market.assessed_value_max > 0) assessedValueCondition.assessed_value_max = market.assessed_value_max;
// orCriteria.push(assessedValueCondition);
// }
// if (market.estimated_value_min > 0 || market.estimated_value_max > 0) {
// const estimatedValueCondition: any = {};
// if (market.estimated_value_min > 0) estimatedValueCondition.value_min = market.estimated_value_min;
// if (market.estimated_value_max > 0) estimatedValueCondition.value_max = market.estimated_value_max;
// orCriteria.push(estimatedValueCondition);
// }
// if (market.year_built_min > 0 || market.year_built_max > 0) {
// const yearBuiltCondition: any = {};
// if (market.year_built_min > 0) yearBuiltCondition.year_built_min = market.year_built_min;
// if (market.year_built_max > 0) yearBuiltCondition.year_built_max = market.year_built_max;
// orCriteria.push(yearBuiltCondition);
// }
// if (orCriteria.length > 0) {
// searchPayload.and = [
// locationCondition,
// { or: orCriteria }
// ];
// } else {
// Object.assign(searchPayload, locationCondition);
// }

// NEW AND LOGIC - All criteria must match
// Start with location condition and add all other criteria to the same object
Object.assign(searchPayload, locationCondition);

// Add units criteria directly to search payload (allow 0 for units_min to include properties from counties that don't report unit counts)
if (market.units_min >= 0 && (market.units_min > 0 || market.units_max > 0)) searchPayload.units_min = market.units_min;
if (market.units_max > 0) searchPayload.units_max = market.units_max;

// Add assessed value criteria directly to search payload
if (market.assessed_value_min > 0) searchPayload.assessed_value_min = market.assessed_value_min;
if (market.assessed_value_max > 0) searchPayload.assessed_value_max = market.assessed_value_max;

// Add estimated value criteria directly to search payload
if (market.estimated_value_min > 0) searchPayload.value_min = market.estimated_value_min;
if (market.estimated_value_max > 0) searchPayload.value_max = market.estimated_value_max;

// Add year built criteria (nulls auto-pass works by default - no special syntax needed)
if (market.year_built_min > 0) searchPayload.year_built_min = market.year_built_min;
if (market.year_built_max > 0) searchPayload.year_built_max = market.year_built_max;

searchPayload.ids_only = true;

Expand Down Expand Up @@ -1537,7 +1561,7 @@ export const BuyBoxModal: React.FC<BuyBoxModalProps> = ({ isOpen, onClose, focus
type="number"
min="0"
max="100"
value={market.units_min || ''}
value={market.units_min !== undefined && market.units_min !== null ? market.units_min.toString() : ''}
placeholder="Min"
onChange={(e) => {
e.stopPropagation();
Expand All @@ -1563,6 +1587,9 @@ export const BuyBoxModal: React.FC<BuyBoxModalProps> = ({ isOpen, onClose, focus
className="w-20 px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
/>
</div>
<p className="text-xs text-gray-500 mt-2">
Tip: Set Min to 0 to include properties with unknown unit count
</p>
</div>

<div>
Expand Down
2 changes: 1 addition & 1 deletion components/shared/CashFlowReportsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export const CashFlowReportsModal: React.FC<CashFlowReportsModalProps> = ({
</div>
<Download className="h-5 w-5 text-blue-600" />
<button
onClick={() => handleDeleteOffer(property.id)}
onClick={(e) => { e.stopPropagation(); handleDeleteOffer(property.id); }}
disabled={deletingId === property.id}
className="p-2 text-red-600 hover:bg-red-50 rounded-md transition-colors disabled:opacity-50"
title="Delete pricing scenario"
Expand Down
Binary file added public/Buy-Box-Guide.pdf
Binary file not shown.