|
| 1 | +/** |
| 2 | + * @license |
| 3 | + * Copyright 2026 Google LLC. All Rights Reserved. |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | +// [START maps_rgm_college_picker] |
| 7 | +import React, { useState, useRef, useEffect } from 'react'; |
| 8 | +import { createRoot } from 'react-dom/client'; |
| 9 | +import { AdvancedMarker, Map, Pin, APIProvider, } from '@vis.gl/react-google-maps'; |
| 10 | +import { PlaceReviews, PlaceDataProvider, PlaceDirectionsButton, IconButton, PlaceOverview, SplitLayout, OverlayLayout, PlacePicker, } from '@googlemaps/extended-component-library/react'; |
| 11 | +const API_KEY = 'GOOGLE_MAPS_API_KEY'; |
| 12 | +const DEFAULT_CENTER = { lat: 38, lng: -98 }; |
| 13 | +const DEFAULT_ZOOM = 4; |
| 14 | +const DEFAULT_ZOOM_WITH_LOCATION = 16; |
| 15 | +/** |
| 16 | + * Sample app that helps users locate a college on the map, with place info such |
| 17 | + * as ratings, photos, and reviews displayed on the side. |
| 18 | + */ |
| 19 | +export default function App() { |
| 20 | + const overlayLayoutRef = useRef(null); |
| 21 | + const pickerRef = useRef(null); |
| 22 | + const [college, setCollege] = useState(undefined); |
| 23 | + /** |
| 24 | + * We track the map's camera state separately and use an onCameraChanged listener. |
| 25 | + * This prevents the map from becoming strictly "controlled" by college.location, |
| 26 | + * which would otherwise lock the camera and prevent the user from panning or zooming. |
| 27 | + */ |
| 28 | + const [cameraProps, setCameraProps] = useState({ |
| 29 | + center: DEFAULT_CENTER, |
| 30 | + zoom: DEFAULT_ZOOM, |
| 31 | + }); |
| 32 | + useEffect(() => { |
| 33 | + if (college?.location) { |
| 34 | + setCameraProps({ |
| 35 | + center: { |
| 36 | + lat: college.location.lat(), |
| 37 | + lng: college.location.lng(), |
| 38 | + }, |
| 39 | + zoom: DEFAULT_ZOOM_WITH_LOCATION, |
| 40 | + }); |
| 41 | + } |
| 42 | + }, [college]); |
| 43 | + /** |
| 44 | + * See https://lit.dev/docs/frameworks/react/#using-slots for why |
| 45 | + * we need to wrap our custom elements in a div with a slot attribute. |
| 46 | + */ |
| 47 | + return (React.createElement("div", { className: "App" }, |
| 48 | + React.createElement(APIProvider, { solutionChannel: "GMP_devsite_samples_v3_rgmcollegepicker", apiKey: API_KEY, version: "beta" }, |
| 49 | + React.createElement(SplitLayout, { rowReverse: true, rowLayoutMinWidth: 700 }, |
| 50 | + React.createElement("div", { className: "SlotDiv", slot: "fixed" }, |
| 51 | + React.createElement(OverlayLayout, { ref: overlayLayoutRef }, |
| 52 | + React.createElement("div", { className: "SlotDiv", slot: "main" }, |
| 53 | + React.createElement(PlacePicker, { className: "CollegePicker", ref: pickerRef, forMap: "gmap", country: ['us', 'ca'], type: "university", placeholder: "Enter a college in the US or Canada", onPlaceChange: () => { |
| 54 | + if (!pickerRef.current?.value) { |
| 55 | + setCollege(undefined); |
| 56 | + } |
| 57 | + else { |
| 58 | + setCollege(pickerRef.current.value); |
| 59 | + } |
| 60 | + } }), |
| 61 | + React.createElement(PlaceOverview, { size: "large", place: college, googleLogoAlreadyDisplayed: true }, |
| 62 | + React.createElement("div", { slot: "action", className: "SlotDiv" }, |
| 63 | + React.createElement(IconButton, { slot: "action", variant: "filled", onClick: () => { |
| 64 | + if (overlayLayoutRef.current) |
| 65 | + void overlayLayoutRef.current.showOverlay(); |
| 66 | + } }, "See Reviews")), |
| 67 | + React.createElement("div", { slot: "action", className: "SlotDiv" }, |
| 68 | + React.createElement(PlaceDirectionsButton, { slot: "action", variant: "filled" }, "Directions")))), |
| 69 | + React.createElement("div", { slot: "overlay", className: "SlotDiv" }, |
| 70 | + React.createElement(IconButton, { className: "CloseButton", onClick: () => { |
| 71 | + if (overlayLayoutRef.current) |
| 72 | + void overlayLayoutRef.current.hideOverlay(); |
| 73 | + } }, "Close"), |
| 74 | + React.createElement(PlaceDataProvider, { place: college }, |
| 75 | + React.createElement(PlaceReviews, null))))), |
| 76 | + React.createElement("div", { className: "SplitLayoutContainer", slot: "main" }, |
| 77 | + React.createElement(Map, { id: "gmap", mapId: "8c732c82e4ec29d9", ...cameraProps, onCameraChanged: (ev) => { |
| 78 | + setCameraProps(ev.detail); |
| 79 | + } }, college?.location && (React.createElement(AdvancedMarker, { position: college.location }, |
| 80 | + React.createElement(Pin, { background: '#FBBC04', glyphColor: '#000', borderColor: '#000' }))))))))); |
| 81 | +} |
| 82 | +export function renderToDom(container) { |
| 83 | + const root = createRoot(container); |
| 84 | + root.render(React.createElement(React.StrictMode, null, |
| 85 | + React.createElement(App, null))); |
| 86 | +} |
| 87 | +// [END maps_rgm_college_picker] |
0 commit comments