Introduces a full Google-Maps-backed provider map for the arrangement wizard's ProvidersStep. Clicking a pin morphs it into a MapPopup at the same coord; pins within 70px of each other collapse into a cluster (ceiling at zoom 13) that opens a ClusterPopup list on click. Row clicks pan + zoom the map to the provider and open their MapPopup. Map-background click routes through an exit transition that fades the popup out before reappearing the pin, via a matching fade-in keyframe on the atom markers. Key additions: - @vis.gl/react-google-maps + @googlemaps/markerclusterer deps - ClusterMarker atom (count badge; verified / unverified palettes) - ClusterPopup molecule (image-free rows; verified icon aligned to name; right-aligned "From $X" column; verified-first sort) - ProviderMap organism (APIProvider + Map + imperative AdvancedMarker layer via createRoot for clusterer compatibility) Component changes: - MapPin: promoted verified palette (brand-700); name now required; name-only and price-only variants dropped; active prop removed in favour of organism-level state; SVG nub with fill+stroke replaces the CSS border-triangle trick so the outline is continuous - MapPopup: `exiting` prop drives close animation; click events stop propagation so the map's onClick can't clear state mid-interaction - ProviderData type gains optional `coords`; demo fixtures populated with real NSW/QLD lat/lng for all 7 providers - ProvidersStep demo route wires ProviderMap into the mapPanel slot Memory: - docs/memory/component-registry updated (ClusterMarker, ClusterPopup, ProviderMap added; MapPin + MapPopup refined; MapCard retired) - docs/memory/session-log captures arc across 2026-04-21/22 and flags next-session work: ProvidersStep polish, mobile layout for list-map WizardLayout, and demo deploy Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
46 lines
1.4 KiB
TypeScript
46 lines
1.4 KiB
TypeScript
import { useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import {
|
|
ProvidersStep,
|
|
EMPTY_FILTER_VALUES,
|
|
type ProviderFilterValues,
|
|
type ProviderSortBy,
|
|
type ListViewMode,
|
|
} from '../../../../components/pages/ProvidersStep';
|
|
import { ProviderMap } from '../../../../components/organisms/ProviderMap';
|
|
import { providers } from '../../../shared/fixtures/providers';
|
|
import { demoNav } from '../DemoNav';
|
|
|
|
export function ProvidersRoute() {
|
|
const navigate = useNavigate();
|
|
const [query, setQuery] = useState('');
|
|
const [filters, setFilters] = useState<ProviderFilterValues>(EMPTY_FILTER_VALUES);
|
|
const [sort, setSort] = useState<ProviderSortBy>('recommended');
|
|
const [view, setView] = useState<ListViewMode>('list');
|
|
|
|
const filtered = providers.filter((p) => p.location.toLowerCase().includes(query.toLowerCase()));
|
|
|
|
return (
|
|
<ProvidersStep
|
|
providers={filtered}
|
|
onSelectProvider={(id) => navigate(`/providers/${id}/packages`)}
|
|
searchQuery={query}
|
|
onSearchChange={setQuery}
|
|
filterValues={filters}
|
|
onFilterChange={setFilters}
|
|
sortBy={sort}
|
|
onSortChange={setSort}
|
|
viewMode={view}
|
|
onViewModeChange={setView}
|
|
onBack={() => window.history.back()}
|
|
navigation={demoNav}
|
|
mapPanel={
|
|
<ProviderMap
|
|
providers={filtered}
|
|
onSelectProvider={(id) => navigate(`/providers/${id}/packages`)}
|
|
/>
|
|
}
|
|
/>
|
|
);
|
|
}
|