From 4a37411827c7ec702c154ab43ae52926dd6fa12d Mon Sep 17 00:00:00 2001 From: amirhossein-haerian Date: Tue, 27 Aug 2024 17:05:48 +0200 Subject: [PATCH 1/6] feat(KUI-1378): refactored the way of getting data --- public/css/kursinfo-web.scss | 33 ++++++++++++++ .../RoundInformation/PlannedModules.jsx | 10 +---- .../RoundInformation/RoundInformation.jsx | 43 +++++++++++++++---- .../RoundInformationContacts.jsx | 8 +--- .../RoundInformationInfoGrid.jsx | 4 +- 5 files changed, 71 insertions(+), 27 deletions(-) diff --git a/public/css/kursinfo-web.scss b/public/css/kursinfo-web.scss index 224214d3..b317d4e4 100644 --- a/public/css/kursinfo-web.scss +++ b/public/css/kursinfo-web.scss @@ -110,6 +110,7 @@ } .roundInformation { + position: relative; padding: 20px; margin-bottom: 30px; background-color: var(--color-background-alt); @@ -187,6 +188,38 @@ background-color: var(--color-background); } } +.shimmer-effect::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(-45deg, #eee 40%, #fafafa 50%, #eee 60%); + background-size: 300%; + background-position-x: 100%; + animation: shimmer 1s infinite linear; + z-index: 10; + pointer-events: none; +} +.fadeIn { + animation: fadeIn .5s ease forwards; +} + +@keyframes shimmer { + to { + background-position-x: 0%; + } +} + +@keyframes fadeIn { + from { + opacity: .2; + } + to { + opacity: 1; + } +} .course-section-list { @include prose.prose; diff --git a/public/js/app/components/RoundInformation/PlannedModules.jsx b/public/js/app/components/RoundInformation/PlannedModules.jsx index 07190655..5bab6da4 100644 --- a/public/js/app/components/RoundInformation/PlannedModules.jsx +++ b/public/js/app/components/RoundInformation/PlannedModules.jsx @@ -1,11 +1,3 @@ import React from 'react' -import { usePlannedModules } from '../../hooks/usePlannedModules' -export const PlannedModules = ({ courseCode, courseRound, selectedSemester }) => { - const { plannedModules } = usePlannedModules({ - courseCode, - semester: selectedSemester, - applicationCode: courseRound.round_application_code, - }) - return -} +export const PlannedModules = ({ plannedModules }) => diff --git a/public/js/app/components/RoundInformation/RoundInformation.jsx b/public/js/app/components/RoundInformation/RoundInformation.jsx index 75addb3c..39489fa1 100644 --- a/public/js/app/components/RoundInformation/RoundInformation.jsx +++ b/public/js/app/components/RoundInformation/RoundInformation.jsx @@ -1,9 +1,11 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import Alert from '../../components-shared/Alert' import BankIdAlert from '../../components/BankIdAlert' import { useLanguage } from '../../hooks/useLanguage' import { useRoundUtils } from '../../hooks/useRoundUtils' +import { useCourseEmployees } from '../../hooks/useCourseEmployees' +import { usePlannedModules } from '../../hooks/usePlannedModules' import { RoundInformationInfoGrid } from './RoundInformationInfoGrid' import { RoundInformationContacts } from './RoundInformationContacts' @@ -14,13 +16,41 @@ function RoundInformation({ courseCode, courseData, courseRound, semesterRoundSt const selectedRoundHeader = createRoundHeader(courseRound) const { selectedSemester } = semesterRoundState + const [pending, setPending] = useState(true) + + const { courseRoundEmployees } = useCourseEmployees({ + courseCode, + selectedSemester, + applicationCode: courseRound?.round_application_code, + }) + + const { plannedModules } = usePlannedModules({ + courseCode, + semester: selectedSemester, + applicationCode: courseRound.round_application_code, + }) + + useEffect(() => { + setPending(true) + }, [courseRound]) + + useEffect(() => { + if (courseRoundEmployees && plannedModules) { + setPending(false) + } + }, [courseRoundEmployees, plannedModules]) + return ( -
+

{translation.courseRoundInformation.round_header} {selectedRoundHeader}

- + @@ -29,12 +59,7 @@ function RoundInformation({ courseCode, courseData, courseRound, semesterRoundSt )}

{translation.courseLabels.header_contact}

- +
) } diff --git a/public/js/app/components/RoundInformation/RoundInformationContacts.jsx b/public/js/app/components/RoundInformation/RoundInformationContacts.jsx index a80bfdde..2c9a100e 100644 --- a/public/js/app/components/RoundInformation/RoundInformationContacts.jsx +++ b/public/js/app/components/RoundInformation/RoundInformationContacts.jsx @@ -1,16 +1,10 @@ import React from 'react' import { useLanguage } from '../../hooks/useLanguage' import { useMissingInfo } from '../../hooks/useMissingInfo' -import { useCourseEmployees } from '../../hooks/useCourseEmployees' -function RoundInformationContacts({ courseCode, courseData, courseRound, selectedSemester }) { +function RoundInformationContacts({ courseData, courseRoundEmployees }) { const { translation } = useLanguage() const { missingInfoLabel } = useMissingInfo() - const { courseRoundEmployees } = useCourseEmployees({ - courseCode, - selectedSemester, - applicationCode: courseRound?.round_application_code, - }) return (
diff --git a/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx b/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx index b14f5104..ceb880a6 100644 --- a/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx +++ b/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx @@ -70,7 +70,7 @@ const Item = ({ children, html, title, infoModalContent }) => { ) } -function RoundInformationInfoGrid({ courseCode, courseRound, selectedSemester }) { +function RoundInformationInfoGrid({ courseCode, courseRound, plannedModules }) { const { translation } = useLanguage() return ( @@ -118,7 +118,7 @@ function RoundInformationInfoGrid({ courseCode, courseRound, selectedSemester }) - + From e2732273ae1c902e5313e8e5a68f6b363838dc67 Mon Sep 17 00:00:00 2001 From: amirhossein-haerian Date: Tue, 27 Aug 2024 20:16:58 +0200 Subject: [PATCH 2/6] feat(KUI-1378): the loder and test cases are ready --- public/css/kursinfo-web.scss | 24 ++++-- .../RoundInformation/RoundInformation.jsx | 8 +- .../__tests__/RoundInformation.test.js | 4 +- .../RoundInformationContacts.test.js | 79 ++----------------- public/js/app/hooks/useCourseEmployees.js | 17 ++-- 5 files changed, 37 insertions(+), 95 deletions(-) diff --git a/public/css/kursinfo-web.scss b/public/css/kursinfo-web.scss index b317d4e4..8a4aefd8 100644 --- a/public/css/kursinfo-web.scss +++ b/public/css/kursinfo-web.scss @@ -114,6 +114,14 @@ padding: 20px; margin-bottom: 30px; background-color: var(--color-background-alt); + .person { + min-height: 31px; + img { + max-width: 40px; + overflow: hidden; + white-space: nowrap; + } + } h3 { margin-block-end: 1rem; @@ -195,15 +203,15 @@ left: 0; width: 100%; height: 100%; - background: linear-gradient(-45deg, #eee 40%, #fafafa 50%, #eee 60%); + background: linear-gradient(-45deg, var(--color-background-alt) 40%, #fafafa 50%, var(--color-background-alt) 60%); background-size: 300%; background-position-x: 100%; animation: shimmer 1s infinite linear; z-index: 10; pointer-events: none; } -.fadeIn { - animation: fadeIn .5s ease forwards; +.fadeIn > * { + animation: fadeIn 1.5s ease forwards; } @keyframes shimmer { @@ -213,14 +221,16 @@ } @keyframes fadeIn { - from { - opacity: .2; + 0% { + opacity: 0; } - to { + 33.33% { + opacity: 0; + } + 100% { opacity: 1; } } - .course-section-list { @include prose.prose; diff --git a/public/js/app/components/RoundInformation/RoundInformation.jsx b/public/js/app/components/RoundInformation/RoundInformation.jsx index 39489fa1..29d424dd 100644 --- a/public/js/app/components/RoundInformation/RoundInformation.jsx +++ b/public/js/app/components/RoundInformation/RoundInformation.jsx @@ -18,13 +18,13 @@ function RoundInformation({ courseCode, courseData, courseRound, semesterRoundSt const [pending, setPending] = useState(true) - const { courseRoundEmployees } = useCourseEmployees({ + const { courseRoundEmployees, isError: courseEmployeesError } = useCourseEmployees({ courseCode, selectedSemester, applicationCode: courseRound?.round_application_code, }) - const { plannedModules } = usePlannedModules({ + const { plannedModules, isError: plannedModulesError } = usePlannedModules({ courseCode, semester: selectedSemester, applicationCode: courseRound.round_application_code, @@ -35,10 +35,10 @@ function RoundInformation({ courseCode, courseData, courseRound, semesterRoundSt }, [courseRound]) useEffect(() => { - if (courseRoundEmployees && plannedModules) { + if ((courseRoundEmployees && plannedModules) || plannedModulesError || courseEmployeesError) { setPending(false) } - }, [courseRoundEmployees, plannedModules]) + }, [courseRoundEmployees, plannedModules, plannedModulesError, courseEmployeesError]) return (
diff --git a/public/js/app/components/__tests__/RoundInformation.test.js b/public/js/app/components/__tests__/RoundInformation.test.js index 047838c2..1cc2adeb 100644 --- a/public/js/app/components/__tests__/RoundInformation.test.js +++ b/public/js/app/components/__tests__/RoundInformation.test.js @@ -25,7 +25,7 @@ const defaultSemesterRoundState = { } describe('Component ', () => { - beforeAll(() => { + beforeEach(() => { usePlannedModules.mockReturnValue({ plannedModules: 'somePlannedModules', }) @@ -72,7 +72,7 @@ describe('Component ', () => { courseRound: mockCourseRound, } - useCourseEmployees.mockReturnValueOnce({ + useCourseEmployees.mockReturnValue({ courseRoundEmployees: { examiners: `${examinersData}'`, responsibles: `${responsiblesData}`, diff --git a/public/js/app/components/__tests__/RoundInformationContacts.test.js b/public/js/app/components/__tests__/RoundInformationContacts.test.js index 201aea16..4871bcfe 100644 --- a/public/js/app/components/__tests__/RoundInformationContacts.test.js +++ b/public/js/app/components/__tests__/RoundInformationContacts.test.js @@ -22,14 +22,7 @@ const withinNextSibling = element => within(nextSibling(element)) describe('Component ', () => { describe('examiners, responsibles and teachers', () => { test('shoud show headers with "missing info" text when data is missing', () => { - render( - - ) + render() const examinerLabel = screen.getByText('Examiner') expect(nextSibling(examinerLabel)).toHaveTextContent('No information inserted') @@ -41,19 +34,14 @@ describe('Component ', () => { }) test('shoud show headers with data inserted as html', () => { - useCourseEmployees.mockReturnValue({ - courseRoundEmployees: { - examiners: '

Test examiners

', - responsibles: '

Test responsibles

', - teachers: '

Test teachers

', - }, - }) render( Test examiners

', + responsibles: '

Test responsibles

', + teachers: '

Test teachers

', + }} /> ) const examinerLabel = screen.getByText('Examiner') @@ -71,58 +59,12 @@ describe('Component ', () => { expect(teacherLink).toHaveTextContent('Test teachers') expect(teacherLink).toHaveAttribute('href', '/profile/testteachers/') }) - - test('should update data when prop changes', () => { - useCourseEmployees.mockImplementation(({ applicationCode }) => - applicationCode === '1111' - ? { courseRoundEmployees: { examiners: 'Examiner for 1111' } } - : applicationCode === '3333' - ? { courseRoundEmployees: { examiners: 'Examiner for 3333' } } - : { courseRoundEmployees: { examiners: '' } } - ) - - const { rerender } = render( - - ) - - expect(nextSibling(screen.getByText('Examiner'))).toHaveTextContent('Examiner for 1111') - - rerender( - - ) - expect(nextSibling(screen.getByText('Examiner'))).toHaveTextContent('No information inserted') - - rerender( - - ) - expect(nextSibling(screen.getByText('Examiner'))).toHaveTextContent('Examiner for 3333') - }) }) describe('cource contact', () => { test('should show header and content for course contact name', () => { render( - + ) const contactLabel = screen.getByText('Contact') expect(contactLabel).toBeInTheDocument() @@ -131,12 +73,7 @@ describe('Component ', () => { "shoud NOT show header if contact name is '%s'", contactNameArg => { render( - + ) const contactLabel = screen.queryByText('Contact') expect(contactLabel).not.toBeInTheDocument() diff --git a/public/js/app/hooks/useCourseEmployees.js b/public/js/app/hooks/useCourseEmployees.js index 0b0a0df8..5517c2f3 100644 --- a/public/js/app/hooks/useCourseEmployees.js +++ b/public/js/app/hooks/useCourseEmployees.js @@ -8,17 +8,12 @@ export const useCourseEmployees = ({ courseCode, selectedSemester, applicationCo const { uri } = context.paths.api.employees - const { data, isError, setApiParams } = useApi( - getCourseEmployees, - { - uri, - courseCode, - selectedSemester, - applicationCode, - }, - {}, - {} - ) + const { data, isError, setApiParams } = useApi(getCourseEmployees, { + uri, + courseCode, + selectedSemester, + applicationCode, + }) useEffect(() => { setApiParams({ uri, courseCode, selectedSemester, applicationCode }) From 73deb9c0ed8cf0a058f501e1c763fd6ebb410c8a Mon Sep 17 00:00:00 2001 From: amirhossein-haerian Date: Thu, 29 Aug 2024 08:46:29 +0200 Subject: [PATCH 3/6] feat(KUI-1378): the optimization is ready --- .../RoundInformation/RoundInformation.jsx | 44 ++++++++++--------- public/js/app/hooks/__tests__/useApi.test.js | 32 +++++++------- public/js/app/hooks/useApi.js | 24 ++++++---- public/js/app/hooks/useCourseEmployees.js | 8 +--- public/js/app/hooks/usePlannedModules.js | 8 +--- 5 files changed, 59 insertions(+), 57 deletions(-) diff --git a/public/js/app/components/RoundInformation/RoundInformation.jsx b/public/js/app/components/RoundInformation/RoundInformation.jsx index 29d424dd..dddc929a 100644 --- a/public/js/app/components/RoundInformation/RoundInformation.jsx +++ b/public/js/app/components/RoundInformation/RoundInformation.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useMemo } from 'react' import Alert from '../../components-shared/Alert' import BankIdAlert from '../../components/BankIdAlert' @@ -16,32 +16,34 @@ function RoundInformation({ courseCode, courseData, courseRound, semesterRoundSt const selectedRoundHeader = createRoundHeader(courseRound) const { selectedSemester } = semesterRoundState - const [pending, setPending] = useState(true) + const memoizedCourseRound = useMemo(() => courseRound, [courseRound]) - const { courseRoundEmployees, isError: courseEmployeesError } = useCourseEmployees({ - courseCode, - selectedSemester, - applicationCode: courseRound?.round_application_code, - }) + const memoizedParams = useMemo( + () => ({ + courseCode, + selectedSemester, + applicationCode: memoizedCourseRound?.round_application_code, + }), + [courseCode, selectedSemester, memoizedCourseRound?.round_application_code] + ) - const { plannedModules, isError: plannedModulesError } = usePlannedModules({ - courseCode, - semester: selectedSemester, - applicationCode: courseRound.round_application_code, - }) + const { + courseRoundEmployees, + isError: courseEmployeesError, + isLoading: courseEmployeesLoading, + } = useCourseEmployees(memoizedParams) - useEffect(() => { - setPending(true) - }, [courseRound]) + const { + plannedModules, + isError: plannedModulesError, + isLoading: plannedModulesIsLoading, + } = usePlannedModules(memoizedParams) - useEffect(() => { - if ((courseRoundEmployees && plannedModules) || plannedModulesError || courseEmployeesError) { - setPending(false) - } - }, [courseRoundEmployees, plannedModules, plannedModulesError, courseEmployeesError]) + const isLoading = courseEmployeesLoading || plannedModulesIsLoading + const isError = courseEmployeesError || plannedModulesError return ( -
+

{translation.courseRoundInformation.round_header} {selectedRoundHeader}

diff --git a/public/js/app/hooks/__tests__/useApi.test.js b/public/js/app/hooks/__tests__/useApi.test.js index 13f6cfcd..f3b64173 100644 --- a/public/js/app/hooks/__tests__/useApi.test.js +++ b/public/js/app/hooks/__tests__/useApi.test.js @@ -90,28 +90,28 @@ describe('useApi', () => { }) ) - const { result } = renderHook(() => useApi(apiToCall, defaultParams, defaultValue, null)) + const { result: firstResult } = renderHook(() => useApi(apiToCall, defaultParams, defaultValue, null)) - expect(result.current.data).toStrictEqual(defaultValue) - expect(result.current.isError).toStrictEqual(false) + expect(firstResult.current.data).toStrictEqual(defaultValue) + expect(firstResult.current.isError).toStrictEqual(false) jest.advanceTimersByTime(100) expect(apiToCall).toHaveBeenCalledTimes(1) - await waitFor(() => expect(result.current.data).toStrictEqual('someNewPlannedModules')) - await waitFor(() => expect(result.current.isError).toStrictEqual(false)) + await waitFor(() => expect(firstResult.current.data).toStrictEqual('someNewPlannedModules')) + await waitFor(() => expect(firstResult.current.isError).toStrictEqual(false)) - result.current.setApiParams({ other: 'params' }) + const { result: secodResult } = renderHook(() => useApi(apiToCall, defaultParams, defaultValue, null)) - await waitFor(() => expect(result.current.data).toStrictEqual(defaultValue)) - await waitFor(() => expect(result.current.isError).toStrictEqual(false)) + await waitFor(() => expect(secodResult.current.data).toStrictEqual(defaultValue)) + await waitFor(() => expect(secodResult.current.isError).toStrictEqual(false)) jest.advanceTimersByTime(100) expect(apiToCall).toHaveBeenCalledTimes(2) - await waitFor(() => expect(result.current.data).toStrictEqual('someOtherPlannedModules')) - await waitFor(() => expect(result.current.isError).toStrictEqual(false)) + await waitFor(() => expect(secodResult.current.data).toStrictEqual('someOtherPlannedModules')) + await waitFor(() => expect(secodResult.current.isError).toStrictEqual(false)) jest.useRealTimers() }) @@ -186,18 +186,20 @@ describe('useApi', () => { }) ) - const { result } = renderHook(() => useApi(apiToCall, defaultParams, null, null)) + const { result: firstResult } = renderHook(() => useApi(apiToCall, defaultParams, null, null)) jest.advanceTimersByTime(100) - await waitFor(() => expect(result.current.isError).toStrictEqual(true)) + await waitFor(() => expect(firstResult.current.isError).toStrictEqual(true)) - result.current.setApiParams({ ...defaultParams, applicationCode: 54321 }) + const { result: secodResult } = renderHook(() => + useApi(apiToCall, { ...defaultParams, applicationCode: 54321 }, null, null) + ) - await waitFor(() => expect(result.current.isError).toStrictEqual(false)) + await waitFor(() => expect(secodResult.current.isError).toStrictEqual(false)) jest.advanceTimersByTime(100) - await waitFor(() => expect(result.current.isError).toStrictEqual(true)) + await waitFor(() => expect(secodResult.current.isError).toStrictEqual(true)) jest.useRealTimers() }) diff --git a/public/js/app/hooks/useApi.js b/public/js/app/hooks/useApi.js index f8b70421..1dd60b59 100644 --- a/public/js/app/hooks/useApi.js +++ b/public/js/app/hooks/useApi.js @@ -1,20 +1,26 @@ import { useEffect, useState } from 'react' import { STATUS } from './api/status' -export const useApi = (apiToCall, initialApiParams, defaultValue, defaulValueIfNullResponse) => { - const [apiParams, setApiParams] = useState(initialApiParams) +export const useApi = (apiToCall, apiParams, defaultValue, defaulValueIfNullResponse) => { const [data, setData] = useState(defaultValue) const [isError, setIsError] = useState(false) + const [isLoading, setIsLoading] = useState(true) useEffect(() => { const fetchData = async () => { + setIsLoading(true) setData(defaultValue) setIsError(false) - - const result = await apiToCall(apiParams) - - setData(result.data || defaulValueIfNullResponse) - setIsError(result.status === STATUS.ERROR) + try { + const result = await apiToCall(apiParams) + setData(result.data || defaulValueIfNullResponse) + setIsError(result.status === STATUS.ERROR) + } catch (error) { + setIsError(true) + setData(defaulValueIfNullResponse) + } finally { + setIsLoading(false) + } } fetchData() @@ -22,11 +28,11 @@ export const useApi = (apiToCall, initialApiParams, defaultValue, defaulValueIfN // we do not want to react on defaultValue and defaulValueIfNullResponse, because otherwise // we cannot use empty objects // eslint-disable-next-line react-hooks/exhaustive-deps - }, [apiToCall, apiParams]) + }, [apiToCall, JSON.stringify(apiParams)]) return { data, isError, - setApiParams, + isLoading, } } diff --git a/public/js/app/hooks/useCourseEmployees.js b/public/js/app/hooks/useCourseEmployees.js index 5517c2f3..6e68bf38 100644 --- a/public/js/app/hooks/useCourseEmployees.js +++ b/public/js/app/hooks/useCourseEmployees.js @@ -1,4 +1,3 @@ -import { useEffect } from 'react' import { useWebContext } from '../context/WebContext' import { useApi } from './useApi' import { getCourseEmployees } from './api/getCourseEmployees' @@ -8,19 +7,16 @@ export const useCourseEmployees = ({ courseCode, selectedSemester, applicationCo const { uri } = context.paths.api.employees - const { data, isError, setApiParams } = useApi(getCourseEmployees, { + const { data, isError, isLoading } = useApi(getCourseEmployees, { uri, courseCode, selectedSemester, applicationCode, }) - useEffect(() => { - setApiParams({ uri, courseCode, selectedSemester, applicationCode }) - }, [applicationCode, courseCode, selectedSemester, setApiParams, uri]) - return { courseRoundEmployees: data, isError, + isLoading, } } diff --git a/public/js/app/hooks/usePlannedModules.js b/public/js/app/hooks/usePlannedModules.js index 018dce15..da724f15 100644 --- a/public/js/app/hooks/usePlannedModules.js +++ b/public/js/app/hooks/usePlannedModules.js @@ -1,4 +1,3 @@ -import { useEffect } from 'react' import { useWebContext } from '../context/WebContext' import { getPlannedModules } from './api/getPlannedModules' import { useApi } from './useApi' @@ -12,21 +11,18 @@ export const usePlannedModules = ({ courseCode, semester, applicationCode }) => const basePath = context.paths.api.plannedSchemaModules.uri - const { data, isError, setApiParams } = useApi( + const { data, isError, isLoading } = useApi( getPlannedModules, { basePath, courseCode, semester, applicationCode }, null, MISSING_INFO ) - useEffect(() => { - setApiParams({ basePath, courseCode, semester, applicationCode }) - }, [applicationCode, basePath, courseCode, semester, setApiParams]) - const plannedModules = data === MISSING_INFO ? missingInfoLabel : data return { plannedModules, isError, + isLoading, } } From f1e229340a7cefff65367b7228a6298643d520ab Mon Sep 17 00:00:00 2001 From: amirhossein-haerian Date: Thu, 29 Aug 2024 10:39:26 +0200 Subject: [PATCH 4/6] fix(KUI-1378): the json.stringify is now removed and more memorization has been used --- public/js/app/hooks/__tests__/useApi.test.js | 19 +++++++++++-------- public/js/app/hooks/useApi.js | 2 +- public/js/app/hooks/useCourseEmployees.js | 18 ++++++++++++------ public/js/app/hooks/usePlannedModules.js | 16 +++++++++++----- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/public/js/app/hooks/__tests__/useApi.test.js b/public/js/app/hooks/__tests__/useApi.test.js index f3b64173..04d8e07a 100644 --- a/public/js/app/hooks/__tests__/useApi.test.js +++ b/public/js/app/hooks/__tests__/useApi.test.js @@ -39,9 +39,10 @@ describe('useApi', () => { }) test('calls apiToCall with given parameters', async () => { - const { result } = renderHook(() => useApi(apiToCall, { one: 'one', two: 2 }, null, null)) + const apiParams1 = { one: 'one', two: 2 } + const { result } = renderHook(() => useApi(apiToCall, apiParams1, null, null)) - expect(apiToCall).toHaveBeenLastCalledWith({ one: 'one', two: 2 }) + expect(apiToCall).toHaveBeenLastCalledWith(apiParams1) await waitFor(() => expect(result.current.data).toStrictEqual('somePlannedModules')) @@ -50,15 +51,18 @@ describe('useApi', () => { data: 'someData', }) - const { result: result2 } = renderHook(() => useApi(anotherApiToCall, { two: 'two', three: 3 }, null, null)) + const apiParams2 = { two: 'two', three: 3 } - expect(anotherApiToCall).toHaveBeenLastCalledWith({ two: 'two', three: 3 }) + const { result: result2 } = renderHook(() => useApi(anotherApiToCall, apiParams2, null, null)) + + expect(anotherApiToCall).toHaveBeenLastCalledWith(apiParams2) await waitFor(() => expect(result2.current.data).toStrictEqual('someData')) }) test('returns data from apiToCall', async () => { - const { result } = renderHook(() => useApi(apiToCall, {}, null, null)) + const params = {} + const { result } = renderHook(() => useApi(apiToCall, params, null, null)) await waitFor(() => expect(result.current.data).toStrictEqual('somePlannedModules')) }) @@ -192,9 +196,8 @@ describe('useApi', () => { await waitFor(() => expect(firstResult.current.isError).toStrictEqual(true)) - const { result: secodResult } = renderHook(() => - useApi(apiToCall, { ...defaultParams, applicationCode: 54321 }, null, null) - ) + const newParams = { ...defaultParams, applicationCode: 54321 } + const { result: secodResult } = renderHook(() => useApi(apiToCall, newParams, null, null)) await waitFor(() => expect(secodResult.current.isError).toStrictEqual(false)) jest.advanceTimersByTime(100) diff --git a/public/js/app/hooks/useApi.js b/public/js/app/hooks/useApi.js index 1dd60b59..2dd6d7c0 100644 --- a/public/js/app/hooks/useApi.js +++ b/public/js/app/hooks/useApi.js @@ -28,7 +28,7 @@ export const useApi = (apiToCall, apiParams, defaultValue, defaulValueIfNullResp // we do not want to react on defaultValue and defaulValueIfNullResponse, because otherwise // we cannot use empty objects // eslint-disable-next-line react-hooks/exhaustive-deps - }, [apiToCall, JSON.stringify(apiParams)]) + }, [apiToCall, apiParams]) return { data, diff --git a/public/js/app/hooks/useCourseEmployees.js b/public/js/app/hooks/useCourseEmployees.js index 6e68bf38..fb0186bf 100644 --- a/public/js/app/hooks/useCourseEmployees.js +++ b/public/js/app/hooks/useCourseEmployees.js @@ -1,3 +1,4 @@ +import { useMemo } from 'react' import { useWebContext } from '../context/WebContext' import { useApi } from './useApi' import { getCourseEmployees } from './api/getCourseEmployees' @@ -7,12 +8,17 @@ export const useCourseEmployees = ({ courseCode, selectedSemester, applicationCo const { uri } = context.paths.api.employees - const { data, isError, isLoading } = useApi(getCourseEmployees, { - uri, - courseCode, - selectedSemester, - applicationCode, - }) + const requestData = useMemo( + () => ({ + uri, + courseCode, + selectedSemester, + applicationCode, + }), + [uri, courseCode, selectedSemester, applicationCode] + ) + + const { data, isError, isLoading } = useApi(getCourseEmployees, requestData) return { courseRoundEmployees: data, diff --git a/public/js/app/hooks/usePlannedModules.js b/public/js/app/hooks/usePlannedModules.js index da724f15..6588cb41 100644 --- a/public/js/app/hooks/usePlannedModules.js +++ b/public/js/app/hooks/usePlannedModules.js @@ -1,3 +1,4 @@ +import { useMemo } from 'react' import { useWebContext } from '../context/WebContext' import { getPlannedModules } from './api/getPlannedModules' import { useApi } from './useApi' @@ -11,13 +12,18 @@ export const usePlannedModules = ({ courseCode, semester, applicationCode }) => const basePath = context.paths.api.plannedSchemaModules.uri - const { data, isError, isLoading } = useApi( - getPlannedModules, - { basePath, courseCode, semester, applicationCode }, - null, - MISSING_INFO + const requestData = useMemo( + () => ({ + basePath, + courseCode, + semester, + applicationCode, + }), + [basePath, courseCode, semester, applicationCode] ) + const { data, isError, isLoading } = useApi(getPlannedModules, requestData, null, MISSING_INFO) + const plannedModules = data === MISSING_INFO ? missingInfoLabel : data return { From b491d9f7cb97bfaee32ecb97cf89356ce7d33784 Mon Sep 17 00:00:00 2001 From: amirhossein-haerian Date: Fri, 30 Aug 2024 08:00:34 +0200 Subject: [PATCH 5/6] fix(KUI-1378): improve the code and fix an issue --- .../js/app/components/RoundInformation/PlannedModules.jsx | 3 --- .../RoundInformation/RoundInformationInfoGrid.jsx | 5 +---- public/js/app/hooks/usePlannedModules.js | 6 +++--- 3 files changed, 4 insertions(+), 10 deletions(-) delete mode 100644 public/js/app/components/RoundInformation/PlannedModules.jsx diff --git a/public/js/app/components/RoundInformation/PlannedModules.jsx b/public/js/app/components/RoundInformation/PlannedModules.jsx deleted file mode 100644 index 5bab6da4..00000000 --- a/public/js/app/components/RoundInformation/PlannedModules.jsx +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react' - -export const PlannedModules = ({ plannedModules }) => diff --git a/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx b/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx index ceb880a6..cdd2cb98 100644 --- a/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx +++ b/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx @@ -3,7 +3,6 @@ import { useLanguage } from '../../hooks/useLanguage' import InfoModal from '../InfoModal' import { CourseMemoLink } from './CourseMemoLink' import { CourseScheduleLink } from './CourseScheduleLink' -import { PlannedModules } from './PlannedModules' // Calculates if a "Show more" button should be displayed, and creates props for content and button elements. const useShowMoreContent = content => { @@ -117,9 +116,7 @@ function RoundInformationInfoGrid({ courseCode, courseRound, plannedModules }) {

{courseRound.round_seats || translation.courseRoundInformation.round_no_seats_limit}

- - - + diff --git a/public/js/app/hooks/usePlannedModules.js b/public/js/app/hooks/usePlannedModules.js index 6588cb41..82e840c0 100644 --- a/public/js/app/hooks/usePlannedModules.js +++ b/public/js/app/hooks/usePlannedModules.js @@ -6,7 +6,7 @@ import { useMissingInfo } from './useMissingInfo' const MISSING_INFO = '' -export const usePlannedModules = ({ courseCode, semester, applicationCode }) => { +export const usePlannedModules = ({ courseCode, selectedSemester, applicationCode }) => { const context = useWebContext() const { missingInfoLabel } = useMissingInfo() @@ -16,10 +16,10 @@ export const usePlannedModules = ({ courseCode, semester, applicationCode }) => () => ({ basePath, courseCode, - semester, + selectedSemester, applicationCode, }), - [basePath, courseCode, semester, applicationCode] + [basePath, courseCode, selectedSemester, applicationCode] ) const { data, isError, isLoading } = useApi(getPlannedModules, requestData, null, MISSING_INFO) From 812ebbffa9dc1394fb890ca606dbcd018b5a59c0 Mon Sep 17 00:00:00 2001 From: amirhossein-haerian Date: Fri, 30 Aug 2024 14:52:30 +0200 Subject: [PATCH 6/6] fix(KUI-1378): the issue for the getPlannedModule is now fixed --- public/js/app/hooks/usePlannedModules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/app/hooks/usePlannedModules.js b/public/js/app/hooks/usePlannedModules.js index 82e840c0..5132ff96 100644 --- a/public/js/app/hooks/usePlannedModules.js +++ b/public/js/app/hooks/usePlannedModules.js @@ -16,7 +16,7 @@ export const usePlannedModules = ({ courseCode, selectedSemester, applicationCod () => ({ basePath, courseCode, - selectedSemester, + semester: selectedSemester, applicationCode, }), [basePath, courseCode, selectedSemester, applicationCode]