Make EV charging an amenity toggle and drop filter select
This commit is contained in:
parent
c08dca02e7
commit
3d13bf3ba3
2 changed files with 16 additions and 45 deletions
|
|
@ -137,6 +137,7 @@ export default function NewListingPage() {
|
|||
{ key: 'microwave', label: t('amenityMicrowave'), icon: '🍲', checked: hasMicrowave, toggle: setHasMicrowave },
|
||||
{ key: 'parking', label: t('amenityFreeParking'), icon: '🅿️', checked: hasFreeParking, toggle: setHasFreeParking },
|
||||
{ key: 'ski', label: t('amenitySkiPass'), icon: '⛷️', checked: hasSkiPass, toggle: setHasSkiPass },
|
||||
{ key: 'ev', label: t('amenityEvAvailable'), icon: '⚡', checked: evChargingAvailable, toggle: setEvChargingAvailable },
|
||||
];
|
||||
|
||||
function updateTranslation(locale: Locale, field: keyof LocaleFields, value: string) {
|
||||
|
|
@ -704,28 +705,6 @@ export default function NewListingPage() {
|
|||
</span>
|
||||
</button>
|
||||
))}
|
||||
<div className="amenity-ev">
|
||||
<div className="amenity-ev-label">{t('evChargingLabel')}</div>
|
||||
<div style={{ color: '#cbd5e1', fontSize: 12, marginBottom: 6 }}>{t('evChargingExplain')}</div>
|
||||
<div className="ev-toggle-group">
|
||||
{[
|
||||
{ value: true, label: t('evChargingYes'), icon: '⚡' },
|
||||
{ value: false, label: t('evChargingNo'), icon: '🚗' },
|
||||
].map((opt) => (
|
||||
<button
|
||||
key={String(opt.value)}
|
||||
type="button"
|
||||
className={`ev-toggle ${evChargingAvailable === opt.value ? 'active' : ''}`}
|
||||
onClick={() => setEvChargingAvailable(opt.value)}
|
||||
>
|
||||
<span aria-hidden className="amenity-emoji">
|
||||
{opt.icon}
|
||||
</span>
|
||||
{opt.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gap: 8, gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))' }}>
|
||||
<label>
|
||||
|
|
|
|||
|
|
@ -183,7 +183,6 @@ export default function ListingsIndexPage() {
|
|||
const [query, setQuery] = useState('');
|
||||
const [city, setCity] = useState('');
|
||||
const [region, setRegion] = useState('');
|
||||
const [evCharging, setEvCharging] = useState<'ALL' | 'YES' | 'NO'>('ALL');
|
||||
const [listings, setListings] = useState<ListingResult[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
|
@ -207,10 +206,7 @@ export default function ListingsIndexPage() {
|
|||
});
|
||||
}, [listings, addressCenter, radiusKm]);
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
if (evCharging === 'ALL') return filteredByAddress;
|
||||
return filteredByAddress.filter((l) => (evCharging === 'YES' ? l.evChargingAvailable : !l.evChargingAvailable));
|
||||
}, [filteredByAddress, evCharging]);
|
||||
const filtered = filteredByAddress;
|
||||
|
||||
const amenityOptions = [
|
||||
{ key: 'sauna', label: t('amenitySauna'), icon: amenityIcons.sauna },
|
||||
|
|
@ -226,6 +222,7 @@ export default function ListingsIndexPage() {
|
|||
{ key: 'microwave', label: t('amenityMicrowave'), icon: amenityIcons.microwave },
|
||||
{ key: 'parking', label: t('amenityFreeParking'), icon: amenityIcons.parking },
|
||||
{ key: 'skipass', label: t('amenitySkiPass'), icon: amenityIcons.ski },
|
||||
{ key: 'ev', label: t('amenityEvAvailable'), icon: amenityIcons.ev },
|
||||
];
|
||||
|
||||
async function fetchListings() {
|
||||
|
|
@ -236,10 +233,13 @@ export default function ListingsIndexPage() {
|
|||
if (query) params.set('q', query);
|
||||
if (city) params.set('city', city);
|
||||
if (region) params.set('region', region);
|
||||
if (evCharging !== 'ALL') params.set('evCharging', evCharging === 'YES' ? 'true' : 'false');
|
||||
if (startDate) params.set('availableStart', startDate);
|
||||
if (endDate) params.set('availableEnd', endDate);
|
||||
amenities.forEach((a) => params.append('amenity', a));
|
||||
const evSelected = amenities.includes('ev');
|
||||
if (evSelected) params.set('evCharging', 'true');
|
||||
amenities
|
||||
.filter((a) => a !== 'ev')
|
||||
.forEach((a) => params.append('amenity', a));
|
||||
const res = await fetch(`/api/listings?${params.toString()}`, { cache: 'no-store' });
|
||||
const data = await res.json();
|
||||
if (!res.ok || data.error) {
|
||||
|
|
@ -314,22 +314,14 @@ export default function ListingsIndexPage() {
|
|||
/>
|
||||
</label>
|
||||
<label>
|
||||
{t('cityFilter')}
|
||||
<input value={city} onChange={(e) => setCity(e.target.value)} placeholder={t('cityFilter')} />
|
||||
</label>
|
||||
<label>
|
||||
{t('regionFilter')}
|
||||
<input value={region} onChange={(e) => setRegion(e.target.value)} placeholder={t('regionFilter')} />
|
||||
</label>
|
||||
<label>
|
||||
{t('evChargingLabel')}
|
||||
<select value={evCharging} onChange={(e) => setEvCharging(e.target.value as any)}>
|
||||
<option value="ALL">{t('evChargingAny')}</option>
|
||||
<option value="YES">{t('evChargingYes')}</option>
|
||||
<option value="NO">{t('evChargingNo')}</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
{t('cityFilter')}
|
||||
<input value={city} onChange={(e) => setCity(e.target.value)} placeholder={t('cityFilter')} />
|
||||
</label>
|
||||
<label>
|
||||
{t('regionFilter')}
|
||||
<input value={region} onChange={(e) => setRegion(e.target.value)} placeholder={t('regionFilter')} />
|
||||
</label>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gap: 10, gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', marginTop: 12 }}>
|
||||
<label>
|
||||
{t('startDate')}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue