1. Overview
This project portfolio presents my contributions towards this project, including the features implemented, technologies used and documentation written.
This project was undertaken during a software engineering module (CS2103T) offered in National University of Singapore (NUS). The objective of this project was to enhance a given 'address book' application by adding more features, tests, and to apply the software engineering practices that we are taught during the module.
My team decided to morph the address book application into a clinic management system.
Aptly named 'CLInic', it focuses on optimising efficiency for its users through the use of a Command Line Interface (hence the 'CLI' in 'CLInic'). With a CLI, users will have to navigate the application and execute commands by typing them directly on the keyboard. Alongside the CLI is the Graphical User Interface (GUI), which mainly serves as visual aids for the user with icons and coloured text in a user-friendly manner. This application uses Java as the main programming language and uses JavaFX, HTML and CSS for the GUI.
CLInic primarily serves as a complete, all-in-one solution for small clinics. It provides clinics with a interactive and efficient system that can handle patient data, medicine stock data, and even has an integrated queue management system for day-to-day clinic operations.
My main responsibility for this project was to implement the UI and storage for the application, amidst some other smaller tasks,
such as the development of the MedicalRecord
attribute of the Patient
.
I played the key role of adding the various UI elements to the application window and connecting them with the application logic.
2. Summary of contributions
This section serves to summarise my key contributions to this project.
-
Major enhancement 1: Added the GUI for the Patient Queue Management System (PQMS)
-
What it does: This GUI window, which resides near the top of the application window, displays to the user the current state of the PQMS.
-
Justification: Having a responsive GUI allows users to be able to refer to and read the queue easily, and to perform any commands on the queue quickly, without having to always call a
queue
command to retrieve required queue information. -
Highlights: This feature was implemented with the help of a little HTML for the display and Javascript that allowed the updating of the information in the GUI after each command. It required a lot of synchronization between the command results, model objects and the display. This was largely handled with some event handling and scripting.
-
More details: Please refer to the Developer Guide, Section 4.6 for a detailed explanation.
-
-
Major enhancement 2: Added storage capabilities for the
MedicalRecord
model and theMedicine
model.-
What it does: This allows the user to be able to add and retrieve
MedicalRecord
andMedicine
objects to the database easily and efficiently. -
Justification: Before this enhancement, any user action that added
MedicalRecord
andMedicine
to the database will not be saved once the user closes the application. We wanted the user to be able to save these information for future use as well. -
Highlights: This feature was implemented with the use of XML, similar to how
Patient
objects were saved to the file in the original addressbook-level4 application. It required the creation of anXmlAdapted-
version of each model object as well as careful handling of the adding and retrieval for each model object. -
More details: Please refer to the Developer Guide, Section 3.5 for a detailed explanation.
-
-
Minor enhancements:
-
Added ability for each
Document
to appear in a pop-up window after the respectiveDocument
commands. -
Added the GUI display for all the
Medicine
objects in the database. This GUI display replaces the left panel displaying thePatient
objects whenever aMedicine
related command is called. -
Added
addMedicalRecordCommand
that allows user to add aMedicalRecord
to a specifiedPatient
.
-
-
Code contributed: Click here to view my contributed code.
-
Other contributions:
-
Documentation:
-
Improved the navigability and readability of the User Guide by separating Section 3 (Features) into sub-sections.
-
-
Enhancements to existing features:
-
Updated the GUI display under
BrowserPanel
to show other information such asCurrentPatient
, PQMS, andPatient
.
-
-
Testing:
-
Wrote tests for all UI features to increase coverage from 75% to 79% (Pull request #111)
-
-
3. Contributions to the User Guide
Listed below are the sections I contributed to the User Guide. This shows my ability to write documentation and instructions meant for end-users of the application. |
3.1. Selecting a patient: select
Need a more detailed view of a patient? Use the select
command to view a patient’s profile!
Alias: s
Format: select INDEX
Pro tip(s):
Selects the patient at the specified INDEX . The index refers to the index number shown in the displayed patient list. The index must be a positive integer (i.e. 1, 2, 3, …).
|
Examples:
-
find Bryan
s 1
Selects the 1st patient in the resulting list of thefind
command.
find Bryan
and s 1
command.3.2. Adding medical records of a patient: addmedicalrecord
Updating a patient’s MedicalRecord
on the fly is easy! Just use the addMedicalRecord
command!
Alias: amr
Format: addmedicalrecord INDEX [b/BLOOD_TYPE] [d/PAST_DISEASES]… [da/DRUG_ALLERGY]… [m/NOTE]…
Pro tip(s):
|
Examples:
-
addmedicalrecord 5 da/Paracetamol d/Diabetes
AddsParacetamol
(under Drug Allergy) andDiabetes
(under Past Diseases) to theMedicalRecord
of the 5th patient.
addmedicalrecord 5 da/Paracetomal d/Diabetes
command-
amr 3 b/B+
AddsB+
(under Blood Type) to theMedicalRecord
of the 3rd patient.
amr 3 b/B+
command4. Contributions to the Developer Guide
Listed below are the sections I contributed to the Developer Guide. This shows my ability to write technical documentation meant for developers, and also the extent of my technical knowledge of the application. |
4.1. Adding a MedicalRecord to a Patient
4.1.1. Current Implementation
The MedicalRecord
class is an attribute of the Patient
class, and it contains information regarding its Patient
's medical records. The MedicalRecord
class:
-
has an attribute
BloodType
which stores the blood type of thePatient
. This attribute is marked asfinal
and cannot be changed. -
contains a
List<DrugAllergy>
which stores the list of drug allergies that thePatient
has. -
contains a
List<Disease>
which stores the list of diseases thePatient
has. -
contains a
List<Note>
which stores the list of notes that belong to thePatient
. EachNote
further comprises aMessage
that stores the actual message of theNote
, and aMap<SerialNumber, Quantity>
attribute which is a record of theSerialNumber
of theMedicine
as well as theQuantity
that had been dispensed to thePatient
during that particular visit.
When a new Patient
is created with the AddCommand
, it is created with a default MedicalRecord
object that contains an empty BloodType
object, an empty List<DrugAllergy>
, an empty List<Disease>
and and empty List<Note>
.
Users can add more information to a specified Patient
's MedicalRecord
by invoking the AddMedicalRecordCommand
, and specifying the corresponding arguments to add to the MedicalRecord
. The arguments should be prefixed with b/
for BloodType
, d/
for Disease
, da/
for DrugAllergy
, and m/
for Note
. All the arguments here are optional arguments, however at least one must be present.
Given below is an example usage scenario and explanation for the inner workings of the AddMedicalRecordCommand
.
Step 1. The user creates a new Patient
object using the AddCommand
. While the user has not provided any arguments for the MedicalRecord
of this Patient
, a empty MedicalRecord
object has been initialised internally and assigned to this created Patient
. Contents of this empty MedicalRecord
is as detailed above.
Step 2. The user wishes to add a MedicalRecord
containing only the BloodType
of the Patient
, and will do so with the AddMedicalRecord
command, and only specifiying the b/
prefix for BloodType
. Note that BloodType
here can only be in a specific format (A[+-], B[+-], O[+-] or AB[+-]).
When this command is executed, the program creates a new MedicalRecord
object with just the BloodType
specified, takes the old MedicalRecord
object of the Patient
(which is empty), and does a merging of the two objects, returning a new MedicalRecord
object. The Patient
is then updated with this new combined MedicalRecord
. The following figure shows the sequence diagram for this command.
4.1.2. Design Considerations
This section lists out some of the different implementations that were considered during the designing phase of this feature, including the rationale for our choice.
Aspect: Execution of the command
-
Alternative 1 (current choice): Create a new
MedicalRecord
object and combine the oldMedicalRecord
with it.-
Pros: Easy to implement and better abstraction.
-
Cons: Redundant creation of new object only to discard it immediately.
-
-
Alternative 2: Add specified arguments of the command directly to the current
MedicalRecord
-
Pros: No redundant creation of extra objects.
-
Cons: Require access to the existing
MedicalRecord
from outside the object, which breaks the abstraction barrier.
-
4.2. Application GUI
4.2.1. Current Implementation
As an extension to the original addressbook-level4 application, more UI elements were added to the application window to serve as visual aid for the user of the application.
In particular, the real-time status of the Patient Queue Management System (PQMS) is reflected to the user via a small window near the top of the application. This is depicted in the figure below:
After QueueCommands
such as register
, serve
, etc., the GUI will automatically update itself as the user enters these commands to reflect the situation of the PQMS at that exact point in time.
This UI element is implemented using JavaFX’s WebView
and a local HTML file. The sequence of events for how the WebView
is updated is as follows:
Step 1. On a fresh start-up of the application, the WebView
is intialized with the local HTML file QueueDisplay.html
that draws the labels and boxes onto the WebView
.
Step 2. After each QueueCommand
, a QueueUpdatedEvent
is posted and the subscribed class QueueDisplay
invokes the runScript()
method on the WebViewScript
object within the class.
Step 3. WebViewScript.runScript()
simply calls an executeScript()
method that subsequently executes some JavaScript code on the HTML file that will render the appropriate illustration to be displayed on the WebView
.
Step 4. On each subsequent QueueCommand
, steps 2 to 3 are repeated to update the display.
The following figure show the code section of the 2 methods that are responsible for the display:
/**
* File: QueueDisplay.java
* Loads a HTML file representing the queue display.
*/
private void loadQueueDisplay(PatientQueue patientQueue, ServedPatientList servedPatientList, CurrentPatient currentPatient) {
List<Patient> patientQueueList = patientQueue == null ? null : patientQueue.getPatientsAsList();
String currentPatientString;
if (currentPatient == null) {
currentPatientString = "empty";
} else {
try {
currentPatientString = currentPatient.getPatient().getName().fullName;
} catch (NullPointerException npe) {
currentPatientString = "empty";
}
}
List<ServedPatient> servedPatients = servedPatientList == null ? null : servedPatientList.getPatientsAsList();
String queueDisplayPage = MainApp.class.getResource(FXML_FILE_FOLDER + DEFAULT_PAGE).toExternalForm();
this.webViewScript.runScript(getScriptForQueueDisplay(patientQueueList, currentPatientString, servedPatients));
loadPage(queueDisplayPage);
}
/**
* File: WebViewScriptManager.java
* This function will run script that is passed as argument.
* @param script script to run.
*/
public void runScript(String script) {
int currentCounter = this.counter;
this.webView.getEngine().getLoadWorker().stateProperty().addListener((ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) -> {
if (newValue == Worker.State.SUCCEEDED && currentCounter == this.counter) {
Platform.runLater(() -> this.webView.getEngine().executeScript(script));
this.counter++;
}
});
}
4.2.2. Design Considerations
This section lists out some of the different implementations that were considered during the designing phase of this feature, including the rationale for our choice.
Aspect: Implementation approach
-
Alternative 1 (current choice): Using a
WebView
to display HTML code-
Pros:
-
Easy to implement, since the code to render the display is a completely separate code. Abstraction barrier is maintained.
-
-
Cons:
-
Might face lagging issues for prolonged time usage, since one new
Listener
object is created for each update.
-
-
-
Alternative 2: Using JavaFX to render the shapes and UI.
-
Pros:
-
Less likely to face efficiency issues since changing of the UI elements happens locally.
-
-
Cons:
-
Hard to implement.
-
-