Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues/KUI 1378 fetch data loader #369

Merged
merged 7 commits into from
Aug 30, 2024
43 changes: 43 additions & 0 deletions public/css/kursinfo-web.scss
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,18 @@
}

.roundInformation {
position: relative;
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;
Expand Down Expand Up @@ -187,7 +196,41 @@
background-color: var(--color-background);
}
}
.shimmer-effect::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
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 1.5s ease forwards;
}

@keyframes shimmer {
to {
background-position-x: 0%;
}
}

@keyframes fadeIn {
0% {
opacity: 0;
}
33.33% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.course-section-list {
@include prose.prose;

Expand Down
11 changes: 0 additions & 11 deletions public/js/app/components/RoundInformation/PlannedModules.jsx

This file was deleted.

45 changes: 36 additions & 9 deletions public/js/app/components/RoundInformation/RoundInformation.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react'
import React, { useMemo } 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'

Expand All @@ -14,13 +16,43 @@ function RoundInformation({ courseCode, courseData, courseRound, semesterRoundSt
const selectedRoundHeader = createRoundHeader(courseRound)
const { selectedSemester } = semesterRoundState

const memoizedCourseRound = useMemo(() => courseRound, [courseRound])

const memoizedParams = useMemo(
() => ({
courseCode,
selectedSemester,
applicationCode: memoizedCourseRound?.round_application_code,
}),
[courseCode, selectedSemester, memoizedCourseRound?.round_application_code]
)

const {
courseRoundEmployees,
isError: courseEmployeesError,
isLoading: courseEmployeesLoading,
} = useCourseEmployees(memoizedParams)

const {
plannedModules,
isError: plannedModulesError,
isLoading: plannedModulesIsLoading,
} = usePlannedModules(memoizedParams)

const isLoading = courseEmployeesLoading || plannedModulesIsLoading
const isError = courseEmployeesError || plannedModulesError

return (
<div className="roundInformation">
<div className={`roundInformation ${!isError && isLoading ? 'shimmer-effect' : 'fadeIn'}`}>
<h3>
{translation.courseRoundInformation.round_header} {selectedRoundHeader}
</h3>

<RoundInformationInfoGrid courseCode={courseCode} courseRound={courseRound} selectedSemester={selectedSemester} />
<RoundInformationInfoGrid
courseCode={courseCode}
courseRound={courseRound}
plannedModules={plannedModules ?? {}}
/>

<BankIdAlert tutoringForm={courseRound.round_tutoring_form} fundingType={courseRound.round_funding_type} />

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

<h3>{translation.courseLabels.header_contact}</h3>
<RoundInformationContacts
courseCode={courseCode}
courseData={courseData}
courseRound={courseRound}
selectedSemester={selectedSemester}
/>
<RoundInformationContacts courseData={courseData} courseRoundEmployees={courseRoundEmployees ?? {}} />
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<div className="roundInformation__contacts">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down Expand Up @@ -70,7 +69,7 @@ const Item = ({ children, html, title, infoModalContent }) => {
)
}

function RoundInformationInfoGrid({ courseCode, courseRound, selectedSemester }) {
function RoundInformationInfoGrid({ courseCode, courseRound, plannedModules }) {
const { translation } = useLanguage()

return (
Expand Down Expand Up @@ -117,9 +116,7 @@ function RoundInformationInfoGrid({ courseCode, courseRound, selectedSemester })
<p>{courseRound.round_seats || translation.courseRoundInformation.round_no_seats_limit}</p>
</Item>
<Item title={translation.courseRoundInformation.round_target_group} html={courseRound.round_target_group} />
<Item title={translation.courseRoundInformation.round_time_slots}>
<PlannedModules courseCode={courseCode} courseRound={courseRound} selectedSemester={selectedSemester} />
</Item>
<Item title={translation.courseRoundInformation.round_time_slots} html={plannedModules} />
<Item title={translation.courseLabels.label_schedule}>
<CourseScheduleLink courseRound={courseRound} />
</Item>
Expand Down
4 changes: 2 additions & 2 deletions public/js/app/components/__tests__/RoundInformation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const defaultSemesterRoundState = {
}

describe('Component <RoundInformation>', () => {
beforeAll(() => {
beforeEach(() => {
usePlannedModules.mockReturnValue({
plannedModules: 'somePlannedModules',
})
Expand Down Expand Up @@ -72,7 +72,7 @@ describe('Component <RoundInformation>', () => {
courseRound: mockCourseRound,
}

useCourseEmployees.mockReturnValueOnce({
useCourseEmployees.mockReturnValue({
courseRoundEmployees: {
examiners: `<span>${examinersData}</span>'`,
responsibles: `<span>${responsiblesData}</span>`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,7 @@ const withinNextSibling = element => within(nextSibling(element))
describe('Component <RoundInformationContacts>', () => {
describe('examiners, responsibles and teachers', () => {
test('shoud show headers with "missing info" text when data is missing', () => {
render(
<RoundInformationContacts
courseCode={'ABC123'}
courseData={{ course_contact_name: undefined }}
courseRound={{}}
selectedSemester={''}
/>
)
render(<RoundInformationContacts courseData={{}} courseRoundEmployees={{}} />)
const examinerLabel = screen.getByText('Examiner')
expect(nextSibling(examinerLabel)).toHaveTextContent('No information inserted')

Expand All @@ -41,19 +34,14 @@ describe('Component <RoundInformationContacts>', () => {
})

test('shoud show headers with data inserted as html', () => {
useCourseEmployees.mockReturnValue({
courseRoundEmployees: {
examiners: '<p class="person"><a href="/profile/testexaminers/">Test examiners</a></p>',
responsibles: '<p class="person"><a href="/profile/testresponsibles/">Test responsibles</a></p>',
teachers: '<p class="person"><a href="/profile/testteachers/">Test teachers</a></p>',
},
})
render(
<RoundInformationContacts
courseCode={'ABC123'}
courseData={{ courseInfo: { course_contact_name: undefined } }}
courseRound={{}}
selectedSemester={''}
courseRoundEmployees={{
examiners: '<p class="person"><a href="/profile/testexaminers/">Test examiners</a></p>',
responsibles: '<p class="person"><a href="/profile/testresponsibles/">Test responsibles</a></p>',
teachers: '<p class="person"><a href="/profile/testteachers/">Test teachers</a></p>',
}}
/>
)
const examinerLabel = screen.getByText('Examiner')
Expand All @@ -71,58 +59,12 @@ describe('Component <RoundInformationContacts>', () => {
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(
<RoundInformationContacts
courseCode={'ABC123'}
courseData={{ courseInfo: { course_contact_name: undefined } }}
courseRound={{ round_application_code: '1111' }}
selectedSemester={''}
/>
)

expect(nextSibling(screen.getByText('Examiner'))).toHaveTextContent('Examiner for 1111')

rerender(
<RoundInformationContacts
courseCode={'ABC123'}
courseData={{ courseInfo: { course_contact_name: undefined } }}
courseRound={{ round_application_code: '2222' }}
selectedSemester={''}
/>
)
expect(nextSibling(screen.getByText('Examiner'))).toHaveTextContent('No information inserted')

rerender(
<RoundInformationContacts
courseCode={'ABC123'}
courseData={{ courseInfo: { course_contact_name: undefined } }}
courseRound={{ round_application_code: '3333' }}
selectedSemester={''}
/>
)
expect(nextSibling(screen.getByText('Examiner'))).toHaveTextContent('Examiner for 3333')
})
})

describe('cource contact', () => {
test('should show header and content for course contact name', () => {
render(
<RoundInformationContacts
courseCode={'ABC123'}
courseData={{ course_contact_name: 'Contact name' }}
courseRound={{}}
selectedSemester={''}
/>
<RoundInformationContacts courseData={{ course_contact_name: 'Contact name' }} courseRoundEmployees={{}} />
)
const contactLabel = screen.getByText('Contact')
expect(contactLabel).toBeInTheDocument()
Expand All @@ -131,12 +73,7 @@ describe('Component <RoundInformationContacts>', () => {
"shoud NOT show header if contact name is '%s'",
contactNameArg => {
render(
<RoundInformationContacts
courseCode={'ABC123'}
courseData={{ course_contact_name: contactNameArg }}
courseRound={{}}
selectedSemester={''}
/>
<RoundInformationContacts courseData={{ course_contact_name: contactNameArg }} courseRoundEmployees={{}} />
)
const contactLabel = screen.queryByText('Contact')
expect(contactLabel).not.toBeInTheDocument()
Expand Down
Loading
Loading