/* Me2You - Property & Vehicle listings (C2C rentals, houses, cars, bikes) */ /* global React, Icon, Price, CondTag, panelStyle, btnPrimary, btnGhost, btnSmall, LeafletMap, CITY_COORDS */ const { useState, useMemo } = React; /* --- Property listings: houses, apartments, rooms, student digs --- */ const PROPERTIES = [ { id:'p1', kind:'rental', type:'Room to share', title:'Single room in 3-bed flat near Wits', monthly:2800, bedrooms:1, bathrooms:1, sqm:14, location:'Braamfontein', suburb:'Braamfontein', coords:[-26.1933, 28.0367], seller:'Lerato N.', available:'Immediate', furnished:true, students:true, pets:false, deposit:2800, description:'Furnished room in a clean shared flat. 5 min walk to Wits campus. Includes wifi, water and lights. 2 female housemates, both postgrad students.' }, { id:'p2', kind:'rental', type:'Bachelor flat', title:'Bachelor flat, secure complex Hatfield', monthly:5200, bedrooms:0, bathrooms:1, sqm:32, location:'Hatfield', suburb:'Hatfield', coords:[-25.7470, 28.2353], seller:'Pieter V.', available:'1 June', furnished:false, students:true, pets:false, deposit:5200, description:'Secure complex, 24-hr access control, parking bay, prepaid electricity. 4 min walk to Tuks main gate.' }, { id:'p3', kind:'rental', type:'2-bed apartment', title:'Modern 2-bed apartment, Sandton CBD', monthly:13500, bedrooms:2, bathrooms:2, sqm:78, location:'Sandton', suburb:'Sandton', coords:[-26.1076, 28.0567], seller:'Grace D.', available:'15 June', furnished:true, students:false, pets:true, deposit:27000, description:'High-rise, 12th floor, full city views. Pool, gym, biometric access. Walking distance to Sandton City and Gautrain.' }, { id:'p4', kind:'rental', type:'Family house', title:'3-bed family home with garden, Soweto', monthly:8500, bedrooms:3, bathrooms:2, sqm:145, location:'Soweto', suburb:'Pimville', coords:[-26.2678, 27.8585], seller:'Sipho M.', available:'1 July', furnished:false, students:false, pets:true, deposit:8500, description:'Spacious family home, large yard, double garage, prepaid water and lights. Quiet street.' }, { id:'p5', kind:'rental', type:'Garden cottage', title:'Garden cottage near UCT', monthly:6800, bedrooms:1, bathrooms:1, sqm:42, location:'Rondebosch', suburb:'Rondebosch', coords:[-33.9636, 18.4747], seller:'Naledi S.', available:'Immediate', furnished:true, students:true, pets:false, deposit:6800, description:'Separate entrance, private patio, full kitchen, fibre wifi included. 8 min from UCT Jammie Shuttle stop.' }, { id:'p6', kind:'rental', type:'Student commune', title:'Room in 5-bed student commune Stellies', monthly:3400, bedrooms:1, bathrooms:2, sqm:16, location:'Stellenbosch', suburb:'Stellenbosch', coords:[-33.9322, 18.8602], seller:'Jan D.', available:'1 February', furnished:true, students:true, pets:false, deposit:3400, description:'Mixed-gender student commune, 5 min cycle from Maties. Cleaner once a week, weekly braais, wifi included.' }, { id:'p7', kind:'sale', type:'2-bed townhouse', title:'2-bed townhouse for sale, secure estate', monthly:0, price:780000, bedrooms:2, bathrooms:1, sqm:84, location:'Roodepoort', suburb:'Wilgeheuwel', coords:[-26.1625, 27.8725], seller:'Hennie V.', available:'Negotiable', furnished:false, students:false, pets:true, deposit:0, description:'For sale by owner. Secure estate, single garage, small private garden. Levies R 1 240/mo. No agent commission.' }, { id:'p8', kind:'sale', type:'4-bed house', title:'4-bed family home for sale, ready to move', monthly:0, price:1450000, bedrooms:4, bathrooms:2, sqm:212, location:'Pretoria', suburb:'Garsfontein', coords:[-25.8003, 28.3045], seller:'Marco P.', available:'Immediate', furnished:false, students:false, pets:true, deposit:0, description:'No agent commission. Private c2c sale. Solar geyser, JoJo tanks, double garage. Title deed in hand.' }, ]; /* --- Vehicle listings: cars, bikes, scooters --- */ const VEHICLES = [ { id:'v1', kind:'car', title:'Toyota Etios 1.5 Xs', year:2018, mileage:78500, price:128000, fuel:'Petrol', transmission:'Manual', location:'Soweto', coords:[-26.2678, 27.8585], seller:'Sipho M.', description:'One owner, full service history at Toyota, just had major service. Aircon ice cold. Selling because upgrading.' }, { id:'v2', kind:'car', title:'VW Polo Vivo 1.4 Trendline', year:2020, mileage:42100, price:165000, fuel:'Petrol', transmission:'Manual', location:'Pretoria', coords:[-25.7479, 28.2293], seller:'Lerato N.', description:'Pristine condition, female-driven, never been in an accident. Service plan valid until Oct 2026.' }, { id:'v3', kind:'car', title:'Ford Ranger 2.2 XLS double cab', year:2017, mileage:142000, price:285000, fuel:'Diesel', transmission:'Manual', location:'Nelspruit', coords:[-25.4753, 30.9694], seller:'David L.', description:'Bakkie in great shape. Tow bar, bull bar, canopy included. New tyres last month.' }, { id:'v4', kind:'car', title:'Hyundai i10 1.1 Motion', year:2015, mileage:98700, price:75000, fuel:'Petrol', transmission:'Manual', location:'Cape Town', coords:[-33.9249, 18.4241], seller:'Naledi S.', description:'Perfect first car or student car. Light on fuel, cheap to insure, papers up to date.' }, { id:'v5', kind:'bike', title:'Honda CBR 125 sport bike', year:2019, mileage:18400, price:24000, fuel:'Petrol', transmission:'Manual', location:'Johannesburg', coords:[-26.2041, 28.0473], seller:'Mandla K.', description:'Lightweight learner bike, full service history. Helmet and jacket included if you collect.' }, { id:'v6', kind:'scooter', title:'Vespa Primavera 150', year:2021, mileage:6200, price:48000, fuel:'Petrol', transmission:'Auto', location:'Sandton', coords:[-26.1076, 28.0567], seller:'Tumi B.', description:'Like-new condition, only used on weekends. Top box included. Pink, very cool.' }, { id:'v7', kind:'bike', title:'Mountain bike, 26", aluminium', year:2022, mileage:0, price:3200, fuel:'-', transmission:'21-speed', location:'Rustenburg', coords:[-25.6672, 27.2424], seller:'Chris N.', description:'21-speed Shimano, hydraulic disc brakes. Used a handful of times. Trail-ready.' }, ]; /* ============================================================ PROPERTY GRID & FILTERS ============================================================== */ function PropertyBrowse({ onSelect }) { const [intent, setIntent] = useState('rent'); // rent | buy | student const [maxRent, setMaxRent] = useState(8000); const [maxPrice, setMaxPrice] = useState(2000000); const [bedrooms, setBedrooms] = useState(0); const [view, setView] = useState('grid'); const filtered = useMemo(() => { let list = PROPERTIES; if (intent === 'rent') list = list.filter(p => p.kind === 'rental'); else if (intent === 'buy') list = list.filter(p => p.kind === 'sale'); else if (intent === 'student') list = list.filter(p => p.students); if (intent === 'rent' || intent === 'student') list = list.filter(p => p.monthly <= maxRent); if (intent === 'buy') list = list.filter(p => (p.price || 0) <= maxPrice); if (bedrooms > 0) list = list.filter(p => p.bedrooms >= bedrooms); return list; }, [intent, maxRent, maxPrice, bedrooms]); const mapMarkers = filtered.map(p => ({ lat: p.coords[0], lng: p.coords[1], label: p.kind === 'sale' ? 'R' : (p.students ? 'S' : '$'), color: p.kind === 'sale' ? '#2D7AC7' : (p.students ? '#2F9E5A' : '#F89A1F'), popup: `${p.title}
${p.kind === 'sale' ? 'R ' + (p.price/1000).toFixed(0) + 'k' : 'R ' + p.monthly.toLocaleString('en-ZA') + '/mo'}
${p.bedrooms} bed - ${p.bathrooms} bath - ${p.sqm} m2`, })); return (

Houses, rooms & apartments

Direct from owners. No agent commission. {filtered.length} listings.

{/* Intent tabs */}
{[ { key:'rent', label:'To rent', icon:'home' }, { key:'buy', label:'To buy', icon:'tag' }, { key:'student', label:'Student rooms', icon:'user-round' }, ].map(i => ( ))}
{/* Filters */}
{(intent === 'rent' || intent === 'student') ? (
setMaxRent(+e.target.value)} style={{flex:1,accentColor:'var(--brand-orange)'}}/> R {maxRent.toLocaleString('en-ZA')}
) : (
setMaxPrice(+e.target.value)} style={{flex:1,accentColor:'var(--brand-orange)'}}/> R {(maxPrice/1000).toFixed(0)}k
)}
{[0,1,2,3,4].map(n => ( ))}
Furnished Pets ok Parking
{view === 'map' && (
)}
{filtered.map(p => onSelect && onSelect(p)}/>)}
); } function PropertyCard({ property, onClick }) { const [hovered, setHovered] = useState(false); const [liked, setLiked] = useState(false); return (
setHovered(true)} onMouseLeave={() => setHovered(false)} style={{ background:'var(--paper)',borderRadius:'var(--radius-lg)', border:'1px solid var(--ink-200)', boxShadow: hovered ? 'var(--shadow-md)' : 'var(--shadow-sm)', cursor:'pointer',transition:'all .2s cubic-bezier(.2,.7,.3,1)', transform: hovered ? 'translateY(-3px)' : 'none', overflow:'hidden',position:'relative' }}>
{property.students && ( STUDENT )} {property.kind === 'sale' && ( FOR SALE )}
{property.type}

{property.title}

{property.suburb}, {property.location}
{property.bedrooms === 0 ? 'Bachelor' : property.bedrooms + ' bed'} - {property.bathrooms} bath - {property.sqm} m2
{property.kind === 'sale' ? ( ) : (
/mo
)}
{property.available}
); } /* ============================================================ PROPERTY DETAIL PAGE ============================================================== */ function PropertyDetail({ property, onBack, onMessage }) { if (!property) return null; return (
{[1,2,3,4].map(i => (
))}

About this place

{property.description}

Features

{[ { icon:'home', label: property.furnished ? 'Furnished' : 'Unfurnished' }, { icon:'shield-check', label: 'Secure parking' }, { icon: property.pets ? 'check' : 'x', label: property.pets ? 'Pets allowed' : 'No pets' }, { icon: property.students ? 'user-round' : 'home', label: property.students ? 'Student-friendly' : 'Quiet area' }, { icon:'wallet', label: 'Prepaid utilities' }, { icon:'map-pin', label: property.sqm + ' m2 floor area' }, ].map((f,i) => (
{f.label}
))}

Location

{property.type}

{property.title}

{property.suburb}, {property.location}
{property.kind === 'sale' ? (
R {(property.price/1000).toFixed(0)}k
Once-off purchase - No agent commission
) : (
R {property.monthly.toLocaleString('en-ZA')} /month
Deposit: R {property.deposit.toLocaleString('en-ZA')}
)}
{property.bedrooms || '-'}
Bedrooms
{property.bathrooms}
Bathrooms
{property.sqm}
m2
Deposit held in Me2You escrow until move-in date confirmed. No fake landlord scams.
{property.seller.charAt(0)}
{property.seller}
Owner - Joined Feb 2026
); } /* ============================================================ VEHICLE BROWSE ============================================================== */ function VehicleBrowse({ onSelect }) { const [type, setType] = useState('all'); const [maxPrice, setMaxPrice] = useState(300000); const [view, setView] = useState('grid'); const filtered = useMemo(() => { let list = VEHICLES; if (type !== 'all') list = list.filter(v => v.kind === type); list = list.filter(v => v.price <= maxPrice); return list; }, [type, maxPrice]); const mapMarkers = filtered.map(v => ({ lat: v.coords[0], lng: v.coords[1], label: v.kind === 'car' ? 'C' : (v.kind === 'bike' ? 'B' : 'S'), color: '#F89A1F', popup: `${v.title}
${v.year} - R ${v.price.toLocaleString('en-ZA')}
${v.mileage.toLocaleString('en-ZA')} km`, })); return (

Cars, bikes & scooters

Informal C2C vehicle sales. {filtered.length} listings.

{[ { key:'all', label:'All vehicles' }, { key:'car', label:'Cars' }, { key:'bike', label:'Bikes' }, { key:'scooter', label:'Scooters' }, ].map(t => ( ))}
setMaxPrice(+e.target.value)} style={{flex:1,accentColor:'var(--brand-orange)'}}/> R {maxPrice.toLocaleString('en-ZA')}
{view === 'map' && (
)}
{filtered.map(v => onSelect && onSelect(v)}/>)}
); } function VehicleCard({ vehicle, onClick }) { const [hovered, setHovered] = useState(false); return (
setHovered(true)} onMouseLeave={() => setHovered(false)} style={{ background:'var(--paper)',borderRadius:'var(--radius-lg)', border:'1px solid var(--ink-200)', boxShadow: hovered ? 'var(--shadow-md)' : 'var(--shadow-sm)', cursor:'pointer',transition:'all .2s cubic-bezier(.2,.7,.3,1)', transform: hovered ? 'translateY(-3px)' : 'none', overflow:'hidden',position:'relative' }}>
{vehicle.year} {vehicle.kind}

{vehicle.title}

{vehicle.mileage.toLocaleString('en-ZA')} km - {vehicle.fuel} - {vehicle.transmission}
{vehicle.location} - {vehicle.seller}
No agent commission
); } /* --- shared mini-styles --- */ const viewBtn = (active) => ({ padding:'6px 14px',borderRadius:999,border:'none',cursor:'pointer', fontFamily:'var(--font-body)',fontWeight:600,fontSize:12, background: active ? 'var(--paper)' : 'transparent', color: active ? 'var(--ink-900)' : 'var(--ink-500)', boxShadow: active ? 'var(--shadow-xs)' : 'none' }); const filterLabel = {display:'block',fontFamily:'var(--font-mono)',fontSize:10,fontWeight:600,color:'var(--ink-500)',textTransform:'uppercase',letterSpacing:'.06em',marginBottom:8}; const chipStyle = {padding:'4px 10px',borderRadius:999,background:'var(--ink-100)',fontSize:11,fontFamily:'var(--font-body)',fontWeight:600,color:'var(--ink-700)'}; /* ============================================================ VEHICLE DETAIL ============================================================== */ function VehicleDetail({ vehicle, onBack, onMessage }) { if (!vehicle) return null; return (
{[1,2,3,4,5].map(i => (
))}

About this {vehicle.kind}

{vehicle.description}

Specifications

{[ { label:'Year', value:vehicle.year }, { label:'Mileage', value: vehicle.mileage > 0 ? vehicle.mileage.toLocaleString('en-ZA') + ' km' : '-' }, { label:'Fuel', value:vehicle.fuel }, { label:'Transmission', value:vehicle.transmission }, { label:'Type', value: vehicle.kind.charAt(0).toUpperCase() + vehicle.kind.slice(1) }, { label:'Location', value:vehicle.location }, ].map((s,i) => (
{s.label}
{s.value}
))}

Location

{vehicle.year} {vehicle.kind}

{vehicle.title}

{vehicle.location}
R {vehicle.price.toLocaleString('en-ZA')}
Direct seller - No agent commission
Deposit held in Me2You escrow until ownership transfer confirmed. NaTIS / V&L verified.
{vehicle.seller.charAt(0)}
{vehicle.seller}
Owner - NaTIS confirmed
); } Object.assign(window, { PropertyBrowse, PropertyDetail, VehicleBrowse, VehicleCard, VehicleDetail, PROPERTIES, VEHICLES });