Live location share - tiles without tile server (PSG-591) (#8962)
* live location without map POC * styles * force map tiles to show no map for test build * check latestlocationstate exists * just use loading style map fallback when cant display map * style map error for tile view * set pointer cursor when map error is clickable * test mbeaconbody with map display error, lint * lint more good * remove changes for first attempt tile * make maperror test id more accurate * fussy import ordering * PR tweaks
This commit is contained in:
parent
e65409861a
commit
60faf6d025
12 changed files with 430 additions and 211 deletions
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useRef } from 'react';
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import {
|
||||
Beacon,
|
||||
|
@ -38,6 +38,8 @@ import DialogSidebar from './DialogSidebar';
|
|||
import DialogOwnBeaconStatus from './DialogOwnBeaconStatus';
|
||||
import BeaconStatusTooltip from './BeaconStatusTooltip';
|
||||
import MapFallback from '../location/MapFallback';
|
||||
import { MapError } from '../location/MapError';
|
||||
import { LocationShareError } from '../../../utils/location';
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
roomId: Room['roomId'];
|
||||
|
@ -83,6 +85,15 @@ const BeaconViewDialog: React.FC<IProps> = ({
|
|||
|
||||
const { bounds, centerGeoUri } = useInitialMapPosition(liveBeacons, focusBeacon);
|
||||
|
||||
const [mapDisplayError, setMapDisplayError] = useState<Error>();
|
||||
|
||||
// automatically open the sidebar if there is no map to see
|
||||
useEffect(() => {
|
||||
if (mapDisplayError) {
|
||||
setSidebarOpen(true);
|
||||
}
|
||||
}, [mapDisplayError]);
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
className='mx_BeaconViewDialog'
|
||||
|
@ -90,11 +101,12 @@ const BeaconViewDialog: React.FC<IProps> = ({
|
|||
fixedWidth={false}
|
||||
>
|
||||
<MatrixClientContext.Provider value={matrixClient}>
|
||||
{ !!liveBeacons?.length ? <Map
|
||||
{ (!!liveBeacons?.length && !mapDisplayError) && <Map
|
||||
id='mx_BeaconViewDialog'
|
||||
bounds={bounds}
|
||||
centerGeoUri={centerGeoUri}
|
||||
interactive
|
||||
onError={setMapDisplayError}
|
||||
className="mx_BeaconViewDialog_map"
|
||||
>
|
||||
{
|
||||
|
@ -109,7 +121,14 @@ const BeaconViewDialog: React.FC<IProps> = ({
|
|||
<ZoomButtons map={map} />
|
||||
</>
|
||||
}
|
||||
</Map> :
|
||||
</Map> }
|
||||
{ mapDisplayError &&
|
||||
<MapError
|
||||
error={mapDisplayError.message as LocationShareError}
|
||||
isMinimised
|
||||
/>
|
||||
}
|
||||
{ !liveBeacons?.length && !mapDisplayError &&
|
||||
<MapFallback
|
||||
data-test-id='beacon-view-dialog-map-fallback'
|
||||
className='mx_BeaconViewDialog_map'
|
||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Icon as WarningBadge } from '../../../../res/img/element-icons/warning-badge.svg';
|
||||
import { _t } from '../../../languageHandler';
|
||||
|
@ -22,18 +23,38 @@ import { getLocationShareErrorMessage, LocationShareError } from '../../../utils
|
|||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import Heading from '../typography/Heading';
|
||||
|
||||
interface Props {
|
||||
onFinished: () => void;
|
||||
export interface MapErrorProps {
|
||||
error: LocationShareError;
|
||||
onFinished?: () => void;
|
||||
isMinimised?: boolean;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const MapError: React.FC<Props> = ({
|
||||
onFinished, error,
|
||||
}) => (<div data-test-id='location-picker-error' className="mx_MapError">
|
||||
<WarningBadge className="mx_MapError_icon" />
|
||||
<Heading className="mx_MapError_heading" size='h3'>{ _t("Unable to load map") }</Heading>
|
||||
<p>
|
||||
{ getLocationShareErrorMessage(error) }
|
||||
</p>
|
||||
<AccessibleButton element='button' kind="primary" onClick={onFinished}>{ _t("OK") }</AccessibleButton>
|
||||
</div>);
|
||||
export const MapError: React.FC<MapErrorProps> = ({
|
||||
error,
|
||||
isMinimised,
|
||||
className,
|
||||
onFinished,
|
||||
onClick,
|
||||
}) => (
|
||||
<div data-test-id='map-rendering-error'
|
||||
className={classNames('mx_MapError', className, { 'mx_MapError_isMinimised': isMinimised })}
|
||||
onClick={onClick}
|
||||
>
|
||||
<WarningBadge className='mx_MapError_icon' />
|
||||
<Heading className='mx_MapError_heading' size='h3'>{ _t('Unable to load map') }</Heading>
|
||||
<p className='mx_MapError_message'>
|
||||
{ getLocationShareErrorMessage(error) }
|
||||
</p>
|
||||
{ onFinished &&
|
||||
<AccessibleButton
|
||||
element='button'
|
||||
kind='primary'
|
||||
onClick={onFinished}
|
||||
>
|
||||
{ _t('OK') }
|
||||
</AccessibleButton>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -30,7 +30,6 @@ interface Props extends React.HTMLAttributes<HTMLDivElement> {
|
|||
const MapFallback: React.FC<Props> = ({ className, isLoading, children, ...rest }) => {
|
||||
return <div className={classNames('mx_MapFallback', className)} {...rest}>
|
||||
<MapFallbackImage className='mx_MapFallback_bg' />
|
||||
{ /* <div className='mx_MapFallback_bg'/> */ }
|
||||
{ isLoading ? <Spinner h={32} w={32} /> : <LocationMarkerIcon className='mx_MapFallback_icon' /> }
|
||||
{ children }
|
||||
</div>;
|
||||
|
|
|
@ -26,17 +26,19 @@ import {
|
|||
import { BeaconLocationState } from 'matrix-js-sdk/src/content-helpers';
|
||||
import { randomString } from 'matrix-js-sdk/src/randomstring';
|
||||
import { M_BEACON } from 'matrix-js-sdk/src/@types/beacon';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import MatrixClientContext from '../../../contexts/MatrixClientContext';
|
||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import Modal from '../../../Modal';
|
||||
import { isBeaconWaitingToStart, useBeacon } from '../../../utils/beacon';
|
||||
import { isSelfLocation } from '../../../utils/location';
|
||||
import { isSelfLocation, LocationShareError } from '../../../utils/location';
|
||||
import { BeaconDisplayStatus, getBeaconDisplayStatus } from '../beacon/displayStatus';
|
||||
import BeaconStatus from '../beacon/BeaconStatus';
|
||||
import OwnBeaconStatus from '../beacon/OwnBeaconStatus';
|
||||
import Map from '../location/Map';
|
||||
import { MapError } from '../location/MapError';
|
||||
import MapFallback from '../location/MapFallback';
|
||||
import SmartMarker from '../location/SmartMarker';
|
||||
import { GetRelationsForEvent } from '../rooms/EventTile';
|
||||
|
@ -136,7 +138,16 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent, getRelati
|
|||
|
||||
const matrixClient = useContext(MatrixClientContext);
|
||||
const [error, setError] = useState<Error>();
|
||||
const displayStatus = getBeaconDisplayStatus(isLive, latestLocationState, error, waitingToStart);
|
||||
const isMapDisplayError = error?.message === LocationShareError.MapStyleUrlNotConfigured ||
|
||||
error?.message === LocationShareError.MapStyleUrlNotReachable;
|
||||
const displayStatus = getBeaconDisplayStatus(
|
||||
isLive,
|
||||
latestLocationState,
|
||||
// if we are unable to display maps because it is not configured for the server
|
||||
// don't display an error
|
||||
isMapDisplayError ? undefined : error,
|
||||
waitingToStart,
|
||||
);
|
||||
const markerRoomMember = isSelfLocation(mxEvent.getContent()) ? mxEvent.sender : undefined;
|
||||
const isOwnBeacon = beacon?.beaconInfoOwner === matrixClient.getUserId();
|
||||
|
||||
|
@ -152,6 +163,7 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent, getRelati
|
|||
roomId: mxEvent.getRoomId(),
|
||||
matrixClient,
|
||||
focusBeacon: beacon,
|
||||
isMapDisplayError,
|
||||
},
|
||||
"mx_BeaconViewDialog_wrapper",
|
||||
false, // isPriority
|
||||
|
@ -160,8 +172,11 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent, getRelati
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='mx_MBeaconBody' ref={ref}>
|
||||
{ displayStatus === BeaconDisplayStatus.Active ?
|
||||
<div
|
||||
className='mx_MBeaconBody'
|
||||
ref={ref}
|
||||
>
|
||||
{ (displayStatus === BeaconDisplayStatus.Active && !isMapDisplayError) ?
|
||||
<Map
|
||||
id={mapId}
|
||||
centerGeoUri={latestLocationState.uri}
|
||||
|
@ -180,10 +195,23 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent, getRelati
|
|||
/>
|
||||
}
|
||||
</Map>
|
||||
: <MapFallback
|
||||
isLoading={displayStatus === BeaconDisplayStatus.Loading}
|
||||
className='mx_MBeaconBody_map mx_MBeaconBody_mapFallback'
|
||||
/>
|
||||
: isMapDisplayError ?
|
||||
<MapError
|
||||
error={error.message as LocationShareError}
|
||||
onClick={onClick}
|
||||
className={classNames(
|
||||
'mx_MBeaconBody_mapError',
|
||||
// set interactive class when maximised map can be opened
|
||||
{ 'mx_MBeaconBody_mapErrorInteractive':
|
||||
displayStatus === BeaconDisplayStatus.Active,
|
||||
},
|
||||
)}
|
||||
isMinimised
|
||||
/> :
|
||||
<MapFallback
|
||||
isLoading={displayStatus === BeaconDisplayStatus.Loading}
|
||||
className='mx_MBeaconBody_map mx_MBeaconBody_mapFallback'
|
||||
/>
|
||||
}
|
||||
{ isOwnBeacon ?
|
||||
<OwnBeaconStatus
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue