From 98fe918436a8969750a661ef7803b88405298fee Mon Sep 17 00:00:00 2001 From: Kevin Chen Date: Sun, 5 Jun 2022 23:08:16 -0400 Subject: [PATCH 1/3] initial --- ui/src/App.tsx | 131 ++++++++++++++++++------ ui/src/PointList/index.tsx | 59 ++++++++--- ui/src/request/updateDriverLocations.ts | 21 +++- 3 files changed, 161 insertions(+), 50 deletions(-) diff --git a/ui/src/App.tsx b/ui/src/App.tsx index f31418e..7af7588 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -3,9 +3,17 @@ import "./App.css"; import { GoogleMap, LoadScript } from "@react-google-maps/api"; import Marker from "./Marker"; import mapStyles from "./mapStyles.json"; -import { Box, Grid } from "@mui/material"; +import { ThemeProvider, createTheme } from "@mui/material/styles"; +import { + Box, + FormControlLabel, + FormGroup, + Grid, + Switch, + Typography, +} from "@mui/material"; import { styled } from "@mui/material/styles"; -import NewDriverList from "./PointList"; +import DriverList from "./PointList"; import Paper from "@mui/material/Paper"; import { useEffectOnce } from "usehooks-ts"; import { @@ -19,6 +27,13 @@ import { import { faker } from "@faker-js/faker"; import listDrivers from "./request/listDrivers"; import getNearestDrivers from "./request/getNearestDrivers"; +import updateDriverLocations from "./request/updateDriverLocations"; + +const darkTheme = createTheme({ + palette: { + mode: "dark", + }, +}); const Item = styled(Paper)(({ theme }) => ({ backgroundColor: theme.palette.mode === "dark" ? "#1A2027" : "#fff", @@ -48,6 +63,8 @@ function newDriverName(): string { function MyMap() { const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY as string; + const [focusedDriverId, setFocusedDriverId] = React.useState(""); + const [queryMode, setQueryMode] = React.useState(false); const [driverLocationsState, setDriverLocationsState] = React.useState({ byId: {}, @@ -73,32 +90,77 @@ function MyMap() { getDriverLocations().catch(console.error); }); + const getNearbyDrivers = (e: google.maps.MapMouseEvent) => { + const lat = e.latLng?.lat() ?? 0; + const lng = e.latLng?.lng() ?? 0; + + // TODO highlight them on map + getNearestDrivers({ + latitude: lat, + longitude: lng, + }); + }; + + const addNewDriver = (e: google.maps.MapMouseEvent) => { + const lat = e.latLng?.lat() ?? 0; + const lng = e.latLng?.lng() ?? 0; + console.log(`clicked (${lat}, ${lng})`); + const dl = { + driverId: newDriverName(), + currentLocation: { + latitude: lat, + longitude: lng, + }, + } as DriverLocation; + setNewDriverLocationsState( + addDriverLocationToState(newDriverLocationsState, dl) + ); + }; + return ( + + + setQueryMode(!queryMode)} + /> + } + label="Mode" + /> + + + + {queryMode ? ( + Click anywhere to rank nearby drivers + ) : ( + Click to add new drivers + )} + - + () => + setFocusedDriverId(driverId)} + buildHandleMouseOut={(driverId: string) => () => + setFocusedDriverId("")} + queryMode={queryMode} + onUpload={() => + updateDriverLocations( + getDriverLocationsFromState(newDriverLocationsState) + ) + } + driverLocations={newDriverLocations} + /> { - const lat = e.latLng?.lat() ?? 0; - const lng = e.latLng?.lng() ?? 0; - console.log(`clicked (${lat}, ${lng})`); - const dl = { - driverId: newDriverName(), - currentLocation: { - latitude: lat, - longitude: lng, - }, - } as DriverLocation; - setNewDriverLocationsState( - addDriverLocationToState(newDriverLocationsState, dl) - ); - }} + onClick={queryMode ? getNearbyDrivers : addNewDriver} options={{ styles: mapStyles, }} @@ -133,22 +195,23 @@ function MyMap() { function App() { return ( - - - + + + + + ); } diff --git a/ui/src/PointList/index.tsx b/ui/src/PointList/index.tsx index 306d710..63fbfb7 100644 --- a/ui/src/PointList/index.tsx +++ b/ui/src/PointList/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { MouseEventHandler } from "react"; import { Box, Button, @@ -49,16 +49,21 @@ function stringAvatar(name: string) { interface ItemProps { driverLocation: DriverLocation; + buildHandleMouseOver?: (driverId: string) => MouseEventHandler; + buildHandleMouseOut?: (driverId: string) => MouseEventHandler; } function Item(props: ItemProps) { - const { driverLocation: dl } = props; + const { + driverLocation: dl, + buildHandleMouseOver, + buildHandleMouseOut, + } = props; const { driverId } = dl; return ( { - console.log("hovered over list item", e); - }} + onMouseOver={buildHandleMouseOver && buildHandleMouseOver(driverId)} + onMouseOut={buildHandleMouseOut && buildHandleMouseOut(driverId)} > @@ -68,28 +73,52 @@ function Item(props: ItemProps) { ); } -interface NewDriverListProps { +interface DriverListProps { driverLocations: DriverLocation[]; + onUpload?: MouseEventHandler; + /** + * Whether the list is showing nearby ranked drivers (Query Mode) or cached drivers that will be created (Mutate Mode) + */ + queryMode: boolean; + buildHandleMouseOver?: (driverId: string) => MouseEventHandler; + buildHandleMouseOut?: (driverId: string) => MouseEventHandler; } -export default function NewDriverList(props: NewDriverListProps) { - const { driverLocations } = props; +export default function DriverList(props: DriverListProps) { + const { + driverLocations, + onUpload: handleClick, + queryMode, + buildHandleMouseOver, + buildHandleMouseOut, + } = props; return ( - New Drivers List + {queryMode ? "Drivers List" : "New Drivers List"} {driverLocations.map((p: DriverLocation, i: number) => ( - + ))} - - - + {!queryMode && ( + + + + )} ); } diff --git a/ui/src/request/updateDriverLocations.ts b/ui/src/request/updateDriverLocations.ts index da53d3b..b6d0111 100644 --- a/ui/src/request/updateDriverLocations.ts +++ b/ui/src/request/updateDriverLocations.ts @@ -1 +1,20 @@ -export default async function () {} +import { BASE_INIT, BASE_URL } from "./base"; +import { DriverLocation } from "../types"; + +export default async function ( + driverLocations: DriverLocation[] +): Promise { + const now = new Date().toISOString(); + await fetch( + `${BASE_URL}/coop.drivers.dispatch.v1beta1.DispatchService/UpdateDriverLocations`, + { + ...BASE_INIT, + body: JSON.stringify({ + locations: driverLocations.map((dl) => ({ + ...dl, + mostRecentHeartbeat: now, + })), + }), + } + ); +} From 3e106625814b575b6cda9fc7886f017f485dc465 Mon Sep 17 00:00:00 2001 From: Kevin Chen Date: Mon, 6 Jun 2022 14:39:40 -0400 Subject: [PATCH 2/3] isNear prop --- ui/src/App.tsx | 20 +++++++++----------- ui/src/Marker/index.tsx | 6 ++++-- ui/src/types.ts | 3 ++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 7af7588..a3314e7 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -23,6 +23,7 @@ import { getDriverLocationsFromState, LatLng, NormalizedDriverLocations, + SearchResult, } from "./types"; import { faker } from "@faker-js/faker"; import listDrivers from "./request/listDrivers"; @@ -75,6 +76,7 @@ function MyMap() { byId: {}, allIds: [], } as NormalizedDriverLocations); + const [searchResults, setSearchResults] = React.useState([]); const newDriverLocations = getDriverLocationsFromState( newDriverLocationsState @@ -90,15 +92,15 @@ function MyMap() { getDriverLocations().catch(console.error); }); - const getNearbyDrivers = (e: google.maps.MapMouseEvent) => { + const getNearbyDrivers = async (e: google.maps.MapMouseEvent) => { const lat = e.latLng?.lat() ?? 0; const lng = e.latLng?.lng() ?? 0; - // TODO highlight them on map - getNearestDrivers({ + const res = await getNearestDrivers({ latitude: lat, longitude: lng, - }); + } as LatLng); + setSearchResults(res?.results ?? []); }; const addNewDriver = (e: google.maps.MapMouseEvent) => { @@ -172,13 +174,9 @@ function MyMap() { - getNearestDrivers({ - latitude: e.latLng?.lat() ?? 0, - longitude: e.latLng?.lng() ?? 0, - }) - } + isNear={searchResults + .map((sr) => sr.driver.driverId) + .includes(dl.driverId)} /> ))} {newDriverLocations.map((dl: DriverLocation, i: number) => ( diff --git a/ui/src/Marker/index.tsx b/ui/src/Marker/index.tsx index a70e8f6..88bff35 100644 --- a/ui/src/Marker/index.tsx +++ b/ui/src/Marker/index.tsx @@ -16,11 +16,13 @@ interface MyMarkerProps { handleMouseOver?: (e: google.maps.MapMouseEvent) => void; handleClick?: (e: google.maps.MapMouseEvent) => void; cached?: boolean; + isNear: boolean; } export default function MyMarker(props: MyMarkerProps) { - const { cached, driverLocation, handleClick, handleMouseOver } = props; - const color = cached ? "orange" : "#FFD700"; + const { cached, isNear, driverLocation, handleClick, handleMouseOver } = + props; + const color = isNear ? "green" : cached ? "orange" : "#FFD700"; const p = driverLocation.currentLocation; return ( Date: Mon, 6 Jun 2022 14:46:23 -0400 Subject: [PATCH 3/3] optional prop --- ui/src/Marker/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/Marker/index.tsx b/ui/src/Marker/index.tsx index 88bff35..83013b4 100644 --- a/ui/src/Marker/index.tsx +++ b/ui/src/Marker/index.tsx @@ -16,7 +16,7 @@ interface MyMarkerProps { handleMouseOver?: (e: google.maps.MapMouseEvent) => void; handleClick?: (e: google.maps.MapMouseEvent) => void; cached?: boolean; - isNear: boolean; + isNear?: boolean; } export default function MyMarker(props: MyMarkerProps) {