Source

components/Dashboard.js

import Container from './Container'
import PropTypes from 'prop-types'
import {
	CartesianGrid,
	Legend,
	Line,
	LineChart,
	PolarAngleAxis,
	PolarGrid,
	Radar,
	RadarChart,
	ReferenceLine,
	ResponsiveContainer,
	Tooltip,
	XAxis,
	YAxis,
} from 'recharts'

/**
 * @var {object[]} data
 * @memberof Dashboard
 * @description Mock data that represents progresses of individual courses containing progress from 3 different students.
 * @example
 * [
 * {
 *  subject: 'ENMA 601',
 *  A: 50,
 *  B: 76,
 *  C: 90,
 *  fullMark: 150
 * }
 * ]
 */
const data = [
	{
		subject: 'ENMA 600',
		A: 50,
		B: 98,
		C: 150,
		fullMark: 150,
	},
	{
		subject: 'ENMA 601',
		A: 48,
		B: 87,
		C: 130,
		fullMark: 150,
	},
	{
		subject: 'ENMA 603',
		A: 52,
		B: 71,
		C: 120,
		fullMark: 150,
	},
	{
		subject: 'ENMA 604',
		A: 99,
		B: 120,
		C: 150,
		fullMark: 150,
	},
	{
		subject: 'ENMA 614',
		A: 62,
		B: 70,
		C: 120,
		fullMark: 150,
	},
	{
		subject: 'ENMA 715',
		A: 25,
		B: 55,
		C: 130,
		fullMark: 150,
	},
]

/**
 * @var {object[]} timeOfCompletion
 * @memberof Dashboard
 * @description Mock data that represents that time of completion of modules/assignments aggregated over time binned by months.
 * @example
 * [
 * {
 * name: "January",
 * you: "385",
 * },
 * ]
 */
const timeOfCompletion = [
	{
		name: 'January',
		you: 100,
	},
	{
		name: 'February',
		you: 195,
	},
	{
		name: 'March',
		you: 305,
	},
	{
		name: 'April',
		you: 380,
	},
	{
		name: 'May',
		you: 370,
	},
	{
		name: 'June',
		you: 265,
	},
	{
		name: 'July',
		you: 220,
	},
	{
		name: 'August',
		you: 175,
	},
	{
		name: 'September',
		you: 140,
	},
	{
		name: 'October',
		you: 100,
	},
	{
		name: 'November',
		you: 80,
	},
	{
		name: 'December',
		you: 65,
	},
]
/**
 * @name Dashboard
 * @component
 * @category Program
 * @returns {React.ReactHTMLElement} - The Dashboard page
 * @description A React component that renders the Dashboard page completely
 */
export default function Dashboard() {
	return (
		<section className="w-full overflow-x-hidden">
			<div className="w-full h-auto xl:h-72 bg-gray-50 flex flex-col xl:flex-row justify-between items-center xl:content-around shadow-md border-b-2 border-gray-50 ">
				<div className="w-full xl:w-1/4 h-full text-center px-3 py-3">
					<ResponsiveContainer width="100%" height="80%">
						<LineChart
							width={500}
							height={300}
							data={timeOfCompletion}
							margin={{
								top: 20,
								right: 50,
								left: 20,
								bottom: 5,
							}}
						>
							<CartesianGrid strokeDasharray="3 3" />
							<XAxis dataKey="name" />
							<YAxis type="number" domain={[0, 400]} />
							<Tooltip />
							<Line
								dataKey="you"
								type="monotone"
								stroke="#92C1E9"
								dot={{ stroke: '#92C1E9', strokeWidth: 1 }}
							/>
						</LineChart>
					</ResponsiveContainer>
					<h3 className="text-lg text-gray-300">
						Estimated Time of Completion
					</h3>
				</div>
				<div className="w-4/5 xl:w-2/4 h-full text-center border-b-2 border-t-2 xl:border-l-2 xl:border-r-2 xl:border-t-0 xl:border-b-0 border-gray-200 px-3 py-3">
					<ResponsiveContainer width="100%" height="80%">
						<RadarChart
							cx="50%"
							cy="50%"
							outerRadius="80%"
							data={data}
						>
							<PolarGrid />
							<PolarAngleAxis dataKey="subject" />
							<Radar
								name="Current semester"
								dataKey="A"
								stroke="#e74d3c"
								fill="#e74d3c"
								fillOpacity={0.5}
							/>
							<Radar
								name="Next semester"
								dataKey="B"
								stroke="#f39d12"
								fill="#f39d12"
								fillOpacity={0.5}
							/>
							<Radar
								name="Projected semester"
								dataKey="C"
								stroke="#7ccc63"
								fill="#7ccc63"
								fillOpacity={0.5}
							/>
							<Legend
								iconType={'diamond'}
								layout="vertical"
								align="right"
								verticalAlign="middle"
								margin={{
									top: 0,
									right: 0,
									bottom: 0,
									left: 150,
								}}
							/>
						</RadarChart>
					</ResponsiveContainer>
					<h3 className="text-lg text-gray-300">
						Course Material Matrix
					</h3>
				</div>
				<div className="w-full xl:w-1/4 h-full text-center px-3 py-3 ">
					<div className="h-4/5 flex items-center justify-center">
						<h2 className="text-7xl">
							<span className="text-yellow-500">528</span>/1500
						</h2>
					</div>
					<h3 className="text-lg text-gray-300">Hours Completed</h3>
				</div>
			</div>
			<Container>
				<div className="w-full flex flex-col flex-wrap md:px-4 md:py-3">
					<div className="flex flex-col lg:flex-row relative max-w-full">
						<Panel className="md:mx-4 md:my-4 my-2 lg:w-1/2 w-full">
							<h1 className="text-xl my-2">Your assignments</h1>
							<RenderLineChart />
						</Panel>
						<Panel className="md:mx-4 md:my-4 my-2 lg:w-1/2 w-full">
							<h1 className="text-xl my-2">Your courses</h1>
						</Panel>
					</div>

					<div className="flex flex-col lg:flex-row relative max-w-full">
						<Panel className="md:mx-4 md:my-4 my-2 lg:w-1/2 w-full">
							<h1 className="text-xl my-2">
								Assignment type scores
							</h1>
						</Panel>
						<Panel className="md:mx-4 md:my-4 my-2 lg:w-1/2 w-full">
							<h1 className="text-xl my-2">
								Module learning format
							</h1>
						</Panel>
					</div>
				</div>
			</Container>
		</section>
	)
}

/**
 * @name Panel
 * @function
 * @memberof Dashboard
 * @description A wrapper component that adds styles and different size variations to the child component that is being passed in via props.
 * @param {React.ReactChild} children - A React Component that we want to render inside the panel wrapper
 * @param {string} className - A string of values that will be inserted into the HTML class attribute that is present in the returned wrapper
 * @returns {React.ReactHTMLElement} - The complete child argument wrapped in a div with the appropriate styles applied
 */
const Panel = ({ children, className }) => {
	return (
		<div
			className={`bg-gray-50 border border-gray-100 rounded-sm shadow-md w-full md:w-2/3 h-auto lg:w-1/2 md:h-96 lg:h-96 max-h-screen relative py-2 px-3 ${className}`}
		>
			{children}
		</div>
	)
}

/**
 * @name RenderLineChart
 * @function
 * @memberof Dashboard
 * @description A simple wrapper component that contains mock data for the line chart. This is a temporary solution until we can get the data from the API.
 * @returns {React.Component} - The line chart component that handles the way the data is visualized
 * @todo Replace the mock data with the data from the API
 */
const RenderLineChart = () => {
	const data = [
		{
			name: 'Assignment 1',
			you: 95,
			avg: 96,
		},
		{
			name: 'Assignment 2',
			you: 95,
			avg: 74,
		},
		{
			name: 'Assignment 3',
			you: 78,
			avg: 57,
		},
		{
			name: 'Assignment 4',
			you: 64,
			avg: 48,
		},
		{
			name: 'Assignment 5',
			you: 30,
			avg: 76,
		},
		{
			name: 'Assignment 6',
			you: 76,
			avg: 80,
		},
		{
			name: 'Assignment 7',
			you: 80,
			avg: 91,
		},
	]

	return (
		<ResponsiveContainer width="100%" height="80%">
			<LineChart
				width={500}
				height={300}
				data={data}
				margin={{
					top: 20,
					right: 50,
					left: 20,
					bottom: 5,
				}}
			>
				<CartesianGrid strokeDasharray="3 3" />
				<XAxis dataKey="name" />
				<YAxis type="number" domain={[0, 100]} />
				<Tooltip />
				<Line
					dataKey="avg"
					type="monotone"
					stroke="#82ca9d"
					dot={{ stroke: 'black', strokeWidth: 1 }}
				/>
				<Line
					dataKey="you"
					type="monotone"
					stroke="#ffc658"
					dot={{ stroke: 'black', strokeWidth: 1 }}
				/>
				<ReferenceLine
					y={75}
					stroke="red"
					isFront={true}
					strokeDasharray="2 2"
				/>
			</LineChart>
		</ResponsiveContainer>
	)
}