/* eslint-disable react/button-has-type */ import { IconLookup, faAdd, faArrowDown, faArrowLeft, faArrowsRotate, faBicycle, faCalendarDays, faCar, faDiamondTurnRight, faEdit, faPersonWalking, faRoute } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; import { IconButton } from 'browndash-components'; import { Position } from 'geojson'; import { IReactionDisposer, ObservableMap, action, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { CirclePicker, ColorResult } from 'react-color'; import { returnFalse, setupMoveUpEvents } from '../../../../ClientUtils'; import { unimplementedFunction } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { CalendarManager } from '../../../util/CalendarManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; import { DocumentView } from '../DocumentView'; import './MapAnchorMenu.scss'; import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; import { MarkerIcons } from './MarkerIcons'; // import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; type MapAnchorMenuType = 'standard' | 'routeCreation' | 'calendar' | 'customize' | 'route'; @observer export class MapAnchorMenu extends AntimodeMenu { // eslint-disable-next-line no-use-before-define static Instance: MapAnchorMenu; private _disposer: IReactionDisposer | undefined; private _commentRef = React.createRef(); private _fileInputRef = React.createRef(); public onMakeAnchor: () => Opt = () => undefined; // Method to get anchor from text search public Center: () => void = unimplementedFunction; public OnClick: (e: PointerEvent) => void = unimplementedFunction; // public OnAudio: (e: PointerEvent) => void = unimplementedFunction; public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap, addAsAnnotation?: boolean) => Opt = () => undefined; public GetAnchor: (savedAnnotations: Opt>, addAsAnnotation: boolean) => Opt = () => undefined; public Delete: () => void = unimplementedFunction; // public MakeTargetToggle: () => void = unimplementedFunction; // public ShowTargetTrail: () => void = unimplementedFunction; public IsTargetToggler: () => boolean = returnFalse; public DisplayRoute: (routeInfoMap: Record | undefined, type: TransportationType) => void = unimplementedFunction; public AddNewRouteToMap: (coordinates: Position[], origin: string, destination: any, createPinForDestination: boolean) => void = unimplementedFunction; public CreatePin: (feature: any) => void = unimplementedFunction; public UpdateMarkerColor: (color: string) => void = unimplementedFunction; public UpdateMarkerIcon: (iconKey: string) => void = unimplementedFunction; public Hide: () => void = unimplementedFunction; public OpenAnimationPanel: (routeDoc: Doc | undefined) => void = unimplementedFunction; @observable menuType: MapAnchorMenuType = 'standard'; @action public setMenuType = (menuType: MapAnchorMenuType) => { this.menuType = menuType; }; private allMapPinDocs: Doc[] = []; private pinDoc: Doc | undefined = undefined; private routeDoc: Doc | undefined = undefined; private title: string | undefined = undefined; public setPinDoc(pinDoc: Doc | undefined) { if (pinDoc) { this.pinDoc = pinDoc; this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`); } } public setRouteDoc(routeDoc: Doc | undefined) { if (routeDoc) { this.routeDoc = routeDoc; this.title = StrCast(routeDoc.title ?? 'Map route'); } } @action public Reset() { this.destinationSelected = false; this.currentRouteInfoMap = undefined; this.destinationFeatures = []; this.selectedDestinationFeature = undefined; this.allMapPinDocs = []; this.title = undefined; this.routeDoc = undefined; this.pinDoc = undefined; } public setAllMapboxPins(pinDocs: Doc[]) { this.allMapPinDocs = pinDocs; pinDocs.forEach((p, idx) => { console.log(`Pin ${idx}: ${p.title}`); }); } public get Active() { return this._left > 0; } constructor(props: any) { super(props); makeObservable(this); MapAnchorMenu.Instance = this; MapAnchorMenu.Instance._canFade = false; } componentWillUnmount() { this.destinationFeatures = []; this.destinationSelected = false; this.selectedDestinationFeature = undefined; this.currentRouteInfoMap = undefined; this._disposer?.(); } componentDidMount() { this._disposer = reaction( () => DocumentView.Selected().slice(), () => MapAnchorMenu.Instance.fadeOut(true) ); } // audioDown = (e: React.PointerEvent) => { // setupMoveUpEvents(this, e, returnFalse, returnFalse, e => this.OnAudio?.(e)); // }; // cropDown = (e: React.PointerEvent) => { // setupMoveUpEvents( // this, // e, // (e: PointerEvent) => { // this.StartCropDrag(e, this._commentCont.current!); // return true; // }, // returnFalse, // e => this.OnCrop?.(e) // ); // }; notePointerDown = (e: React.PointerEvent) => { setupMoveUpEvents( this, e, moveEv => { this.StartDrag(moveEv, this._commentRef.current!); return true; }, returnFalse, clickEv => this.OnClick(clickEv) ); }; static top = React.createRef(); // public get Top(){ // return this.top // } @action DirectionsClick = () => { this.menuType = 'routeCreation'; }; @action CustomizeClick = () => { this.currentRouteInfoMap = undefined; this.menuType = 'customize'; }; @action BackClick = () => { this.currentRouteInfoMap = undefined; this.menuType = 'standard'; }; @action TriggerFileInputClick = () => { if (this._fileInputRef) { this._fileInputRef.current?.click(); // Trigger the file input click event } }; @action onMarkerColorChange = (color: ColorResult) => { if (this.pinDoc) { this.pinDoc.markerColor = color.hex; } }; revertToOriginalMarker = () => { if (this.pinDoc) { this.pinDoc.markerType = 'MAP_PIN'; this.pinDoc.markerColor = '#ff5722'; } }; onMarkerIconChange = (iconKey: string) => { if (this.pinDoc) { this.pinDoc.markerType = iconKey; } }; @observable destinationFeatures: any[] = []; @observable destinationSelected: boolean = false; @observable selectedDestinationFeature: any = undefined; @observable createPinForDestination: boolean = true; @observable currentRouteInfoMap: Record | undefined = undefined; @observable selectedTransportationType: TransportationType = 'driving'; @action handleTransportationTypeChange = (newType: TransportationType) => { if (newType !== this.selectedTransportationType) { this.selectedTransportationType = newType; this.DisplayRoute(this.currentRouteInfoMap, newType); } }; @action handleSelectedDestinationFeature = (destinationFeature: any) => { this.selectedDestinationFeature = destinationFeature; }; @action toggleCreatePinForDestinationCheckbox = () => { this.createPinForDestination = !this.createPinForDestination; }; @action handleDestinationSearchChange = async (searchText: string) => { if (this.selectedDestinationFeature !== undefined) this.selectedDestinationFeature = undefined; const features = await MapboxApiUtility.forwardGeocodeForFeatures(searchText); if (features) { runInAction(() => { this.destinationFeatures = features; }); } }; getRoutes = async (destinationFeature: any) => { const currentPinLong: number = NumCast(this.pinDoc?.longitude); const currentPinLat: number = NumCast(this.pinDoc?.latitude); if (currentPinLong && currentPinLat && destinationFeature.center) { const routeInfoMap = await MapboxApiUtility.getDirections([currentPinLong, currentPinLat], destinationFeature.center); if (routeInfoMap) { runInAction(() => { this.currentRouteInfoMap = routeInfoMap; }); this.DisplayRoute(routeInfoMap, 'driving'); } } // get route menu, set it equal to here // create a temporary route // create pin if createPinForDestination was clicked }; HandleAddRouteClick = () => { if (this.currentRouteInfoMap && this.selectedTransportationType && this.selectedDestinationFeature) { const { coordinates } = this.currentRouteInfoMap[this.selectedTransportationType]; console.log(coordinates); console.log(this.selectedDestinationFeature); this.AddNewRouteToMap(coordinates, this.title ?? '', this.selectedDestinationFeature, this.createPinForDestination); } }; getMarkerIcon = (): JSX.Element | undefined => { if (this.pinDoc) { const markerType = StrCast(this.pinDoc.markerType); const markerColor = StrCast(this.pinDoc.markerColor); return MarkerIcons.getFontAwesomeIcon(markerType, '2x', markerColor); } return undefined; }; getDirectionsButton: JSX.Element = (} color={SettingsManager.userColor} />); getAddToCalendarButton = (docType: string): JSX.Element => ( { CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc); }} icon={} color={SettingsManager.userColor} /> ); addToCalendarButton: JSX.Element = ( CalendarManager.Instance.open(undefined, this.pinDoc)} icon={} color={SettingsManager.userColor} /> ); getLinkNoteToDocButton = (docType: string): JSX.Element => (
} color={SettingsManager.userColor} />
); linkNoteToPinOrRoutenButton: JSX.Element = (
} color={SettingsManager.userColor} />
); customizePinButton: JSX.Element = (} color={SettingsManager.userColor} />); centerOnPinButton: JSX.Element = ( } color={SettingsManager.userColor} /> ); backButton: JSX.Element = ( } color={SettingsManager.userColor} /> ); addRouteButton: JSX.Element = ( } color={SettingsManager.userColor} /> ); getDeleteButton = (type: string) => ( } color={SettingsManager.userColor} /> ); animateRouteButton: JSX.Element = ( this.OpenAnimationPanel(this.routeDoc)} icon={} color={SettingsManager.userColor} />); revertToOriginalMarkerButton = ( this.revertToOriginalMarker()} icon={} color={SettingsManager.userColor} /> ); render() { const buttons = (
{this.menuType === 'standard' && ( <> {this.getDeleteButton('pin')} {this.getDirectionsButton} {this.getAddToCalendarButton('pin')} {this.getLinkNoteToDocButton('pin')} {this.customizePinButton} {this.centerOnPinButton} )} {this.menuType === 'routeCreation' && ( <> {this.backButton} {this.addRouteButton} )} {this.menuType === 'route' && ( <> {this.getDeleteButton('route')} {this.animateRouteButton} {this.getAddToCalendarButton('route')} {this.getLinkNoteToDocButton('route')} )} {this.menuType === 'customize' && ( <> {this.backButton} {this.revertToOriginalMarkerButton} )} {/* {this.IsTargetToggler !== returnFalse && ( } color={SettingsManager.userColor} /> )} */}
); return this.getElement(
{this.menuType === 'standard' &&
{this.title}
} {this.menuType === 'routeCreation' && (
this.handleDestinationSearchChange(searchText)} onChange={(e: any, feature: any, reason: any) => { if (reason === 'clear') { this.handleSelectedDestinationFeature(undefined); } else if (reason === 'selectOption') { this.handleSelectedDestinationFeature(feature); } }} options={this.destinationFeatures.filter(feature => feature.place_name).map(feature => feature)} getOptionLabel={(feature: any) => feature.place_name} // eslint-disable-next-line react/jsx-props-no-spreading renderInput={(params: any) => } /> {!this.selectedDestinationFeature ? null : !this.allMapPinDocs.some(pinDoc => pinDoc.title === this.selectedDestinationFeature.place_name) && (
} />
)} {/* */}
)} {this.currentRouteInfoMap && (
this.handleTransportationTypeChange('driving')} icon={} color={this.selectedTransportationType === 'driving' ? 'lightblue' : 'grey'} /> this.handleTransportationTypeChange('cycling')} icon={} color={this.selectedTransportationType === 'cycling' ? 'lightblue' : 'grey'} /> this.handleTransportationTypeChange('walking')} icon={} color={this.selectedTransportationType === 'walking' ? 'lightblue' : 'grey'} />
Duration: {this.currentRouteInfoMap[this.selectedTransportationType].duration}
Distance: {this.currentRouteInfoMap[this.selectedTransportationType].distance}
)} {this.menuType === 'customize' && (
Current Marker:
{this.getMarkerIcon()}
this.onMarkerColorChange(color)} />
{Object.keys(MarkerIcons.FAMarkerIconsMap).map(iconKey => (
this.onMarkerIconChange(iconKey)} icon={MarkerIcons.getFontAwesomeIcon(iconKey, '1x', 'white')} />
))}
)} {this.menuType === 'route' && this.routeDoc &&
{StrCast(this.routeDoc.title)}
} {buttons}
, true ); } }