();
-
+ const matrixClient = useContext(MatrixClientContext);
const displayStatus = getBeaconDisplayStatus(isLive, latestLocationState, error);
-
const markerRoomMember = isSelfLocation(mxEvent.getContent()) ? mxEvent.sender : undefined;
+ const isOwnBeacon = beacon?.beaconInfoOwner === matrixClient.getUserId();
+
return (
{ displayStatus === BeaconDisplayStatus.Active ?
@@ -106,6 +108,7 @@ const MBeaconBody: React.FC = React.forwardRef(({ mxEvent }, ref) =>
id={`${mapId}-marker`}
geoUri={latestLocationState.uri}
roomMember={markerRoomMember}
+ useMemberColor
/>
}
@@ -116,12 +119,19 @@ const MBeaconBody: React.FC = React.forwardRef(({ mxEvent }, ref) =>
}
}
-
+ { isOwnBeacon ?
+ :
+
+ }
);
});
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index bc238477f9..084d3bf979 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2905,11 +2905,14 @@
"Beta": "Beta",
"Leave the beta": "Leave the beta",
"Join the beta": "Join the beta",
+ "Live until %(expiryTime)s": "Live until %(expiryTime)s",
"Loading live location...": "Loading live location...",
"Live location ended": "Live location ended",
+ "Live location error": "Live location error",
"An error occured whilst sharing your live location": "An error occured whilst sharing your live location",
"You are sharing your live location": "You are sharing your live location",
"%(timeRemaining)s left": "%(timeRemaining)s left",
+ "Live location enabled": "Live location enabled",
"An error occured whilst sharing your live location, please try again": "An error occured whilst sharing your live location, please try again",
"An error occurred while stopping your live location, please try again": "An error occurred while stopping your live location, please try again",
"Stop sharing": "Stop sharing",
diff --git a/test/components/views/beacon/BeaconStatus-test.tsx b/test/components/views/beacon/BeaconStatus-test.tsx
index 5be5cfe08d..db4153defa 100644
--- a/test/components/views/beacon/BeaconStatus-test.tsx
+++ b/test/components/views/beacon/BeaconStatus-test.tsx
@@ -17,7 +17,6 @@ limitations under the License.
import React from 'react';
import { mount } from 'enzyme';
import { Beacon } from 'matrix-js-sdk/src/matrix';
-import { act } from 'react-dom/test-utils';
import BeaconStatus from '../../../../src/components/views/beacon/BeaconStatus';
import { BeaconDisplayStatus } from '../../../../src/components/views/beacon/displayStatus';
@@ -26,6 +25,7 @@ import { findByTestId, makeBeaconInfoEvent } from '../../../test-utils';
describe('', () => {
const defaultProps = {
displayStatus: BeaconDisplayStatus.Loading,
+ label: 'test label',
};
const getComponent = (props = {}) =>
mount();
@@ -40,28 +40,42 @@ describe('', () => {
expect(component).toMatchSnapshot();
});
- it('renders active state without stop buttons', () => {
- // mock for stable snapshot
- jest.spyOn(Date, 'now').mockReturnValue(123456789);
- const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:server', {}, '$1'));
- const component = getComponent({ beacon, displayStatus: BeaconDisplayStatus.Active });
- expect(component).toMatchSnapshot();
- });
-
- it('renders active state with stop button', () => {
- const stopBeacon = jest.fn();
- const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:sever'));
- const component = getComponent({
- beacon,
- stopBeacon,
- displayStatus: BeaconDisplayStatus.Active,
- });
- expect(findByTestId(component, 'beacon-status-stop-beacon')).toMatchSnapshot();
-
- act(() => {
- findByTestId(component, 'beacon-status-stop-beacon').at(0).simulate('click');
+ describe('active state', () => {
+ it('renders without children', () => {
+ // mock for stable snapshot
+ jest.spyOn(Date, 'now').mockReturnValue(123456789);
+ const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:server', {}, '$1'));
+ const component = getComponent({ beacon, displayStatus: BeaconDisplayStatus.Active });
+ expect(component).toMatchSnapshot();
});
- expect(stopBeacon).toHaveBeenCalled();
+ it('renders with children', () => {
+ const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:sever'));
+ const component = getComponent({
+ beacon,
+ children: test,
+ displayStatus: BeaconDisplayStatus.Active,
+ });
+ expect(findByTestId(component, 'test-child')).toMatchSnapshot();
+ });
+
+ it('renders static remaining time when displayLiveTimeRemaining is falsy', () => {
+ // mock for stable snapshot
+ jest.spyOn(Date, 'now').mockReturnValue(123456789);
+ const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:server', {}, '$1'));
+ const component = getComponent({ beacon, displayStatus: BeaconDisplayStatus.Active });
+ expect(component.text().includes('Live until 11:17')).toBeTruthy();
+ });
+
+ it('renders live time remaining when displayLiveTimeRemaining is truthy', () => {
+ // mock for stable snapshot
+ jest.spyOn(Date, 'now').mockReturnValue(123456789);
+ const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:server', {}, '$1'));
+ const component = getComponent({
+ beacon, displayStatus: BeaconDisplayStatus.Active,
+ displayLiveTimeRemaining: true,
+ });
+ expect(component.text().includes('1h left')).toBeTruthy();
+ });
});
});
diff --git a/test/components/views/beacon/OwnBeaconStatus-test.tsx b/test/components/views/beacon/OwnBeaconStatus-test.tsx
new file mode 100644
index 0000000000..a76e514538
--- /dev/null
+++ b/test/components/views/beacon/OwnBeaconStatus-test.tsx
@@ -0,0 +1,161 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import { mount } from 'enzyme';
+import { act } from 'react-dom/test-utils';
+import { mocked } from 'jest-mock';
+import { Beacon } from 'matrix-js-sdk/src/matrix';
+
+import OwnBeaconStatus from '../../../../src/components/views/beacon/OwnBeaconStatus';
+import { BeaconDisplayStatus } from '../../../../src/components/views/beacon/displayStatus';
+import { useOwnLiveBeacons } from '../../../../src/utils/beacon';
+import { findByTestId, makeBeaconInfoEvent } from '../../../test-utils';
+
+jest.mock('../../../../src/utils/beacon/useOwnLiveBeacons', () => ({
+ useOwnLiveBeacons: jest.fn(),
+}));
+
+describe('', () => {
+ const defaultProps = {
+ displayStatus: BeaconDisplayStatus.Loading,
+ };
+ const userId = '@user:server';
+ const roomId = '!room:server';
+ let defaultBeacon;
+ const getComponent = (props = {}) =>
+ mount();
+
+ beforeEach(() => {
+ jest.spyOn(global.Date, 'now').mockReturnValue(123456789);
+ mocked(useOwnLiveBeacons).mockClear().mockReturnValue({});
+
+ defaultBeacon = new Beacon(makeBeaconInfoEvent(userId, roomId));
+ });
+
+ it('renders without a beacon instance', () => {
+ const component = getComponent();
+ expect(component).toMatchSnapshot();
+ });
+
+ it('renders loading state correctly', () => {
+ const component = getComponent();
+ expect(component.find('BeaconStatus').props()).toBeTruthy();
+ });
+
+ describe('Active state', () => {
+ it('renders stop button', () => {
+ const displayStatus = BeaconDisplayStatus.Active;
+ mocked(useOwnLiveBeacons).mockReturnValue({
+ onStopSharing: jest.fn(),
+ });
+ const component = getComponent({ displayStatus, beacon: defaultBeacon });
+ expect(component.text()).toContain('Live location enabled');
+
+ expect(findByTestId(component, 'beacon-status-stop-beacon').length).toBeTruthy();
+ });
+
+ it('stops sharing on stop button click', () => {
+ const displayStatus = BeaconDisplayStatus.Active;
+ const onStopSharing = jest.fn();
+ mocked(useOwnLiveBeacons).mockReturnValue({
+ onStopSharing,
+ });
+ const component = getComponent({ displayStatus, beacon: defaultBeacon });
+
+ act(() => {
+ findByTestId(component, 'beacon-status-stop-beacon').at(0).simulate('click');
+ });
+
+ expect(onStopSharing).toHaveBeenCalled();
+ });
+ });
+
+ describe('errors', () => {
+ it('renders in error mode when displayStatus is error', () => {
+ const displayStatus = BeaconDisplayStatus.Error;
+ const component = getComponent({ displayStatus });
+ expect(component.text()).toEqual('Live location error');
+
+ // no actions for plain error
+ expect(component.find('AccessibleButton').length).toBeFalsy();
+ });
+
+ describe('with wire error', () => {
+ it('renders in error mode', () => {
+ const displayStatus = BeaconDisplayStatus.Active;
+ mocked(useOwnLiveBeacons).mockReturnValue({
+ hasWireError: true,
+ onResetWireError: jest.fn(),
+ });
+ const component = getComponent({ displayStatus, beacon: defaultBeacon });
+ expect(component.text()).toContain('Live location error');
+ // retry button
+ expect(findByTestId(component, 'beacon-status-reset-wire-error').length).toBeTruthy();
+ });
+
+ it('retry button resets wire error', () => {
+ const displayStatus = BeaconDisplayStatus.Active;
+ const onResetWireError = jest.fn();
+ mocked(useOwnLiveBeacons).mockReturnValue({
+ hasWireError: true,
+ onResetWireError,
+ });
+ const component = getComponent({ displayStatus, beacon: defaultBeacon });
+ act(() => {
+ findByTestId(component, 'beacon-status-reset-wire-error').at(0).simulate('click');
+ });
+
+ expect(onResetWireError).toHaveBeenCalled();
+ });
+ });
+
+ describe('with stopping error', () => {
+ it('renders in error mode', () => {
+ const displayStatus = BeaconDisplayStatus.Active;
+ mocked(useOwnLiveBeacons).mockReturnValue({
+ hasWireError: false,
+ hasStopSharingError: true,
+ onStopSharing: jest.fn(),
+ });
+ const component = getComponent({ displayStatus, beacon: defaultBeacon });
+ expect(component.text()).toContain('Live location error');
+ // retry button
+ expect(findByTestId(component, 'beacon-status-stop-beacon-retry').length).toBeTruthy();
+ });
+
+ it('retry button retries stop sharing', () => {
+ const displayStatus = BeaconDisplayStatus.Active;
+ const onStopSharing = jest.fn();
+ mocked(useOwnLiveBeacons).mockReturnValue({
+ hasStopSharingError: true,
+ onStopSharing,
+ });
+ const component = getComponent({ displayStatus, beacon: defaultBeacon });
+ act(() => {
+ findByTestId(component, 'beacon-status-stop-beacon-retry').at(0).simulate('click');
+ });
+
+ expect(onStopSharing).toHaveBeenCalled();
+ });
+ });
+ });
+
+ it('renders loading state correctly', () => {
+ const component = getComponent();
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/test/components/views/beacon/__snapshots__/BeaconStatus-test.tsx.snap b/test/components/views/beacon/__snapshots__/BeaconStatus-test.tsx.snap
index cf0ef32754..5e2b6673da 100644
--- a/test/components/views/beacon/__snapshots__/BeaconStatus-test.tsx.snap
+++ b/test/components/views/beacon/__snapshots__/BeaconStatus-test.tsx.snap
@@ -1,43 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` renders active state with stop button 1`] = `
-Array [
-
-
- Stop
-
- ,
-
- Stop
-
,
-]
-`;
+exports[` active state renders with children 1`] = `null`;
-exports[` renders active state without stop buttons 1`] = `
+exports[` active state renders without children 1`] = `
renders active state without stop buttons 1`] = `
"timeout": 3600000,
"timestamp": 123456789,
},
- "_events": Object {
- "Beacon.update": [Function],
- },
- "_eventsCount": 1,
+ "_events": Object {},
+ "_eventsCount": 0,
"_isLive": undefined,
"_latestLocationState": undefined,
"_maxListeners": undefined,
@@ -79,6 +42,7 @@ exports[` renders active state without stop buttons 1`] = `
}
}
displayStatus="Active"
+ label="test label"
>
renders active state without stop buttons 1`] = `
/>
- renders active state without stop buttons 1`] = `
"timeout": 3600000,
"timestamp": 123456789,
},
- "_events": Object {
- "Beacon.update": [Function],
- },
- "_eventsCount": 1,
+ "_events": Object {},
+ "_eventsCount": 0,
"_isLive": undefined,
"_latestLocationState": undefined,
"_maxListeners": undefined,
@@ -137,12 +100,11 @@ exports[` renders active state without stop buttons 1`] = `
}
>
- 1h left
+ Live until 11:17
-
+
@@ -151,6 +113,7 @@ exports[` renders active state without stop buttons 1`] = `
exports[` renders loading state 1`] = `
renders loading state 1`] = `
className="mx_StyledLiveBeaconIcon mx_BeaconStatus_icon mx_StyledLiveBeaconIcon_idle"
/>
-
- Loading live location...
-
+
+
+ Loading live location...
+
+
`;
@@ -174,6 +141,7 @@ exports[` renders loading state 1`] = `
exports[` renders stopped state 1`] = `
renders stopped state 1`] = `
className="mx_StyledLiveBeaconIcon mx_BeaconStatus_icon mx_StyledLiveBeaconIcon_idle"
/>
-
- Live location ended
-
+
+
+ Live location ended
+
+
`;
diff --git a/test/components/views/beacon/__snapshots__/OwnBeaconStatus-test.tsx.snap b/test/components/views/beacon/__snapshots__/OwnBeaconStatus-test.tsx.snap
new file mode 100644
index 0000000000..4d8b4e7660
--- /dev/null
+++ b/test/components/views/beacon/__snapshots__/OwnBeaconStatus-test.tsx.snap
@@ -0,0 +1,35 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` renders without a beacon instance 1`] = `
+
+
+
+
+
+
+
+
+ Loading live location...
+
+
+
+
+
+`;