import {useState} from 'react';
import type {LocalPlace} from '@o2o/shared';
import {useSite} from '@site/lib/site-context';
import {naverMapSearchUrl} from '@site/lib/format';
import {PhotoCard} from '../kit/Card';
import {Sheet} from '../paper/Sheet';
const WALK = 80;
const RANGES = [
{id: 'all', label: '전체', test: () => true},
{id: 'w5', label: '걸어서 5분 이내', test: (m: number) => m <= 5 * WALK},
{id: 'w10', label: '걸어서 10분 이내', test: (m: number) => m <= 10 * WALK},
{id: 'far', label: '걸어서 10분 이상', test: (m: number) => m > 10 * WALK},
] as const;
const FIRST_SPOTS = 6;
const FIRST_EATS = 5;
const HOME_ROWS = 3;
function meters(place: LocalPlace): number {
if (place.distanceMeters != null) return place.distanceMeters;
const m = /^([\d.]+)\s*(km|m)$/i.exec((place.distanceText ?? '').trim());
return m ? Number(m[1]) * (m[2].toLowerCase() === 'km' ? 1000 : 1) : Infinity;
}
const byDistance = (a: LocalPlace, b: LocalPlace) => meters(a) - meters(b);
const inRange = (id: string) => RANGES.find((r) => r.id === id)?.test ?? (() => true);
function RangeTabs({places, value, onChange}: {places: LocalPlace[]; value: string; onChange: (id: string) => void}) {
const tabs = RANGES.filter((r, i) => {
const n = places.filter((p) => r.test(meters(p))).length;
return i === 0 || (n > 0 && n < places.length);
});
if (tabs.length < 2) return null;
return (
{tabs.map((r) => (
))}
);
}
export function Around() {
const payload = useSite();
const {local} = payload;
const spots = [...local.attractions].sort(byDistance);
const eats = [...local.restaurants].sort(byDistance);
const rail = [...spots, ...eats].filter((place) => place.imageUrl).sort(byDistance);
const [open, setOpen] = useState(null);
const [spotRange, setSpotRange] = useState('all');
const [eatRange, setEatRange] = useState('all');
const firstSpots = FIRST_SPOTS;
if (rail.length === 0 && eats.length === 0) return null;
const shownSpots = spots.filter((p) => inRange(spotRange)(meters(p)));
const shownEats = eats.filter((p) => inRange(eatRange)(meters(p)));
const place = (item: LocalPlace, withText = true) => (
);
const spot = (item: LocalPlace) => (
setOpen(item)}
/>
);
return (
<>
{rail.length > 0 && (
AROUND
주변 안내
걸어서 닿는 명소와 맛집입니다.
{rail.slice(0, HOME_ROWS).map(spot)}
지역 소개에서 모두 보기
)}
{spots.length > 0 && (
AROUND
주변 명소 {spots.length}곳
걸어서 닿는 곳부터 차로 가는 곳까지 묶었습니다.
{shownSpots.slice(0, firstSpots).map(spot)}
{shownSpots.length > firstSpots && (
{shownSpots.length - firstSpots}곳 더 보기
{shownSpots.slice(firstSpots).map(spot)}
)}
)}
{eats.length > 0 && (
EAT
주변 맛집 {eats.length}곳
{shownEats.slice(0, FIRST_EATS).map((item) => place(item, false))}
{shownEats.length > FIRST_EATS && (
{shownEats.length - FIRST_EATS}곳 더 보기
{shownEats.slice(FIRST_EATS).map((item) => place(item, false))}
)}
)}
setOpen(null)} label={open?.name ?? ''}>
{open && (
<>
{open.imageUrl &&
}
{open.name}
{[open.distanceText, open.category].filter(Boolean).join(' · ')}
{open.description && {open.description}
}
네이버에서 보기
>
)}
>
);
}