Skip to content

Commit

Permalink
✨(front) remove StudentViewersList and use ViewersList instead
Browse files Browse the repository at this point in the history
The StudentViewersList is not used anymore and the ViewersList replaces it. The
Viewers component makes some little changes to the UI of the viewers list and
add 'on-stage request' management features directly into the list.
  • Loading branch information
roro-lv committed Apr 6, 2022
1 parent 68afcac commit 43b7026
Show file tree
Hide file tree
Showing 15 changed files with 146 additions and 347 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ right (and close / open it)
- rename LiveRegistration model in LiveSession
- Disable jitsi prejoin page
- Admin can access all LiveSession belonging to a video
- Move on-stage request functional (in Instructor view) from under
the video to the ViewersList in the right panel


### Fixed

Expand Down
150 changes: 135 additions & 15 deletions src/frontend/components/LiveVideoPanel/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,48 @@
import React from 'react';
import { render, screen } from '@testing-library/react';

import { getDecodedJwt } from 'data/appData';
import {
LivePanelItem,
useLivePanelState,
} from 'data/stores/useLivePanelState';
import { videoMockFactory } from 'utils/tests/factories';
import { useParticipantsStore } from 'data/stores/useParticipantsStore';
import {
participantMockFactory,
videoMockFactory,
} from 'utils/tests/factories';
import { renderImageSnapshot } from 'utils/tests/imageSnapshot';
import { wrapInIntlProvider } from 'utils/tests/intl';

import { DecodedJwt } from 'types/jwt';
import { LiveVideoPanel } from '.';

const mockAskingParticipant = participantMockFactory();
const mockParticipant = participantMockFactory();

const mockVideo = videoMockFactory({
participants_asking_to_join: [mockAskingParticipant],
participants_in_discussion: [mockParticipant],
});

jest.mock('data/appData', () => ({
getDecodedJwt: () => ({
permissions: {
can_access_dashboard: false,
can_update: false,
},
}),
getDecodedJwt: jest.fn(),
}));

const video = videoMockFactory();
const mockGetDecodedJwt = getDecodedJwt as jest.MockedFunction<
typeof getDecodedJwt
>;

describe('<LiveVideoPanel />', () => {
beforeEach(() => {
jest.resetAllMocks();
});

it('closes the panel if no item is selected', () => {
mockGetDecodedJwt.mockReturnValue({
permissions: {
can_access_dashboard: false,
can_update: false,
},
} as DecodedJwt);
const mockSetPanelVisibility = jest.fn();
useLivePanelState.setState({
currentItem: undefined,
Expand All @@ -36,7 +55,7 @@ describe('<LiveVideoPanel />', () => {
});

const { container } = render(
wrapInIntlProvider(<LiveVideoPanel video={video} />),
wrapInIntlProvider(<LiveVideoPanel video={mockVideo} />),
);

expect(mockSetPanelVisibility).toBeCalled();
Expand All @@ -47,6 +66,12 @@ describe('<LiveVideoPanel />', () => {
});

it('renders the content with selection', () => {
mockGetDecodedJwt.mockReturnValue({
permissions: {
can_access_dashboard: false,
can_update: false,
},
} as DecodedJwt);
useLivePanelState.setState({
currentItem: LivePanelItem.APPLICATION,
availableItems: [
Expand All @@ -56,7 +81,7 @@ describe('<LiveVideoPanel />', () => {
],
});

render(wrapInIntlProvider(<LiveVideoPanel video={video} />));
render(wrapInIntlProvider(<LiveVideoPanel video={mockVideo} />));

screen.getByRole('tablist');
screen.getByRole('tab', { name: 'application' });
Expand All @@ -66,13 +91,96 @@ describe('<LiveVideoPanel />', () => {
screen.getByText('application content');
});

it('renders the correct viewers list if the user is not an instructor', () => {
mockGetDecodedJwt.mockReturnValue({
permissions: {
can_update: false,
},
} as DecodedJwt);

useParticipantsStore.setState({
participants: [
{
...mockParticipant,
isInstructor: false,
isOnStage: false,
},
],
});
useLivePanelState.setState({
currentItem: LivePanelItem.VIEWERS_LIST,
availableItems: [
LivePanelItem.APPLICATION,
LivePanelItem.CHAT,
LivePanelItem.VIEWERS_LIST,
],
});

render(wrapInIntlProvider(<LiveVideoPanel video={mockVideo} />));

screen.getByRole('tablist');
screen.getByRole('tab', { name: 'application' });
screen.getByRole('tab', { name: 'chat' });
screen.getByRole('tab', { name: 'viewers' });

screen.getByText('On stage');
screen.getByText(mockParticipant.name);
expect(screen.queryByText('Demands')).toEqual(null);
expect(screen.queryByText(mockAskingParticipant.name)).toEqual(null);
});

it('renders the correct viewers list if the user is an instructor', () => {
mockGetDecodedJwt.mockReturnValue({
permissions: {
can_update: true,
},
} as DecodedJwt);

useParticipantsStore.setState({
participants: [
{
...mockParticipant,
isInstructor: false,
isOnStage: false,
},
],
});

useLivePanelState.setState({
currentItem: LivePanelItem.VIEWERS_LIST,
availableItems: [
LivePanelItem.APPLICATION,
LivePanelItem.CHAT,
LivePanelItem.VIEWERS_LIST,
],
});

render(wrapInIntlProvider(<LiveVideoPanel video={mockVideo} />));

screen.getByRole('tablist');
screen.getByRole('tab', { name: 'application' });
screen.getByRole('tab', { name: 'chat' });
screen.getByRole('tab', { name: 'viewers' });

screen.getByText('On stage');
screen.getByText(mockParticipant.name);
screen.getByText('Demands');
screen.getByText(mockAskingParticipant.name);
});

it('does not render tabs with only one item available', () => {
mockGetDecodedJwt.mockReturnValue({
permissions: {
can_access_dashboard: false,
can_update: false,
},
} as DecodedJwt);
useLivePanelState.setState({
currentItem: LivePanelItem.APPLICATION,
availableItems: [LivePanelItem.APPLICATION],
});

render(wrapInIntlProvider(<LiveVideoPanel video={video} />));
render(wrapInIntlProvider(<LiveVideoPanel video={mockVideo} />));

expect(screen.queryByRole('tablist')).not.toBeInTheDocument();
expect(
Expand All @@ -87,6 +195,12 @@ describe('<LiveVideoPanel />', () => {
});

it('renders with appropriate style on large screen', async () => {
mockGetDecodedJwt.mockReturnValue({
permissions: {
can_access_dashboard: false,
can_update: false,
},
} as DecodedJwt);
useLivePanelState.setState({
currentItem: LivePanelItem.APPLICATION,
availableItems: [
Expand All @@ -96,10 +210,16 @@ describe('<LiveVideoPanel />', () => {
],
});

await renderImageSnapshot(<LiveVideoPanel video={video} />);
await renderImageSnapshot(<LiveVideoPanel video={mockVideo} />);
});

it('renders with appropriate style on small screen', async () => {
mockGetDecodedJwt.mockReturnValue({
permissions: {
can_access_dashboard: false,
can_update: false,
},
} as DecodedJwt);
useLivePanelState.setState({
currentItem: LivePanelItem.APPLICATION,
availableItems: [
Expand All @@ -109,6 +229,6 @@ describe('<LiveVideoPanel />', () => {
],
});

await renderImageSnapshot(<LiveVideoPanel video={video} />, 300, 300);
await renderImageSnapshot(<LiveVideoPanel video={mockVideo} />, 300, 300);
});
});
7 changes: 4 additions & 3 deletions src/frontend/components/LiveVideoPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { Tabs, Box, Grommet, ResponsiveContext, ThemeType } from 'grommet';
import styled from 'styled-components';

import { Chat } from 'components/Chat';
import { StudentViewersList } from 'components/StudentViewersList';
import { ViewersList } from 'components/ViewersList';
import { getDecodedJwt } from 'data/appData';
import {
LivePanelItem,
useLivePanelState,
} from 'data/stores/useLivePanelState';
import { Video } from 'types/tracks';
import { ShouldNotHappen } from 'utils/errors/exception';
import { theme } from 'utils/theme/theme';

import { LiveVideoTabPanel } from './LiveVideoTabPanel';

const StyledGrommet = styled(Grommet)`
Expand Down Expand Up @@ -57,6 +57,7 @@ export const LiveVideoPanel = ({ video }: LiveVideoPanelProps) => {
setPanelVisibility: state.setPanelVisibility,
}),
);
const canUpdate = getDecodedJwt().permissions.can_update;

// close panel if there is nothing to display
useEffect(() => {
Expand Down Expand Up @@ -97,7 +98,7 @@ export const LiveVideoPanel = ({ video }: LiveVideoPanelProps) => {
content = <p>application content</p>;
break;
case LivePanelItem.VIEWERS_LIST:
content = <StudentViewersList video={video} />;
content = <ViewersList isInstructor={canUpdate} video={video} />;
break;
default:
throw new ShouldNotHappen(currentItem);
Expand Down
6 changes: 4 additions & 2 deletions src/frontend/components/StudentLiveWrapper/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ describe('<StudentLiveWrapper /> as a viewer', () => {

const viewersTabButton = screen.getByRole('tab', { name: 'viewers' });
userEvent.click(viewersTabButton);
screen.getByText('Other participants');
expect(screen.queryByText('On stage')).toBeNull();
expect(screen.queryByText('Other participants')).toBeNull();

expect(useLivePanelState.getState().availableItems).toEqual([
LivePanelItem.CHAT,
Expand Down Expand Up @@ -586,7 +587,8 @@ describe('<StudentLiveWrapper /> as a streamer', () => {

const viewersTabButton = screen.getByRole('tab', { name: 'viewers' });
userEvent.click(viewersTabButton);
screen.getByText('Other participants');
expect(screen.queryByText('On stage')).toBeNull();
expect(screen.queryByText('Other participants')).toBeNull();

expect(useLivePanelState.getState().availableItems).toEqual([
LivePanelItem.CHAT,
Expand Down
Binary file not shown.

This file was deleted.

This file was deleted.

Binary file not shown.
Binary file not shown.

This file was deleted.

Loading

0 comments on commit 43b7026

Please sign in to comment.