Live location share - link to timeline tile from share warning (PSF-1078) (#8752)

* navigate to live location tile from left panel live warning

Signed-off-by: Kerry Archibald <kerrya@element.io>

* navigate to beacon tile from room live share warning

Signed-off-by: Kerry Archibald <kerrya@element.io>

* add cursor

Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
Kerry 2022-06-07 12:15:09 +02:00 committed by GitHub
parent f65e8d088e
commit 56b0b79fb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 11 deletions

View file

@ -26,6 +26,7 @@ limitations under the License.
color: $primary-content;
background-color: $system;
cursor: pointer;
}
.mx_RoomLiveShareWarning_icon {

View file

@ -16,7 +16,7 @@ limitations under the License.
import classNames from 'classnames';
import React, { useEffect } from 'react';
import { Beacon, BeaconIdentifier, Room } from 'matrix-js-sdk/src/matrix';
import { Beacon, BeaconIdentifier } from 'matrix-js-sdk/src/matrix';
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { _t } from '../../../languageHandler';
@ -33,13 +33,12 @@ interface Props {
/**
* Choose the most relevant beacon
* and get its roomId
*/
const chooseBestBeaconRoomId = (
const chooseBestBeacon = (
liveBeaconIds: BeaconIdentifier[],
updateErrorBeaconIds: BeaconIdentifier[],
locationErrorBeaconIds: BeaconIdentifier[],
): Room['roomId'] | undefined => {
): Beacon | undefined => {
// both lists are ordered by creation timestamp in store
// so select latest beacon
const beaconId = updateErrorBeaconIds?.[0] ?? locationErrorBeaconIds?.[0] ?? liveBeaconIds?.[0];
@ -48,7 +47,7 @@ const chooseBestBeaconRoomId = (
}
const beacon = OwnBeaconStore.instance.getBeaconById(beaconId);
return beacon?.roomId;
return beacon;
};
const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): string => {
@ -116,15 +115,18 @@ const LeftPanelLiveShareWarning: React.FC<Props> = ({ isMinimized }) => {
return null;
}
const relevantBeaconRoomId = chooseBestBeaconRoomId(
const relevantBeacon = chooseBestBeacon(
liveBeaconIds, beaconIdsWithStoppingError, beaconIdsWithLocationPublishError,
);
const onWarningClick = relevantBeaconRoomId ? () => {
const onWarningClick = relevantBeacon ? () => {
dispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: relevantBeaconRoomId,
room_id: relevantBeacon.roomId,
metricsTrigger: undefined,
event_id: relevantBeacon.beaconInfoId,
scroll_into_view: true,
highlighted: true,
});
} : undefined;

View file

@ -21,11 +21,14 @@ import { _t } from '../../../languageHandler';
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
import { useOwnLiveBeacons } from '../../../utils/beacon';
import AccessibleButton from '../elements/AccessibleButton';
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
import Spinner from '../elements/Spinner';
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
import { Icon as CloseIcon } from '../../../../res/img/image-view/close.svg';
import LiveTimeRemaining from './LiveTimeRemaining';
import dispatcher from '../../../dispatcher/dispatcher';
import { ViewRoomPayload } from '../../../dispatcher/payloads/ViewRoomPayload';
import { Action } from '../../../dispatcher/actions';
const getLabel = (hasLocationPublishError: boolean, hasStopSharingError: boolean): string => {
if (hasLocationPublishError) {
@ -57,6 +60,13 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
const hasError = hasStopSharingError || hasLocationPublishError;
// eat events from buttons so navigate to tile
// is not triggered
const stopPropagationWrapper = (callback: () => void) => (e?: ButtonEvent) => {
e?.stopPropagation();
callback();
};
const onButtonClick = () => {
if (hasLocationPublishError) {
onResetLocationPublishError();
@ -65,8 +75,20 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
}
};
const onClick = () => {
dispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: beacon.roomId,
metricsTrigger: undefined,
event_id: beacon.beaconInfoId,
scroll_into_view: true,
highlighted: true,
});
};
return <div
className='mx_RoomLiveShareWarning'
onClick={onClick}
>
<StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" withError={hasError} />
@ -82,7 +104,7 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
<AccessibleButton
className='mx_RoomLiveShareWarning_stopButton'
data-test-id='room-live-share-primary-button'
onClick={onButtonClick}
onClick={stopPropagationWrapper(onButtonClick)}
kind='danger'
element='button'
disabled={stoppingInProgress}
@ -94,7 +116,7 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
title={_t('Stop sharing and close')}
element='button'
className='mx_RoomLiveShareWarning_closeButton'
onClick={onStopSharing}
onClick={stopPropagationWrapper(onStopSharing)}
>
<CloseIcon className='mx_RoomLiveShareWarning_closeButtonIcon' />
</AccessibleButton> }

View file

@ -126,6 +126,9 @@ describe('<LeftPanelLiveShareWarning />', () => {
metricsTrigger: undefined,
// latest beacon's room
room_id: roomId2,
event_id: beacon2.beaconInfoId,
highlighted: true,
scroll_into_view: true,
});
});
@ -158,6 +161,9 @@ describe('<LeftPanelLiveShareWarning />', () => {
metricsTrigger: undefined,
// error beacon's room
room_id: roomId1,
event_id: beacon1.beaconInfoId,
highlighted: true,
scroll_into_view: true,
});
});
@ -264,6 +270,9 @@ describe('<LeftPanelLiveShareWarning />', () => {
metricsTrigger: undefined,
// stopping error beacon's room
room_id: beacon2.roomId,
event_id: beacon2.beaconInfoId,
highlighted: true,
scroll_into_view: true,
});
});
});

View file

@ -32,6 +32,8 @@ import {
resetAsyncStoreWithClient,
setupAsyncStoreWithClient,
} from '../../../test-utils';
import defaultDispatcher from '../../../../src/dispatcher/dispatcher';
import { Action } from '../../../../src/dispatcher/actions';
jest.useFakeTimers();
describe('<RoomLiveShareWarning />', () => {
@ -117,6 +119,7 @@ describe('<RoomLiveShareWarning />', () => {
afterAll(() => {
jest.spyOn(global.Date, 'now').mockRestore();
localStorageSpy.mockRestore();
jest.spyOn(defaultDispatcher, 'dispatch').mockRestore();
});
const getExpiryText = wrapper => findByTestId(wrapper, 'room-live-share-expiry').text();
@ -263,6 +266,24 @@ describe('<RoomLiveShareWarning />', () => {
expect(clearIntervalSpy).toHaveBeenCalled();
});
it('navigates to beacon tile on click', () => {
const dispatcherSpy = jest.spyOn(defaultDispatcher, 'dispatch');
const component = getComponent({ roomId: room1Id });
act(() => {
component.simulate('click');
});
expect(dispatcherSpy).toHaveBeenCalledWith({
action: Action.ViewRoom,
event_id: room1Beacon1.getId(),
room_id: room1Id,
highlighted: true,
scroll_into_view: true,
metricsTrigger: undefined,
});
});
describe('stopping beacons', () => {
it('stops beacon on stop sharing click', () => {
const component = getComponent({ roomId: room2Id });

View file

@ -20,6 +20,7 @@ exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is
>
<div
className="mx_RoomLiveShareWarning"
onClick={[Function]}
>
<StyledLiveBeaconIcon
className="mx_RoomLiveShareWarning_icon"