diff --git a/src/components/views/beacon/displayStatus.ts b/src/components/views/beacon/displayStatus.ts index ee65991070f..73bc7bec306 100644 --- a/src/components/views/beacon/displayStatus.ts +++ b/src/components/views/beacon/displayStatus.ts @@ -25,14 +25,18 @@ export enum BeaconDisplayStatus { export const getBeaconDisplayStatus = ( isLive: boolean, latestLocationState?: BeaconLocationState, - error?: Error): BeaconDisplayStatus => { + error?: Error, + waitingToStart?: boolean, +): BeaconDisplayStatus => { if (error) { return BeaconDisplayStatus.Error; } + if (waitingToStart) { + return BeaconDisplayStatus.Loading; + } if (!isLive) { return BeaconDisplayStatus.Stopped; } - if (!latestLocationState) { return BeaconDisplayStatus.Loading; } diff --git a/src/components/views/messages/MBeaconBody.tsx b/src/components/views/messages/MBeaconBody.tsx index bd581d1bce8..91c54d701a4 100644 --- a/src/components/views/messages/MBeaconBody.tsx +++ b/src/components/views/messages/MBeaconBody.tsx @@ -23,7 +23,7 @@ import MatrixClientContext from '../../../contexts/MatrixClientContext'; import { useEventEmitterState } from '../../../hooks/useEventEmitter'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; -import { useBeacon } from '../../../utils/beacon'; +import { isBeaconWaitingToStart, useBeacon } from '../../../utils/beacon'; import { isSelfLocation } from '../../../utils/location'; import { BeaconDisplayStatus, getBeaconDisplayStatus } from '../beacon/displayStatus'; import BeaconStatus from '../beacon/BeaconStatus'; @@ -39,6 +39,7 @@ const useBeaconState = (beaconInfoEvent: MatrixEvent): { description?: string; latestLocationState?: BeaconLocationState; isLive?: boolean; + waitingToStart?: boolean; } => { const beacon = useBeacon(beaconInfoEvent); @@ -56,12 +57,19 @@ const useBeaconState = (beaconInfoEvent: MatrixEvent): { return {}; } + // a beacon's starting timestamp can be in the future + // (either from small deviations in system clock times, or on purpose from another client) + // a beacon is only live between its start timestamp and expiry + // detect when a beacon is waiting to become live + // and display a loading state + const waitingToStart = !!beacon && isBeaconWaitingToStart(beacon); const { description } = beacon.beaconInfo; return { beacon, description, isLive, + waitingToStart, latestLocationState, }; }; @@ -84,12 +92,13 @@ const MBeaconBody: React.FC = React.forwardRef(({ mxEvent }, ref) => beacon, isLive, latestLocationState, + waitingToStart, } = useBeaconState(mxEvent); const mapId = useUniqueId(mxEvent.getId()); const matrixClient = useContext(MatrixClientContext); const [error, setError] = useState(); - const displayStatus = getBeaconDisplayStatus(isLive, latestLocationState, error); + const displayStatus = getBeaconDisplayStatus(isLive, latestLocationState, error, waitingToStart); const markerRoomMember = isSelfLocation(mxEvent.getContent()) ? mxEvent.sender : undefined; const isOwnBeacon = beacon?.beaconInfoOwner === matrixClient.getUserId(); diff --git a/src/utils/beacon/duration.ts b/src/utils/beacon/duration.ts index c49eef1bd55..bbd51c7b5d4 100644 --- a/src/utils/beacon/duration.ts +++ b/src/utils/beacon/duration.ts @@ -39,3 +39,10 @@ export const sortBeaconsByLatestExpiry = (left: Beacon, right: Beacon): number = // aka sort by timestamp descending export const sortBeaconsByLatestCreation = (left: Beacon, right: Beacon): number => right.beaconInfo.timestamp - left.beaconInfo.timestamp; + +// a beacon's starting timestamp can be in the future +// (either from small deviations in system clock times, or on purpose from another client) +// a beacon is only live between its start timestamp and expiry +// detect when a beacon is waiting to become live +export const isBeaconWaitingToStart = (beacon: Beacon): boolean => + !beacon.isLive && beacon.beaconInfo.timestamp > Date.now() && getBeaconExpiryTimestamp(beacon) > Date.now(); diff --git a/test/components/views/messages/MBeaconBody-test.tsx b/test/components/views/messages/MBeaconBody-test.tsx index e9cb719f7f2..b817ac29959 100644 --- a/test/components/views/messages/MBeaconBody-test.tsx +++ b/test/components/views/messages/MBeaconBody-test.tsx @@ -111,6 +111,19 @@ describe('', () => { expect(component.text()).toEqual("Live location ended"); }); + it('renders loading beacon UI for a beacon that has not started yet', () => { + const beaconInfoEvent = makeBeaconInfoEvent( + aliceId, + roomId, + // puts this beacons start timestamp in the future + { isLive: true, timestamp: now + 60000, timeout: 500 }, + '$alice-room1-1', + ); + makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient }); + const component = getComponent({ mxEvent: beaconInfoEvent }); + expect(component.text()).toEqual("Loading live location..."); + }); + it('does not open maximised map when on click when beacon is stopped', () => { const beaconInfoEvent = makeBeaconInfoEvent(aliceId, roomId,