Developer Guide
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for Manual Testing
- Appendix: Effort
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Main
has two classes called Main
and MainApp
. It is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup methods where necessary.
Commons
represents a collection of classes used by multiple other components.
The rest of the App consists of four components.
-
UI
: The UI of the App. -
Logic
: The command executor. -
Model
: Holds the data of the App in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
Each of the four components,
- defines its API in an
interface
with the same name as the Component. - exposes its functionality using a concrete
{Component Name}Manager
class (which implements the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component (see the class diagram given below) defines its API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class which implements the Logic
interface.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
The sections below give more details of each component.
UI component
API :
Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, ResidenceListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
- Executes user commands using the
Logic
component. - Listens for changes to
Model
data so that the UI can be updated with the modified data.
Logic component
API :
Logic.java
-
Logic
uses theResidenceTrackerParser
class to parse the user command. - This results in a
Command
object which is executed by theLogicManager
. - The command execution can affect the
Model
(e.g. adding a residence). - The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. - In addition, the
CommandResult
object can also instruct theUi
to perform certain actions, such as displaying help to the user.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("delete 1")
API call.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Model component
API : Model.java
The Model
,
- stores a
UserPref
object that represents the user’s preferences. - stores the residence tracker data.
- exposes an unmodifiable
ObservableList<Residence>
that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - does not depend on any of the other three components.
Tag
list in the ResidenceTracker
, which Residence
references. This allows ResidenceTracker
to only require one Tag
object per unique Tag
, instead of each Residence
needing their own Tag
object.Storage component
API : Storage.java
The Storage
component,
- can save
UserPref
objects in json format and read it back. - can save the residence tracker data in json format and read it back.
Common classes
Classes used by multiple components are in the seedu.address.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Remind feature
Implementation
The proposed mechanism is facilitated by the logic
component described above. It filters the displayed Residence
list to show those with bookings starting in the next 7 days. It makes use of the following new method in Residence
.
-
Residence#hasUpcomingBooking()
— Returns true if theResidence
has a booking starting in the next 7 days.
These operations make use of the Model
interface’s Model#updateFilteredResidenceList(Predicate<Residence> predicate)
method. Model
has a new public static Predicate
named PREDICATE_UPCOMING_BOOKED_RESIDENCES
.
Given below is an example usage scenario and how the reminder filtering mechanism behaves at each step.
Step 1. The user launches the application for the first time. The ResidenceTracker
will be initialized with the sample residence tracker data.
Step 2. The user executes addb 2 n/New Tenant p/098 ...
command to add a booking that starts within the next 7 days to the 2nd residence in the residence tracker. The addb
command calls Residence#addBooking(Booking booking)
, which adds a new booking to the 2nd residence.
Step 3. The user executes remind
to list all residences with upcoming bookings. The remind
command also calls Model#updateFilteredResidenceList(Predicate<Residence> predicate)
, causing a filtered list of Residence
s to be displayed which includes the updated residence from the previous step.
Step 4. Any successful execution of commands add
, addb
, edit
, editb
, delete
, deleteb
or list
will return to the previous display of the full residence list.
The following sequence diagram shows how the operation works. The predicate
parameter here is the Model
’s public static variable PREDICATE_UPCOMING_BOOKED_RESIDENCES
. Notice how this sequence diagram differs from the delete operation sequence diagram above as there is no CommandParser
class involved:
The Model
in the diagram above refers to the Model API interface that the Logic
component interacts with. The sequence diagram below shows what happens under the hood in the Model
component to sort residences:
Design consideration: How the remind
feature is implemented
-
Alternative 1 (current choice): Checks if residences have bookings starting in the next 7 days.
- Pros: Easy to implement.
- Cons: User is forced to actively use the command to be reminded.
-
Alternative 2: Residences are automatically displayed with residences having upcoming bookings on top.
- Pros: Users will be able to see the residences that need the most urgent attention on top of their list without interacting with the app.
- Cons: The users will not be able to tell how many in the list will need to be cleaned urgently for the next 7 days. Using colour codes to differentiate these residences from the rest will make it visually more unpleasant for the users as it already uses colour coding for bookings.
Status feature
Implementation
The proposed mechanism is facilitated by the logic
component described above. It updates clean status of multiple Residences
at one time. It makes use of the following new method.
-
StatusCommand#createUpdatedResidence()
— Create updated residence with the required clean status and the same other data. -
StatusCommandParser#paser()
— Manage the status command input, return a status command with required clean status and target residence index list.
These operations make use of the Model
interface’s Model#updateFilteredResidenceList(Predicate<Residence> predicate)
method to update the order of residence list,
and Model#setResidence()
to update the residence in the residence list.
Given below is an example usage scenario and how the status
filtering mechanism behaves at each step.
Step 1. The user launches the application for the first time. The ResidenceTracker
will be initialized with the initial residence tracker state, which has three sample residences.
Step 2. The user executes two or more inputadd n/NAME a/ADDRESS c/y ...
command to add multiple residence with the same clean status “CLEAN”. The add
command calls addResidence()
which checks and adds new residence to the end of unique residence list where “UNCLEAN” residences is in front of “CLEAN” residences.
Step 3. The user plans to set the forth and fifth residences clean status from “CLEAN” to “UNCLEAN” since bookings finished. So the user executes the command status unclean 4 5
.
Step 4. The command is parsed by StatusCommandParser
and returns a StatusCommand
to be executed.
Step 5. StatusCommand#execute
checks if the residence exists and if status expression is correct.
Step 6. The method then calls StatusCommand#createUpdatedResidence()
to create status-updated residence one by one, and calls Model#setResidence
to set the these residences.
Finally, it calls Model#updateFilteredResidenceList(Predicate<Residence> predicate)
, causing an ordered list of Residence
s to be displayed.
The following sequence diagram shows how the status operation works:
The following activity diagram summarizes what happens when a user executes a status
command:
Design consideration: How to update clean status of residences
-
Alternative 1 (current choice): Create status-updated residences one by one and set them to residence list through function
Model#setResidence
- Pros: Easy to implement,and not change the existing structure.
- Cons: Adopt a loop, spending extra storage to create new residences.
-
Alternative 2: use index to find residences in residence list and set their clean status directly
- Pros: Can change status directly, don’t need to spend extra storage to create residence.
- Cons: it needs new function to find residences by the index and change their clean status, which may damage security of residence list.
Edit Booking feature
Implementation
The proposed mechanism is facilitated by the logic
component described above. It edits the details of existing bookings that are currently in Residence Tracker. It makes use of the following methods.
-
EditBookingCommandParser#parse
parses the prefixes and the corresponding parameters to be edited. -
BookingList#containsExclude
determines if edited dates are valid by checking if it overlaps with any of the existing bookings. -
EditBookingCommand#execute
finds the target residence and target booking and edits the corresponding details accordingly.
After EditBookingCommand#execute
finds the target residence and booking, it makes use of BookingList#setBooking
and Model#setResidence
to update the booking of the residence in the residence list.
Given below is an example usage scenario of how the editing of bookings work.
Step 1. The user launches the application. ResidenceTracker
is initialised with prior saved data of residences.
Step 2. The user plans to edit the end date of a booking since the tenants requested for an extension. The user executes the command editb r/2 b/1 e/01-01-2022
to edit the end date of the first booking of the second residence displayed in ResidenceTracker
.
Step 3. The command is parsed by EditBookingCommandParser
and returns a EditBookingCommand
to be executed.
Step 4. Editbookingcommand#execute
checks if the residence and booking exists and if the edited end date is valid.
Step 5. The method then calls BookingList#setBooking
to set the edited booking before calling Model#setResidence
to set the edited residence. Finally, it calls Model#updateFilteredResidenceList(Predicate<Residence> predicate)
, causing an ordered list of Residence
s to be displayed.
Below shows the sequence diagram of EditBookingCommand
And the activity diagram:
Design Consideration: Checking if the edited booking has dates that overlap with other bookings of the residence
Implementation of edit booking creates a editedBooking
before calling BookingList#setBooking
to replace bookingToEdit
with editedBooking
. There is a need to ensure that editedBooking
has no overlap dates with other bookings. However, if BookingList#contains
(method that checks if a booking overlaps with other bookings in the bookingList
) is called, it is likely that it returns true
because editedBooking
has overlapping dates with bookingToEdit
since at this point, bookingToEdit
still exists in the bookingList
.
-
Alternative 1 (current choice): Verify the validity of
BookingList#setBooking
by simulating the deletion ofbookingToEdit
and addition ofeditedBooking
through a method inBookingList
- Pros: allows the use of
BookingList#setBooking
, separatingEditBookingCommand
fromAddingBookingCommand
andDeleteBookingCommand
. - Cons: creating a method that is similar to
BookingList#contains
.
- Pros: allows the use of
Booking class
Design Consideration:
-
Alternative 1 (current choice): Morph
Person
class intoBooking
class- Pros: With the
doesOverlap
method ofBookingTime
, it is convenient to ensure that there are no overlapping bookings forResidence
s. - Cons: All references to
Person
in existing classes, tests, and test utilities would have to be replaced, and new ones would have to be designed to accommodateBooking
s.
- Pros: With the
-
Alternative 2: Preserve
Person
class- Pros: If the same person is making multiple bookings, storing
Person
s would save time spent on re-entering the same details (e.g.TenantName
andPhone
). - Cons: Considering ResidenceTracker’s target users would have a high turnover rate for their rental properties, keeping records of
Person
s could result in excessive storage usage. Furthermore, mostPerson
s would probably only be used once, which makes storing them wasteful.
- Pros: If the same person is making multiple bookings, storing
-
Alternative 2: After creating
editedBooking
, useDeleteBookingCommand
onbookingToEdit
andAddBookingCommand
to addeditedBooking
back to thebookingList
- Pros:
AddBookingCommand
handles the check for overlapping dates foreditedBooking
. Previous issue ofbookingToEdit
existing in thebookingList
is solved by deletion. - Cons: ties the implementation of
EditBookingCommand
toAddBookingCommand
andDeleteBookingCommand
.
- Pros:
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- busy user that has to manage a considerable number of residences
- is constantly renting out residences; high turnover rate
- prefers working on laptop over mobile
- is able to type quickly
- prefers using a keyboard to using a mouse
- is familiar with CLI apps
Value proposition: easily keep track of residences and inform cleaning agency whenever necessary
User stories
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * |
new user | See a list of all commands | refer to instructions when I forget how to use the App |
* * * |
user | add a new residence | manage all the residences I wish to keep track of |
* * * |
user | delete a residence | remove residences that I no longer need to track |
* * * |
user | find a residence by name | review details of specific residences without having to go through the entire list |
* * |
new user | clear all sample residences | begin using Residence Tracker with my own data quickly |
* * |
user | edit a residence | change the information of a residence when necessary |
* * |
user | exit the application | use my computer for other matters |
* * |
user | go through a tutorial guide | quickly learn the usage of the application |
* * |
user | add a new booking of a residence | keep track of all booking information of my residences |
* * |
user | edit a new booking of a residence | change the information of booking when necessary |
* * |
user | delete a new booking of a residence | remove booking details that I no longer need to track |
* * |
busy user | be reminded me of upcoming bookings | quickly view the residences that need to be urgently cleaned |
* * |
busy user renting out many residences | update status of multiple residence at once | save time and get to my other works |
{More to be added}
Use cases
(For all use cases below, the System is the ResidenceTracker
and the Actor is the user
, unless specified otherwise)
Use case (UC01): Add a residence
MSS
- User adds in the details of a residence.
- User validates the details of the residence to be added.
- System confirms the addition and residence is added to the list of existing residence.
- System saves the updated data.
Use case ends.
Extensions
- 2a. System detects error in submission if user did not provide all relevant fields correctly.
- 2a1. ResidenceTracker shows an error message.
use case restarts from 1.
- 2a1. ResidenceTracker shows an error message.
Use case (UC02): Delete a residence
MSS
- User deletes a residence.
- System validates the residence to be deleted.
- System deletes the respective entry of the residence.
- System saves the updated data.
Use case ends.
Extensions
- 2a. System detects an error in the user input.
- 2a1. System requests for the expected format to delete a residence.
-
2a2. User inputs the corrected details to delete a residence.
Use case resumes at step 2.
Use case(UC03): Find a residence
MSS
- User searches residences with keywords.
- System returns the residence(s) which include the keyword in their name.
Use case ends.
Extensions
- 1a. System found no matching residences.
- 1a1. A corresponding message is shown and the residence list displayed is empty.
Use case ends.
- 1a1. A corresponding message is shown and the residence list displayed is empty.
Use case(UC04): View list of all residences
MSS
- User lists all residences.
- System displays all residences in the list.
Use case ends.
Use case(UC05): Edit information of a residence
MSS
- User edits a residence.
- System validates the edits to the given residence.
- System updates the residence accordingly.
- System saves the updated data.
Use case ends.
Extensions
- 2a. System detects an error in the user input.
- 2a1. System requests for the expected input format to edit a residence.
- 2a2. User inputs the corrected details to edit a residence.
Use case resumes at step 2.
Use case (UC06): Show all available commands
MSS
- User requests the help page.
- System displays the help page.
Use case ends.
Use case (UC07): Exit the application
MSS
- User exits the application.
- System shuts down.
Use case ends.
Use case(UC08): Update clean status of multiple residences at once
MSS
- User updates multiple residences’ clean status at once.
- System confirms the validity of clean status and residences provided.
- System updates the required residences’ clean status.
- System saves the updated data.
Use case ends.
Extensions
-
2a. System detects an error in the user input.
- 2a1. System requests for the expected format to update multiple residences’ clean status.
- 2a2. User inputs the corrected details to update multiple residences’ clean status.
Use case resumes at step 2.
Use case(UC09): Add a new booking to a specific residence
MSS
- User adds a new booking to a residence.
- System confirms the validity of the residence and the new booking details.
- System adds the new booking to the residence’s booking list.
- System saves the updated data.
Use case ends.
Extensions
-
2a. System detects an error in the user input.
- 2a1. System requests for the expected format to add a booking to a residence.
- 2a2. User inputs the corrected details to add a booking to a residence.
Use case resumes at step 2.
Use case(UC10): Edit a booking of a specific residence
MSS
- User edits a residence’s booking.
- System confirms the validity of the residence and the edited booking details.
- System updates the given booking in the residence’s booking list.
- System saves the updated data.
Use case ends.
Extensions
-
2a. System detects an error in the user input
- 2a1. System requests for the expected format of editing a residence’s booking.
- 2a2. User inputs the corrected details to edit a residence’s booking.
Use case resumes at step 2.
Use case (UC11): Delete a booking of a specific residence
MSS
- User deletes a booking from a residence.
- System validates the booking to be deleted.
- System deletes the respective entry of the booking from the given residence.
- System saves the updated data.
Use case ends.
Extensions
-
2a. System detects an error in the user input.
- 2a1. System requests for the correct format to delete a booking from a residence.
- 2a2. User inputs the corrected details to delete a booking from a residence.
Use case resumes at step 2.
Use case (UC12): Get reminder of residences with upcoming bookings
MSS
- User requests a reminder of residences with upcoming bookings.
- System shows a list of all residences with bookings starting in the next 7 days.
Use case ends.
Use case (UC13): CLear all residence at once
MSS
- User chooses to clear all residences.
- System deletes all residence data from the storage file.
Use case ends.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 100 residences without a noticeable sluggishness in performance for typical usage.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- user inputs should be processed and executed within one second.
{More to be added}
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
-
Residence Status:
- Clean: The residence has been cleaned
- Unclean: The residence needs to be cleaned
Appendix: Instructions for Manual Testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
Adding a residence
-
Adding a residence
-
Prerequisites: User should have launched residence tracker.
-
Test case:
add n/Amber Park a/22 Bedok Street
Expected: A new residence named ‘Amber Park’ and with address ‘22 Bedok Street’ will display in the list of residences. It is initialised with ‘Clean’ as its default status since this optional field is left empty. -
Test case:
add n/Midtown Modern a/18 Tan Quee Lan Street c/n t/popular
Expected: A new residence named ‘Midtown Modern’ with address ‘18 Tan Quee Lan Street’ will display in the list of residences. It should have ‘Unclean’ as its clean status and ‘popular’ as a tag. -
Test case:
add n/Capetown
Expected: No residence is added. Error details shown in the status message to indicate the required and optional parameters of the command. Status bar remains the same.
-
Deleting a residence
-
Deleting a residence while all residences are being shown
-
Prerequisites: User should have launched residence tracker with some residence data or use
list
command to display all the residences. -
Test case:
delete 1
Expected: First residence is deleted from the list. Details of the deleted residence is shown in the status message. -
Test case:
delete 0
Expected: No residence is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete
,delete x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
Editing a residence
-
Editing a residence while all the residences are being shown
-
Prerequisites: User should have launched residence tracker with some residence data or use
list
command to display all the residences. Add at least 2 residences marked asUnclean
and 2 other residences marked asClean
. -
Test case:
edit 2 c/y
Expected: Changes the clean status of the second residence in the list to ‘clean’. The displayed residence list may re-order itself such that this residence will now be displayed below all the other residences marked ‘unclean’. -
Test case:
edit 2
Expected: No residence is edited. Error details regarding missing parameters shown in the status message. Status bar remains the same. -
Test case:
edit x n/NameToChange
when there are less thanx
residences shown in the residence list.
Expected: No residence is edited. Error details regarding invalid residence index shown in the status message. Status bar remains the same.
-
Multiple clean status updates
-
Changing the clean status of multiple residences at once
-
Prerequisites: User should have launched residence tracker with some residence data or use
list
command to display all the residences. Have at least 2 residences marked asUnclean
and 2 other residences marked asClean
. -
Test case:
status clean 1 2 3 4
Expected: Changes the clean status of the first 4 residence in the list toClean
. The displayed residence list may re-order itself such that these updated residences will now be displayed below all the other residences markedUnclean
. -
Test case:
status unclean 1 2 x
when there are less thanx
residences in the residence list.
Expected: No residence is updated. Error details regarding invalid residence index shown in the status message. Status bar remains the same.
-
Adding a booking
-
Adding a booking to a specific residence
-
Prerequisites: User should have launched residence tracker with some residence data or use
list
command to display all the residences. Have at least 2 residences in the list. -
Test case:
addb 2 n/Bob p/91234567 s/01-01-2022 e/01-02-2022
Expected: A corresponding booking with the details given is shown in theBOOKINGS
column of the 2nd residence. If this is an upcoming booking, it should be highlighted in green. -
Test case:
addb 1 n/Sandy p/87654321 s/09-08-2021 e/122-08-2021
Expected: No booking is added. Error details regarding invalid date format shown in the status message. Status bar remains the same. -
Test case:
addb x n/Sandy p/87654321 s/09-08-2021 e/12-08-2021
when there are less thanx
residences in the residence list.
Expected: No booking is added. Error details regarding invalid residence index shown in the status message. Status bar remains the same.
-
Deleting a booking
-
Deleting a booking from a specific residence
-
Prerequisites: User should have launched residence tracker with some residence data or use
list
command to display all the residences. Have at least 2 residences in the list. -
Test case:
deleteb r/2 b/2
Expected: The second booking of the second residence will be deleted. Details of the deleted booking will be shown in the status message. -
Test case:
deleteb r/2 b/x
when the second residence has less thanx
bookings.
Expected: No booking is deleted. Error details regarding invalid booking index shown in the status message. Status bar remains the same.
-
Editing a booking
-
Editing a booking from a specific residence
-
Prerequisites: User should have launched residence tracker with some residence data or use
list
command to display all the residences. Have at least 2 residences in the list. -
Test case:
editb r/2 b/2 n/Bob
Expected: The tenant name of the second booking of the second residence will be changed toBob
and the details of the edited booking will be shown in the status message. -
Test case:
editb r/2 b/2 e/31-05-2021
when there exists another booking that lasts from30-05-2021
to01-06-2021
.
Expected: No booking is edited. Error details regarding overlap of bookings for this residence shown in the status message. Status bar remains the same.
-
Reminder of upcoming bookings
-
Showing only the residences with upcoming bookings in the next seven days (excluding today).
-
Prerequisites: User should have launched residence tracker with some residence data or use
list
command to display all the residences. Have at least 1 residence with booking starting in the next 7 days. -
Test case:
remind
Expected: residences with upcoming bookings starting in the next seven days (excluding the current day) will be displayed. The list will be sorted to show residences markedUnclean
before residences markedClean
.
-
Modifying data files
-
Dealing with corrupted data files
-
Prerequisites: There are some stored residences in the residence tracker. The app is closed.
-
Test case: corrupted
residencetracker.json
- Steps:
- Edit the
residencetracker.json
such that it becomes an invalid format by removing a single}
at the end of the file. - Open the residence tracker.
- Edit the
Expected: The residence tracker will start but the residence list will be empty (i.e all previous data is lost). Add a few residences and try other commands. They should work as expected.
- Steps:
-
Test case: missing
residencetracker.json
- Steps:
- Exit the residence tracker.
- Delete the
residencetracker.json
from the/data
directory. - Open the residence tracker.
Expected: The residence tracker will start with only the sample data.
- Steps:
-
Appendix: Effort
ResidenceTracker is a brownfield project that builds on the existing code base of AddressBook3. It contains around 7k LOC of additional implementation, testing, documentation and refactoring as logged by RepoSense.
The Person
class was refactored into a residence class with different parameters. We added new parameters such as BookingList
and CleanStatusTag
. The BookingList
is like a second entity which stores a unique list of bookings and has it’s own parameters.
Quite some time was spent on the refactoring of classes due to changes especially in fixing of broken tests caused by the refactoring.
The bulk of our features is based around the implementation of CleanStatusTag
and BookingList
as these will be essential to our target users in managing residences. Since this app is designed to help manage a user’s residences for rent, the key point of this app would be to help keep track of the residences’ bookings and clean status to plan cleaning schedules.
There was careful consideration and discussion on product development with a user centric approach. As such, we made minor changes to improve user experience such as sorting the residences based on clean status, bookings based on timing and colour indicators for bookings to signify the different statuses (expired, ongoing, upcoming).
The Ui was also redesigned to add an additional column of bookings for each residence, including other changes to the design and color scheme of the application to optimise screen space rather than having all the information vertically on the app.