diff --git a/res/css/_components.scss b/res/css/_components.scss index aefd86326e..38d539248c 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -4,6 +4,7 @@ @import "./_font-sizes.scss"; @import "./_font-weights.scss"; @import "./_spacing.scss"; +@import "./components/views/beacon/_BeaconStatus.scss"; @import "./components/views/beacon/_LeftPanelLiveShareWarning.scss"; @import "./components/views/beacon/_LiveTimeRemaining.scss"; @import "./components/views/beacon/_RoomLiveShareWarning.scss"; diff --git a/res/css/components/views/beacon/_BeaconStatus.scss b/res/css/components/views/beacon/_BeaconStatus.scss new file mode 100644 index 0000000000..fa971ffd0f --- /dev/null +++ b/res/css/components/views/beacon/_BeaconStatus.scss @@ -0,0 +1,60 @@ +/* +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. +*/ + +.mx_BeaconStatus { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + + box-sizing: border-box; + padding: $spacing-8; + + color: var(--color); + font-size: $font-12px; +} + +.mx_BeaconStatus_Loading, +.mx_BeaconStatus_Stopped { + --color: $tertiary-content; +} + +.mx_BeaconStatus_Active, +.mx_BeaconStatus_Error { + --color: $primary-content; +} + +.mx_BeaconStatus_icon { + height: 32px; + width: 32px; + + flex: 0 0 32px; + margin-right: $spacing-8; +} + +.mx_BeaconStatus_activeDescription { + flex: 1; + display: flex; + flex-direction: column; + line-height: $font-14px; +} + +.mx_BeaconStatus_stopButton { + // override button link_inline styles + color: $alert !important; + font-weight: $font-semi-bold !important; + text-transform: uppercase; +} diff --git a/res/css/components/views/beacon/_RoomLiveShareWarning.scss b/res/css/components/views/beacon/_RoomLiveShareWarning.scss index 1449193e7b..f82c7f4de4 100644 --- a/res/css/components/views/beacon/_RoomLiveShareWarning.scss +++ b/res/css/components/views/beacon/_RoomLiveShareWarning.scss @@ -48,6 +48,10 @@ limitations under the License. margin-left: $spacing-16; } +.mx_RoomLiveShareWarning_stopButton { + margin-left: $spacing-16; +} + .mx_RoomLiveShareWarning_closeButtonIcon { height: $font-18px; padding: $spacing-4; diff --git a/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss b/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss index e31279c34b..9096c3c71f 100644 --- a/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss +++ b/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss @@ -33,3 +33,8 @@ limitations under the License. background-color: $alert; border-color: $alert; } + +.mx_StyledLiveBeaconIcon.mx_StyledLiveBeaconIcon_idle { + background-color: $quaternary-content; + border-color: $quaternary-content; +} diff --git a/res/css/components/views/messages/_MBeaconBody.scss b/res/css/components/views/messages/_MBeaconBody.scss index 067359a4df..ae90d25132 100644 --- a/res/css/components/views/messages/_MBeaconBody.scss +++ b/res/css/components/views/messages/_MBeaconBody.scss @@ -48,6 +48,13 @@ limitations under the License. color: $quaternary-content; } +.mx_MBeaconBody_chin { + position: absolute; + bottom: 0; + width: 100%; + background-color: $overlay-background; +} + .mx_EventTile[data-layout="bubble"] .mx_EventTile_line .mx_MBeaconBody { max-width: 100%; width: 450px; diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 7921a4e1a8..176a1dd9f3 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -8,6 +8,7 @@ $quinary-content: #394049; $system: #21262C; $background: #15191E; +$overlay-background: rgba($background, 0.85); $panel-base: #8D97A5; // This color is not intended for use in the app $panels: rgba($system, 0.9); diff --git a/res/themes/legacy-dark/css/_legacy-dark.scss b/res/themes/legacy-dark/css/_legacy-dark.scss index 03ba8c70ea..2180e15e8f 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.scss +++ b/res/themes/legacy-dark/css/_legacy-dark.scss @@ -98,6 +98,8 @@ $quaternary-content: #6F7882; $quinary-content: $quaternary-content; $system: #21262C; $background: $primary-bg-color; +$overlay-background: rgba($background, 0.85); + $panels: rgba($system, 0.9); $panel-base: #8D97A5; // This color is not intended for use in the app $panel-selected: rgba($panel-base, 0.3); diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index b039cfa70f..86b189b533 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -151,6 +151,8 @@ $quaternary-content: #6F7882; $quinary-content: $quaternary-content; $system: #F4F6FA; $background: $primary-bg-color; +$overlay-background: rgba($background, 0.85); + $panels: rgba($system, 0.9); $panel-base: #8D97A5; // This color is not intended for use in the app $panel-selected: rgba($tertiary-content, 0.3); diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 73e2ee71c0..adebf7a2ce 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -35,6 +35,7 @@ $quinary-content: #E3E8F0; $system: #F4F6FA; $background: #ffffff; +$overlay-background: rgba($background, 0.85); $panels: rgba($system, 0.9); $panel-selected: rgba($tertiary-content, 0.3); diff --git a/src/components/views/beacon/BeaconStatus.tsx b/src/components/views/beacon/BeaconStatus.tsx new file mode 100644 index 0000000000..15c94732fc --- /dev/null +++ b/src/components/views/beacon/BeaconStatus.tsx @@ -0,0 +1,71 @@ +/* +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, { HTMLProps } from 'react'; +import classNames from 'classnames'; +import { Beacon } from 'matrix-js-sdk/src/matrix'; + +import StyledLiveBeaconIcon from './StyledLiveBeaconIcon'; +import { _t } from '../../../languageHandler'; +import AccessibleButton from '../elements/AccessibleButton'; +import LiveTimeRemaining from './LiveTimeRemaining'; +import { BeaconDisplayStatus } from './displayStatus'; + +interface Props { + displayStatus: BeaconDisplayStatus; + beacon?: Beacon; + label?: string; + // assumes permission to stop was checked by parent + stopBeacon?: () => void; +} + +const BeaconStatus: React.FC> = + ({ beacon, displayStatus, label, stopBeacon, className, ...rest }) => { + const isIdle = displayStatus === BeaconDisplayStatus.Loading || + displayStatus === BeaconDisplayStatus.Stopped; + + return
+ + { displayStatus === BeaconDisplayStatus.Loading && { _t('Loading live location...') } } + { displayStatus === BeaconDisplayStatus.Stopped && { _t('Live location ended') } } + + { /* TODO error */ } + + { displayStatus === BeaconDisplayStatus.Active && beacon && <> +
+ { label } + +
+ { stopBeacon && { _t('Stop') } + } + + } +
; + }; + +export default BeaconStatus; diff --git a/src/components/views/beacon/RoomLiveShareWarning.tsx b/src/components/views/beacon/RoomLiveShareWarning.tsx index 89fb1cfb46..01c749a26a 100644 --- a/src/components/views/beacon/RoomLiveShareWarning.tsx +++ b/src/components/views/beacon/RoomLiveShareWarning.tsx @@ -14,86 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useEffect, useState } from 'react'; +import React from 'react'; import classNames from 'classnames'; -import { - Room, - Beacon, - BeaconIdentifier, -} from 'matrix-js-sdk/src/matrix'; +import { Room } from 'matrix-js-sdk/src/matrix'; import { _t } from '../../../languageHandler'; import { useEventEmitterState } from '../../../hooks/useEventEmitter'; import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore'; -import { sortBeaconsByLatestExpiry } from '../../../utils/beacon'; +import { useOwnLiveBeacons } from '../../../utils/beacon'; import AccessibleButton 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'; -/** - * It's technically possible to have multiple live beacons in one room - * Select the latest expiry to display, - * and kill all beacons on stop sharing - */ -type LiveBeaconsState = { - beacon?: Beacon; - onStopSharing?: () => void; - onResetWireError?: () => void; - stoppingInProgress?: boolean; - hasStopSharingError?: boolean; - hasWireError?: boolean; -}; -const useLiveBeacons = (liveBeaconIds: BeaconIdentifier[], roomId: string): LiveBeaconsState => { - const [stoppingInProgress, setStoppingInProgress] = useState(false); - const [error, setError] = useState(); - - const hasWireError = useEventEmitterState( - OwnBeaconStore.instance, - OwnBeaconStoreEvent.WireError, - () => - OwnBeaconStore.instance.hasWireErrors(roomId), - ); - - // reset stopping in progress on change in live ids - useEffect(() => { - setStoppingInProgress(false); - setError(undefined); - }, [liveBeaconIds]); - - // select the beacon with latest expiry to display expiry time - const beacon = liveBeaconIds.map(beaconId => OwnBeaconStore.instance.getBeaconById(beaconId)) - .sort(sortBeaconsByLatestExpiry) - .shift(); - - const onStopSharing = async () => { - setStoppingInProgress(true); - try { - await Promise.all(liveBeaconIds.map(beaconId => OwnBeaconStore.instance.stopBeacon(beaconId))); - } catch (error) { - // only clear loading in case of error - // to avoid flash of not-loading state - // after beacons have been stopped but we wait for sync - setError(error); - setStoppingInProgress(false); - } - }; - - const onResetWireError = () => { - liveBeaconIds.map(beaconId => OwnBeaconStore.instance.resetWireError(beaconId)); - }; - - return { - onStopSharing, - onResetWireError, - beacon, - stoppingInProgress, - hasWireError, - hasStopSharingError: !!error, - }; -}; - const getLabel = (hasWireError: boolean, hasStopSharingError: boolean): string => { if (hasWireError) { return _t('An error occured whilst sharing your live location, please try again'); @@ -116,7 +50,7 @@ const RoomLiveShareWarningInner: React.FC = ({ l stoppingInProgress, hasStopSharingError, hasWireError, - } = useLiveBeacons(liveBeaconIds, roomId); + } = useOwnLiveBeacons(liveBeaconIds); if (!beacon) { return null; @@ -147,6 +81,7 @@ const RoomLiveShareWarningInner: React.FC = ({ l { !stoppingInProgress && !hasError && } { // use error styling when true withError?: boolean; + isIdle?: boolean; } -const StyledLiveBeaconIcon: React.FC = ({ className, withError, ...props }) => +const StyledLiveBeaconIcon: React.FC = ({ className, withError, isIdle, ...props }) => ; export default StyledLiveBeaconIcon; diff --git a/src/components/views/messages/MBeaconBody.tsx b/src/components/views/messages/MBeaconBody.tsx index 9bbb627879..ed40bfdda7 100644 --- a/src/components/views/messages/MBeaconBody.tsx +++ b/src/components/views/messages/MBeaconBody.tsx @@ -27,7 +27,9 @@ import { BeaconDisplayStatus, getBeaconDisplayStatus } from '../beacon/displaySt import Spinner from '../elements/Spinner'; import Map from '../location/Map'; import SmartMarker from '../location/SmartMarker'; +import BeaconStatus from '../beacon/BeaconStatus'; import { IBodyProps } from "./IBodyProps"; +import { _t } from '../../../languageHandler'; const useBeaconState = (beaconInfoEvent: MatrixEvent): { beacon?: Beacon; @@ -76,6 +78,7 @@ const useUniqueId = (eventId: string): string => { const MBeaconBody: React.FC = React.forwardRef(({ mxEvent }, ref) => { const { + beacon, isLive, latestLocationState, } = useBeaconState(mxEvent); @@ -113,6 +116,12 @@ const MBeaconBody: React.FC = React.forwardRef(({ mxEvent }, ref) => } } + ); }); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c5769f9902..a3ab40d344 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2079,6 +2079,7 @@ "Pick a date to jump to": "Pick a date to jump to", "Go": "Go", "Error processing audio message": "Error processing audio message", + "View live location": "View live location", "React": "React", "Reply in thread": "Reply in thread", "Can't create a thread from an event with an existing relation": "Can't create a thread from an event with an existing relation", @@ -2900,6 +2901,8 @@ "Beta": "Beta", "Leave the beta": "Leave the beta", "Join the beta": "Join the beta", + "Loading live location...": "Loading live location...", + "Live location ended": "Live location ended", "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", diff --git a/src/utils/beacon/index.ts b/src/utils/beacon/index.ts index 62db92dc1a..3da707b603 100644 --- a/src/utils/beacon/index.ts +++ b/src/utils/beacon/index.ts @@ -17,3 +17,4 @@ limitations under the License. export * from './duration'; export * from './geolocation'; export * from './useBeacon'; +export * from './useOwnLiveBeacons'; diff --git a/src/utils/beacon/useBeacon.ts b/src/utils/beacon/useBeacon.ts index fbe5d2ff8a..91b00104a1 100644 --- a/src/utils/beacon/useBeacon.ts +++ b/src/utils/beacon/useBeacon.ts @@ -68,5 +68,11 @@ export const useBeacon = (beaconInfoEvent: MatrixEvent): Beacon | undefined => { } }, [beaconInstanceEventId, beaconInfoEvent]); + useEffect(() => { + if (beacon) { + beacon.monitorLiveness(); + } + }, [beacon]); + return beacon; }; diff --git a/src/utils/beacon/useOwnLiveBeacons.ts b/src/utils/beacon/useOwnLiveBeacons.ts new file mode 100644 index 0000000000..32361f01c9 --- /dev/null +++ b/src/utils/beacon/useOwnLiveBeacons.ts @@ -0,0 +1,87 @@ +/* +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 { useEffect, useState } from "react"; +import { Beacon, BeaconIdentifier } from "matrix-js-sdk/src/matrix"; + +import { useEventEmitterState } from "../../hooks/useEventEmitter"; +import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../stores/OwnBeaconStore"; +import { sortBeaconsByLatestExpiry } from "./duration"; + +type LiveBeaconsState = { + beacon?: Beacon; + onStopSharing?: () => void; + onResetWireError?: () => void; + stoppingInProgress?: boolean; + hasStopSharingError?: boolean; + hasWireError?: boolean; +}; + +/** + * Monitor the current users own beacons + * While current implementation only allows one live beacon per user per room + * In future it will be possible to have multiple live beacons in one room + * Select the latest expiry to display, + * and kill all beacons on stop sharing + */ +export const useOwnLiveBeacons = (liveBeaconIds: BeaconIdentifier[]): LiveBeaconsState => { + const [stoppingInProgress, setStoppingInProgress] = useState(false); + const [error, setError] = useState(); + + const hasWireError = useEventEmitterState( + OwnBeaconStore.instance, + OwnBeaconStoreEvent.WireError, + () => + liveBeaconIds.some(OwnBeaconStore.instance.beaconHasWireError), + ); + + // reset stopping in progress on change in live ids + useEffect(() => { + setStoppingInProgress(false); + setError(undefined); + }, [liveBeaconIds]); + + // select the beacon with latest expiry to display expiry time + const beacon = liveBeaconIds.map(beaconId => OwnBeaconStore.instance.getBeaconById(beaconId)) + .sort(sortBeaconsByLatestExpiry) + .shift(); + + const onStopSharing = async () => { + setStoppingInProgress(true); + try { + await Promise.all(liveBeaconIds.map(beaconId => OwnBeaconStore.instance.stopBeacon(beaconId))); + } catch (error) { + // only clear loading in case of error + // to avoid flash of not-loading state + // after beacons have been stopped but we wait for sync + setError(error); + setStoppingInProgress(false); + } + }; + + const onResetWireError = () => { + liveBeaconIds.map(beaconId => OwnBeaconStore.instance.resetWireError(beaconId)); + }; + + return { + onStopSharing, + onResetWireError, + beacon, + stoppingInProgress, + hasWireError, + hasStopSharingError: !!error, + }; +}; diff --git a/test/components/views/beacon/BeaconStatus-test.tsx b/test/components/views/beacon/BeaconStatus-test.tsx new file mode 100644 index 0000000000..5be5cfe08d --- /dev/null +++ b/test/components/views/beacon/BeaconStatus-test.tsx @@ -0,0 +1,67 @@ +/* +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 { 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'; +import { findByTestId, makeBeaconInfoEvent } from '../../../test-utils'; + +describe('', () => { + const defaultProps = { + displayStatus: BeaconDisplayStatus.Loading, + }; + const getComponent = (props = {}) => + mount(); + + it('renders loading state', () => { + const component = getComponent({ displayStatus: BeaconDisplayStatus.Loading }); + expect(component).toMatchSnapshot(); + }); + + it('renders stopped state', () => { + const component = getComponent({ displayStatus: BeaconDisplayStatus.Stopped }); + 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'); + }); + + expect(stopBeacon).toHaveBeenCalled(); + }); +}); diff --git a/test/components/views/beacon/RoomLiveShareWarning-test.tsx b/test/components/views/beacon/RoomLiveShareWarning-test.tsx index 2c02286881..6fa6098f2c 100644 --- a/test/components/views/beacon/RoomLiveShareWarning-test.tsx +++ b/test/components/views/beacon/RoomLiveShareWarning-test.tsx @@ -100,7 +100,7 @@ describe('', () => { }); afterEach(async () => { - jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockRestore(); + jest.spyOn(OwnBeaconStore.instance, 'beaconHasWireError').mockRestore(); await resetAsyncStoreWithClient(OwnBeaconStore.instance); }); @@ -319,20 +319,24 @@ describe('', () => { describe('with wire errors', () => { it('displays wire error when mounted with wire errors', async () => { - const hasWireErrorsSpy = jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true); + const wireErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'beaconHasWireError') + .mockReturnValue(true); const component = getComponent({ roomId: room2Id }); expect(component).toMatchSnapshot(); - expect(hasWireErrorsSpy).toHaveBeenCalledWith(room2Id); + expect(wireErrorSpy).toHaveBeenCalledWith( + getBeaconInfoIdentifier(room2Beacon1), 0, [getBeaconInfoIdentifier(room2Beacon1)], + ); }); it('displays wire error when wireError event is emitted and beacons have errors', async () => { - const hasWireErrorsSpy = jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(false); + const wireErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'beaconHasWireError') + .mockReturnValue(false); const component = getComponent({ roomId: room2Id }); // update mock and emit event act(() => { - hasWireErrorsSpy.mockReturnValue(true); + wireErrorSpy.mockReturnValue(true); OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.WireError, getBeaconInfoIdentifier(room2Beacon1)); }); component.setProps({}); @@ -345,12 +349,13 @@ describe('', () => { }); it('stops displaying wire error when errors are cleared', async () => { - const hasWireErrorsSpy = jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true); + const wireErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'beaconHasWireError') + .mockReturnValue(true); const component = getComponent({ roomId: room2Id }); // update mock and emit event act(() => { - hasWireErrorsSpy.mockReturnValue(false); + wireErrorSpy.mockReturnValue(false); OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.WireError, getBeaconInfoIdentifier(room2Beacon1)); }); component.setProps({}); @@ -363,7 +368,7 @@ describe('', () => { }); it('clicking retry button resets wire errors', async () => { - jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true); + jest.spyOn(OwnBeaconStore.instance, 'beaconHasWireError').mockReturnValue(true); const resetErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'resetWireError'); const component = getComponent({ roomId: room2Id }); @@ -376,7 +381,7 @@ describe('', () => { }); it('clicking close button stops beacons', async () => { - jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true); + jest.spyOn(OwnBeaconStore.instance, 'beaconHasWireError').mockReturnValue(true); const stopBeaconSpy = jest.spyOn(OwnBeaconStore.instance, 'stopBeacon'); const component = getComponent({ roomId: room2Id }); diff --git a/test/components/views/beacon/__snapshots__/BeaconStatus-test.tsx.snap b/test/components/views/beacon/__snapshots__/BeaconStatus-test.tsx.snap new file mode 100644 index 0000000000..cf0ef32754 --- /dev/null +++ b/test/components/views/beacon/__snapshots__/BeaconStatus-test.tsx.snap @@ -0,0 +1,195 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders active state with stop button 1`] = ` +Array [ + +
+ Stop +
+
, +
+ Stop +
, +] +`; + +exports[` renders active state without stop buttons 1`] = ` + +
+ +
+ +
+ + + 1h left + + +
+
+ +`; + +exports[` renders loading state 1`] = ` + +
+ +
+ + + Loading live location... + +
+ +`; + +exports[` renders stopped state 1`] = ` + +
+ +
+ + + Live location ended + +
+ +`; diff --git a/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap b/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap index 18efb2c8ab..fda11d8e82 100644 --- a/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap +++ b/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap @@ -1,10 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` when user has live beacons and geolocation is available renders correctly with one live beacon in room 1`] = `"
You are sharing your live location1h left
"`; +exports[` when user has live beacons and geolocation is available renders correctly with one live beacon in room 1`] = `"
You are sharing your live location1h left
"`; -exports[` when user has live beacons and geolocation is available renders correctly with two live beacons in room 1`] = `"
You are sharing your live location12h left
"`; +exports[` when user has live beacons and geolocation is available renders correctly with two live beacons in room 1`] = `"
You are sharing your live location12h left
"`; -exports[` when user has live beacons and geolocation is available stopping beacons displays error when stop sharing fails 1`] = `"
An error occurred while stopping your live location, please try again
"`; +exports[` when user has live beacons and geolocation is available stopping beacons displays error when stop sharing fails 1`] = `"
An error occurred while stopping your live location, please try again
"`; exports[` when user has live beacons and geolocation is available with wire errors displays wire error when mounted with wire errors 1`] = ` when user has live beacons and geolocation is An error occured whilst sharing your live location, please try again when user has live beacons and geolocation is tabIndex={0} >