From a21e06b901dadd41dc619201c3772a0eb0d4cf30 Mon Sep 17 00:00:00 2001 From: Lina Ebeid Date: Thu, 7 Mar 2024 15:32:05 +0100 Subject: [PATCH] feat: move analytics tab to analytics view (#141) * feat: move analytics tab to analytics view * fix: remove navigate to analytics tab at builder view --- cypress/e2e/Admin/AdminView.cy.ts | 13 ------- .../Analytics/AnalyticsDetailedCharts.cy.ts | 25 ++++++------ .../Analytics/AnalyticsGeneralCharts.cy.ts | 38 ++++--------------- cypress/support/commands.ts | 6 +-- src/components/Analytics/AnalyticsMenu.tsx | 36 ++++++------------ src/components/Analytics/AnalyticsView.tsx | 11 ++++++ src/components/navigation/AdminView.tsx | 9 ----- src/components/views/View.tsx | 3 ++ src/config/selectors.tsx | 1 - 9 files changed, 46 insertions(+), 96 deletions(-) rename cypress/e2e/{Admin => }/Analytics/AnalyticsDetailedCharts.cy.ts (82%) rename cypress/e2e/{Admin => }/Analytics/AnalyticsGeneralCharts.cy.ts (73%) create mode 100644 src/components/Analytics/AnalyticsView.tsx diff --git a/cypress/e2e/Admin/AdminView.cy.ts b/cypress/e2e/Admin/AdminView.cy.ts index a4c9eaf4..571e18d1 100644 --- a/cypress/e2e/Admin/AdminView.cy.ts +++ b/cypress/e2e/Admin/AdminView.cy.ts @@ -4,9 +4,7 @@ import { getSettingsByName } from '../../../src/components/context/utilities'; import { APP_SETTING_NAMES } from '../../../src/config/constants'; import { ADD_NEW_QUESTION_TITLE_CY, - ANALYTICS_CONTAINER_CY, CREATE_VIEW_CONTAINER_CY, - NAVIGATION_ANALYTICS_BUTTON_CY, NAVIGATION_CREATE_QUIZ_BUTTON_CY, NAVIGATION_RESULT_BUTTON_CY, NAVIGATION_TAB_CONTAINER_CY, @@ -39,12 +37,6 @@ describe('Admin View', () => { 'have.text', "There isn't any question to display" ); - - cy.get(dataCyWrapper(NAVIGATION_ANALYTICS_BUTTON_CY)).click(); - cy.get(dataCyWrapper(ANALYTICS_CONTAINER_CY)).should( - 'have.text', - "There isn't any question to display" - ); }); /** @@ -86,14 +78,9 @@ export const testAdminViewBaseLayout = () => { cy.get(dataCyWrapper(NAVIGATION_TAB_CONTAINER_CY)).should('be.visible'); cy.get(dataCyWrapper(NAVIGATION_CREATE_QUIZ_BUTTON_CY)).should('be.visible'); cy.get(dataCyWrapper(NAVIGATION_RESULT_BUTTON_CY)).should('be.visible'); - cy.get(dataCyWrapper(NAVIGATION_ANALYTICS_BUTTON_CY)).should('be.visible'); cy.get(dataCyWrapper(NAVIGATION_RESULT_BUTTON_CY)).click(); // after we click on result, the table component should be visible and the table cy.get(dataCyWrapper(CREATE_VIEW_CONTAINER_CY)).should('not.exist'); cy.get(dataCyWrapper(TABLE_BY_QUESTION_CONTAINER_CY)).should('be.visible'); - - // after clicking on analytics, the component should be visible - cy.get(dataCyWrapper(NAVIGATION_ANALYTICS_BUTTON_CY)).click(); - cy.get(dataCyWrapper(ANALYTICS_CONTAINER_CY)).should('be.visible'); }; diff --git a/cypress/e2e/Admin/Analytics/AnalyticsDetailedCharts.cy.ts b/cypress/e2e/Analytics/AnalyticsDetailedCharts.cy.ts similarity index 82% rename from cypress/e2e/Admin/Analytics/AnalyticsDetailedCharts.cy.ts rename to cypress/e2e/Analytics/AnalyticsDetailedCharts.cy.ts index 3942530c..7fe3fa7e 100644 --- a/cypress/e2e/Admin/Analytics/AnalyticsDetailedCharts.cy.ts +++ b/cypress/e2e/Analytics/AnalyticsDetailedCharts.cy.ts @@ -1,20 +1,21 @@ -import { getSettingsByName } from '../../../../src/components/context/utilities'; +import { getSettingsByName } from '../../../src/components/context/utilities'; import { APP_SETTING_NAMES, QuestionType, -} from '../../../../src/config/constants'; +} from '../../../src/config/constants'; import { buildAnalyticsDetailedChartCy, buildAnalyticsDetailedQuestionTabMenuCy, dataCyWrapper, -} from '../../../../src/config/selectors'; -import { ANSWER_REGEXP } from '../../../../src/utils/fillInTheBlanks'; -import { APP_DATA_LOT_QUESTIONS_LOT_USERS } from '../../../fixtures/appData'; -import { APP_SETTINGS_LOT_QUESTIONS } from '../../../fixtures/appSettings'; -import { MEMBERS_RESULT_TABLES } from '../../../fixtures/members'; -import { verifySelectedMenu } from '../../../utils/autoScrollableMenuSelected'; +} from '../../../src/config/selectors'; +import { ANSWER_REGEXP } from '../../../src/utils/fillInTheBlanks'; +import { APP_DATA_LOT_QUESTIONS_LOT_USERS } from '../../fixtures/appData'; +import { APP_SETTINGS_LOT_QUESTIONS } from '../../fixtures/appSettings'; +import { MEMBERS_RESULT_TABLES } from '../../fixtures/members'; +import { verifySelectedMenu } from '../../utils/autoScrollableMenuSelected'; describe('Analytics Detailed', () => { + it('Selecting detailed chart display correct answer frequency chart based on question type', () => { cy.setupAnalyticsForCheck( APP_SETTINGS_LOT_QUESTIONS, @@ -38,13 +39,13 @@ describe('Analytics Detailed', () => { case QuestionType.FILL_BLANKS: q.data.text .match(ANSWER_REGEXP) - .map((word, idx) => { + .map((word, idx) => // todo: use id instead of label - return { + ({ label: `Question answer frequency blank ${idx + 1}`, id: `Question answer frequency blank ${idx + 1}`, - }; - }) + }) + ) .forEach((qLabel, idx, labels) => { // Goes to chart cy.get( diff --git a/cypress/e2e/Admin/Analytics/AnalyticsGeneralCharts.cy.ts b/cypress/e2e/Analytics/AnalyticsGeneralCharts.cy.ts similarity index 73% rename from cypress/e2e/Admin/Analytics/AnalyticsGeneralCharts.cy.ts rename to cypress/e2e/Analytics/AnalyticsGeneralCharts.cy.ts index a6ed282a..70838bc1 100644 --- a/cypress/e2e/Admin/Analytics/AnalyticsGeneralCharts.cy.ts +++ b/cypress/e2e/Analytics/AnalyticsGeneralCharts.cy.ts @@ -1,5 +1,5 @@ -import { getSettingsByName } from '../../../../src/components/context/utilities'; -import { APP_SETTING_NAMES } from '../../../../src/config/constants'; +import { getSettingsByName } from '../../../src/components/context/utilities'; +import { APP_SETTING_NAMES } from '../../../src/config/constants'; import { ANALYTICS_CONTAINER_CY, ANALYTICS_GENERAL_CORRECT_RESPONSE_PERCENTAGE_CY, @@ -9,14 +9,14 @@ import { buildAnalyticsDetailedQuestionTabMenuCy, buildAutoScrollableMenuLinkCy, dataCyWrapper, -} from '../../../../src/config/selectors'; -import { APP_DATA_LOT_QUESTIONS_LOT_USERS } from '../../../fixtures/appData'; +} from '../../../src/config/selectors'; +import { APP_DATA_LOT_QUESTIONS_LOT_USERS } from '../../fixtures/appData'; import { APP_SETTINGS_FEW_QUESTIONS, APP_SETTINGS_LOT_QUESTIONS, -} from '../../../fixtures/appSettings'; -import { MEMBERS_RESULT_TABLES } from '../../../fixtures/members'; -import { verifySelectedMenu } from '../../../utils/autoScrollableMenuSelected'; +} from '../../fixtures/appSettings'; +import { MEMBERS_RESULT_TABLES } from '../../fixtures/members'; +import { verifySelectedMenu } from '../../utils/autoScrollableMenuSelected'; const generalCharts = [ { @@ -103,30 +103,6 @@ describe('Analytics General', () => { }); }); - // bug: transition fails in cypress - // it('Analytics, click chart in menu goes to correct charts', () => { - // cy.setupAnalyticsForCheck( - // APP_SETTINGS_LOT_QUESTIONS, - // APP_DATA_LOT_QUESTIONS_LOT_USERS, - // MEMBERS_RESULT_TABLES - // ); - - // generalCharts.forEach(({ selector, chartTitle, label, id }, index) => { - // cy.get(dataCyWrapper(buildAutoScrollableMenuLinkCy(id))) - // .scrollIntoView() - // .click(); - // // check that correct menu is selected - // verifySelectedMenu(index, generalCharts); - - // cy.get(dataCyWrapper(selector)).should('be.visible'); - - // // Check the title of the chart as well - // cy.get(dataCyWrapper(selector)) - // .find('.gtitle') - // .should('have.text', chartTitle); - // }); - // }); - it('Scroll to chart, select correct menu entry', () => { cy.setupAnalyticsForCheck( APP_SETTINGS_LOT_QUESTIONS, diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index c6cb504f..e116b2da 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -15,7 +15,6 @@ import { EXPLANATION_PLAY_CY, HINTS_CY, HINTS_PLAY_CY, - NAVIGATION_ANALYTICS_BUTTON_CY, NAVIGATION_RESULT_BUTTON_CY, NUMBER_OF_ATTEMPTS_TEXT_CY, RESULT_TABLES_RESULT_BY_USER_BUTTON_CY, @@ -151,15 +150,12 @@ Cypress.Commands.add( }, appContext: { permission: PermissionLevel.Admin, - context: Context.Builder, + context: Context.Analytics, }, members, }); cy.visit('/'); - - // navigate to Analytics - cy.get(dataCyWrapper(NAVIGATION_ANALYTICS_BUTTON_CY)).click(); } ); diff --git a/src/components/Analytics/AnalyticsMenu.tsx b/src/components/Analytics/AnalyticsMenu.tsx index ea08d635..cb58ed8d 100644 --- a/src/components/Analytics/AnalyticsMenu.tsx +++ b/src/components/Analytics/AnalyticsMenu.tsx @@ -1,7 +1,6 @@ import groupBy from 'lodash.groupby'; import { - RefObject, SyntheticEvent, useCallback, useContext, @@ -46,19 +45,7 @@ import GeneralCharts from './generalCharts/GeneralCharts'; const SLIDE_BAR_WIDTH = 16; -type Props = { - headerElem: RefObject; -}; - -export type ChartRefs = RefObject<{ [key: string]: unknown }>; - -/** - * Component that represents the Analytics menu. Handle which charts have to be drawn. - * - * @param headerElem The header element if any, used to calculate the remaining height that this object can take - * in the window - */ -const AnalyticsMenu = ({ headerElem }: Props): JSX.Element => { +const AnalyticsMenu = (): JSX.Element => { const { t } = useTranslation(); // Fetch all the data here, as it is used by multiple children, avoid to fetch it in all children @@ -73,12 +60,11 @@ const AnalyticsMenu = ({ headerElem }: Props): JSX.Element => { useState(true); const chartRefs = useRef({}); const chartContainerRef = useRef(null); - const [stackElem, setStackElem] = useState(null); - const [sideMenuElem, setSideMenuElem] = useState(null); + const stackElem = useRef(null); + const sideMenuElem = useRef(null); + const chartTabs = useRef(null); - const maxResultViewHeight = useMaxAvailableHeightInWindow( - headerElem?.current - ); + const maxResultViewHeight = useMaxAvailableHeightInWindow(null); const maxHeightScrollableMenu = useMaxAvailableHeightWithParentHeight( maxResultViewHeight, chartTabs.current @@ -90,8 +76,8 @@ const AnalyticsMenu = ({ headerElem }: Props): JSX.Element => { [questions] ); - const stackElemWidth = useElementWidth(stackElem); - const sideMenuElemWidth = useElementWidth(sideMenuElem); + const stackElemWidth = useElementWidth(stackElem.current); + const sideMenuElemWidth = useElementWidth(sideMenuElem.current); // TODO: check if it is possible to delete old answers app data // For now, when a question is removed, the user answers still exists. @@ -200,10 +186,10 @@ const AnalyticsMenu = ({ headerElem }: Props): JSX.Element => { return order.length > 0 ? ( responses && nValidResponses && nValidResponses > 0 ? ( - - setStackElem(elem)}> + + setSideMenuElem(elem)} + ref={sideMenuElem} sx={{ minWidth: '8em', maxWidth: '12em', @@ -249,7 +235,7 @@ const AnalyticsMenu = ({ headerElem }: Props): JSX.Element => { })} - + ( + + + +); + +export default AnalyticsView; diff --git a/src/components/navigation/AdminView.tsx b/src/components/navigation/AdminView.tsx index 41b04e30..db7bb3a2 100644 --- a/src/components/navigation/AdminView.tsx +++ b/src/components/navigation/AdminView.tsx @@ -5,12 +5,10 @@ import { Tab, Tabs } from '@mui/material'; import Box from '@mui/material/Box'; import { - NAVIGATION_ANALYTICS_BUTTON_CY, NAVIGATION_CREATE_QUIZ_BUTTON_CY, NAVIGATION_RESULT_BUTTON_CY, NAVIGATION_TAB_CONTAINER_CY, } from '../../config/selectors'; -import AnalyticsMenu from '../Analytics/AnalyticsMenu'; import CreateView from '../create/CreateView'; import ResultTables from '../results/ResultTables'; import TabPanel from './TabPanel'; @@ -37,10 +35,6 @@ const AdminView = () => { data-cy={NAVIGATION_CREATE_QUIZ_BUTTON_CY} /> - @@ -49,9 +43,6 @@ const AdminView = () => { - - - ); }; diff --git a/src/components/views/View.tsx b/src/components/views/View.tsx index 8f364668..4754272d 100644 --- a/src/components/views/View.tsx +++ b/src/components/views/View.tsx @@ -7,6 +7,7 @@ import { Context, PermissionLevel } from '@graasp/sdk'; import { DEFAULT_LANG } from '../../config/constants'; import i18n from '../../config/i18n'; +import AnalyticsView from '../Analytics/AnalyticsView'; import { QuizProvider } from '../context/QuizContext'; import AdminView from '../navigation/AdminView'; import PlayView from '../play/PlayView'; @@ -31,6 +32,8 @@ const View = (): JSX.Element => { return ; } } + case Context.Analytics: + return ; case Context.Player: default: return ; diff --git a/src/config/selectors.tsx b/src/config/selectors.tsx index d39d5c09..c3631181 100644 --- a/src/config/selectors.tsx +++ b/src/config/selectors.tsx @@ -114,7 +114,6 @@ export const TABLE_BY_USER_QUESTION_NAME_HEADER_CY = export const TABLE_BY_USER_ANSWER_DATA_CY = 'tableByUserAnswerData'; export const TABLE_BY_USER_DATE_DATA_CY = 'tableByUserDateData'; export const TABLE_BY_USER_CORRECT_ICON_CY = 'tableByUserCorrectIcon'; -export const NAVIGATION_ANALYTICS_BUTTON_CY = 'navigationAnalyticsButton'; export const ANALYTICS_CONTAINER_CY = 'analyticsContainer'; export const ANALYTICS_GENERAL_TAB_MENU_CY = 'analyticsGeneralTabMenu'; export const buildAnalyticsDetailedQuestionTabMenuCy = (qTitle: string) =>