This is a doctor booking page web application that allows patients to schedule appointments with doctors.
On the home page, patients can see all the doctors. Clicing "Book Appointment" will direct them to the doctors page.
On a doctors profile page, patients can see the doctors opening hours, and their availability of specific days. If a booking timeslot is not available, the timeslot will be disabled. Patiens will not be allowed to make a booking.
On booking success, the patient is notified that the booking was done. If this was an error on their part, they're allowed a brief moment to cancel the appointment by clicking "cancel"
Patients can view all of their bookings which are sorted with the upcoming bookings first. Patients can cancel bookings by selecting the "Cancel" button.
To make a booking with a doctor, a patient needs to provide their information. On the top-right of the navigation menu is the ability to switch users. For simplicity sake, only two different users can be selected.
To start the application, first install the NPM packages
npm install
Start the development site using
npm run dev
To build use
npm run build
Create a .env.local file in the root directory
touch .env.local
For the app to work, you will need two environment variable
VITE_API_URL=<backend_url>
VITE_API_KEY=<backend_access_token>
This app was developed with Typescript, ReactJS, Vite, and the shadcn/ui with TailwindCSS.
- Typescript helps ensure typesafety
- Vite provides fast build times and instant updates on the browser which helps with the frontend development
- ReactJS is an easy-to-use framework with great performance for developing multi-page web applications
- shadcn/ui is an open source component library built with tailwindcss that makes development easier. New to using shadcn/ui, but it really helped in the development of the UI
Note: the components within /components/ui are all generated by shadcn/ui. It has a different naming convention then what I am using. I tried to change the names of all those components, but Netlify build kept giving errors so I've reverted it back.
Main dependencies are:
- axios: Used to make api calls. Rather than using fetch, axios has a lot of useful built-in behavior (i.e. auto parsing JSON) which streamlines the process for handling API calls.
- zustand: A state management library that is fairly easy to use over it's competitor Redux. Using state management to handle user information, data from doctors, data of user bookings, etc.
- react-router-dom: For accessing different routes in the application like "/" home, "/bookings" and "/doctors/:id"
- react-day-picker: For the calendar input so the user can choose a data on the calendar
The rest of the dependencies are mostly from shadcn/ui. Since it's an open source component, it's possible to remove some for different use cases, but I decided to leave them in here to simplify development.
Drawbacks to having all these dependencies are the added bundle size. For this application complexity, there aren't many other drawbacks to using this dependencies. Some minor drawbacks are:
- zustand: smaller community of developers in comparison to Redux
- react-day-picker: may not be as customizable if need a specific calendar feature
Currently this project does not have any unit tests. The following are suggested tests to add to this application.
GET Bookings
- returns an array of Booking elements
POST Booking
- setting the start time to before or after opening hours should result in invalid booking
- setting the date to before current date should result in invalid booking
- an empty body will return a 400 error with a 4-element string array
- an invalid doctorId will return a 404 error
- a successful post will create an id, and set the status to confirmed
GET Booking (not implemented)
- a valid booking id will return a valid booking element
- an invalid booking id will return null with a 200 status
PATCH Booking
- patching "status" to cancelled will result in a confirmed booking to become cancelled
- patching "status" to confirmed will result in a cancelled booking to become confirmed
- patching without "status" value will result in a 400 error
- patching with a valid "status" and other parameters of different values will only update the status
GET Doctors
- returns an array of Doctor elements
GET Doctor
- a valid doctorId will return a valid Doctor elements
- an invalid doctorId will return a 404 error with "doctor not found" as a message
- on mount renders "find doctors"
- calls api to get doctors and renders a list of doctors which can be found by the "Dr." keyword match
- an empty list should result in a text that says "there are no available doctors"
- on mount calls api to get doctor and renders information that should contain "dr." "open hours" and "address". It should also contain "book an appointment" "booking date" "timeslots"
- with no bookings, all the timeslots of a future existing date will be not disabled
- with a list of bookings set for the whole day, all the timeslots of that date will be disabled
- cannot click the "prev" button if the date is the current date
- selecting a valid date and timeslot will enable the "book appointment" button
- bookings by other users should disable timeslots in doctor profile booking page
- on mount renders "manage bookings"
- calls api to get bookings and doctor information and displays users bookings with all the doctors, which can be testing by counting "dr."s
- no bookings by the user should result in a text that says "there are no bookings"
Here are some of the assumptions I've made:
- get Doctors will return a non-empty list of Doctors
Booking
date
should be mandatoryBooking
status
can be set as eithercancelled
orconfirmed
. The model states it's eithercancel
orconfirmed
which is incorrect.- I kept the time in a 24 hour format.
- api calls will either return as 2** or 4** codes
Here are some opinions I've made:
- Should
Doctor
description
be mandatory if it's empty for all doctors? - Does a
Doctor
opening_hours
element always have 7 elements? If it's closed, why not just have no element for that day since there's no need to set "start" and "end".
Considering deploying this project to production? Here are some extra things to do:
- Create user authentication so users cannot easily switch to other users, and see their bookings
- Ensure there's robust error handling and reporting like handling API failures, alongisde network issues, and unexpected user inputs
Change the times from a 24-hour format to a 12-hour format.
For the search doctors page "/":
- the patient can search by a doctors name
- the patient can filter doctors by their openings hours
- the patient can filter doctors by location
- the patient can see a small note if they have an upcoming booking with a doctor
For the manage bookings page "/bookings":
- the patient can filter bookings by doctors name
- the patient can sort the bookings by date
- the patient can filter bookings by dates
And for both doctors, and bookings page, it would be nice to allow the patient to select a different viewing format: Card and List/Table (Row). The List/Table (Row) may be simpler to view multiple bookigns at once.
A patient doesn't need to see thee bookings that they've cancelled, so that can be removed.
However, a patient should be able to see the bookings they've confirmed but are now in the past. There can be a tab to show current bookings
and another one that says past bookings
.
To make a booking, a patient needs to include their name. Although the backend is simple as it only requires their name, I think it would be a better and more safe approach to have authenticated users so the system would not be misused.
On the doctor profile card, it would be good to see the upcoming bookings made by that user. If there are more than 2 bookings, selecting "see all bookings" will redirect the user to the /bookings
page with a specific query filtering doctors.
Fixes:
- Handle errors for booking on the same day. From my testing, it seems this isn't allowed as the backend doesn't update.
UI/UX Considerations:
- If the unavailable timeslot is booked by the user, then show it disabled but in a different color.
Functionality:
- Don't allow users to make a booking with the same doctor on the same day.
- Don't allow users to make a booking with another doctor if that booking overlaps with another booking(i.e. Yil cannot book May 28th at 10AM with both Dr. Bob and Dr. Dog)
Tanstack React Query provides asynchronous state management. It would simplify the hooks, and with the built-in querying functions, mutation functions, refetching and more, it can make the process getting doctors and bookings much simpler.
One assumption is that the list of doctors will not be updated often. Therefore, there's no need to refetch the doctors if it exists on the patients local storage. A query with a specific staleTime
can be added here.
As mentioned above:
Note: the components within /components/ui are all generated by shadcn/ui. It has a different naming convention then what I am using. I tried to change the names of all those components, but Netlify build kept giving errors so I've reverted it back.
Therefore, a small improvement to the project would be to keep the same naming convention for all the files. Either by finding a way to rename the names within /components/ui
or changing the rest of the files to match the shadcn/ui
naming convention.
Make the site pink ;)