Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions app/views/RoomView/List/components/EmptyRoom.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
import { ImageBackground, StyleSheet } from 'react-native';

import { useTheme } from '../../../../theme';

const styles = StyleSheet.create({
image: {
width: '100%',
height: '100%',
position: 'absolute'
}
});
import { RoomBackground } from '../../components/RoomBackground';

const EmptyRoom = ({ length, rid }: { length: number; rid: string }) => {
const { theme } = useTheme();
if (length === 0 || !rid) {
return <ImageBackground source={{ uri: `message_empty_${theme === 'dark' ? 'black' : theme}` }} style={styles.image} />;
return <RoomBackground />;
}
return null;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react-native';
import { Provider } from 'react-redux';
import { createStore as createReduxStore } from 'redux';

import RoomGate from '../index';
import RoomView from '../index';
import { type IRoomViewProps } from '../definitions';
import { type TRoomOrPreview } from '../../../definitions/TRoom';
import { isInviteSubscription } from '../../../lib/methods/isInviteSubscription';
Expand All @@ -29,11 +29,6 @@ jest.mock('../components/EncryptedRoom', () => {
const { View: RNView } = require('react-native');
return { EncryptedRoom: () => createElement(RNView, { testID: 'encrypted-screen' }) };
});
jest.mock('../components/RoomRouteInvalid', () => {
const { createElement } = require('react');
const { View: RNView } = require('react-native');
return { RoomRouteInvalid: () => createElement(RNView, { testID: 'route-invalid-screen' }) };
});
jest.mock('../hooks/useHeader', () => ({ useHeader: jest.fn() }));
jest.mock('../hooks/useE2EEStatus', () => ({
useE2EEStatus: jest.fn(() => ({ showMissingE2EEKey: false, showE2EEDisabledRoom: false, hasE2EEWarning: false }))
Expand All @@ -58,20 +53,20 @@ jest.mock('../stores/RoomStore', () => {
};
});

const renderGate = (params: Record<string, unknown> | null = { rid: 'rid-1', t: 'c' }) => {
const renderRoomView = (params: Record<string, unknown> | null = { rid: 'rid-1', t: 'c' }) => {
const reduxStore = createReduxStore(() => ({ server: { version: '6.1.0' } }));
const route = { params: params ?? undefined } as unknown as IRoomViewProps['route'];
const navigation = { setOptions: jest.fn() } as unknown as IRoomViewProps['navigation'];
return render(
<Provider store={reduxStore}>
<View>
<RoomGate route={route} navigation={navigation} />
<RoomView route={route} navigation={navigation} />
</View>
</Provider>
);
};

describe('RoomGate', () => {
describe('RoomView', () => {
beforeEach(() => {
jest.clearAllMocks();
room.current = { rid: 'rid-1', t: 'c' };
Expand All @@ -80,30 +75,30 @@ describe('RoomGate', () => {
});

it('mounts the room screen when the room is not blocked', () => {
renderGate();
renderRoomView();

expect(screen.getByTestId('room-screen')).toBeOnTheScreen();
});

it('renders the invalid-route state instead of a room when the route has no identity', () => {
renderGate(null);
it('renders the empty-room background instead of a room when the route has no identity', () => {
renderRoomView(null);

expect(screen.getByTestId('route-invalid-screen')).toBeOnTheScreen();
expect(screen.getByTestId('room-view-empty')).toBeOnTheScreen();
expect(screen.queryByTestId('room-screen')).toBeNull();
});

it('renders the invalid-route state when the route has a rid but no type', () => {
renderGate({ rid: 'rid-1' });
it('renders the empty-room background when the route has a rid but no type', () => {
renderRoomView({ rid: 'rid-1' });

expect(screen.getByTestId('route-invalid-screen')).toBeOnTheScreen();
expect(screen.getByTestId('room-view-empty')).toBeOnTheScreen();
expect(screen.queryByTestId('room-screen')).toBeNull();
});

it('keeps the room screen unmounted while the room is an invite', () => {
room.current = { id: 'sub-1', rid: 'rid-1', t: 'c' } as TRoomOrPreview;
jest.mocked(isInviteSubscription).mockReturnValue(true);

renderGate();
renderRoomView();

expect(screen.getByTestId('invited-screen')).toBeOnTheScreen();
expect(screen.queryByTestId('room-screen')).toBeNull();
Expand All @@ -113,7 +108,7 @@ describe('RoomGate', () => {
room.current = { id: 'sub-1', rid: 'rid-1', t: 'c', encrypted: true } as TRoomOrPreview;
jest.mocked(useE2EEStatus).mockReturnValue({ showMissingE2EEKey: true, showE2EEDisabledRoom: false, hasE2EEWarning: true });

renderGate();
renderRoomView();

expect(screen.getByTestId('missing-key-screen')).toBeOnTheScreen();
expect(screen.queryByTestId('room-screen')).toBeNull();
Expand All @@ -123,7 +118,7 @@ describe('RoomGate', () => {
room.current = { id: 'sub-1', rid: 'rid-1', t: 'c', encrypted: true } as TRoomOrPreview;
jest.mocked(useE2EEStatus).mockReturnValue({ showMissingE2EEKey: false, showE2EEDisabledRoom: true, hasE2EEWarning: true });

renderGate();
renderRoomView();

expect(screen.getByTestId('encrypted-screen')).toBeOnTheScreen();
expect(screen.queryByTestId('room-screen')).toBeNull();
Expand Down
23 changes: 23 additions & 0 deletions app/views/RoomView/components/RoomBackground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type ReactElement } from 'react';
import { ImageBackground, StyleSheet } from 'react-native';

import { useTheme } from '../../../theme';

const styles = StyleSheet.create({
image: {
width: '100%',
height: '100%',
position: 'absolute'
}
});

export const RoomBackground = (): ReactElement => {
const { theme } = useTheme();
return (
<ImageBackground
source={{ uri: `message_empty_${theme === 'dark' ? 'black' : theme}` }}
style={styles.image}
testID='room-view-empty'
/>
);
};
12 changes: 0 additions & 12 deletions app/views/RoomView/components/RoomRouteInvalid.tsx

This file was deleted.

11 changes: 6 additions & 5 deletions app/views/RoomView/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,18 @@ import { type MessageRoomState } from '../../containers/message/stores/MessageRo
export type IRoomViewProps = Pick<IBaseScreen<ChatsStackParamList, 'RoomView'>, 'navigation' | 'route'>;

export interface IRoomScreenInput {
rid: string;
t: string;
rid?: string;
t?: string;
tmid?: string;
name?: string;
initialRoom: TRoomOrPreview;
roomUserId?: string | null;
}

export type TRoomRouteParse = { status: 'valid'; input: IRoomScreenInput } | { status: 'invalid' };

export interface IRoomScreenProps extends Pick<IRoomViewProps, 'route'>, Pick<IRoomScreenInput, 'rid' | 't' | 'tmid'> {
export interface IRoomScreenProps extends Pick<IRoomViewProps, 'route'> {
rid: string;
t: string;
tmid?: string;
roomStore: RoomStore;
ready: boolean;
}
Expand Down
25 changes: 8 additions & 17 deletions app/views/RoomView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,20 @@ import { isInviteSubscription } from '../../lib/methods/isInviteSubscription';
import { getInvitationActions, getInvitationText } from '../../lib/methods/getInvitationData';
import { type IInviteSubscription } from '../../definitions';
import { isSubscriptionModel } from '../../definitions/TRoom';
import { type IRoomScreenInput, type IRoomViewProps } from './definitions';
import { type IRoomViewProps } from './definitions';
import { EncryptedRoom } from './components/EncryptedRoom';
import { InvitedRoomScreen } from './components/InvitedRoomScreen';
import { MissingRoomE2EEKey } from './components/MissingRoomE2EEKey';
import { RoomRouteInvalid } from './components/RoomRouteInvalid';
import { RoomBackground } from './components/RoomBackground';
import RoomScreen from './RoomScreen';
import { parseRoomRoute } from './services/parseRoomRoute';
import { createRoomStore, observeRoom } from './stores/RoomStore';
import { type RoomStore } from './definitions';
import { useE2EEStatus } from './hooks/useE2EEStatus';
import { useHeader } from './hooks/useHeader';

interface IRoomGateProps extends IRoomViewProps {
input: IRoomScreenInput;
}

const RoomGate = ({ route, navigation, input }: IRoomGateProps) => {
const RoomView = ({ route, navigation }: IRoomViewProps) => {
const [input] = useState(() => parseRoomRoute(route.params));
const { rid, t, tmid, name, initialRoom, roomUserId } = input;

const [roomStore] = useState<RoomStore>(() => createRoomStore({ rid, initialRoom, roomUserId }));
Expand All @@ -40,6 +37,10 @@ const RoomGate = ({ route, navigation, input }: IRoomGateProps) => {

useHeader({ rid, tmid, name, roomStore });

if (!rid || !t) {
return <RoomBackground />;
}

if (invitation) {
return (
<InvitedRoomScreen
Expand All @@ -65,14 +66,4 @@ const RoomGate = ({ route, navigation, input }: IRoomGateProps) => {
return <RoomScreen route={route} rid={rid} t={t} tmid={tmid} roomStore={roomStore} ready={ready} />;
};

const RoomView = ({ route, navigation }: IRoomViewProps) => {
const [parsed] = useState(() => parseRoomRoute(route.params));

if (parsed.status === 'invalid') {
return <RoomRouteInvalid navigation={navigation} />;
}

return <RoomGate route={route} navigation={navigation} input={parsed.input} />;
};

export default RoomView;
16 changes: 5 additions & 11 deletions app/views/RoomView/services/parseRoomRoute.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { getUidDirectMessage } from '../../../lib/methods/helpers';
import { type IRoomViewProps, type TRoomRouteParse } from '../definitions';
import { type IRoomScreenInput, type IRoomViewProps } from '../definitions';
import { type TRoomOrPreview } from '../../../definitions/TRoom';

export const parseRoomRoute = (params: IRoomViewProps['route']['params']): TRoomRouteParse => {
if (!params?.rid || !params.t) {
return { status: 'invalid' };
}
const { rid, t, tmid, name, fname, prid, visitor, joinCodeRequired, roomUserId } = params;
const initialRoom: TRoomOrPreview = { rid, t, name, fname, prid, visitor, joinCodeRequired };
return {
status: 'valid',
input: { rid, t, tmid, name, initialRoom, roomUserId: roomUserId ?? getUidDirectMessage(initialRoom) }
};
export const parseRoomRoute = (params: IRoomViewProps['route']['params']): IRoomScreenInput => {
const { rid, t, tmid, name, fname, prid, visitor, joinCodeRequired, roomUserId } = params ?? {};
const initialRoom: TRoomOrPreview = { rid: rid ?? '', t: t ?? '', name, fname, prid, visitor, joinCodeRequired };
return { rid, t, tmid, name, initialRoom, roomUserId: roomUserId ?? getUidDirectMessage(initialRoom) };
};
Loading