From 5c4895a96e0ad74702862077c2cbac40a8031cdd Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Mon, 21 Jun 2021 18:06:40 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(front)=20redirect=20instructor=20t?= =?UTF-8?q?o=20the=20dashboard=20when=20live=20is=20stopped?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a live is stopped, an instructor show the page saying the video is not found. We should redirect him to the dashboard when the live is stopped or stopping and he has update permission. --- CHANGELOG.md | 4 ++ .../components/ErrorComponents/index.tsx | 18 ++++++- .../PublicVideoDashboard/index.spec.tsx | 53 +++++++++++++++++-- .../components/PublicVideoDashboard/index.tsx | 12 ++++- 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b05f5d2f8b..2686b0dccd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed + +- Redirect instructor to the dashboard when live is stopped + ## [3.20.0] - 2021-06-18 ### Added diff --git a/src/frontend/components/ErrorComponents/index.tsx b/src/frontend/components/ErrorComponents/index.tsx index ebdb99485d..00a9ebc151 100644 --- a/src/frontend/components/ErrorComponents/index.tsx +++ b/src/frontend/components/ErrorComponents/index.tsx @@ -15,7 +15,8 @@ export interface ErrorComponentsProps { | 'upload' | 'liveIncompatible' | 'liveInit' - | 'liveToVod'; + | 'liveToVod' + | 'liveStopped'; } const FullScreenErrorStyled = styled(LayoutMainArea)` @@ -141,6 +142,21 @@ const messages = { id: 'components.ErrorComponents.liveToVod.text', }, }, + liveStopped: { + text: { + defaultMessage: + 'This live has now ended. If the host decides to publish the recording, the video will be available here in a while.', + description: + 'Text explaining that a live has ended and that the VOD may be available soon.', + id: 'components.ErrorComponents.liveStopped.text', + }, + title: { + defaultMessage: 'This live has ended', + description: + 'Title for a user without update permission when a live is stopped or stopping', + id: 'components.ErrorComponents.liveStopped.title', + }, + }, }; export const ErrorMessage: React.FC = ({ code }) => ( diff --git a/src/frontend/components/PublicVideoDashboard/index.spec.tsx b/src/frontend/components/PublicVideoDashboard/index.spec.tsx index c10bead91c..6ed5ae2701 100644 --- a/src/frontend/components/PublicVideoDashboard/index.spec.tsx +++ b/src/frontend/components/PublicVideoDashboard/index.spec.tsx @@ -3,10 +3,10 @@ import fetchMock from 'fetch-mock'; import { cleanup, render, screen, waitFor } from '@testing-library/react'; import { ImportMock } from 'ts-mock-imports'; +import { DASHBOARD_ROUTE } from '../Dashboard/route'; import { FULL_SCREEN_ERROR_ROUTE } from '../ErrorComponents/route'; import * as useTimedTextTrackModule from '../../data/stores/useTimedTextTrack'; import { liveState, timedTextMode } from '../../types/tracks'; -import { converseMounter } from '../../utils/converse'; import { timedTextMockFactory, videoMockFactory, @@ -30,11 +30,17 @@ const mockCreatePlayer = createPlayer as jest.MockedFunction< typeof createPlayer >; +let mockCanUpdate: boolean; const mockVideo = videoMockFactory(); jest.mock('../../data/appData', () => ({ appData: { video: mockVideo, }, + getDecodedJwt: () => ({ + permissions: { + can_update: mockCanUpdate, + }, + }), })); const useTimedTextTrackStub = ImportMock.mockFunction( @@ -67,6 +73,7 @@ describe('PublicVideoDashboard', () => { mockCreatePlayer.mockResolvedValue({ destroy: jest.fn(), }); + mockCanUpdate = false; }); afterEach(() => { @@ -287,7 +294,7 @@ describe('PublicVideoDashboard', () => { expect(container.querySelector('#converse-container')).toBeInTheDocument(); }); - it('redirects to the error component when live state is stopped or stopping', () => { + it('redirects to the error component when user has no update permission and live state is stopped or stopping', () => { [liveState.STOPPED, liveState.STOPPING].forEach((state) => { const video = videoMockFactory({ live_state: state, @@ -297,6 +304,46 @@ describe('PublicVideoDashboard', () => { wrapInRouter( , [ + { + path: DASHBOARD_ROUTE(), + render: ({ match }) => ( + {`dashboard ${match.params.objectType}`} + ), + }, + { + path: FULL_SCREEN_ERROR_ROUTE(), + render: ({ match }) => ( + {`Error Component: ${match.params.code}`} + ), + }, + ], + ), + ), + ); + + screen.getByText('Error Component: liveStopped'); + + cleanup(); + }); + }); + + it('redirects to the dashboard when user has update permission and live state is stopped or stopping', () => { + mockCanUpdate = true; + [liveState.STOPPED, liveState.STOPPING].forEach((state) => { + const video = videoMockFactory({ + live_state: state, + }); + render( + wrapInIntlProvider( + wrapInRouter( + , + [ + { + path: DASHBOARD_ROUTE(), + render: ({ match }) => ( + {`dashboard ${match.params.objectType}`} + ), + }, { path: FULL_SCREEN_ERROR_ROUTE(), render: ({ match }) => ( @@ -308,7 +355,7 @@ describe('PublicVideoDashboard', () => { ), ); - screen.getByText('Error Component: notFound'); + screen.getByText('dashboard videos'); cleanup(); }); diff --git a/src/frontend/components/PublicVideoDashboard/index.tsx b/src/frontend/components/PublicVideoDashboard/index.tsx index 71ddb1c0c0..e8f0d61ab8 100644 --- a/src/frontend/components/PublicVideoDashboard/index.tsx +++ b/src/frontend/components/PublicVideoDashboard/index.tsx @@ -3,13 +3,16 @@ import React from 'react'; import { Redirect } from 'react-router-dom'; import { Chat } from '../Chat'; +import { DASHBOARD_ROUTE } from '../Dashboard/route'; import { DownloadVideo } from '../DownloadVideo'; import { FULL_SCREEN_ERROR_ROUTE } from '../ErrorComponents/route'; import { Transcripts } from '../Transcripts'; import VideoPlayer from '../VideoPlayer'; import { WaitingLiveVideo } from '../WaitingLiveVideo'; +import { getDecodedJwt } from '../../data/appData'; import { useTimedTextTrack } from '../../data/stores/useTimedTextTrack'; import { useVideo } from '../../data/stores/useVideo'; +import { modelName } from '../../types/models'; import { liveState, timedTextMode, @@ -52,8 +55,13 @@ const PublicVideoDashboard = ({ ); case liveState.STOPPED: case liveState.STOPPING: - // nothing to show - return ; + // user has update permission, we redirect him to the dashboard + if (getDecodedJwt().permissions.can_update) { + return ; + } + + // otherwise the user can only see a message + return ; default: // waiting message return ;