lmao
This commit is contained in:
parent
03445188ea
commit
524580eb25
102 changed files with 36625 additions and 1295 deletions
|
|
@ -23,12 +23,13 @@ import { getTutorialStyles } from '../../lib/tutorial-styles';
|
|||
import Joyride from 'react-joyride';
|
||||
import {
|
||||
useTravelTime,
|
||||
TRANSPORT_MODES,
|
||||
MODE_LABELS,
|
||||
type TransportMode,
|
||||
travelFieldKey,
|
||||
type TravelTimeInitial,
|
||||
} from '../../hooks/useTravelTime';
|
||||
import { apiUrl, assertOk, buildFilterString, logNonAbortError } from '../../lib/api';
|
||||
import { apiUrl, assertOk, authHeaders, buildFilterString, logNonAbortError } from '../../lib/api';
|
||||
import { useLicense } from '../../hooks/useLicense';
|
||||
import UpgradeModal from '../ui/UpgradeModal';
|
||||
import { SpinnerIcon } from '../ui/icons/SpinnerIcon';
|
||||
import { MapPinIcon } from '../ui/icons/MapPinIcon';
|
||||
|
||||
|
|
@ -54,6 +55,9 @@ interface MapPageProps {
|
|||
ogMode?: boolean;
|
||||
isMobile?: boolean;
|
||||
initialTravelTime?: TravelTimeInitial;
|
||||
user?: { id: string; subscription: string } | null;
|
||||
onLoginClick?: () => void;
|
||||
onRegisterClick?: () => void;
|
||||
}
|
||||
|
||||
export default function MapPage({
|
||||
|
|
@ -73,6 +77,9 @@ export default function MapPage({
|
|||
ogMode,
|
||||
isMobile = false,
|
||||
initialTravelTime,
|
||||
user,
|
||||
onLoginClick,
|
||||
onRegisterClick,
|
||||
}: MapPageProps) {
|
||||
const [selectedPOICategories, setSelectedPOICategories] =
|
||||
useState<Set<string>>(initialPOICategories);
|
||||
|
|
@ -125,6 +132,9 @@ export default function MapPage({
|
|||
// Travel time hook
|
||||
const travelTime = useTravelTime(initialTravelTime);
|
||||
|
||||
// License hook
|
||||
const license = useLicense();
|
||||
|
||||
// Map data hook
|
||||
const mapData = useMapData({
|
||||
filters,
|
||||
|
|
@ -164,20 +174,21 @@ export default function MapPage({
|
|||
// POI data
|
||||
const pois = usePOIData(mapData.bounds, selectedPOICategories);
|
||||
|
||||
// Compute data range for travel time slider per mode (full min/max for slider bounds)
|
||||
const travelTimeDataRanges = useMemo((): Partial<Record<TransportMode, [number, number]>> => {
|
||||
const ranges: Partial<Record<TransportMode, [number, number]>> = {};
|
||||
for (const mode of TRANSPORT_MODES) {
|
||||
const entry = travelTime.entries[mode];
|
||||
if (!entry?.destination) continue;
|
||||
// Compute data range for travel time slider per entry index (full min/max for slider bounds)
|
||||
const travelTimeDataRanges = useMemo((): globalThis.Map<number, [number, number]> => {
|
||||
const ranges = new globalThis.Map<number, [number, number]>();
|
||||
for (let i = 0; i < travelTime.entries.length; i++) {
|
||||
const entry = travelTime.entries[i];
|
||||
if (!entry.slug) continue;
|
||||
const fieldName = `avg_${travelFieldKey(entry)}`;
|
||||
const vals: number[] = [];
|
||||
for (const item of mapData.data) {
|
||||
const val = item[`travel_time_${mode}`];
|
||||
const val = item[fieldName];
|
||||
if (typeof val === 'number' && !isNaN(val)) vals.push(val);
|
||||
}
|
||||
if (vals.length === 0) continue;
|
||||
vals.sort((a, b) => a - b);
|
||||
ranges[mode] = [vals[0], vals[vals.length - 1]];
|
||||
ranges.set(i, [vals[0], vals[vals.length - 1]]);
|
||||
}
|
||||
return ranges;
|
||||
}, [travelTime.entries, mapData.data]);
|
||||
|
|
@ -253,7 +264,7 @@ export default function MapPage({
|
|||
const url = apiUrl('export', params);
|
||||
|
||||
setExporting(true);
|
||||
fetch(url)
|
||||
fetch(url, authHeaders())
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
return res.blob();
|
||||
|
|
@ -397,8 +408,8 @@ export default function MapPage({
|
|||
onClearOpenInfoFeature={onClearPendingInfoFeature}
|
||||
travelTimeEntries={travelTime.entries}
|
||||
travelTimeDataRanges={travelTimeDataRanges}
|
||||
onTravelTimeEnableMode={travelTime.handleEnableMode}
|
||||
onTravelTimeDisableMode={travelTime.handleDisableMode}
|
||||
onTravelTimeAddEntry={travelTime.handleAddEntry}
|
||||
onTravelTimeRemoveEntry={travelTime.handleRemoveEntry}
|
||||
onTravelTimeSetDestination={travelTime.handleSetDestination}
|
||||
onTravelTimeRangeChange={travelTime.handleTimeRangeChange}
|
||||
aiFilterLoading={aiFilters.loading}
|
||||
|
|
@ -478,14 +489,14 @@ export default function MapPage({
|
|||
>
|
||||
{/* Legend */}
|
||||
{(() => {
|
||||
const primaryMode = TRANSPORT_MODES.find(
|
||||
(m) => travelTime.entries[m]?.destination && mapData.travelTimeColorRanges[m]
|
||||
const primaryIdx = travelTime.entries.findIndex(
|
||||
(e, i) => e.slug && mapData.travelTimeColorRanges.get(i)
|
||||
);
|
||||
if (primaryMode) {
|
||||
if (primaryIdx >= 0) {
|
||||
return (
|
||||
<MapLegend
|
||||
featureLabel={`Travel time (${MODE_LABELS[primaryMode]})`}
|
||||
range={mapData.travelTimeColorRanges[primaryMode]!}
|
||||
featureLabel={`Travel time (${MODE_LABELS[travelTime.entries[primaryIdx].mode]})`}
|
||||
range={mapData.travelTimeColorRanges.get(primaryIdx)!}
|
||||
showCancel={false}
|
||||
onCancel={handleCancelPin}
|
||||
mode="feature"
|
||||
|
|
@ -539,6 +550,16 @@ export default function MapPage({
|
|||
renderProperties={renderPropertiesPane}
|
||||
/>
|
||||
)}
|
||||
|
||||
{mapData.licenseRequired && (
|
||||
<UpgradeModal
|
||||
isLoggedIn={!!user}
|
||||
onLoginClick={onLoginClick ?? (() => {})}
|
||||
onRegisterClick={onRegisterClick ?? (() => {})}
|
||||
onStartCheckout={() => license.startCheckout()}
|
||||
onDismiss={() => {}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -664,6 +685,16 @@ export default function MapPage({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{mapData.licenseRequired && (
|
||||
<UpgradeModal
|
||||
isLoggedIn={!!user}
|
||||
onLoginClick={onLoginClick ?? (() => {})}
|
||||
onRegisterClick={onRegisterClick ?? (() => {})}
|
||||
onStartCheckout={() => license.startCheckout()}
|
||||
onDismiss={() => {}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue