// ListingsScreen — search results: filter rail + property grid.
const _filterSelectStyle = {
padding: '0 32px 0 12px',
height: 44,
border: '1px solid var(--border-default)',
borderRadius: 'var(--radius-md)',
background: 'var(--surface-card)',
fontFamily: 'var(--font-body)',
fontSize: 13.5,
color: 'var(--text-strong)',
outline: 'none',
cursor: 'pointer',
appearance: 'none',
WebkitAppearance: 'none',
width: '100%',
backgroundImage: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\")",
backgroundRepeat: 'no-repeat',
backgroundPosition: 'right 10px center',
};
const _labelStyle = {
fontFamily: 'var(--font-body)',
fontSize: 11,
fontWeight: 600,
letterSpacing: '0.08em',
textTransform: 'uppercase',
color: 'var(--text-muted)',
marginBottom: 6,
display: 'block',
};
const BAIRROS = ['Cabo Branco', 'Tambaú', 'Manaíra', 'Bessa', 'Altiplano', 'Jardim Oceania'];
const TIPOS = ['Apartamento', 'Casa', 'Cobertura', 'Flat', 'Terreno'];
function FilterSelect({ label, value, onChange, options, placeholder }) {
const { t } = window.useLang();
return (
{t(label)}
onChange(e.target.value)} style={_filterSelectStyle}>
{t(placeholder)}
{options.map(o => typeof o === 'string'
? {t(o)}
: {t(o.label)}
)}
);
}
function _XIcon() {
return (
);
}
function parseRawPrice(s) {
if (!s) return 0;
return parseFloat(s.replace(/[^0-9]/g, '')) || 0;
}
function ListingsScreen({ onOpenProperty, initialKind, initialNeighborhood, initialFeatured, initialPropertyType, initialLaunch, initialLuxury }) {
const { PropertyCard, Button } = window.SBLImVeisDesignSystem_08a506;
const { isMobile, isTablet } = window.useResponsive();
const { t } = window.useLang();
const all = window.SBL_DATA.properties;
const featured = !!initialFeatured;
const launch = !!initialLaunch;
const luxury = !!initialLuxury;
const [kind, setKind] = React.useState(initialKind || 'all');
const [neighborhood, setNeighborhood] = React.useState(initialNeighborhood || '');
const [propertyType, setPropertyType] = React.useState(initialPropertyType || '');
const [minBeds, setMinBeds] = React.useState('');
const [priceRange, setPriceRange] = React.useState('');
const [sortBy, setSortBy] = React.useState('');
const [showFilters, setShowFilters] = React.useState(false);
const [showFavs, setShowFavs] = React.useState(false);
const [favIds, setFavIds] = React.useState(() => {
try { return JSON.parse(localStorage.getItem('sbl_favorites') || '[]'); } catch { return []; }
});
React.useEffect(() => {
function sync() {
try { setFavIds(JSON.parse(localStorage.getItem('sbl_favorites') || '[]')); } catch {}
}
window.addEventListener('sbl:favorites-changed', sync);
return () => window.removeEventListener('sbl:favorites-changed', sync);
}, []);
const thirtyDaysAgo = React.useMemo(() => new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(), []);
const filtered = React.useMemo(() => {
return all.filter(p => {
if (showFavs && !favIds.includes(p.id)) return false;
if (launch && (!p.createdAt || p.createdAt < thirtyDaysAgo)) return false;
if (luxury && !p.featured && parseRawPrice(p.price) < 1000000) return false;
if (kind !== 'all' && p.kind !== kind) return false;
if (featured && !p.featured) return false;
if (neighborhood) {
const loc = ((p.location || '') + ' ' + (p.neighborhood || '')).toLowerCase();
if (!loc.includes(neighborhood.toLowerCase())) return false;
}
if (propertyType) {
const typeStr = ((p.type || '') + ' ' + (p.title || '')).toLowerCase();
if (!typeStr.includes(propertyType.toLowerCase())) return false;
}
if (minBeds && (p.beds || 0) < parseInt(minBeds)) return false;
if (priceRange && (p.kind === 'sale' || kind === 'sale')) {
const num = parseRawPrice(p.price);
if (priceRange === 'ate500k' && num > 500000) return false;
if (priceRange === '500k1m' && (num <= 500000 || num > 1000000)) return false;
if (priceRange === 'acima1m' && num <= 1000000) return false;
}
return true;
});
}, [all, kind, featured, launch, luxury, neighborhood, propertyType, minBeds, priceRange, showFavs, favIds, thirtyDaysAgo]);
const list = React.useMemo(() => {
return [...filtered].sort((a, b) => {
if (sortBy === 'price-asc') return parseRawPrice(a.price) - parseRawPrice(b.price);
if (sortBy === 'price-desc') return parseRawPrice(b.price) - parseRawPrice(a.price);
return 0;
});
}, [filtered, sortBy]);
const activeCount = [neighborhood, propertyType, minBeds, priceRange, showFavs ? 'fav' : ''].filter(Boolean).length;
function clearAllFilters() {
setNeighborhood(''); setPropertyType(''); setMinBeds(''); setPriceRange(''); setShowFavs(false);
}
const pageTitle = (() => {
if (launch) return t('Lançamentos em João Pessoa');
if (luxury) return t('Imóveis de Luxo em João Pessoa');
if (neighborhood) return t('Imóveis em {bairro}', { bairro: neighborhood });
if (featured) return t('Imóveis de Luxo em João Pessoa');
if (kind === 'sale') return t('Imóveis à Venda em João Pessoa');
if (kind === 'season') return t('Temporada em João Pessoa');
if (kind === 'rent') return t('Aluguel em João Pessoa');
return t('Imóveis em João Pessoa');
})();
const Chip = ({ id, label }) => {
const active = kind === id && !neighborhood && !featured && !propertyType && !showFavs && !launch && !luxury;
return (
setKind(id)} style={{
fontFamily: 'var(--font-body)', fontSize: isMobile ? 12.5 : 13.5, fontWeight: 500,
padding: isMobile ? '8px 12px' : '9px 18px', borderRadius: 'var(--radius-pill)', cursor: 'pointer',
border: '1px solid ' + (active ? 'var(--brown-500)' : 'var(--border-default)'),
background: active ? 'var(--brown-500)' : 'var(--surface-card)',
color: active ? 'var(--cream-50)' : 'var(--warmgray-600)',
transition: 'all var(--dur-base) var(--ease-out)', flexShrink: 0,
}}>{label}
);
};
const tagSty = {
display: 'inline-flex', alignItems: 'center', gap: 6,
padding: isMobile ? '8px 12px' : '9px 16px', borderRadius: 'var(--radius-pill)',
background: 'var(--brown-500)', color: 'var(--cream-50)',
fontFamily: 'var(--font-body)', fontSize: isMobile ? 12.5 : 13.5, fontWeight: 600,
border: 'none', cursor: 'pointer', flexShrink: 0,
};
const priceLabel = { ate500k: 'Até R$ 500k', '500k1m': 'R$ 500k–1mi', acima1m: 'Acima R$ 1mi' };
return (
{/* Page head */}
{t('Portfólio')}
{pageTitle}
{/* Desktop filters */}
{!isMobile && (
{activeCount > 0 ? (
<_XIcon /> {t('Limpar')} ({activeCount})
) :
}
)}
{/* Toolbar */}
{/* Active filter tags + kind chips */}
{favIds.length > 0 && (
setShowFavs(f => !f)} style={{
fontFamily: 'var(--font-body)', fontSize: isMobile ? 12.5 : 13.5, fontWeight: 600,
padding: isMobile ? '8px 12px' : '9px 18px', borderRadius: 'var(--radius-pill)', cursor: 'pointer',
border: '1px solid ' + (showFavs ? '#c0415a' : 'var(--border-default)'),
background: showFavs ? '#c0415a' : 'var(--surface-card)',
color: showFavs ? '#fff' : 'var(--warmgray-600)',
display: 'flex', alignItems: 'center', gap: 6, flexShrink: 0,
transition: 'all var(--dur-base) var(--ease-out)',
}}>
♥ {t('Meus favoritos')} ({favIds.length})
)}
{launch && 🆕 {t('Lançamentos — últimos 30 dias')} }
{luxury && ✦ {t('Imóveis de luxo')} }
{neighborhood && setNeighborhood('')} style={tagSty}>📍 {neighborhood} <_XIcon /> }
{propertyType && setPropertyType('')} style={tagSty}>🏠 {t(propertyType)} <_XIcon /> }
{minBeds && setMinBeds('')} style={tagSty}>🛏 {minBeds}+ {t('quartos')} <_XIcon /> }
{priceRange && setPriceRange('')} style={tagSty}>💰 {t(priceLabel[priceRange])} <_XIcon /> }
{featured && ✨ {t('Imóveis de luxo')} }
{!neighborhood && !featured && !propertyType && !showFavs && !launch && !luxury && (
<>
>
)}
{/* Count + sort / mobile filter button */}
{list.length === 1 ? t('1 encontrado') : t('{n} encontrados', { n: list.length })}
{isMobile && (
setShowFilters(true)} style={{
flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
padding: '10px 16px', borderRadius: 'var(--radius-md)',
border: '1px solid ' + (activeCount > 0 ? 'var(--brown-500)' : 'var(--border-default)'),
background: activeCount > 0 ? 'var(--brown-500)' : 'var(--surface-card)',
color: activeCount > 0 ? 'var(--cream-50)' : 'var(--text-body)',
fontFamily: 'var(--font-body)', fontSize: 13.5, fontWeight: 500, cursor: 'pointer',
}}>
{t('Filtros')}{activeCount > 0 ? ` (${activeCount})` : ''}
)}
{!isMobile && (
setSortBy(e.target.value)}
style={{ ..._filterSelectStyle, height: 38, fontSize: 13 }}>
{t('Mais recentes')}
{t('Menor preço')}
{t('Maior preço')}
)}
{/* Grid */}
{list.length === 0 ? (
🏠
{t('Nenhum imóvel encontrado')}
{neighborhood
? t('Não há imóveis em {bairro} com os filtros selecionados.', { bairro: neighborhood })
: t('Não há imóveis disponíveis para os filtros selecionados.')}
{activeCount > 0 && (
{t('Limpar filtros')}
)}
) : (
{list.map(p =>
onOpenProperty(p.id)} />)}
{t('Carregar mais imóveis')}
)}
{/* Mobile filter bottom sheet */}
{showFilters && (
setShowFilters(false)}
style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.5)' }} />
{t('Filtros')}
{activeCount > 0 && (
{t('Limpar tudo')}
)}
setShowFilters(false)} style={{
width: '100%', marginTop: 28, padding: 14, borderRadius: 'var(--radius-md)',
background: 'var(--brown-700)', color: 'var(--cream-50)',
fontFamily: 'var(--font-body)', fontSize: 15, fontWeight: 600,
border: 'none', cursor: 'pointer',
}}>
{list.length === 1 ? t('Ver 1 imóvel') : t('Ver {n} imóveis', { n: list.length })}
)}
);
}
window.ListingsScreen = ListingsScreen;