Link to project: https://amber-frontend.vercel.app
Link to the frontend's repo: https://github.com/hiluan/amber-frontend/
Link to the backend's repo: https://github.com/hiluan/amber-backend/
amber-assessment-luan-pham-walk-through.mp4
Tech used: React.js, Redux.js (Redux Toolkit), Node.js, Express.js, Framer Motion, React-Icons, Cors, DotEnv, MongoDB, Heroku, AWS Amplify.
- Frontend with React.js, Redux.js (Redux Toolkit), Framer Motion, React-Icons, AWS Amplify:
- React.js: Front-point App built to display the provided sample data following the prompt.
- Redux.js: This library is used for managing and centralizing the app state per request from the prompt.
- Framer Motion: helps create animated effects.
- AWS Amplify: Amazon cloud service is used for hosting the frontend.
- Backend with Node.js, Express.js, Cors, DotEnv, MongoDB, and Heroku:
- Node.js: End-point App built to connect to our database for reading and updating provided sample data in real-time.
- MongoDB: A cluster and a collection are created in this database service to host the provided sample data and connect it to the Node.js App.
- Heroku: This cloud platform is used for hosting the backend. The free tier ended on Nov 28, 2022.
- Fetching Data with React Hook
useEffect()
:App.js
-
Requirements checked (1/4): Fetch the mock data by creating a Node.js or Python endpoint: The React Hook useEffect() is triggered once the app starts. Keep in mind that we have an empty array at the end for executing useEffect() only once. It then fetches the data from the Node.js endpoint hosted on Heroku.
-
Requirements checked (2/4): Implement this feature using React(preferably with Redux): After finishing fetching, Redux.js dispatches the data to the global state.
- I used
Set()
during the execution ofuseEffect()
to store all values of years from the data for best practices instead of thinking that it has only 2 values of years. It's then converted into anarray
, sorted, and passed down toRadio
asprops
.
- Redux / Redux Toolkit
- I separated the global states into two slices: -
dbSlice.js
stores the whole data for later use without having to fetch it over and over again whenever I need it.-recordsSlice.js
stores the values of the current chart and grid.
Responsive design: View on Ipad mini
Two states before finishing fetching
Two states after finishing fetching
- The 'Students' class:
_getStudents.js
-
The main class in the app provides the right values for the chart and grid.
-
_totalStudent(hash)
gets the total number of students in all or any years.-_getDecimal(num)
gets decimals for percentage calculation. -
all()
filters the number of students of all years by course. -
byCourse(year)
filters the number of students by year and course. -
byInstructor(year, course)
filters the number of students by year, course, and instructor.
- Radio Button Group:
radio.js
years
fromApp.js
are mapped as radio buttons.Anytime a radio button is clicked, it willdispatch
the required methods of classStudents
with all info of that year to the global state via Redux:students.byCourse(year)
andstudents.byInstructor(year, course)
.
- Pie Chart:
chart.js
Recharts
from React libraries breaks down the number of students by course. It gets info from thecourses
state and displays them on the screen. The user can click on the chart to select a specific course at any time viahandleGrid()
. This method dispatches the required methods of classStudents
to the global state via Redux:students.byInstructor(year, course)
.
Responsive design: View on Google Chrome
- Data Grid:
recordLisit.js
- The grid displays detailed student data for a specific course with alternating background colors for the rows. The grid becomes visible only after the user chooses a course. If the number of students' figures is below average, it'll be in bold.
Responsive design: View on Iphone 12
Data Grid and Pie Chart
- Responsive, Animations, and Effects
-
While it is fetching the data, a loading animation runs on the screen to let users know that the app is working for them.
-
The background has a gradient animated effect to make the app more attractive.
-
By applying CSS tricks like using
max-height
tocontainer
that has auto height, and settranslateX
to chart's positions, I made sure the app flows seamlessly when new objects are added to the view of the user, responsively. -
Framer Motion from React libraries is used to make the appearance of the data grid and the radio button taps are more interesting and attractive. The cells of the data grid have the spaces needed to remain in their original form. For example,s when switching from "All" to "2015", the grid stays as it is without having to resize.
-
Requirements checked (3/4): The implementation should work for all major browser platforms: all major browsers were tested.
-
Requirements checked (4/4): Implement responsive design and scale for both desktop and mobile browsers: I broke the views down into 3 CSS files.
480.css
is for screens with widths lower than 480px,768.css
is for screens from 481px - 768px, and1200.css
is for screens from 769px to 1200px.
All methods from class Students
are O(n) of time complexity since I had to traverse through the whole dataset to get all the info I needed. I used Hashmaps and arrays there to make sure the app run with O(1) of space complexity. Yet the app has O(n) of space complexity due to storing the whole dataset in the global state via Redux. The combination of both is acceptable performance.
The array colors
in chart.js
needs to be a method that automatically generates more colors following the number of years in the dataset.
I shouldn't show the younglings at my grandmom's Thanksgiving party some 'awesome color-changing animation' if I wanted to finish the assessment sooner.