Skip to content

Commit

Permalink
Merge branch 'master' into branch-updateUG1
Browse files Browse the repository at this point in the history
  • Loading branch information
alfaloo authored Apr 12, 2024
2 parents a152f33 + 389c448 commit 267a08b
Show file tree
Hide file tree
Showing 19 changed files with 344 additions and 20 deletions.
136 changes: 122 additions & 14 deletions docs/DeveloperGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,31 +394,139 @@ Alternative implementation for consideration
2. This will centralise the behaviours, and reduce the amount of code needed to perform the delete function.
3. A further extension is to do so with all other overlapping functionalities, such as `add` or `edit`, however we leave that possibility for future discussion and refinement.

### Find `Person`
Queries a `Person` entry, either `Doctor` or `Patient` by indicating their name or a substring of their name.
This command is implemented through the `FindCommand` class which extends the `Command` class.

### Query `doctor` and `patient`
The `find` command is able to take in multiple parameters (at least one), each of these parameters are read as strings, and act as separate queries. This is a feature of the `find` command, to have the capability of parsing both parameters as a short-hand feature.
Example, the command `find hans doe` is equivalent of returning the logical 'or' result of `find hans` and `find doe`.

Queries a 'doctor' or 'patient' entry by indicating their name or a substring of their name.
This command is implemented through the `QueryDoctor` and `QueryPatient` classes which extend the `Command` class.
* Step 1. User enters a `find` command.
* Step 2. The `AddressBookParser` will call `parseCommand` on the user's input string and return an instance of `findCommandParser`.
* Step 3. The `parse` command in `FindCommandParser` checks if at least one parameter is present.
* If the field is missing, a `ParseException` is thrown, and the UI displays an error message.

* Step 1. User enters an `querypatient` or `querydoctor` command.
* Step 2. The `AddressBookParser` will call `parseCommand` on the user's input string and return an instance of `queryDoctorCommandParser` or `queryPatientCommandParser`.
* Step 3. The `parse` command in `queryDoctorCommandParser` or `queryPatientCommandParser` calls `ParserUtil` to create instances of objects for each of the fields.
* If there are any missing fields, a `CommandException` is thrown.
* If input arguments does not match contraints for the fields, a `IllegalArgumentException` is thrown.
The activity diagram below demonstrates this error handling process in more detail.

<img src="images/FindActivityDiagram.png" width="800" />

* Step 4. The `parse` command in `FindCommandParser` returns an instance of `FindCommand`.
* Step 5. The `LogicManager` calls the `execute` method in `FindCommand`.
* Step 6. The `execute` method in `FindCommand` executes and calls `updateFilteredPersonList` in model with the `NameContainsKeywordsPredicate` to get a filtered list of person entries of the entered keyword(s), both `patient` and `doctor` entries can be displayed.
* Step 7. A Success message gets printed onto the results display to notify user and the list of matching results is produced.

The sequence diagram below closely describes the interaction between the various components during the execution of the `FindCommand`.

<img src="images/FindPersonSequenceDiagram.png" width="800" />

Alternative implementations considered
1. The following sections describes the behaviour of querying `doctor` and `patient` entries by separate commands by all of the entry's fields, both following a very similar logic to how the `find` command is implemented. We might consider using flags to be more precise with our searches, (e.g a -doctor or -patient flag to indicate we wish to search for only `doctor` and `patient` entries respectively) so as to avoid the need to create additional commands. However, we felt that this approach overloaded the `find` method too much, and overcomplicated the `find` command's usage.
2. Even if the `find` command was to be overloaded with flags, we foresaw that the creation of distinct commands to fit the flags parsed by the `find` command was unavoidable. As such, it was prudent to start with the implementation of the distinct commands first (as described in the following sections, each tied to a specific command), and leave the overloading of the `find` command as a later increment.


### Query `doctor`
Queries a `doctor` entry by indicating the exact string, or substring of any of a `doctor`'s fields - name, nric, phone number and date of birth (as displayed on the UI. e.g 30 January 2023).
This command is implemented through the `QueryDoctorCommand` class which extends the `Command` class.

Similar to the `find` command, the `doctor` query command is able to take in multiple parameters (at least one), each of these parameters are read as strings, and act as separate queries, with the result returned being the logical 'or' result of applying a `doctor` query to each parameter separately.

* Step 1. User enters a `doctor` command.
* Step 2. The `AddressBookParser` will call `parseCommand` on the user's input string and return an instance of `QueryDoctorCommandParser`.
* Step 3. The `parse` command in `QueryDoctorCommandParser` checks if at least one parameter is present.
* If the field is missing, a `ParseException` is thrown, and the UI displays an error message.

The activity diagram below demonstrates this error handling process in more detail.

<img src="images/QueryPersonActivityDiagram.png" width="800" />
<img src="images/QueryDoctorActivityDiagram.png" width="800" />

* Step 4. The `parse` command in `queryDoctorCommandParser` or `queryDoctorCommandParser` return an instance of `queryPatientCommand` or `queryPatientCommand` respectively.
* Step 5. The `LogicManager` calls the `execute` method in `queryDoctorCommandParser` or `queryDoctorCommandParser`.
* Step 6. The `execute` method in `queryDoctorCommandParser` or `queryDoctorCommandParser` executes and calls `updateFilteredPersonList` in model to get a filtered list of `Doctor` or `Patient`.
* Step 4. The `parse` command in `QueryDoctorCommandParser` returns an instance of `QueryDoctorCommand`.
* Step 5. The `LogicManager` calls the `execute` method in `QueryDoctorCommand`.
* Step 6. The `execute` method in `QueryDoctorCommand` executes and calls `updateFilteredPersonList` in model with the `DoctorContainsKeywordsPredicate` to get a filtered list of only `Doctor` entries of the entered keywords(s).
* Step 7. Success message gets printed onto the results display to notify user and the list of matching results is produced.


Why is this implemented this way?
1. Making both `Doctor` and `Patient` class extend the `Person` class makes it easier to execute query operations.
2. `Doctor` and `Patient` all exhibit similar qualities, and thus can inherit from the `Person` superclass.
1. The backend execution of the `doctor` command and the `find` command are very similar, however the choice to separate the two query commands is justified due to the expansion of fields in the `doctor` query, conceptually making them distinct commands.
2. Furthermore, there is an additional check to check if an entry is of type `doctor` that is not present in the `find` command.


### Query `patient`
Queries a `patient` entry by indicating the exact string, or substring of any of a `patient`'s fields - name, nric, phone number and date of birth (as displayed on the UI. e.g 30 January 2023).
This command is implemented through the `QueryPatientCommand` class which extends the `Command` class.

Similar to the `find` command, the `patient` query command is able to take in multiple parameters (at least one), each of these parameters are read as strings, and act as separate queries, with the result returned being the logical 'or' result of applying a `patient` query to each parameter separately.

* Step 1. User enters a `patient` command.
* Step 2. The `AddressBookParser` will call `parseCommand` on the user's input string and return an instance of `QueryPatientCommandParser`.
* Step 3. The `parse` command in `QueryPatientCommandParser` checks if at least one parameter is present.
* If the field is missing, a `ParseException` is thrown, and the UI displays an error message.

The activity diagram below demonstrates this error handling process in more detail.

<img src="images/QueryPatientActivityDiagram.png" width="800" />

* Step 4. The `parse` command in `QueryPatientCommandParser` returns an instance of `QueryPatientCommand`.
* Step 5. The `LogicManager` calls the `execute` method in `QueryPatientCommand`.
* Step 6. The `execute` method in `QueryPatientCommand` executes and calls `updateFilteredPersonList` in model with the `PatientContainsKeywordsPredicate` to get a filtered list of only `Patient` entries of the entered keywords(s).
* Step 7. Success message gets printed onto the results display to notify user and the list of matching results is produced.


Why is this implemented this way?
1. The backend execution of the `patient` command and the `find` command are very similar, however the choice to separate the two query commands is justified due to the expansion of fields in the `patient` query, conceptually making them distinct commands.
2. Furthermore, there is an additional check to check if an entry is of type `patient` that is not present in the `find` command.


### Query `apptfordoctor`
Queries an `appointment` entry that has the associated `doctor`'s `Nric`, by indicating the exact `Nric` of the doctor as the search parameter.
This command is implemented through the `apptfordoctor` class which extends the `Command` class.

The `apptfordoctor` command takes in multiple parameters (at least one), and each of these parameters are read as strings (not case-sensitive, i.e S1234567A is equivalent to s1234567a), and returns the logical 'or' result of applying the `apptfordoctor` command to each parameter separately. <u>**Note that no errors will not be thrown if the inputted `Nric`(s) are not of the appropriate form** </u>(i.e Begins with one of S, T, G, F, or M, followed by 7 numerical digits, then ended by an alphabetical letter), but rather the expected return result is that no queries will be found.

* Step 1. User enters an `QueryDoctorAppointment` command.
* Step 2. The `AddressBookParser` will call `parseCommand` on the user's input string and return an instance of `QueryDoctorAppointmentCommandParser`.
* Step 3. The `parse` command in `QueryDoctorAppointmentCommandParser` checks if at least one parameter is present.
* If the field is missing, a `ParseException` is thrown, and the UI displays an error message.

The activity diagram below demonstrates this error handling process in more detail.

<img src="images/QueryDoctorAppointmentActivityDiagram.png" width="800" />

* Step 4. The `parse` command in `QueryDoctorAppointmentCommandParser` returns an instance of `QueryDoctorAppointmentCommand`.
* Step 5. The `LogicManager` calls the `execute` method in `QueryDoctorAppointmentCommand`.
* Step 6. The `execute` method in `QueryDoctorAppointmentCommand` executes and calls `updateFilteredAppointmentList` in model with the `AppointmentContainsDoctorPredicate` to get a filtered list of appointment entries with the entered keyword(s), only those `appointment`(s) that have the associated `doctor`'s `Nric` entries are be displayed.
* Step 7. Success message gets printed onto the results display to notify user and the list of matching results is produced.


Why is this implemented this way?
1. This command closely resembles the `find` command, but can be seen as a stricter version as the results queried do not include substring searches. Therefore, it is justified to separate this command from the `find` command as two distinct commands with distinct `commandParsers`.
2. The rationale behind excluding substring searches for `appointment`(s) is that if a hospital clerk is searching for a specific `doctor`'s scheduled `appointment`(s), the hospital clerk already has the `doctor`'s unique `Nric` and hence including substring querying is irrelevant.


### Query `apptforpatient`

Queries an `appointment` entry that has the associated `patient`'s `Nric`, by indicating the exact `Nric` of the patient as the search parameter.
This command is implemented through the `apptforpatient` class which extends the `Command` class.

The `apptforpatient` command takes in multiple parameters (at least one), and each of these parameters are read as strings (not case-sensitive, i.e S1234567A is equivalent to s1234567a), and returns the logical 'or' result of applying the `apptforpatient` command to each parameter separately. <u>**Note that no errors will not be thrown if the inputted `Nric`(s) are not of the appropriate form** </u>(i.e Begins with one of S, T, G, F, or M, followed by 7 numerical digits, then ended by an alphabetical letter), but rather the expected return result is that no queries will be found.

* Step 1. User enters an `QueryPatientAppointment` command.
* Step 2. The `AddressBookParser` will call `parseCommand` on the user's input string and return an instance of `QueryPatientAppointmentCommandParser`.
* Step 3. The `parse` command in `QueryPatientAppointmentCommandParser` checks if at least one parameter is present.
* If the field is missing, a `ParseException` is thrown, and the UI displays an error message.

The activity diagram below demonstrates this error handling process in more detail.

<img src="images/QueryPatientAppointmentActivityDiagram.png" width="800" />

* Step 4. The `parse` command in `QueryPatientAppointmentCommandParser` returns an instance of `QueryPatientAppointmentCommand`.
* Step 5. The `LogicManager` calls the `execute` method in `QueryPatientAppointmentCommand`.
* Step 6. The `execute` method in `QueryPatientAppointmentCommand` executes and calls `updateFilteredAppointmentList` in model with the `AppointmentContainsPatientPredicate` to get a filtered list of appointment entries with the entered keyword(s), only those `appointment`(s) that have the associated `patient`'s `Nric` entries are be displayed.
* Step 7. Success message gets printed onto the results display to notify user and the list of matching results is produced.


Why is this implemented this way?
1. This command closely resembles the `find` command, but can be seen as a stricter version as the results queried do not include substring searches. Therefore, it is justified to separate this command from the `find` command as two distinct commands with distinct `commandParsers`.
2. The rationale behind excluding substring searches for `appointment`(s) is that if a hospital clerk is searching for a specific `patient`'s scheduled `appointment`(s), the hospital clerk already has the `patient`'s unique `Nric` and hence including substring querying is irrelevant.


[//]: # (### \[Proposed\] Undo/redo feature)
Expand Down
35 changes: 33 additions & 2 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,42 @@
layout: page
title: User Guide
---

## Welcome to MediCLI!
[Welcome note]
MediCLI is a **desktop app for managing persons involved in a hospital, optimised for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). Targeted at fast typing hospital clerks, MediCLI allows them to manage doctors, patients and appointments faster than traditional GUI apps.

## Who can benefit from MediCLI?
[Target audience]


* Table of Contents
{:toc}

---------------------------------------------------------
## Purpose of UG

## How to use this UG

--------------------------------------------------------------------------------------------------------------------
## Key Product Information
[provides a user-centric statement detailing
product information, including product
description and an overview of main
features.]

## Quick start
## Quick start Guide
[-offers detailed information on how users
can get started, encompassing installation
instructions, compatibility with different
operating systems, elements of the graphical
user interface (GUI), and a tutorial on using
the command-line interface (CLI).]

### Compatibility
[OS]

### Installation

1. Ensure you have Java `11` or above installed in your Computer.

Expand All @@ -22,6 +49,10 @@ MediCLI is a **desktop app for managing persons involved in a hospital, optimise
A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.<br>
![Ui](images/Ui.png)

### How to use the command line interface (CLI)

### Initial start-up and sample use-case

1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.<br>
Some example commands you can try:

Expand Down
20 changes: 20 additions & 0 deletions docs/diagrams/FindActivityDiagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@startuml
skin rose
skinparam ActivityFontSize 15
skinparam ArrowFontSize 12

start
:User enters command to query a person,\nthe person can be either a doctor or patient.;


if () then ([missing required fields])
:Show error message\nfor missing required fields;
else ([else])
:Search the person from person list;
:Update the 'person' panel\nin the GUI to display the list;
:Show success message\nwith found person(s) information;
endif


stop
@enduml
65 changes: 65 additions & 0 deletions docs/diagrams/FindPersonSequenceDiagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@startuml
!include style.puml
skinparam ArrowFontStyle plain

box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
participant ":FindCommandParser" as FindCommandParser LOGIC_COLOR
participant "e:FindCommand" as FindCommand LOGIC_COLOR
participant ":CommandResult" as CommandResult LOGIC_COLOR
end box

box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
end box

[-> LogicManager : execute("find ...")
activate LogicManager

LogicManager -> AddressBookParser : parseCommand("find ...")
activate AddressBookParser

create FindCommandParser
AddressBookParser -> FindCommandParser
activate FindCommandParser

create FindCommand
FindCommandParser -> FindCommand : : parse("find ...")
activate FindCommand

FindCommand --> FindCommandParser
deactivate FindCommand

FindCommandParser --> AddressBookParser
deactivate FindCommandParser

'Hidden arrow to position the destroy marker below the end of the activation bar.
FindCommandParser -[hidden]-> AddressBookParser
destroy FindCommandParser

AddressBookParser --> LogicManager
deactivate AddressBookParser

LogicManager -> FindCommand : execute()
activate FindCommand

FindCommand -> Model : find(person)
activate Model

Model --> FindCommand
deactivate Model

create CommandResult
FindCommand -> CommandResult
activate CommandResult

CommandResult --> FindCommand : result
deactivate CommandResult

FindCommand --> LogicManager : result
deactivate FindCommand

[<--LogicManager
deactivate LogicManager
@enduml
20 changes: 20 additions & 0 deletions docs/diagrams/QueryDoctorActivityDiagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@startuml
skin rose
skinparam ActivityFontSize 15
skinparam ArrowFontSize 12

start
:User enters command to query doctor(s);


if () then ([missing required fields])
:Show error message\nfor missing required fields;
else ([else])
:Search doctor(s) from person list;
:Update the 'person' panel\nin the GUI to display the list;
:Show success message\nwith queried doctor(s) information;
endif


stop
@enduml
20 changes: 20 additions & 0 deletions docs/diagrams/QueryDoctorAppointmentActivityDiagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@startuml
skin rose
skinparam ActivityFontSize 15
skinparam ArrowFontSize 12

start
:User enters command to query appointment with the associated doctor;


if () then ([missing required fields])
:Show error message\nfor missing required fields;
else ([else])
:Search Appointments(s) from person list;
:Update the 'appointment' panel\nin the GUI to display the list;
:Show success message\nwith queried appointment information;
endif


stop
@enduml
20 changes: 20 additions & 0 deletions docs/diagrams/QueryPatientActivityDiagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@startuml
skin rose
skinparam ActivityFontSize 15
skinparam ArrowFontSize 12

start
:User enters command to query patient(s);


if () then ([missing required fields])
:Show error message\nfor missing required fields;
else ([else])
:Search patient(s) from person list;
:Update the 'person' panel\nin the GUI to display the list;
:Show success message\nwith queried patient(s) information;
endif


stop
@enduml
Loading

0 comments on commit 267a08b

Please sign in to comment.