mirror of https://github.com/vector-im/riot-web
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>pull/28788/head^2
parent
f65e8d088e
commit
56b0b79fb7
|
@ -26,6 +26,7 @@ limitations under the License.
|
||||||
|
|
||||||
color: $primary-content;
|
color: $primary-content;
|
||||||
background-color: $system;
|
background-color: $system;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomLiveShareWarning_icon {
|
.mx_RoomLiveShareWarning_icon {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useEffect } from 'react';
|
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 { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
@ -33,13 +33,12 @@ interface Props {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose the most relevant beacon
|
* Choose the most relevant beacon
|
||||||
* and get its roomId
|
|
||||||
*/
|
*/
|
||||||
const chooseBestBeaconRoomId = (
|
const chooseBestBeacon = (
|
||||||
liveBeaconIds: BeaconIdentifier[],
|
liveBeaconIds: BeaconIdentifier[],
|
||||||
updateErrorBeaconIds: BeaconIdentifier[],
|
updateErrorBeaconIds: BeaconIdentifier[],
|
||||||
locationErrorBeaconIds: BeaconIdentifier[],
|
locationErrorBeaconIds: BeaconIdentifier[],
|
||||||
): Room['roomId'] | undefined => {
|
): Beacon | undefined => {
|
||||||
// both lists are ordered by creation timestamp in store
|
// both lists are ordered by creation timestamp in store
|
||||||
// so select latest beacon
|
// so select latest beacon
|
||||||
const beaconId = updateErrorBeaconIds?.[0] ?? locationErrorBeaconIds?.[0] ?? liveBeaconIds?.[0];
|
const beaconId = updateErrorBeaconIds?.[0] ?? locationErrorBeaconIds?.[0] ?? liveBeaconIds?.[0];
|
||||||
|
@ -48,7 +47,7 @@ const chooseBestBeaconRoomId = (
|
||||||
}
|
}
|
||||||
const beacon = OwnBeaconStore.instance.getBeaconById(beaconId);
|
const beacon = OwnBeaconStore.instance.getBeaconById(beaconId);
|
||||||
|
|
||||||
return beacon?.roomId;
|
return beacon;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): string => {
|
const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): string => {
|
||||||
|
@ -116,15 +115,18 @@ const LeftPanelLiveShareWarning: React.FC<Props> = ({ isMinimized }) => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const relevantBeaconRoomId = chooseBestBeaconRoomId(
|
const relevantBeacon = chooseBestBeacon(
|
||||||
liveBeaconIds, beaconIdsWithStoppingError, beaconIdsWithLocationPublishError,
|
liveBeaconIds, beaconIdsWithStoppingError, beaconIdsWithLocationPublishError,
|
||||||
);
|
);
|
||||||
|
|
||||||
const onWarningClick = relevantBeaconRoomId ? () => {
|
const onWarningClick = relevantBeacon ? () => {
|
||||||
dispatcher.dispatch<ViewRoomPayload>({
|
dispatcher.dispatch<ViewRoomPayload>({
|
||||||
action: Action.ViewRoom,
|
action: Action.ViewRoom,
|
||||||
room_id: relevantBeaconRoomId,
|
room_id: relevantBeacon.roomId,
|
||||||
metricsTrigger: undefined,
|
metricsTrigger: undefined,
|
||||||
|
event_id: relevantBeacon.beaconInfoId,
|
||||||
|
scroll_into_view: true,
|
||||||
|
highlighted: true,
|
||||||
});
|
});
|
||||||
} : undefined;
|
} : undefined;
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,14 @@ import { _t } from '../../../languageHandler';
|
||||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
|
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
|
||||||
import { useOwnLiveBeacons } from '../../../utils/beacon';
|
import { useOwnLiveBeacons } from '../../../utils/beacon';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
|
||||||
import Spinner from '../elements/Spinner';
|
import Spinner from '../elements/Spinner';
|
||||||
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
|
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
|
||||||
import { Icon as CloseIcon } from '../../../../res/img/image-view/close.svg';
|
import { Icon as CloseIcon } from '../../../../res/img/image-view/close.svg';
|
||||||
import LiveTimeRemaining from './LiveTimeRemaining';
|
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 => {
|
const getLabel = (hasLocationPublishError: boolean, hasStopSharingError: boolean): string => {
|
||||||
if (hasLocationPublishError) {
|
if (hasLocationPublishError) {
|
||||||
|
@ -57,6 +60,13 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
|
||||||
|
|
||||||
const hasError = hasStopSharingError || hasLocationPublishError;
|
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 = () => {
|
const onButtonClick = () => {
|
||||||
if (hasLocationPublishError) {
|
if (hasLocationPublishError) {
|
||||||
onResetLocationPublishError();
|
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
|
return <div
|
||||||
className='mx_RoomLiveShareWarning'
|
className='mx_RoomLiveShareWarning'
|
||||||
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
<StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" withError={hasError} />
|
<StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" withError={hasError} />
|
||||||
|
|
||||||
|
@ -82,7 +104,7 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className='mx_RoomLiveShareWarning_stopButton'
|
className='mx_RoomLiveShareWarning_stopButton'
|
||||||
data-test-id='room-live-share-primary-button'
|
data-test-id='room-live-share-primary-button'
|
||||||
onClick={onButtonClick}
|
onClick={stopPropagationWrapper(onButtonClick)}
|
||||||
kind='danger'
|
kind='danger'
|
||||||
element='button'
|
element='button'
|
||||||
disabled={stoppingInProgress}
|
disabled={stoppingInProgress}
|
||||||
|
@ -94,7 +116,7 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
|
||||||
title={_t('Stop sharing and close')}
|
title={_t('Stop sharing and close')}
|
||||||
element='button'
|
element='button'
|
||||||
className='mx_RoomLiveShareWarning_closeButton'
|
className='mx_RoomLiveShareWarning_closeButton'
|
||||||
onClick={onStopSharing}
|
onClick={stopPropagationWrapper(onStopSharing)}
|
||||||
>
|
>
|
||||||
<CloseIcon className='mx_RoomLiveShareWarning_closeButtonIcon' />
|
<CloseIcon className='mx_RoomLiveShareWarning_closeButtonIcon' />
|
||||||
</AccessibleButton> }
|
</AccessibleButton> }
|
||||||
|
|
|
@ -126,6 +126,9 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
||||||
metricsTrigger: undefined,
|
metricsTrigger: undefined,
|
||||||
// latest beacon's room
|
// latest beacon's room
|
||||||
room_id: roomId2,
|
room_id: roomId2,
|
||||||
|
event_id: beacon2.beaconInfoId,
|
||||||
|
highlighted: true,
|
||||||
|
scroll_into_view: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -158,6 +161,9 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
||||||
metricsTrigger: undefined,
|
metricsTrigger: undefined,
|
||||||
// error beacon's room
|
// error beacon's room
|
||||||
room_id: roomId1,
|
room_id: roomId1,
|
||||||
|
event_id: beacon1.beaconInfoId,
|
||||||
|
highlighted: true,
|
||||||
|
scroll_into_view: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -264,6 +270,9 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
||||||
metricsTrigger: undefined,
|
metricsTrigger: undefined,
|
||||||
// stopping error beacon's room
|
// stopping error beacon's room
|
||||||
room_id: beacon2.roomId,
|
room_id: beacon2.roomId,
|
||||||
|
event_id: beacon2.beaconInfoId,
|
||||||
|
highlighted: true,
|
||||||
|
scroll_into_view: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,6 +32,8 @@ import {
|
||||||
resetAsyncStoreWithClient,
|
resetAsyncStoreWithClient,
|
||||||
setupAsyncStoreWithClient,
|
setupAsyncStoreWithClient,
|
||||||
} from '../../../test-utils';
|
} from '../../../test-utils';
|
||||||
|
import defaultDispatcher from '../../../../src/dispatcher/dispatcher';
|
||||||
|
import { Action } from '../../../../src/dispatcher/actions';
|
||||||
|
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
describe('<RoomLiveShareWarning />', () => {
|
describe('<RoomLiveShareWarning />', () => {
|
||||||
|
@ -117,6 +119,7 @@ describe('<RoomLiveShareWarning />', () => {
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
jest.spyOn(global.Date, 'now').mockRestore();
|
jest.spyOn(global.Date, 'now').mockRestore();
|
||||||
localStorageSpy.mockRestore();
|
localStorageSpy.mockRestore();
|
||||||
|
jest.spyOn(defaultDispatcher, 'dispatch').mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
const getExpiryText = wrapper => findByTestId(wrapper, 'room-live-share-expiry').text();
|
const getExpiryText = wrapper => findByTestId(wrapper, 'room-live-share-expiry').text();
|
||||||
|
@ -263,6 +266,24 @@ describe('<RoomLiveShareWarning />', () => {
|
||||||
expect(clearIntervalSpy).toHaveBeenCalled();
|
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', () => {
|
describe('stopping beacons', () => {
|
||||||
it('stops beacon on stop sharing click', () => {
|
it('stops beacon on stop sharing click', () => {
|
||||||
const component = getComponent({ roomId: room2Id });
|
const component = getComponent({ roomId: room2Id });
|
||||||
|
|
|
@ -20,6 +20,7 @@ exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="mx_RoomLiveShareWarning"
|
className="mx_RoomLiveShareWarning"
|
||||||
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<StyledLiveBeaconIcon
|
<StyledLiveBeaconIcon
|
||||||
className="mx_RoomLiveShareWarning_icon"
|
className="mx_RoomLiveShareWarning_icon"
|
||||||
|
|
Loading…
Reference in New Issue