Skip to content

Commit

Permalink
feat: Add weekly schedule UI
Browse files Browse the repository at this point in the history
  • Loading branch information
AuraAlba committed Feb 1, 2024
1 parent 8540b79 commit 7314377
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 14 deletions.
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"date-fns": "^3.3.1",
"prop-types": "15.8.1",
"react": "16.14.0",
"react-date-range": "^2.0.0-alpha.4",
"react-dom": "16.14.0",
"react-intl": "^5.25.1",
"react-paragon-topaz": "^1.2.1",
Expand Down
19 changes: 18 additions & 1 deletion src/features/Dashboard/DashboardPage/_test_/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('DashboardPage component', () => {
},
],
},
classes: {
classesNoInstructors: {
data: [
{
classId: 'ccx-v1:demo+demo1+2020+ccx1',
Expand All @@ -35,6 +35,21 @@ describe('DashboardPage component', () => {
},
],
},
classes: {
data: [
{
classId: 'ccx-v1:demo+demo1+2020+ccx2',
className: 'ccx 2',
masterCourseName: 'Demo Course 1',
instructors: [],
numberOfStudents: 0,
numberOfPendingStudents: 0,
maxStudents: 20,
startDate: '2024-01-23T21:50:51Z',
endDate: null,
},
],
},
},
};

Expand All @@ -56,5 +71,7 @@ describe('DashboardPage component', () => {
expect(getByText('ccx 1')).toBeInTheDocument();
expect(getByText('Demo Course 1')).toBeInTheDocument();
expect(getByText('License Name 1')).toBeInTheDocument();
expect(getByText('Class schedule')).toBeInTheDocument();
expect(getByText('ccx 2')).toBeInTheDocument();
});
});
6 changes: 6 additions & 0 deletions src/features/Dashboard/DashboardPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import StudentsMetrics from 'features/Students/StudentsMetrics';
import LicensesTable from 'features/Licenses/LicensesTable';
import { Button } from 'react-paragon-topaz';
import InstructorAssignSection from 'features/Dashboard/InstructorAssignSection';
import WeeklySchedule from 'features/Dashboard/WeeklySchedule';

import { fetchLicensesData } from 'features/Dashboard/data';
import { updateActiveTab } from 'features/Main/data/slice';
Expand Down Expand Up @@ -50,6 +51,11 @@ const DashboardPage = () => {
{Object.keys(selectedInstitution).length > 0 ? `Welcome to ${selectedInstitution?.name}` : `Welcome to ${stateInstitution[0]?.name}`}
</h2>
<StudentsMetrics />
<Row className="schedule-section">
<Col lg="9" xs="12">
<WeeklySchedule />
</Col>
</Row>
<Row>
<Col lg="9" xs="12">
<div className="license-section">
Expand Down
4 changes: 4 additions & 0 deletions src/features/Dashboard/DashboardPage/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@
box-shadow: 0px 3px 12px 0px rgba(0, 0, 0, 0.16);
border-radius: 0.375rem;
}

.schedule-section {
margin-bottom: 2rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jest.mock('@edx/frontend-platform/logging', () => ({
describe('Instructor Assign component', () => {
const mockStore = {
dashboard: {
classes: {
classesNoInstructors: {
data: [
{
classId: 'ccx-v1:demo+demo1+2020+ccx1',
Expand Down
4 changes: 2 additions & 2 deletions src/features/Dashboard/InstructorAssignSection/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import 'features/Dashboard/InstructorAssignSection/index.scss';
const InstructorAssignSection = () => {
const dispatch = useDispatch();
const selectedInstitution = useSelector((state) => state.main.selectedInstitution);
const classesData = useSelector((state) => state.dashboard.classes.data);
const classesData = useSelector((state) => state.dashboard.classesNoInstructors.data);
const [classCards, setClassCards] = useState([]);
const numberOfClasses = 2;

useEffect(() => {
if (Object.keys(selectedInstitution).length > 0) {
dispatch(fetchClassesData(selectedInstitution?.id));
dispatch(fetchClassesData(selectedInstitution?.id, false));
}
}, [selectedInstitution, dispatch]);

Expand Down
59 changes: 59 additions & 0 deletions src/features/Dashboard/WeeklySchedule/_test_/index.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import WeeklySchedule from 'features/Dashboard/WeeklySchedule';
import '@testing-library/jest-dom/extend-expect';
import { renderWithProviders } from 'test-utils';

jest.mock('@edx/frontend-platform/logging', () => ({
logError: jest.fn(),
}));

describe('WeeklySchedule component', () => {
const mockStore = {
dashboard: {
classes: {
data: [
{
classId: 'ccx-v1:demo+demo1+2020+ccx1',
className: 'ccx 1',
masterCourseName: 'Demo Course 1',
instructors: [
'instructor1',
],
numberOfStudents: 0,
numberOfPendingStudents: 0,
maxStudents: 20,
startDate: '2024-01-23T21:50:51Z',
endDate: null,
},
{
classId: 'ccx-v1:demo+demo1+2020+ccx2',
className: 'ccx 2',
masterCourseName: 'Demo Course 1',
instructors: [
'instructor1',
],
numberOfStudents: 0,
numberOfPendingStudents: 0,
maxStudents: 20,
startDate: '2023-10-02T12:58:43Z',
endDate: null,
},
],
},
},
};
const component = renderWithProviders(
<WeeklySchedule />,
{ preloadedState: mockStore },
);

test('renders components', () => {
const { getByText } = component;

expect(getByText('Class schedule')).toBeInTheDocument();
expect(getByText('ccx 1')).toBeInTheDocument();
expect(getByText('Jan 23, 2024')).toBeInTheDocument();
expect(getByText('ccx 2')).toBeInTheDocument();
expect(getByText('Oct 2, 2023')).toBeInTheDocument();
});
});
79 changes: 79 additions & 0 deletions src/features/Dashboard/WeeklySchedule/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';

import { DateRange } from 'react-date-range';
import {
startOfWeek,
endOfWeek,
format,
} from 'date-fns';

import { fetchClassesData } from 'features/Dashboard/data';

import 'features/Dashboard/WeeklySchedule/index.scss';

const WeeklySchedule = () => {
const dispatch = useDispatch();
const selectedInstitution = useSelector((state) => state.main.selectedInstitution);
const classesData = useSelector((state) => state.dashboard.classes.data);
const [classList, setClassList] = useState([]);
const startWeek = startOfWeek(new Date());
const endWeek = endOfWeek(new Date());
const [stateDate, setStateDate] = useState([
{
startDate: startWeek,
endDate: endWeek,
key: 'selection',
},
]);
const numberOfClasses = 3;

useEffect(() => {
if (Object.keys(selectedInstitution).length > 0) {
dispatch(fetchClassesData(selectedInstitution?.id, true));
}
}, [selectedInstitution, dispatch]);

useEffect(() => {
// Display only the first 'NumberOfClasses' on the homepage.
if (classesData.length > numberOfClasses) {
setClassList(classesData.slice(0, numberOfClasses));
} else {
setClassList(classesData);
}
}, [classesData]);

return (
<>
<div className="header-schedule">
<h3>Class schedule</h3>
</div>
<div className="content-schedule d-flex justify-content-between">
<div className="container-class-schedule">
{classList.map(classInfo => {
const date = format(new Date(classInfo?.startDate), 'PP');
return (
<div className="class-schedule" key={classInfo?.classId}>
<div className="class-text">
<p className="class-name">{classInfo?.className}</p>
<p className="class-descr">
<i className="fa-sharp fa-regular fa-calendar-day" />{date}
</p>
</div>
</div>
);
})}
</div>
<DateRange
showDateDisplay={false}
onChange={item => setStateDate([item.selection])}
moveRangeOnFirstSelection={false}
ranges={stateDate}
rangeColors={['#e4faff']}
/>
</div>
</>
);
};

export default WeeklySchedule;
87 changes: 87 additions & 0 deletions src/features/Dashboard/WeeklySchedule/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
@import "assets/colors.scss";

.header-schedule {
background-color: $primary;
padding: 1rem;
border-top-right-radius: 0.375rem;
border-top-left-radius: 0.375rem;

h3 {
color: $color-white;
margin: 0;
}
}

.content-schedule {
box-shadow: 0px 3px 12px 0px rgba(0, 0, 0, 0.16);
border-radius: 0.375rem;

.rdrDay:not(.rdrDayPassive) .rdrInRange ~ .rdrDayNumber span,
.rdrDay:not(.rdrDayPassive) .rdrStartEdge ~ .rdrDayNumber span,
.rdrDay:not(.rdrDayPassive) .rdrEndEdge ~ .rdrDayNumber span,
.rdrDay:not(.rdrDayPassive) .rdrSelected ~ .rdrDayNumber span {
color: $primary;
}

.rdrStartEdge {
border-top: 1px solid $primary;
border-left: 1px solid $primary;
border-bottom: 1px solid $primary;
}

.rdrInRange {
border-top: 1px solid $primary;
border-bottom: 1px solid $primary;
}

.rdrEndEdge {
border-top: 1px solid $primary;
border-right : 1px solid $primary;
border-bottom: 1px solid $primary;
}

.rdrCalendarWrapper {
border-radius: 0.375rem;
}

.rdrMonthAndYearPickers select,
.rdrMonthAndYearPickers select {
font-weight: 700;
}
}

.container-class-schedule {
width: 100%;
background: $color-white;
padding: 0.8rem;
border-radius: 0.375rem;
border-right: 1px solid $gray-20;

.class-schedule {
margin-top: 0.5rem;
border-bottom: 1px solid $gray-20;

.class-name {
margin: 0;
font-weight: 600;
color: $primary;
}

.class-descr {
margin: 0;
font-size: 12px;
}

.fa-calendar-day {
margin-right: 8px;
}
}

.class-text {
border-left: 3px solid $primary;
padding-left: 1rem;
padding-left: 1rem;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
}
}
Loading

0 comments on commit 7314377

Please sign in to comment.