diff --git a/res/css/components/views/beacon/_DialogSidebar.pcss b/res/css/components/views/beacon/_DialogSidebar.pcss index 1edf5840e3..c33f74e036 100644 --- a/res/css/components/views/beacon/_DialogSidebar.pcss +++ b/res/css/components/views/beacon/_DialogSidebar.pcss @@ -55,3 +55,8 @@ limitations under the License. overflow: auto; } } + +.mx_DialogSidebar_noResults { + font-size: $font-14px; + color: $secondary-content; +} diff --git a/src/components/views/beacon/BeaconViewDialog.tsx b/src/components/views/beacon/BeaconViewDialog.tsx index 50a880c1b3..aedab883f3 100644 --- a/src/components/views/beacon/BeaconViewDialog.tsx +++ b/src/components/views/beacon/BeaconViewDialog.tsx @@ -68,7 +68,7 @@ const getBoundsCenter = (bounds: Bounds): string | undefined => { }); }; -const useInitialMapPosition = (liveBeacons: Beacon[], { beacon, ts }: FocusedBeaconState): { +const useMapPosition = (liveBeacons: Beacon[], { beacon, ts }: FocusedBeaconState): { bounds?: Bounds; centerGeoUri: string; } => { const [bounds, setBounds] = useState(getBeaconBounds(liveBeacons)); @@ -113,7 +113,7 @@ const BeaconViewDialog: React.FC = ({ const [isSidebarOpen, setSidebarOpen] = useState(false); - const { bounds, centerGeoUri } = useInitialMapPosition(liveBeacons, focusedBeaconState); + const { bounds, centerGeoUri } = useMapPosition(liveBeacons, focusedBeaconState); const [mapDisplayError, setMapDisplayError] = useState(); @@ -135,7 +135,7 @@ const BeaconViewDialog: React.FC = ({ fixedWidth={false} > - { (!!liveBeacons?.length && !mapDisplayError) && = ({ isMinimised /> } - { !liveBeacons?.length && !mapDisplayError && + { !centerGeoUri && !mapDisplayError && { const ownBeacon = useEventEmitterState( - OwnProfileStore.instance, + OwnBeaconStore.instance, OwnBeaconStoreEvent.LivenessChange, () => { const [ownBeaconId] = OwnBeaconStore.instance.getLiveBeaconIds(roomId); diff --git a/src/components/views/beacon/DialogSidebar.tsx b/src/components/views/beacon/DialogSidebar.tsx index 0b5442cade..70cf8fe94c 100644 --- a/src/components/views/beacon/DialogSidebar.tsx +++ b/src/components/views/beacon/DialogSidebar.tsx @@ -46,13 +46,18 @@ const DialogSidebar: React.FC = ({ -
    - { beacons.map((beacon) => onBeaconClick(beacon)} - />) } -
+ { beacons?.length + ?
    + { beacons.map((beacon) => onBeaconClick(beacon)} + />) } +
+ :
+ { _t('No live locations') } +
+ } ; }; diff --git a/test/components/views/beacon/BeaconViewDialog-test.tsx b/test/components/views/beacon/BeaconViewDialog-test.tsx index 12c82968a5..e5c8535eef 100644 --- a/test/components/views/beacon/BeaconViewDialog-test.tsx +++ b/test/components/views/beacon/BeaconViewDialog-test.tsx @@ -25,6 +25,7 @@ import { getBeaconInfoIdentifier, } from 'matrix-js-sdk/src/matrix'; import maplibregl from 'maplibre-gl'; +import { mocked } from 'jest-mock'; import BeaconViewDialog from '../../../../src/components/views/beacon/BeaconViewDialog'; import { @@ -103,6 +104,7 @@ describe('', () => { beforeEach(() => { jest.spyOn(OwnBeaconStore.instance, 'getLiveBeaconIds').mockRestore(); + jest.spyOn(OwnBeaconStore.instance, 'getBeaconById').mockRestore(); jest.spyOn(global.Date, 'now').mockReturnValue(now); jest.clearAllMocks(); }); @@ -193,7 +195,24 @@ describe('', () => { expect(mockMap.fitBounds).toHaveBeenCalledTimes(1); }); - it('renders a fallback when no live beacons remain', () => { + it('renders a fallback when there are no locations', () => { + // this is a cornercase, should not be a reachable state in UI anymore + const onFinished = jest.fn(); + const room = setupRoom([defaultEvent]); + room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent)); + const component = getComponent({ onFinished }); + + // map placeholder + expect(findByTestId(component, 'beacon-view-dialog-map-fallback')).toMatchSnapshot(); + + act(() => { + findByTestId(component, 'beacon-view-dialog-fallback-close').at(0).simulate('click'); + }); + + expect(onFinished).toHaveBeenCalled(); + }); + + it('renders map without markers when no live beacons remain', () => { const onFinished = jest.fn(); const room = setupRoom([defaultEvent]); const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent)); @@ -206,9 +225,14 @@ describe('', () => { const anotherBeaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: false }, - '$bob-room1-1', + '$alice-room1-2', ); + expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 51, lon: 41 }); + // reset call counts + mocked(mockMap.setCenter).mockClear(); + mocked(mockMap.fitBounds).mockClear(); + act(() => { // emits RoomStateEvent.BeaconLiveness room.currentState.setStateEvents([anotherBeaconEvent]); @@ -216,14 +240,13 @@ describe('', () => { component.setProps({}); - // map placeholder - expect(findByTestId(component, 'beacon-view-dialog-map-fallback')).toMatchSnapshot(); - - act(() => { - findByTestId(component, 'beacon-view-dialog-fallback-close').at(0).simulate('click'); - }); - - expect(onFinished).toHaveBeenCalled(); + // no more avatars + expect(component.find('MemberAvatar').length).toBeFalsy(); + // map still rendered + expect(component.find('Map').length).toBeTruthy(); + // map location unchanged + expect(mockMap.setCenter).not.toHaveBeenCalled(); + expect(mockMap.fitBounds).not.toHaveBeenCalled(); }); describe('sidebar', () => { diff --git a/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap b/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap index 648ed3e93f..535707633a 100644 --- a/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap +++ b/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` renders a fallback when no live beacons remain 1`] = ` +exports[` renders a fallback when there are no locations 1`] = ` Array [ renders sidebar correctly without beacons 1`] = ` /> -
    +
    + No live locations +
    );