diff --git a/README.adoc b/README.adoc index 0ad72da1a5ba..497e7fd4377a 100644 --- a/README.adoc +++ b/README.adoc @@ -1,38 +1,32 @@ -= Address Book (Level 4) += Health Book + ifdef::env-github,env-browser[:relfileprefix: docs/] -https://travis-ci.org/nusCS2113-AY1819S1/addressbook-level4[image:https://travis-ci.org/nusCS2113-AY1819S1/addressbook-level4.svg?branch=master[Build Status]] -https://ci.appveyor.com/project/damithc/addressbook-level4[image:https://ci.appveyor.com/api/projects/status/3boko2x2vr5cc3w2?svg=true[Build status]] -https://coveralls.io/github/se-edu/addressbook-level4?branch=master[image:https://coveralls.io/repos/github/se-edu/addressbook-level4/badge.svg?branch=master[Coverage Status]] -https://www.codacy.com/app/damith/addressbook-level4?utm_source=github.com&utm_medium=referral&utm_content=se-edu/addressbook-level4&utm_campaign=Badge_Grade[image:https://api.codacy.com/project/badge/Grade/fc0b7775cf7f4fdeaf08776f3d8e364a[Codacy Badge]] -https://gitter.im/se-edu/Lobby[image:https://badges.gitter.im/se-edu/Lobby.svg[Gitter chat]] +https://travis-ci.org/CS2113-AY1819S1-T12-2/main[image:https://travis-ci.org/CS2113-AY1819S1-T12-2/main.svg?branch=master[Build Status]] +https://app.codacy.com/app/xhxh96/main?utm_source=github.com&utm_medium=referral&utm_content=CS2113-AY1819S1-T12-2/main&utm_campaign=Badge_Grade_Dashboard[image:https://api.codacy.com/project/badge/Grade/b3b9161e1b4a424aa5d1da1a6e759be6[Codacy Badge]] ifdef::env-github[] -image::docs/images/Ui.png[width="600"] +image::docs/images/MockUi.png[width="600"] endif::[] ifndef::env-github[] -image::images/Ui.png[width="600"] +image::images/MockUi.png[width="600"] endif::[] -* This is a desktop Address Book application. It has a GUI but most of the user interactions happen using a CLI (Command Line Interface). -* It is a Java sample application intended for students learning Software Engineering while using Java as the main programming language. -* It is *written in OOP fashion*. It provides a *reasonably well-written* code example that is *significantly bigger* (around 6 KLoC)than what students usually write in beginner-level SE modules. -* What's different from https://github.com/se-edu/addressbook-level3[level 3]: -** A more sophisticated GUI that includes a list panel and an in-built Browser. -** More test cases, including automated GUI testing. -** Support for _Build Automation_ using Gradle and for _Continuous Integration_ using Travis CI. +Health Book is a desktop address book application targeted at health care professionals who seek to retrieve their patients' personal details and health-related information all in one place. +The application provides both a Command Line Interface (CLI) for input of data and a Graphical User Interface (GUI) for displaying of output (patient's personal details and health-related information). +The application is fully written in Java, allowing cross-platform compatibility. == Site Map * <> * <> -* <> * <> * <> == Acknowledgements +* This application is a fork of the original Address Book 4 application by https://github.com/se-edu/[SE-Edu Initiatives]. * Some parts of this sample application were inspired by the excellent http://code.makery.ch/library/javafx-8-tutorial/[Java FX tutorial] by _Marco Jakob_. * Libraries used: https://github.com/TestFX/TestFX[TextFX], https://bitbucket.org/controlsfx/controlsfx/[ControlsFX], https://github.com/FasterXML/jackson[Jackson], https://github.com/google/guava[Guava], https://github.com/junit-team/junit5[JUnit5] diff --git a/addressbook.jar b/addressbook.jar new file mode 100644 index 000000000000..f81b4513d47b Binary files /dev/null and b/addressbook.jar differ diff --git a/build.gradle b/build.gradle index f8e614f8b49b..8ebbd2f91f02 100644 --- a/build.gradle +++ b/build.gradle @@ -207,8 +207,8 @@ asciidoctor { idprefix: '', // for compatibility with GitHub preview idseparator: '-', 'site-root': "${sourceDir}", // must be the same as sourceDir, do not modify - 'site-name': 'AddressBook-Level4', - 'site-githuburl': 'https://github.com/se-edu/addressbook-level4', + 'site-name': 'Health Book', + 'site-githuburl': 'https://github.com/CS2113-AY1819S1-T12-2/main', 'site-seedu': true, // delete this line if your project is not a fork (not a SE-EDU project) ] diff --git a/docs/AboutUs.adoc b/docs/AboutUs.adoc index e647ed1e715a..4dce35ae4df6 100644 --- a/docs/AboutUs.adoc +++ b/docs/AboutUs.adoc @@ -4,53 +4,47 @@ :imagesDir: images :stylesDir: stylesheets -AddressBook - Level 4 was developed by the https://se-edu.github.io/docs/Team.html[se-edu] team. + -_{The dummy content given below serves as a placeholder to be used by future forks of the project.}_ + +Health Book was developed by the https://github.com/CS2113-AY1819S1-T12-2[T12-2] team. + {empty} + We are a team based in the http://www.comp.nus.edu.sg[School of Computing, National University of Singapore]. == Project Team -=== John Doe -image::damithc.jpg[width="150", align="left"] -{empty}[http://www.comp.nus.edu.sg/~damithch[homepage]] [https://github.com/damithc[github]] [<>] +=== Hovan Tan Fang Hao +image::xshaivan.png[width="150", align="left"] +{empty}[https://github.com/xShaivan[github]] -Role: Project Advisor +Role: Project Manager ''' -=== John Roe -image::lejolly.jpg[width="150", align="left"] -{empty}[http://github.com/lejolly[github]] [<>] +=== Cheong Chee Mun Brandon +image::brandonccm1996.png[width="150", align="left"] +{empty}[http://github.com/brandonccm1996[github]] -Role: Team Lead + -Responsibilities: UI +Role: Development Lead ''' -=== Johnny Doe -image::yijinl.jpg[width="150", align="left"] -{empty}[http://github.com/yijinl[github]] [<>] +=== Chew Kah Meng +image::chewkahmeng.png[width="150", align="left"] +{empty}[http://github.com/chewkahmeng[github]] -Role: Developer + -Responsibilities: Data +Role: Quality Assurance Lead ''' -=== Johnny Roe -image::m133225.jpg[width="150", align="left"] -{empty}[http://github.com/m133225[github]] [<>] - -Role: Developer + -Responsibilities: Dev Ops + Threading +=== Chok Xin Yan +image::chokxy.png[width="150", align="left"] +{empty}[http://github.com/chokxy[github]] +Role: Design Lead ''' -=== Benson Meier -image::yl_coder.jpg[width="150", align="left"] -{empty}[http://github.com/yl-coder[github]] [<>] +=== Cheng XianHao +image::xhxh96.png[width="150", align="left"] +{empty}[http://github.com/xhxh96[github]] -Role: Developer + -Responsibilities: UI +Role: Subject Matter Expert ''' diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index ea58481e4740..8dc832b85f68 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -12,9 +12,9 @@ ifdef::env-github[] :note-caption: :information_source: :warning-caption: :warning: endif::[] -:repoURL: https://github.com/se-edu/addressbook-level4/tree/master +:repoURL: https://github.com/CS2113-AY1819S1-T12-2/main -By: `Team SE-EDU`      Since: `Jun 2016`      Licence: `MIT` +By: `Team T12-2`      Since: `Aug 2018`      Licence: `MIT` == Setting up @@ -98,6 +98,20 @@ When you are ready to start coding, 1. Get some sense of the overall design by reading <>. 2. Take a look at <>. +== Introduction + +Health Book (or some other name that we will be deciding later) is an address book application that is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place. Command Line Interface is utilized mainly for the input, while GUI is used mainly to display the output. By combining these 2 interfaces, Health Book aims to provide healthcare professionals with the speed and efficiency obtained from a CLI while retaining the systematic view of information through the GUI. + +=== User Profile + +Health Book is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place. + +=== Value Proposition + +With many patients to attend to, healthcare professionals need to focus much of their attention and care on their patients and less on administrative matters. Health Book is a one-stop application for healthcare professionals to create, read, update or delete (CRUD) patient’s information, reducing the need for long and troublesome paperwork and simplifying administrative work. + +Command Line Interface is utilized mainly for the input, while GUI is used mainly to display the output. By combining these 2 interfaces, Health Book also aims to provide healthcare professionals with the speed and efficiency obtained from a CLI while retaining the systematic view of information through the GUI. + == Design [[Design-Architecture]] @@ -319,6 +333,96 @@ image::UndoRedoActivityDiagram.png[width="650"] ** Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as `HistoryManager` now needs to do two different things. // end::undoredo[] +// tag::addinfo +=== Additional Information +== Current Implementation +The `addinfo` command is facilitated by the `AddInfoPersonDescriptor` class. Essentially, it is in-charged of changing the `Nric`, `DateOfBirth` attributes in a `Person` class. + +The command requires user to input an `index` based on the result of the `list` command. Upon getting the `index` input, the `AddInfoCommand` selects the `Person` based on the index from the `model`. + +This is followed by copying the existing attributes of the `Person` selected into an `editPerson` so that existing attributes like `Names` and `Phone` will not be edited. + +The command then checks for the arguments after the `index`. If an appropriate argument (eg. `\n`) has been found, it will tokenize the string following the argument. The tokenized string will then be parsed into the function in the `ParserUtil` class which checks for the validity of the string. +If the string is valid, the object that is to be edited will be returned. Otherwise, an exception will be raised. + +Once the objects that are to be edited (eg. `NRIC`, `DateOfBirth`) have been returned, they will be processed by the `AddPersonInfoDescriptor` class which changes the respective values of the objects that are to be edited. +The `Person` object that is returned will be used to replace the `Person` that was to be edited. +// end::addinfo + +// tag:: medicalhistory[] +=== Medical History features +==== Current Implementation + +The `addhist` command first takes in the index of the patient followed by the prefixes of information to be stored in the medical history. +The user input will go through `AddHistCommandParser.java` and `AddressBookParser.java` to ensure user input conforms to the expected format. +It is then returned as an AddHistCommand object for execution. +In `AddHistCommand.java`, the `execute`method will run. +The list of patients is retrieved from `model.getFilteredPersonList()` and stored under `lastShownList`. +Using the `index` specified in the command, the patient at that index will be the `personToEdit` for its medical history. +The method `model.updatePerson()` and `model.updateFilteredPersonList()` will update the contents of the patient's medical history. +Execution ends when `CommandResult(generateSuccessMessage(editedPerson))` generates a success message after medical history has been added. + +// end:: medicalhistory[] + +// tag::addappt[] +=== AddAppointment feature +==== Current Implementation + +The addappt mechanism is facilitated by `VersionedAddressBook`. + +Additionally, it implements the following operations: + +* `Model#getFilteredPersonList()` -- Obtains the entire current list of persons that is being displayed to the user +* `VersionedAddressBook#updatePerson()` -- Updates the specified person with the new data. +* indicateAddressBookChanged() -- Raises an event to indicate the AddressBook in the model has changed + +These operations are exposed in the `Model` interface as `Model#updatePerson()`, `Model#updateFilteredPersonList()` and `Model#commitAddressBook()` respectively. + +Given below is an example usage scenario and how the addappt mechanism behaves at each step. + +Step 1. The user launches the application. If it is the first time he/she is launching it, the `VersionedAddressBook` will be initialized with a sample address book data. If he/she has launched it and has made changes before, the `VersionedAddressBook` will be launched with the data he has previously saved in his previous launch. + +Step 2. The user executes `addappt 1 s/16/09/2018 1500 e/16/09/2018 1530 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan` command to add an appointment to the 1st person in the list that the address book is currently showing. The `addappt` command obtains the data of the person that the user is trying to change based on the index that the user has input. + +Step 3. The `addappt` command will obtain the set of appts that the person previously had, copy it to a new set of appts, and add the appt which the user wants to add into the new set. + +Step 4. The `addappt` command will call `Model#updatePerson()` to update the person with this new set of appts. The `addappt` command will also call `Model#updateFilteredPersonList()` to update the list that is being showed to the user. Lastly, the `addappt` command will call `Model#commitAddressBook()` to update the addressBookStateList and currentStatePointer. + +The following sequence diagram shows how the addappt operation works: + +image::AddApptSequenceDiagram.png[width="800"] +//end:: addappt[] + +// tag::addreport[] +=== AddMedicalReport feature +==== Current Implementation + +The addreport mechanism is facilitated by `VersionedAddressBook`. + +Additionally, it implements the following operations: + +* `Model#getFilteredPersonList()` -- Obtains the entire current list of persons that is being displayed to the user +* `VersionedAddressBook#updatePerson()` -- Updates the specified person with the new data. +* indicateAddressBookChanged() -- Raises an event to indicate the AddressBook in the model has changed. + +These operations are exposed in the `Model` interface as `Model#updatePerson()`, `Model#updateFilteredPersonList()` and `Model#commitAddressBook()` respectively. + +Given below is an example usage scenario and how the addreport mechanism behaves at each step. + +Step 1. The user launches the application. If it is the first time he/she is launching it, the `VersionedAddressBook` will be initialized with a sample address book data. If he/she has launched it and has made changes before, the `VersionedAddressBook` will be launched with the data he has previously saved in his previous launch. + +Step 2. The user executes `addreport 1 t/Asthma d/01/01/2018 i/Prescribed XXX medicine, next appointment on 02/02/2018` command to add a medical report to the 1st person in the list that the address book is currently showing. The `addreport` command obtains the data of the person that the user is trying to change based on the index that the user has input. + +Step 3. The `addreport` command will obtain the set of reports that the person previously had, copy it to a new set of reports, and add the report which the user wants to add into the new set. + +Step 4. The `addreport` command will call `Model#updatePerson()` to update the person with this new set of reports. The `addreport` command will call `Model#updateFilteredPersonList()` to update the list that the user is shown. + +Step 5. The `addreport` command will call `Model#commitAddressBook()` to update the addressBookStateList and currentStatePointer. + +The following sequence diagram shows how the addreport operation works: +image::AddMedicalReportSequenceDiagram.png[width="800"] +//end:: addreport[] + // tag::dataencryption[] === [Proposed] Data Encryption @@ -813,15 +917,17 @@ See this https://github.com/se-edu/addressbook-level4/pull/599[PR] for the step- [appendix] == Product Scope -*Target user profile*: +Health Book is an address book application that is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place. Command Line Interface is utilized mainly for the input, while GUI is used mainly to display the output. By combining these 2 interfaces, Health Book aims to provide healthcare professionals with the speed and efficiency obtained from a CLI while retaining the systematic view of information through the GUI. + +*Target user profile*: Health Book is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place. -* has a need to manage a significant number of contacts +* has a need to manage a significant number of patients * prefer desktop apps over other types * can type fast * prefers typing over mouse input * is reasonably comfortable using CLI apps -*Value proposition*: manage contacts faster than a typical mouse/GUI driven app +*Value proposition*: With many patients to attend to, healthcare professionals need to focus much of their attention and care on their patients and less on administrative matters. Health Book is a one-stop application for healthcare professionals to create, read, update or delete (CRUD) patient’s information, reducing the need for long and troublesome paperwork and simplifying administrative work. [appendix] == User Stories @@ -831,62 +937,604 @@ Priorities: High (must have) - `* * \*`, Medium (nice to have) - `* \*`, Low (un [width="59%",cols="22%,<23%,<25%,<30%",options="header",] |======================================================================= |Priority |As a ... |I want to ... |So that I can... -|`* * *` |new user |see usage instructions |refer to instructions when I forget how to use the App +|`* * *` |doctor |see usage instructions |refer to instructions when I forget how to use the App -|`* * *` |user |add a new person | +|`* * *` |doctor |add, edit, and delete patients and their medical informaton |keep track of my patients and not prescribe them the wrong medication -|`* * *` |user |delete a person |remove entries that I no longer need +|`* * *` |doctor |find a patient by name |locate details of patients without having to go through the entire list -|`* * *` |user |find a person by name |locate details of persons without having to go through the entire list +|`* * *` |doctor |have a platform to view my patients' past medical history |compare with their current symptoms to predict future health risks -|`* *` |user |hide <> by default |minimize chance of someone else seeing them by accident +|`* * *` |doctor |know my patient’s drug allergy if he/she has any |prescribe the drugs without causing other medical conditions -|`*` |user with many persons in the address book |sort persons by name |locate a person easily -|======================================================================= +|`* * *` |doctor |know if there is any follow-up actions for a particular patient, or if the medical case for the patient has closed |know if the patient has been discharged + +|`* * *` |doctor |have a sorted list of all my patients in terms of their personal particulars/medical information (allergies, blood type, address, last visited country) and past medical history |assess them more quickly and easily, and understand the past medical issues that my patients faced + +|`* * *` |doctor |import/export files to other computers |send patients’ data to other hospitals if the patient transfers there + +|`* * *` |doctor |see all my patient’s appointments if there is any |remind my patients to come for appointments days in advance + +|`* *` |doctor |have an inventory list |keep track and replenish stocks + +|`* *` |doctor |have image functionality in the feature (medical history) |view X-rays and scans where applicable to provide better diagnosis + +|`* *` |doctor |rank patients’ past illnesses in terms of severity (medical history) |efficiently perform certain checkups to ensure their condition is kept in check + +|`* *` |doctor |be able to see all appointments for the day and how many people have appointments |I can schedule appointments easily when people call in and request for an appointment, I can schedule them an empty timeslot + +|`* *` |doctor |be able to see where patients live on a map |I can do house visits easily and deliver medication to them -_{More to be added}_ +|`* *` |doctor |see the patients' prescriptions given to them by previous doctors they have visited for each entry in their medical history (medical history) |understand how their medical condition is based on medication taken + +|`*` |doctor |encrypt all my patients’ info |my patients’ data will be protected from hackers +|======================================================================= [appendix] == Use Cases -(For all use cases below, the *System* is the `AddressBook` and the *Actor* is the `user`, unless specified otherwise) +(For all use cases below, the *System* is the `Health Book`, unless specified otherwise) -[discrete] -=== Use case: Delete person +=== Use case: Viewing of available commands: `help` + +*MSS* + +1. User requests to see a list of available commands. +2. System displays the list of commands that the user can enter. ++ +Use case ends. + +=== Use case: Adding a patient: `add` + +*MSS* + +1. User requests to add a patient into the System. +2. System adds the patient into the System and displays a message that the addition is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to add patient. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of adding a patient. ++ +Use case ends. + +=== Use case: Listing all patients: `list` + +*MSS* + +1. User requests to see a list of all patients in the System. +2. System shows user a list of all patients. ++ +Use case ends. + +*Extensions* + +[none] +* 2a. List is empty. ++ +[none] +** 2a1. System shows user a message that there are no patients entered yet and prompts user to add patient. ++ +Use case ends. + +=== Use case: Editing basic information of patient: `edit` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to edit a specific patient in the list with updated details. +2. System updates the patient’s information with the new details and displays a message that the edit is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to edit patient. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of editing a patient. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +=== Use case: Finding patients by categories: `find` + +*MSS* + +1. User requests to find a patient in the list by categories. (eg. name, age, blood type, marital status) +2. System shows user a list of patients who are in requested category. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to find patient. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of finding a patient. ++ +Use case ends. + +[none] +* 1b. User provides an invalid category or keyword. ++ +[none] +** 1b1. System shows an error message that category or keyword is invalid. ++ +Use case ends. + +=== Use case: Deleting a patient: `delete` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to delete a person in the list using the patient’s index. +2. System deletes the user who has that index and displays a message that deletion is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to delete patient. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of editing a patient. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +=== Use case: Adding an appointment into patient’s timetable: `addappt` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to add an appointment into patient’s timetable. +2. System adds the appointment into patient’s timetable and displays a message that the addition is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to add appointment. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of adding appointment. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +[none] +* 1c. Patient’s timetable already has an appointment which overlaps with the new appointment in terms of timing. ++ +[none] +** 1c1. System shows an error message that there is an overlapped appointment, and shows both the appointments which overlap each other. ++ +Use case ends. + +=== Use case: Viewing a patient’s appointments: `viewappts` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to view all appointments in the patient’s timetable. +2. System displays all appointments in the patient’s timetable. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to view appointments. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of viewing appointments. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +[none] +* 1c. User requests to view all appointments of a patient who does not have any appointment. ++ +[none] +** 1c1. System shows message that the patient does not have any appointments. ++ +Use case ends. + +=== Use case: Editing an appointment in a patient’s timetable: `editappt` +Assume that user has already requested the System to view appointments for a patient. *MSS* -1. User requests to list persons -2. AddressBook shows a list of persons -3. User requests to delete a specific person in the list -4. AddressBook deletes the person +1. User requests to edit an appointment in the patient’s timetable with new details. +2. System updates the appointment in the patient’s timetable with the new details and displays a message that edit is successful. + Use case ends. *Extensions* [none] -* 2a. The list is empty. +* 1a. User uses the wrong format to edit appointment. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of editing appointment. + Use case ends. -* 3a. The given index is invalid. +[none] +* 1b. User provides an invalid index for the list. + [none] -** 3a1. AddressBook shows an error message. +** 1b1. System shows an error message that the index is invalid. + -Use case resumes at step 2. +Use case ends. -_{More to be added}_ +[none] +* 1c. Patient’s timetable already has an appointment which overlaps with the new appointment in terms of timing. ++ +[none] +** 1c1. System shows an error message that there is an overlapped appointment, and shows both the appointments which overlap each other. ++ +Use case ends. + +=== Use case: Deleting an appointment in a patient’s timetable: `deleteappt` +Assume that user has already requested the System to view appointments for a patient. + +*MSS* + +1. User requests to delete an appointment in the patient’s timetable. +2. System deletes the appointment in the patient’s timetable and displays a message that deletion is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to delete appointment. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of deleting appointment. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +=== Use case: Adding optional information of patient: `addinfo` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to add optional information for patient. +2. System adds optional information for the patient and displays a message that entry for optional information is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to add optional information i.e. wrong command or invalid data for the fields. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of adding optional information. System will ignore invalid commands or data and process only the valid commands and data. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +=== Use case: Editing optional information of patient: `editinfo` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to edit optional information for patient. +2. System edits optional information for the patient and displays a message that edit for optional information is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to edit optional information i.e. wrong command or invalid data for the fields. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of adding optional information. System will ignore invalid commands or data and process only the valid commands and data. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +[none] +* 1c. User requests to edit information that does not exist. ++ +[none] +** 1c1. System shows an error message that the information does not exist. System will ignore the edit request for that field and process the valid edit requests for other fields ++ +Use case ends. + +=== Use case: Adding of Medical Report: `addreport` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to add medical report for patient. +2. System adds medical report for the patient and displays a message that addition of medical report is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to add medical report. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of adding medical report. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +=== Use case: Editing of Medical Report: `editreport` +Assume that user has already requested the System to display a list of medical reports for a patient. + +*MSS* + +1. User requests to edit medical report for patient. +2. System edits medical report for the patient and displays a message that edit of medical report is successful. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to edit medical report. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of editing medical report. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +=== Use case: List of Medical Report: `listreport` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to view all medical reports for a patient. +2. System displays all medical reports for the patient. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User uses the wrong format to list medical reports. ++ +[none] +** 1a1. System shows error message that format is wrong and gives user an example on the correct format of listing medical reports. ++ +Use case ends. + +[none] +* 1b. User provides an invalid index for the list. ++ +[none] +** 1b1. System shows an error message that the index is invalid. ++ +Use case ends. + +[none] +* 1c. User requests to view all medical reports for a patient who does not have any medical report. ++ +[none] +** 1c1. System shows message that the patient does not have any medical report. ++ +Use case ends. + +=== Use case: Sort patients list: `sortlist` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User requests to sort the patients by a category and order. +2. System displays a sorted list of the patients and displays a message that the list is successfully sorted. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User chooses to sort by a category that does not exist (for example: the letter does not exist or refer to any category ie “z”, “3” or “-”). ++ +[none] +** 1a1. System shows an error message that the category does not exist. ++ +Use case ends. + +[none] +* 1b. User inputs an invalid order_index. ++ +[none] +** 1b1. System shows an error message that the order index does not exist. ++ +Use case ends. + +=== Use case: Viewing information of patients: `view` +Assume that user has already requested the System to display a list of patients. + +*MSS* + +1. User chooses to view information of patient. +2. System requests for the details of information. +3. User enters the requested details. +4. System shows the requested information of patient. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User provides an invalid index for the list. ++ +[none] +** 1a1. System shows an error message that the index is invalid. ++ +Use case ends. + +[none] +* 3a. System detects an error in the entered data. ++ +[none] +** 3a1. System requests for the correct data. +** 3a2. User enters new data. +** Steps 3a1 and 3a2 are repeated until data entered is correct. ++ +Use case resumes at step 4. + +=== Use case: Import files to other computers: `import` + +*MSS* + +1. User chooses to import patient info of a specific patient and specifies the directory and the text file where he wants to import it from. +2. System imports patient info from a txt file. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User provides an invalid index for the list. ++ +[none] +** 1a1. System shows an error message that the index is invalid. ++ +Use case ends. + +[none] +* 1b. Directory information or text file name that user inputs is invalid. ++ +[none] +** 1b1. System displays a message that the location given is invalid. ++ +Use case ends. + +=== Use case: Export files to other computers: `export` + +*MSS* + +1. User chooses to export patient info of a specific patient and specifies the directory and file name which he wants to export to. +2. System exports patient into a txt file in the specified directory. ++ +Use case ends. + +*Extensions* + +[none] +* 1a. User provides an invalid index for the list. ++ +[none] +** 1a1. System shows an error message that the index is invalid. ++ +Use case ends. + +[none] +* 1b. Directory information or text file name that user inputs is invalid. ++ +[none] +** 1b1. System displays a message that the location given is invalid. ++ +Use case ends. [appendix] == Non Functional Requirements +[discrete] +=== Environment Requirements . Should work on any <> as long as it has Java `9` or higher installed. -. Should be able to hold up to 1000 persons 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. +. Should work on both 32-bit and 64-bit environments. -_{More to be added}_ +[discrete] +=== Business/Domain Rules +. Should be able to store up to 1000 patients' information without a noticeable sluggishness in performance for typical usage. + +[discrete] +=== Constraints +. System data is only stored locally and not on the cloud. + +[discrete] +=== Quality requirements +. The layout of the system will be simple and understandable by even doctors who are not proficient with computer systems. +. Might-have: all information will be encrypted. + +[discrete] +=== Notes about project scope +. The product is not required to handle the printing of reports/profile pages. [appendix] == Glossary diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 7e0070e12f49..cf78c3a1e0d9 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 4 - User Guide += HealthBook - User Guide :site-section: UserGuide :toc: :toc-title: @@ -12,15 +12,15 @@ ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: endif::[] -:repoURL: https://github.com/se-edu/addressbook-level4 +:repoURL: https://github.com/CS2113-AY1819S1-T12-2 -By: `Team SE-EDU` Since: `Jun 2016` Licence: `MIT` +By: `Team T12-2` Since: `Aug 2018` Licence: `MIT` == Introduction -AddressBook Level 4 (AB4) is for those who *prefer to use a desktop app for managing contacts*. More importantly, AB4 is *optimized for those who prefer to work with a Command Line Interface* (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB4 can get your contact management tasks done faster than traditional GUI apps. Interested? Jump to the <> to get started. Enjoy! +Health Book (or some other name that we will be deciding later) is an address book application that is *catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information* all in one place. *Command Line Interface is utilized mainly for the input*, while GUI is used mainly to display the output. By combining these 2 interfaces, Health Book aims to provide healthcare professionals with the speed and efficiency obtained from a CLI while retaining the systematic view of information through the GUI. -== Quick Start +== Quick Start (to be edited in the future) . Ensure you have Java version `9` or later installed in your Computer. . Download the latest `addressbook.jar` link:{repoURL}/releases[here]. @@ -50,16 +50,35 @@ e.g. typing *`help`* and pressing kbd:[Enter] will open the help window. * Items in square brackets are optional e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. * Items with `…`​ after them can be used multiple times including zero times e.g. `[t/TAG]...` can be used as `{nbsp}` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. * Parameters can be in any order e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. + +*Application Workflow* + +1. Healthcare professionals can create new patient entries with the following mandatory details (i.e. regarded as basic information): + a. Name + b. Phone Number + c. Email Address +2. The following information are optional (i.e. regarded as additional information) and is not required for the creation of patient entries. In fact, these information can only be filled in after the patient entry has been created in step 1: + a. NRIC Number + b. Date of Birth + c. Height + d. Weight + e. Gender + f. Occupation. + g. Marital Status + h. Family Members +3. Medical report/diagnosis can only be added or after patient entries have been created. Additional information need not be completed to attach medical report/diagnosis to a patient. All fields in medical report are mandatory and cannot be omitted during the creation process. + ==== -=== Viewing help : `help` +=== Viewing of available commands : `help` +Displays the list of commands available. + Format: `help` === Adding a person: `add` -Adds a person to the address book + -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` +Create a new patient entry into the health book + +Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS` [TIP] A person can have any number of tags (including 0) @@ -67,37 +86,37 @@ A person can have any number of tags (including 0) Examples: * `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` -* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal` +* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567` -=== Listing all persons : `list` +=== Listing all patients : `list` -Shows a list of all persons in the address book. + +Shows a list of all persons in the health book. + Format: `list` -=== Editing a person : `edit` +=== Editing basic information of patient person : `edit` -Edits an existing person in the address book. + -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]...` +Edits an existing patient in the health book. + +Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS]` **** * Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index *must be a positive integer* 1, 2, 3, ... * At least one of the optional fields must be provided. * Existing values will be updated to the input values. * When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative. -* You can remove all the person's tags by typing `t/` without specifying any tags after it. +* You can remove all the patient's tags by typing `t/` without specifying any tags after it. **** Examples: * `edit 1 p/91234567 e/johndoe@example.com` + -Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively. +Edits the phone number and email address of the 1st patient to be `91234567` and `johndoe@example.com` respectively. * `edit 2 n/Betsy Crower t/` + -Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags. +Edits the name of the 2nd patient to be `Betsy Crower` and clears all existing tags. -=== Locating persons by name: `find` +=== Finding patients by categories: `find` -Finds persons whose names contain any of the given keywords. + -Format: `find KEYWORD [MORE_KEYWORDS]` +Finds patients by categories such as their name, age and marital status. + +Format: `find category/KEYWORD UNDER CATEGORY` **** * The search is case insensitive. e.g `hans` will match `Hans` @@ -109,14 +128,18 @@ Format: `find KEYWORD [MORE_KEYWORDS]` Examples: -* `find John` + +* `find n/John` + Returns `john` and `John Doe` -* `find Betsy Tim John` + -Returns any person having names `Betsy`, `Tim`, or `John` +* `find n/Betsy Tim John` + +Returns any patient having names `Betsy`, `Tim`, or `John` +* `find ms/married` +Returns any patient who is married. +* `find age/18` +Returns any patient who is 18 years old. -=== Deleting a person : `delete` +=== Deleting a patient : `delete` -Deletes the specified person from the address book. + +Deletes the specified patient from the health book. + Format: `delete INDEX` **** @@ -130,131 +153,228 @@ Examples: * `list` + `delete 2` + Deletes the 2nd person in the address book. -* `find Betsy` + +* `find n/Betsy` + `delete 1` + Deletes the 1st person in the results of the `find` command. -=== Selecting a person : `select` +=== Adding patient's medical history: `addhist` -Selects the person identified by the index number used in the displayed person list. + -Format: `select INDEX` +Adds the medical history of a patient. + +Format: `addhist INDEX hsd/MEDICAL_HISTORY_DATE hsa/ALLERGY hsc/PREVIOUS_COUNTRY_VISITED` **** -* Selects the person and loads the Google search page the person at the specified `INDEX`. +* Adds an entry in the medical history of the patient for the patient at the specified INDEX. * The index refers to the index number shown in the displayed person list. -* The index *must be a positive integer* `1, 2, 3, ...` **** Examples: -* `list` + -`select 2` + -Selects the 2nd person in the address book. -* `find Betsy` + -`select 1` + -Selects the 1st person in the results of the `find` command. +* `addhist 1 hsd/ 10/10/2010 hsa/ Alcohol hsc/ Kuwait` +Adds a medical history entry for the 1st person in the list on 10/10/2010 with an alcohol allergy and Kuwait as previous country visited. -=== Listing entered commands : `history` +=== Adding an appointment into patient's timetable: `addappt` -Lists all the commands that you have entered in reverse chronological order. + -Format: `history` +Adds an appointment into the specified patient's timetable. + +Format: `addappt INDEX d/DATE s/START_TIME e/END_TIME v/VENUE i/APPOINTMENT_INFORMATION dn/DOCTOR_NAME` -[NOTE] -==== -Pressing the kbd:[↑] and kbd:[↓] arrows will display the previous and next input respectively in the command box. -==== +**** +* Adds an appointment for the patient at the specified INDEX. +* The index refers to the index number shown in the displayed person list. +**** -// tag::undoredo[] -=== Undoing previous command : `undo` +Examples: -Restores the address book to the state before the previous _undoable_ command was executed. + -Format: `undo` +* `addappt 2 d/12092018 s/1300 e/1400 v/Consultation Room 12 i/Diabetes Checkup dn/Dr Tan` + +Adds an appointment for the 2nd person in the list on 12/09/2018 from 1300-1400 at Consultation Room 12 for a diabetes checkup by Dr Tan -[NOTE] -==== -Undoable commands: those commands that modify the address book's content (`add`, `delete`, `edit` and `clear`). -==== +=== Viewing a patient's appointments timetable: `viewappts` + +Shows a list of all appointments in the specified patient's timetable. + +Format: `viewappts INDEX` + +**** +* Views all appointments of the patient at the specified index. +* The index refers to the index number shown in the displayed person list. +**** + +Examples: + +* `viewappts 2` + +Views all appointments of the 2nd person in the list. + +=== Editing an appointment in a patient's timetable: `editappt` + +Edits a specified appointment in the patient's timetable. + +Format: `editappt INDEX [d/DATE] [s/START_TIME] [e/END_TIME] +[v/VENUE] [i/APPOINTMENT_INFORMATION] [dn/DOCTOR_NAME]` + +**** +* Edits a patient’s appointment at the specified index. +* The index refers to the index number shown in the displayed appointment list. +* At least one of the optional fields must be provided. +* Existing values will be updated to the input values. +**** + +Examples: + +* `editappt 2 s/1400 e/1500 v/Consultation Room 13` + +Edits the 2nd appointment in the list to have start time of 1400, end time of 1500, +and venue of Consultation Room 13. + +=== Deleting an appointment in a patient’s timetable: `deleteappt` + +Deletes a specified appointment in the patient’s timetable. + +Format: `deleteappt INDEX` + +**** +* Deletes a patient’s appointment at the specified index. +* The index refers to the index number shown in the displayed appointment list. +**** Examples: -* `delete 1` + -`list` + -`undo` (reverses the `delete 1` command) + +* `deleteappt 2` + +Deletes the 2nd appointment in the displayed appointment list. + +=== Adding additional information of patient: `addinfo` + +Add the following additional information: NRIC, DOB (in DDMMYYYY format), height (cm), weight (kg), +gender, occupation, marital status, family member. + +Note: age field will be auto-calculated once DOB is populated + +Format: `addinfo INDEX [i/NRIC] [d/DOB]` + +.Constraints for `[i/NRIC]`: +* Must start with 'S' or 'T' followed by 7 digits before ending with an alphabet + +.Constraints for `[d/DOB]`: +* Must be in the format `dd-MM-YYYY` + +Work In Progress: `[h/HEIGHT] [w/WEIGHT] [g/GENDER] [o/OCCUPATION] [m/MARITAL_STATUS] [f/FAMILY_MEMBER_INDEX]` -* `select 1` + -`list` + -`undo` + -The `undo` command fails as there are no undoable commands executed previously. +Examples: -* `delete 1` + -`clear` + -`undo` (reverses the `clear` command) + -`undo` (reverses the `delete 1` command) + +* `addinfo 2 n/S9123456A d/01-01-1990` + +For patient in index 2, populate NRIC field with S91234567A, date of birth field +with 01-01-1990, height field with 154, gender field with Male and associate +patient in index 3 as family member. -=== Redoing the previously undone command : `redo` +=== Adding of Medical Report: `addreport` -Reverses the most recent `undo` command. + -Format: `redo` +Add medical diagnosis/report to the patient. + +Format: `addreport INDEX [t/TITLE] [d/DATE] [i/INFORMATION]` Examples: -* `delete 1` + -`undo` (reverses the `delete 1` command) + -`redo` (reapplies the `delete 1` command) + +* `addreport 3 t/Asthma d/01/01/2018 i/Prescribed XXX medicine, next appointment on 02/02/2018.` + +Adds a new medical report for patient at index 3 titled Asthma, dated 01/01/2018 with the report's information. + +=== Editing of Medical Report: `editreport` + +Edit existing medical diagnosis/report of the patient. + +Format: `editreport INDEX_PATIENT INDEX_REPORT [t/TITLE] [d/DATE] [i/INFORMATION]` + +**** +* `INDEX_PATIENT` refers to the index shown in the displayed person list +* `INDEX_REPORT` refers to the index shown in the displayed report list +**** -* `delete 1` + -`redo` + -The `redo` command fails as there are no `undo` commands executed previously. +Examples: -* `delete 1` + -`clear` + -`undo` (reverses the `clear` command) + -`undo` (reverses the `delete 1` command) + -`redo` (reapplies the `delete 1` command) + -`redo` (reapplies the `clear` command) + -// end::undoredo[] +* `editreport 3 1 t/Depression d/02/02/2018 i/Prescribed XXX medicine, next appointment on 03/03/2018.` + +Edits title, date and information of existing medical report at index 1 for patient at index 3. -=== Clearing all entries : `clear` +=== List of Medical Report: `listreport` -Clears all entries from the address book. + -Format: `clear` +List all medical diagnosis/reports of a patient + +Format: `listreport INDEX` -=== Exiting the program : `exit` +Examples: -Exits the program. + -Format: `exit` +* `listreport 1` + +List all medical reports/diagnosis that are attached to patient at index 1. -=== Saving the data +=== Sort patients list: `sortlist` -Address book data are saved in the hard disk automatically after any command that changes the data. + -There is no need to save manually. +Sort the list of patients according to a specific category. + +Format: `sortlist CATEGORY ORDER_INDEX` -// tag::dataencryption[] -=== Encrypting data files `[coming in v2.0]` +`CATEGORY` refers to certain types of important patient information such as name, blood type, +allergy etc. and each of these information will be defined by their first letter. (ie n for name) +`ORDER_INDEX` can be 1 or 2 where 1 means in alphabetical and 2 means in reverse order. -_{explain how the user can enable/disable data encryption}_ -// end::dataencryption[] +Example: + +* `sortlist n 2` + +Sort the patient list by their names in reverse order (Z → A). + +=== View patient’s information: `view` + +View patient’s general and additional information. + +Format: `view INDEX` + +Example: + +* `view 1` + +Display information of patient at index 1 + +=== Import files to other computers: `import` + +Import patient’s info as a txt file from a specified directory and file name. + +Format: `import DIRECTORY_NAME/FILE_NAME` + +Example: + +* `import Desktop/patient1info.txt` + +=== Export files to other computers: `export` + +Export patient’s info as a txt file to a specified directory and file name. + +Format: `export INDEX DIRECTORY_NAME/FILE_NAME` + +Example: + +* `export 1 Desktop/patient1info.txt` == FAQ -*Q*: How do I transfer my data to another Computer? + -*A*: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous Address Book folder. +Empty. == Command Summary -* *Add* `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` + -e.g. `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague` -* *Clear* : `clear` -* *Delete* : `delete INDEX` + -e.g. `delete 3` -* *Edit* : `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]...` + -e.g. `edit 2 n/James Lee e/jameslee@example.com` -* *Find* : `find KEYWORD [MORE_KEYWORDS]` + -e.g. `find James Jake` +* *Add* `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS` + +e.g. `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` * *List* : `list` -* *Help* : `help` -* *Select* : `select INDEX` + -e.g.`select 2` -* *History* : `history` -* *Undo* : `undo` -* *Redo* : `redo` +* *Edit* : `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS]` + +e.g. `edit 1 p/91234567 e/johndoe@example.com` +* *Find* : `find category/KEYWORD UNDER CATEGORY` + +e.g. `find ms/married` + +e.g. `find age/18` + +e.g. `find n/Betsy Tim John` +* *Delete* : `delete INDEX` + +e.g. `delete 2` +* *Add Timetable* : `add timetable INDEX d/DATE s/START_TIME e/END_TIME v/VENUE i/APPOINTMENT_INFORMATION dn/DOCTOR_NAME` + +e.g. `add timetable 2 d/12092018 s/1300 e/1400 v/Consultation Room 12 i/Diabetes Checkup dn/Dr Tan` +* *View Timetable* : `view timetable INDEX` + +e.g. `view timetable 2` +* *Edit Timetable* : `edit timetable INDEX [d/DATE] [s/START_TIME] [e/END_TIME] [v/VENUE] [i/APPOINTMENT_INFORMATION] [dn/DOCTOR_NAME]` + +e.g.`edit timetable 2 s/1400 e/1500 v/Consultation Room 13` +* *Delete Timetable* : `delete timetable INDEX` + +e.g. `delete timetable 2` +* *Add Information* : `addinfo INDEX [n/NRIC] [d/DOB] [h/HEIGHT] [w/WEIGHT] [g/GENDER] [o/OCCUPATION] [m/MARITAL_STATUS] [f/FAMILY_MEMBER_INDEX]` + +e.g. `addinfo 2 n/S9123456A d/01011990 h/154 g/M f/3` +* *Edit Information* : `editinfo INDEX [n/NRIC] [d/DOB] [h/HEIGHT] [w/WEIGHT] [g/GENDER] [o/OCCUPATION] [m/MARITAL_STATUS] [f/FAMILY_MEMBER_INDEX]` + +e.g. `editinfo 2 n/S9123456A d/01011990 h/154 g/M f/3` +* *Add Medical Report* : `addreport INDEX [t/TITLE] [d/DATE] [mr/MEDICAL_REPORT]` + +e.g. `addreport 3 t/ASTHMA d/01012018 mr/Patient diagnosed with asthma and prescribed XXX medicine. Next appointment on 02-02-2018.` +* *Edit Medical Report* : `editreport INDEX_PATIENT INDEX_REPORT [t/TITLE] [d/DATE] [mr/MEDICAL_REPORT]` + +e.g. `editreport 3 1 t/DEPRESSION d/02012018 mr/Patient diagnosed with depression and prescribed XXX medicine. Next appointment is on 03-02-2018.` +* *List Medical Report* : `listreport INDEX` + +e.g. `listreport 1` +* *Sort* : `sortlist CATEGORY ORDER_INDEX` + +e.g. `sortlist n 2` +* *View* : `view INDEX` + +e.g. view 1 +* *Import Document* : `import DIRECTORY_NAME/FILE_NAME` + +e.g. `import Desktop/patient1info.txt` +* *Export Document* : `export INDEX DIRECTORY_NAME/FILE_NAME` + +e.g. `export 1 Desktop/patient1info.txt` diff --git a/docs/UsingGradle.adoc b/docs/UsingGradle.adoc index d1be2f3b7c3a..05f66ca27fcb 100644 --- a/docs/UsingGradle.adoc +++ b/docs/UsingGradle.adoc @@ -47,7 +47,7 @@ Creates the `addressbook.jar` file in the `build/jar` folder, _if the current fi e.g. `./gradlew shadowJar` **** -To force Gradle to create the JAR file even if the current one is up-to-date, you can '`clean`' first. + +To force Gradle to create the JAR file even if the current one is up-to-reportDate, you can '`clean`' first. + e.g. `./gradlew clean shadowJar` **** diff --git a/docs/images/AddApptSequenceDiagram.png b/docs/images/AddApptSequenceDiagram.png new file mode 100644 index 000000000000..b1b110ef636c Binary files /dev/null and b/docs/images/AddApptSequenceDiagram.png differ diff --git a/docs/images/AddMedicalReportSequenceDiagram.png b/docs/images/AddMedicalReportSequenceDiagram.png new file mode 100644 index 000000000000..e342e6b2b211 Binary files /dev/null and b/docs/images/AddMedicalReportSequenceDiagram.png differ diff --git a/docs/images/MockUi.png b/docs/images/MockUi.png new file mode 100644 index 000000000000..b14efb74ffda Binary files /dev/null and b/docs/images/MockUi.png differ diff --git a/docs/images/brandonccm1996.png b/docs/images/brandonccm1996.png new file mode 100644 index 000000000000..c728a8b2544f Binary files /dev/null and b/docs/images/brandonccm1996.png differ diff --git a/docs/images/chewkahmeng.png b/docs/images/chewkahmeng.png new file mode 100644 index 000000000000..34e7bee5c22c Binary files /dev/null and b/docs/images/chewkahmeng.png differ diff --git a/docs/images/chokxy.png b/docs/images/chokxy.png new file mode 100644 index 000000000000..ed2617696d31 Binary files /dev/null and b/docs/images/chokxy.png differ diff --git a/docs/images/damithc.jpg b/docs/images/damithc.jpg deleted file mode 100644 index 127543883893..000000000000 Binary files a/docs/images/damithc.jpg and /dev/null differ diff --git a/docs/images/lejolly.jpg b/docs/images/lejolly.jpg deleted file mode 100644 index 2d1d94e0cf5d..000000000000 Binary files a/docs/images/lejolly.jpg and /dev/null differ diff --git a/docs/images/m133225.jpg b/docs/images/m133225.jpg deleted file mode 100644 index fd14fb94593a..000000000000 Binary files a/docs/images/m133225.jpg and /dev/null differ diff --git a/docs/images/xhxh96.png b/docs/images/xhxh96.png new file mode 100644 index 000000000000..4901ce73798d Binary files /dev/null and b/docs/images/xhxh96.png differ diff --git a/docs/images/xshaivan.png b/docs/images/xshaivan.png new file mode 100644 index 000000000000..c97aa890cf9d Binary files /dev/null and b/docs/images/xshaivan.png differ diff --git a/docs/images/yijinl.jpg b/docs/images/yijinl.jpg deleted file mode 100644 index adbf62ad9406..000000000000 Binary files a/docs/images/yijinl.jpg and /dev/null differ diff --git a/docs/images/yl_coder.jpg b/docs/images/yl_coder.jpg deleted file mode 100644 index 17b48a732272..000000000000 Binary files a/docs/images/yl_coder.jpg and /dev/null differ diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java index 1deb3a1e4695..86fb3a5a6ed6 100644 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ b/src/main/java/seedu/address/commons/core/Messages.java @@ -9,5 +9,6 @@ public class Messages { public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; - + public static final String MESSAGE_PERSONS_SORTED = "%1$d persons sorted!"; + public static final String MESSAGE_INVALID_COMMAND = "Invalid command format! \n%1$s"; } diff --git a/src/main/java/seedu/address/logic/commands/AddApptCommand.java b/src/main/java/seedu/address/logic/commands/AddApptCommand.java new file mode 100644 index 000000000000..1ae76cf7f46d --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddApptCommand.java @@ -0,0 +1,111 @@ +package seedu.address.logic.commands; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_DRNAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_END; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_INFO; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_START; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_VENUE; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.person.Person; +import seedu.address.model.timetable.Appt; + +/** + * Adds an appointment to a person's timetable. + */ +public class AddApptCommand extends Command { + + public static final String COMMAND_WORD = "addappt"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an appointment to a patient's timetable, the" + + " patient will be identified by the index number used in the last person listing.\n" + + "Parameters: INDEX (must be a positive integer) " + + PREFIX_APPT_START + "[START] " + + PREFIX_APPT_END + "[END] " + + PREFIX_APPT_VENUE + "[VENUE] " + + PREFIX_APPT_INFO + "[INFO] " + + PREFIX_APPT_DRNAME + "[DOCTOR'S NAME]\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_APPT_START + "16/09/2018 1500 " + + PREFIX_APPT_END + "16/09/2018 1530 " + + PREFIX_APPT_VENUE + "Consultation Room 12 " + + PREFIX_APPT_INFO + "Diabetes Checkup " + + PREFIX_APPT_DRNAME + "Dr Tan"; + + public static final String MESSAGE_ADD_APPT_SUCCESS = "Added appt to Person: %1$s"; + public static final String MESSAGE_DELETE_APPT_SUCCESS = "Removed appt from Person: %1$s"; + + private final Index index; + private final Appt appt; + + /** + * @param index of the person in the filtered person list to add appt + * @param appt of the person to be updated to + */ + public AddApptCommand(Index index, Appt appt) { + requireAllNonNull(index, appt); + this.index = index; + this.appt = appt; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + Person personToEdit = lastShownList.get(index.getZeroBased()); + Set oldAppts = personToEdit.getAppts(); + Set newAppts = new HashSet<>(); + for (Appt appt : oldAppts) { + newAppts.add(appt); + } + newAppts.add(appt); + Person editedPerson = new Person(personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), + personToEdit.getAddress(), personToEdit.getMedicalReports(), personToEdit.getMedHistory(), newAppts, + personToEdit.getNric(), personToEdit.getDateOfBirth(), personToEdit.getTags()); + + model.updatePerson(personToEdit, editedPerson); + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + model.commitAddressBook(); + + return new CommandResult(generateSuccessMessage(editedPerson)); + } + + /** + * Generates a command execution success message when the appt is added to + * {@code personToEdit}. + */ + private String generateSuccessMessage(Person personToEdit) { + return String.format(MESSAGE_ADD_APPT_SUCCESS, personToEdit); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof AddApptCommand)) { + return false; + } + + // state check + AddApptCommand e = (AddApptCommand) other; + return index.equals(e.index) && appt.equals(e.appt); + } +} diff --git a/src/main/java/seedu/address/logic/commands/AddHistCommand.java b/src/main/java/seedu/address/logic/commands/AddHistCommand.java new file mode 100644 index 000000000000..68c17a6196bb --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddHistCommand.java @@ -0,0 +1,97 @@ +package seedu.address.logic.commands; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_HISTORY_ALLERGY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_HISTORY_COUNTRY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_HISTORY_DATE; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.person.Person; + +/** + * Adds/Edits medical history of a patient in the Health Book. + */ + +public class AddHistCommand extends Command { + + public static final String COMMAND_WORD = "addhist"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds/Edits medical history of a patient " + + "by their index number." + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_HISTORY_DATE + " 24/08/1993 " + + PREFIX_HISTORY_ALLERGY + " Alcohol " + + PREFIX_HISTORY_COUNTRY + " Kuwait "; + + public static final String MESSAGE_ADD_MEDHISTORY_SUCCESS = "Added medical history to Person: %1$s"; + public static final String MESSAGE_DELETE_MEDHISTORY_SUCCESS = "Removed medical history from Person: %1$s"; + private final Index index; + private final MedHistory medHistory; + /** + * @param index of the patient in the filtered patient list to add medical history + * @param medHistory of the person to be updated to + */ + public AddHistCommand(Index index, MedHistory medHistory) { + requireAllNonNull(index, medHistory); + this.index = index; + this.medHistory = medHistory; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + List lastShownList = model.getFilteredPersonList(); + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + Person personToEdit = lastShownList.get(index.getZeroBased()); + Set fullMedHistories = personToEdit.getMedHistory(); + Set newMedHistories = new HashSet<>(); + // for loop overwrites all existing history with itself + for (MedHistory medHistory : fullMedHistories) { + newMedHistories.add(medHistory); + } + // adds the new history from command + newMedHistories.add(medHistory); + Person editedPerson = new Person(personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), + personToEdit.getAddress(), personToEdit.getMedicalReports(), newMedHistories, personToEdit.getAppts(), + personToEdit.getNric(), personToEdit.getDateOfBirth(), personToEdit.getTags()); + model.updatePerson(personToEdit, editedPerson); + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + model.commitAddressBook(); + return new CommandResult(generateSuccessMessage(editedPerson)); + } + + /** + * Generates a command execution success message based on whether the medical history is added to or removed from + * {@code personToEdit}. + */ + private String generateSuccessMessage(Person personToEdit) { + return String.format(MESSAGE_ADD_MEDHISTORY_SUCCESS, personToEdit); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + // instanceof handles nulls + if (!(other instanceof AddHistCommand)) { + return false; + } + // state check + AddHistCommand e = (AddHistCommand) other; + return index.equals(e.index) + && medHistory.equals(e.medHistory); + } +} diff --git a/src/main/java/seedu/address/logic/commands/AddInfoCommand.java b/src/main/java/seedu/address/logic/commands/AddInfoCommand.java new file mode 100644 index 000000000000..6ac973713ba6 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddInfoCommand.java @@ -0,0 +1,173 @@ +package seedu.address.logic.commands; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.CollectionUtil; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medicalreport.MedicalReport; +import seedu.address.model.person.Address; +import seedu.address.model.person.DateOfBirth; +import seedu.address.model.person.Email; +import seedu.address.model.person.Name; +import seedu.address.model.person.Nric; +import seedu.address.model.person.Person; +import seedu.address.model.person.Phone; +import seedu.address.model.tag.Tag; +import seedu.address.model.timetable.Appt; + +/** + * Edits optional details of an existing patient in the address book. + */ + +public class AddInfoCommand extends Command { + public static final String COMMAND_WORD = "addinfo"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Edits the additional information of the person identified " + + "by the index number used in the last person listing. " + + "Existing information will be overwritten by the input.\n" + + "Parameters: INDEX (must be a positive integer) " + + "Example: " + COMMAND_WORD + " 1 "; + + public static final String MESSAGE_NOT_EDITED = "At least one field to add additional information must be provided"; + public static final String MESSAGE_ADD_INFO_SUCCESS = "Added additional info to Person: %1$s"; + public static final String MESSAGE_DELETE_INFO_SUCCESS = "Removed additional info to person: %1$s"; + + private final Index index; + private final AddInfoPersonDescriptor addInfoPersonDescriptor; + + + /** + * + * @param index of the person in the filter person list to edit the additional info + * @param addInfoPersonDescriptor details to add to the person + */ + public AddInfoCommand(Index index, AddInfoPersonDescriptor addInfoPersonDescriptor) { + requireAllNonNull(index, addInfoPersonDescriptor); + + this.index = index; + this.addInfoPersonDescriptor = new AddInfoPersonDescriptor(addInfoPersonDescriptor); + } + + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireAllNonNull(model); + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + Person personToEdit = lastShownList.get(index.getZeroBased()); + Person editedPerson = createEditedPerson(personToEdit, addInfoPersonDescriptor); + + model.updatePerson(personToEdit, editedPerson); + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + model.commitAddressBook(); + return new CommandResult(String.format(MESSAGE_ADD_INFO_SUCCESS, editedPerson)); + } + + /** + * Creates and returns a {@code Person} with the details of {@code personToEdit} + * edited with {@code editPersonDescriptor}. + */ + private static Person createEditedPerson(Person personToEdit, AddInfoPersonDescriptor addInfoPersonDescriptor) { + assert personToEdit != null; + + Name name = personToEdit.getName(); + Phone phone = personToEdit.getPhone(); + Email email = personToEdit.getEmail(); + Address address = personToEdit.getAddress(); + Set appts = personToEdit.getAppts(); + Set medicalReports = personToEdit.getMedicalReports(); + Set medHistory = personToEdit.getMedHistory(); + Set tags = personToEdit.getTags(); + + Nric updatedNric = addInfoPersonDescriptor.getNric().orElse(personToEdit.getNric()); + DateOfBirth updatedDateOfBirth = addInfoPersonDescriptor.getDateOfBirth().orElse(personToEdit.getDateOfBirth()); + + return new Person(name, phone, email, address, medicalReports, medHistory, appts, + updatedNric, updatedDateOfBirth, tags); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof AddInfoCommand)) { + return false; + } + + // state check + AddInfoCommand e = (AddInfoCommand) other; + return index.equals(e.index) + && addInfoPersonDescriptor.equals(e.addInfoPersonDescriptor); + } + + /** + * Stores the details to add additional info to the person. Each non-empty field value will replace the + * corresponding field value of the person + */ + public static class AddInfoPersonDescriptor { + private Nric nric; + private DateOfBirth dateOfBirth; + + public AddInfoPersonDescriptor() {} + + public AddInfoPersonDescriptor(AddInfoPersonDescriptor toCopy) { + setNric(toCopy.nric); + setDateOfBirth(toCopy.dateOfBirth); + } + + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(nric, dateOfBirth); + } + + public void setNric(Nric nric) { + this.nric = nric; + } + + public Optional getNric() { + return Optional.ofNullable(nric); + } + + public void setDateOfBirth(DateOfBirth dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public Optional getDateOfBirth() { + return Optional.ofNullable(dateOfBirth); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof AddInfoPersonDescriptor)) { + return false; + } + + AddInfoPersonDescriptor e = (AddInfoPersonDescriptor) other; + + return getNric().equals(e.getNric()) + && getDateOfBirth().equals(e.getDateOfBirth()); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/AddMedicalReportCommand.java b/src/main/java/seedu/address/logic/commands/AddMedicalReportCommand.java new file mode 100644 index 000000000000..3867282fc6a6 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddMedicalReportCommand.java @@ -0,0 +1,101 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TITLE; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.medicalreport.MedicalReport; +import seedu.address.model.person.Person; + +/** + * Adds a medical report to a person. + */ +public class AddMedicalReportCommand extends Command { + + public static final String COMMAND_WORD = "addreport"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person's medical report by the index number" + + " used in the list.\n" + + "Parameters: [INDEX] (must be a positive integer) " + + PREFIX_TITLE + "[TITLE] " + + PREFIX_DATE + "[DATE] " + + PREFIX_INFORMATION + "[INFORMATION]\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_TITLE + "Asthma " + + PREFIX_DATE + "01/01/2018 " + + PREFIX_INFORMATION + "prescribed XXX medicine, next appointment on 02/02/2018. "; + + public static final String MESSAGE_ADD_REPORT_SUCCESS = "Added medical report to Person: %1$s"; + + private final Index index; + private final MedicalReport report; + + /** + * Creates an AddMedicalReportCommand to add the specified {@code index and report} + * @param index of the person in the filtered person list to add medical report + * @param report details of medical report + */ + public AddMedicalReportCommand(Index index, MedicalReport report) { + requireNonNull(index); + requireNonNull(report); + this.index = index; + this.report = report; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + Person personToEdit = lastShownList.get(index.getZeroBased()); + Set oldReports = personToEdit.getMedicalReports(); + Set newReports = new HashSet<>(); + for (MedicalReport report : oldReports) { + newReports.add(report); + } + newReports.add(report); + Person editedPerson = new Person(personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), + personToEdit.getAddress(), newReports, personToEdit.getMedHistory(), personToEdit.getAppts(), + personToEdit.getNric(), personToEdit.getDateOfBirth(), personToEdit.getTags()); + + model.updatePerson(personToEdit, editedPerson); + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + model.commitAddressBook(); + + return new CommandResult(generateSuccessMessage(editedPerson)); + } + + private String generateSuccessMessage(Person personToEdit) { + return String.format(MESSAGE_ADD_REPORT_SUCCESS, personToEdit); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + // instanceof handles nulls + if (!(other instanceof AddMedicalReportCommand)) { + return false; + } + // state check + AddMedicalReportCommand e = (AddMedicalReportCommand) other; + return index.equals(e.index) + && report.equals(e.report); + } +} diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index dc782d8e230f..3d00a3b942c9 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -20,12 +20,17 @@ import seedu.address.logic.CommandHistory; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medicalreport.MedicalReport; import seedu.address.model.person.Address; +import seedu.address.model.person.DateOfBirth; import seedu.address.model.person.Email; import seedu.address.model.person.Name; +import seedu.address.model.person.Nric; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.timetable.Appt; /** * Edits the details of an existing person in the address book. @@ -99,9 +104,16 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); + + Set updatedReports = personToEdit.getMedicalReports(); // edit command disallow editing reports + Set updatedMedHistory = personToEdit.getMedHistory(); // edit command does not edit MedHistory now + Set updatedAppts = personToEdit.getAppts(); // edit command does not allow editing appts + Nric updatedNric = personToEdit.getNric(); + DateOfBirth updatedDateOfBirth = personToEdit.getDateOfBirth(); Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); + return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedReports, + updatedMedHistory, updatedAppts, updatedNric, updatedDateOfBirth, updatedTags); } @Override diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java index beb178e3a3f5..551186c4913d 100644 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ b/src/main/java/seedu/address/logic/commands/FindCommand.java @@ -2,30 +2,35 @@ import static java.util.Objects.requireNonNull; +import java.util.function.Predicate; + import seedu.address.commons.core.Messages; import seedu.address.logic.CommandHistory; import seedu.address.model.Model; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.Person; /** - * Finds and lists all persons in address book whose name contains any of the argument keywords. + * Finds and lists all persons in address book whose prefix contains any of the argument keyword. * Keyword matching is case insensitive. + * v1.2 find by 1 keyword for name, phone, email, address, tag + * v1.3 will find by different categories with 1 keyword each */ public class FindCommand extends Command { public static final String COMMAND_WORD = "find"; - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of " - + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose PREFIX contain any " + + "of the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" + + "Parameters: PREFIX KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " n/ " + " alice" + " or " + "p/ " + "91234567."; - private final NameContainsKeywordsPredicate predicate; + private final Predicate predicate; - public FindCommand(NameContainsKeywordsPredicate predicate) { + public FindCommand(Predicate predicate) { this.predicate = predicate; } + @Override public CommandResult execute(Model model, CommandHistory history) { requireNonNull(model); diff --git a/src/main/java/seedu/address/logic/commands/SortCommand.java b/src/main/java/seedu/address/logic/commands/SortCommand.java new file mode 100644 index 000000000000..647f259e6352 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/SortCommand.java @@ -0,0 +1,30 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import seedu.address.commons.core.Messages; +import seedu.address.logic.CommandHistory; +import seedu.address.model.Model; + +/** + * Sorts and lists all persons in address book by their name. + * (Currently can only sort by PREFIX name and ORDER 1) + */ + +public class SortCommand extends Command { + public static final String COMMAND_WORD = "sort"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + " all persons by PREFIX by preferred order " + + "and display as a list with index numbers.\n" + + "Parameters: PREFIX INDEX (1 for alphabetical, 2 for reverse order) \n" + + "Example: " + COMMAND_WORD + " n/ " + "1"; + + @Override + public CommandResult execute(Model model, CommandHistory history) { + requireNonNull(model); + model.updateSortedPersonList(PREDICATE_SHOW_ALL_PERSONS); + return new CommandResult( + String.format(Messages.MESSAGE_PERSONS_SORTED, model.getSortedPersonList().size())); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddApptCommandParser.java b/src/main/java/seedu/address/logic/parser/AddApptCommandParser.java new file mode 100644 index 000000000000..62465ee0a55c --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/AddApptCommandParser.java @@ -0,0 +1,64 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_DRNAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_END; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_INFO; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_START; +import static seedu.address.logic.parser.CliSyntax.PREFIX_APPT_VENUE; + +import java.util.stream.Stream; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.AddApptCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.timetable.Appt; +import seedu.address.model.timetable.ApptDateTime; +import seedu.address.model.timetable.ApptDrName; +import seedu.address.model.timetable.ApptInfo; +import seedu.address.model.timetable.ApptVenue; + +/** + * Parses input arguments and creates a new {@code AddApptCommand} object + */ +public class AddApptCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the {@code AddApptCommand} + * and returns a {@code AddApptCommand} object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public AddApptCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_APPT_START, PREFIX_APPT_END, + PREFIX_APPT_VENUE, PREFIX_APPT_INFO, PREFIX_APPT_DRNAME); + + if (!arePrefixesPresent(argMultimap, PREFIX_APPT_START, PREFIX_APPT_END, PREFIX_APPT_VENUE, PREFIX_APPT_INFO, + PREFIX_APPT_DRNAME)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddApptCommand.MESSAGE_USAGE)); + } + + Index index; + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddApptCommand.MESSAGE_USAGE), ive); + } + + ApptDateTime start = ParserUtil.parseApptTime(argMultimap.getValue(PREFIX_APPT_START).get()); + ApptDateTime end = ParserUtil.parseApptTime(argMultimap.getValue(PREFIX_APPT_END).get()); + ApptVenue venue = ParserUtil.parseApptVenue(argMultimap.getValue(PREFIX_APPT_VENUE).get()); + ApptInfo info = ParserUtil.parseApptInfo(argMultimap.getValue(PREFIX_APPT_INFO).get()); + ApptDrName drName = ParserUtil.parseApptDrName(argMultimap.getValue(PREFIX_APPT_DRNAME).get()); + return new AddApptCommand(index, new Appt(start, end, venue, info, drName)); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java index 3b8bfa035e83..c4f57213cbe0 100644 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java @@ -7,17 +7,23 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import java.util.HashSet; import java.util.Set; import java.util.stream.Stream; import seedu.address.logic.commands.AddCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medicalreport.MedicalReport; import seedu.address.model.person.Address; +import seedu.address.model.person.DateOfBirth; import seedu.address.model.person.Email; import seedu.address.model.person.Name; +import seedu.address.model.person.Nric; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.timetable.Appt; /** * Parses input arguments and creates a new AddCommand object @@ -42,9 +48,15 @@ public AddCommand parse(String args) throws ParseException { Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()); + Set medHistories = new HashSet<>(); + Set appts = new HashSet<>(); // add command does not allow adding appts straight away + Nric nric = new Nric(""); + Set reports = new HashSet<>(); // add command does not allow adding reports straight away + DateOfBirth dateOfBirth = new DateOfBirth("01-01-1970"); Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); - Person person = new Person(name, phone, email, address, tagList); + Person person = new Person(name, phone, email, address, reports, medHistories, appts, nric, dateOfBirth, + tagList); return new AddCommand(person); } diff --git a/src/main/java/seedu/address/logic/parser/AddHistCommandParser.java b/src/main/java/seedu/address/logic/parser/AddHistCommandParser.java new file mode 100644 index 000000000000..5c80a6f8f9c6 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/AddHistCommandParser.java @@ -0,0 +1,63 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_HISTORY_ALLERGY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_HISTORY_COUNTRY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_HISTORY_DATE; + +import java.util.stream.Stream; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.AddHistCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.medhistory.Allergy; +import seedu.address.model.medhistory.MedHistDate; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medhistory.PrevCountry; + + +/** + * Parses input arguments and create a {@code AddHistCommand} object + */ + +public class AddHistCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the {@code AddHistCommand} + * and returns a {@code AddHistCommand} object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + + public AddHistCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_HISTORY_DATE, PREFIX_HISTORY_ALLERGY, + PREFIX_HISTORY_COUNTRY); + + if (!arePrefixesPresent(argMultimap, PREFIX_HISTORY_DATE, PREFIX_HISTORY_ALLERGY, + PREFIX_HISTORY_COUNTRY)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddHistCommand.MESSAGE_USAGE)); + } + + Index index; + + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddHistCommand.MESSAGE_USAGE), ive); + } + + Allergy allergy = ParserUtil.parseAllergy(argMultimap.getValue(PREFIX_HISTORY_ALLERGY).get()); + PrevCountry prevCountry = ParserUtil.parsePrevCountry(argMultimap.getValue(PREFIX_HISTORY_COUNTRY).get()); + MedHistDate medHistDate = ParserUtil.parseMedHistDate(argMultimap.getValue(PREFIX_HISTORY_DATE).get()); + return new AddHistCommand(index, new MedHistory (medHistDate, allergy, prevCountry)); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddInfoCommandParser.java b/src/main/java/seedu/address/logic/parser/AddInfoCommandParser.java new file mode 100644 index 000000000000..690af0d3fd69 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/AddInfoCommandParser.java @@ -0,0 +1,50 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADD_INFO_DOB; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADD_INFO_NRIC; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.AddInfoCommand; +import seedu.address.logic.commands.AddInfoCommand.AddInfoPersonDescriptor; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new {@code AddInfoCommand} object + */ +public class AddInfoCommandParser implements Parser { + /** + * + * Parse the given {@code String} of arguments in the context of {@code AddInfoCommand} + * and returns a {@code AddInfoCommand} object for execution. + * @throws ParseException if the user input does not conform to expected format + */ + public AddInfoCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultiMap = ArgumentTokenizer.tokenize(args, PREFIX_ADD_INFO_NRIC, PREFIX_ADD_INFO_DOB); + + Index index; + try { + index = ParserUtil.parseIndex(argMultiMap.getPreamble()); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddInfoCommand.MESSAGE_USAGE), ive); + } + + AddInfoPersonDescriptor addInfoPersonDescriptor = new AddInfoPersonDescriptor(); + if (argMultiMap.getValue(PREFIX_ADD_INFO_NRIC).isPresent()) { + addInfoPersonDescriptor.setNric(ParserUtil.parseNric(argMultiMap.getValue(PREFIX_ADD_INFO_NRIC).get())); + } + if (argMultiMap.getValue(PREFIX_ADD_INFO_DOB).isPresent()) { + addInfoPersonDescriptor.setDateOfBirth(ParserUtil.parseDateOfBirth( + argMultiMap.getValue(PREFIX_ADD_INFO_DOB).get())); + } + + if (!addInfoPersonDescriptor.isAnyFieldEdited()) { + throw new ParseException(AddInfoCommand.MESSAGE_NOT_EDITED); + } + + return new AddInfoCommand(index, addInfoPersonDescriptor); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddMedicalReportCommandParser.java b/src/main/java/seedu/address/logic/parser/AddMedicalReportCommandParser.java new file mode 100644 index 000000000000..ff3f3bc4c387 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/AddMedicalReportCommandParser.java @@ -0,0 +1,59 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TITLE; + +import java.util.stream.Stream; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.AddMedicalReportCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.medicalreport.Information; +import seedu.address.model.medicalreport.MedicalReport; +import seedu.address.model.medicalreport.ReportDate; +import seedu.address.model.medicalreport.Title; + +/** + * Parses input arguments and creates a new AddMedicalReport object + */ +public class AddMedicalReportCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the AddMedicalReportCommand + * and returns an AddMedicalReportCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + + public AddMedicalReportCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_TITLE, PREFIX_DATE, + PREFIX_INFORMATION); + if (!arePrefixesPresent(argMultimap, PREFIX_TITLE, PREFIX_DATE, PREFIX_INFORMATION)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND, AddMedicalReportCommand.MESSAGE_USAGE)); + } + + Index index; + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND, AddMedicalReportCommand.MESSAGE_USAGE)); + } + + Title title = ParserUtil.parseTitle(argMultimap.getValue(PREFIX_TITLE).get()); + ReportDate date = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get()); + Information information = ParserUtil.parseInformation(argMultimap.getValue(PREFIX_INFORMATION).get()); + + return new AddMedicalReportCommand(index, new MedicalReport(title, date, information)); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index b7d57f5db86a..0199978df851 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -6,7 +6,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import seedu.address.logic.commands.AddApptCommand; import seedu.address.logic.commands.AddCommand; +import seedu.address.logic.commands.AddHistCommand; +import seedu.address.logic.commands.AddInfoCommand; +import seedu.address.logic.commands.AddMedicalReportCommand; import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.DeleteCommand; @@ -18,6 +22,7 @@ import seedu.address.logic.commands.ListCommand; import seedu.address.logic.commands.RedoCommand; import seedu.address.logic.commands.SelectCommand; +import seedu.address.logic.commands.SortCommand; import seedu.address.logic.commands.UndoCommand; import seedu.address.logic.parser.exceptions.ParseException; @@ -51,12 +56,18 @@ public Command parseCommand(String userInput) throws ParseException { case AddCommand.COMMAND_WORD: return new AddCommandParser().parse(arguments); + case AddMedicalReportCommand.COMMAND_WORD: + return new AddMedicalReportCommandParser().parse(arguments); + case EditCommand.COMMAND_WORD: return new EditCommandParser().parse(arguments); case SelectCommand.COMMAND_WORD: return new SelectCommandParser().parse(arguments); + case SortCommand.COMMAND_WORD: + return new SortCommand(); + case DeleteCommand.COMMAND_WORD: return new DeleteCommandParser().parse(arguments); @@ -84,6 +95,15 @@ public Command parseCommand(String userInput) throws ParseException { case RedoCommand.COMMAND_WORD: return new RedoCommand(); + case AddApptCommand.COMMAND_WORD: + return new AddApptCommandParser().parse(arguments); + + case AddInfoCommand.COMMAND_WORD: + return new AddInfoCommandParser().parse(arguments); + + case AddHistCommand.COMMAND_WORD: + return new AddHistCommandParser().parse(arguments); + default: throw new ParseException(MESSAGE_UNKNOWN_COMMAND); } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 75b1a9bf1190..459dc1743608 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -5,11 +5,39 @@ */ public class CliSyntax { - /* Prefix definitions */ + /* Prefix definitions for Person */ public static final Prefix PREFIX_NAME = new Prefix("n/"); public static final Prefix PREFIX_PHONE = new Prefix("p/"); public static final Prefix PREFIX_EMAIL = new Prefix("e/"); public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); + /* Prefix definitions for Medical Report */ + public static final Prefix PREFIX_INFORMATION = new Prefix("i/"); + public static final Prefix PREFIX_TITLE = new Prefix("t/"); + public static final Prefix PREFIX_DATE = new Prefix("d/"); + + /* Prefix definitions for MedHistory */ + public static final Prefix PREFIX_HISTORY_BLOODTYPE = new Prefix("hsb/"); + public static final Prefix PREFIX_HISTORY_DATE = new Prefix("hsd/"); + public static final Prefix PREFIX_HISTORY_COUNTRY = new Prefix("hsc/"); + public static final Prefix PREFIX_HISTORY_ALLERGY = new Prefix("hsa/"); + + /* Prefix definitions for Additional Information */ + public static final Prefix PREFIX_ADD_INFO_NRIC = new Prefix("i/"); + public static final Prefix PREFIX_ADD_INFO_DOB = new Prefix("d/"); + public static final Prefix PREFIX_ADD_INFO_HEIGHT = new Prefix("h/"); + public static final Prefix PREFIX_ADD_INFO_WEIGHT = new Prefix("w/"); + public static final Prefix PREFIX_ADD_INFO_GENDER = new Prefix("g/"); + public static final Prefix PREFIX_ADD_INFO_OCCUPATION = new Prefix("/o"); + public static final Prefix PREFIX_ADD_INFO_MARITAL = new Prefix("/m"); + public static final Prefix PREFIX_ADD_INFO_FAMILY = new Prefix("/f"); + + /* Prefix definitions for Appt */ + public static final Prefix PREFIX_APPT_START = new Prefix("s/"); + public static final Prefix PREFIX_APPT_END = new Prefix("e/"); + public static final Prefix PREFIX_APPT_VENUE = new Prefix("v/"); + public static final Prefix PREFIX_APPT_INFO = new Prefix("i/"); + public static final Prefix PREFIX_APPT_DRNAME = new Prefix("d/"); + } diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java index b186a967cb94..31d37259c94c 100644 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java @@ -6,10 +6,15 @@ import seedu.address.logic.commands.FindCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.AddressContainsKeywordsPredicate; +import seedu.address.model.person.EmailContainsKeywordsPredicate; import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.PhoneContainsKeywordsPredicate; +import seedu.address.model.person.TagContainsKeywordsPredicate; /** * Parses input arguments and creates a new FindCommand object + * Switch cases for static attributes */ public class FindCommandParser implements Parser { @@ -25,9 +30,33 @@ public FindCommand parse(String args) throws ParseException { String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); } + String[] nameKeywords = trimmedArgs.split("\\s+"); - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); + switch(nameKeywords[0]) { + + case "n/": + return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords[1]))); + + case "p/": + //create PhoneContainsKeywordsPredicate + return new FindCommand(new PhoneContainsKeywordsPredicate(Arrays.asList(nameKeywords[1]))); + + case "e/": + //create EmailContainsKeywordsPredicate + return new FindCommand(new EmailContainsKeywordsPredicate(Arrays.asList(nameKeywords[1]))); + + case "a/": + //create AddressContainsKeywordsPredicate + return new FindCommand(new AddressContainsKeywordsPredicate(Arrays.asList(nameKeywords[1]))); + + case "t/": + //create TagContainsKeywordsPredicate + return new FindCommand(new TagContainsKeywordsPredicate(Arrays.asList(nameKeywords[1]))); + + default: + throw new ParseException(MESSAGE_INVALID_COMMAND_FORMAT); + } } } diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 76daf40807e2..214e6674e06d 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -2,6 +2,8 @@ import static java.util.Objects.requireNonNull; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -9,11 +11,23 @@ import seedu.address.commons.core.index.Index; import seedu.address.commons.util.StringUtil; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.medhistory.Allergy; +import seedu.address.model.medhistory.MedHistDate; +import seedu.address.model.medhistory.PrevCountry; +import seedu.address.model.medicalreport.Information; +import seedu.address.model.medicalreport.ReportDate; +import seedu.address.model.medicalreport.Title; import seedu.address.model.person.Address; +import seedu.address.model.person.DateOfBirth; import seedu.address.model.person.Email; import seedu.address.model.person.Name; +import seedu.address.model.person.Nric; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.timetable.ApptDateTime; +import seedu.address.model.timetable.ApptDrName; +import seedu.address.model.timetable.ApptInfo; +import seedu.address.model.timetable.ApptVenue; /** * Contains utility methods used for parsing strings in the various *Parser classes. @@ -92,9 +106,48 @@ public static Email parseEmail(String email) throws ParseException { if (!Email.isValidEmail(trimmedEmail)) { throw new ParseException(Email.MESSAGE_EMAIL_CONSTRAINTS); } + return new Email(trimmedEmail); } + /** + * Parses a {@code String nric} into an {@code Nric}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code nric} is invalid. + */ + public static Nric parseNric(String nric) throws ParseException { + requireNonNull(nric); + String trimmedNric = nric.trim(); + if (!Nric.isValidNric(trimmedNric)) { + throw new ParseException(Nric.MESSAGE_NRIC_CONSTRAINTS); + } + return new Nric(trimmedNric); + } + + /** + * Parses a {@code String nric} into an {@code Nric}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code nric} is invalid. + */ + public static DateOfBirth parseDateOfBirth(String dateOfBirth) throws ParseException { + requireNonNull(dateOfBirth); + String trimmedDateOfBirth = dateOfBirth.trim(); + if (!DateOfBirth.isValidDate(trimmedDateOfBirth)) { + throw new ParseException(DateOfBirth.DATE_OF_BIRTH_CONSTRAINTS); + } + + try { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + LocalDate.parse(dateOfBirth, dateTimeFormatter); + } catch (Exception e) { + throw new ParseException(DateOfBirth.DATE_OF_BIRTH_VALUE_EXCEEDED); + } + + return new DateOfBirth(trimmedDateOfBirth); + } + /** * Parses a {@code String tag} into a {@code Tag}. * Leading and trailing whitespaces will be trimmed. @@ -121,4 +174,132 @@ public static Set parseTags(Collection tags) throws ParseException } return tagSet; } + + /** + * Parses a {@code String allergy} into an {@code Allergy}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code allergy} is invalid. + * ParseException is omitted for now. + */ + public static Allergy parseAllergy(String allergy) { + requireNonNull(allergy); + String trimmedAllergy = allergy.trim(); + + return new Allergy(trimmedAllergy); + } + + /** + * Parses a {@code String prevCountry} into an {@code PrevCountry}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code prevCountry} is invalid. + * ParseException is omitted for now. + */ + public static MedHistDate parseMedHistDate(String medHistDate) { + requireNonNull(medHistDate); + String trimmedMedHistDate = medHistDate.trim(); + + return new MedHistDate(trimmedMedHistDate); + } + + /** + * Parses a {@code String prevCountry} into an {@code PrevCountry}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code prevCountry} is invalid. + * ParseException is omitted for now. + */ + public static PrevCountry parsePrevCountry(String prevCountry) { + requireNonNull(prevCountry); + String trimmedPrevCountry = prevCountry.trim(); + + return new PrevCountry(trimmedPrevCountry); + } + + /** + * ================================================== + * PARSER FOR MEDICAL REPORT SUBFIELDS + * ================================================== + */ + + /** + * Parses a {@code String title} into an {@code Title}. + * Leading and trailing whitespaces will be trimmed. + */ + public static Title parseTitle(String title) { + requireNonNull(title); + String trimmedTitle = title.trim(); + return new Title(trimmedTitle); + } + + /** + * Parses a {@code String date} into an {@code ReportDate}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code date} is invalid. + * ParseException is omitted for now. + + */ + public static ReportDate parseDate(String date) { + requireNonNull(date); + String trimmedDate = date.trim(); + return new ReportDate(trimmedDate); + } + + /** + * Parses a {@code String information} into an {@code Information}. + * Leading and trailing whitespaces will be trimmed. + */ + public static Information parseInformation(String information) { + requireNonNull(information); + String trimmedInformation = information.trim(); + return new Information(trimmedInformation); + } + + /** + * ================================================== + * PARSER FOR APPT SUBFIELDS + * ================================================== + */ + + /** + * Parses a {@code String apptDateTime} into an {@code ApptDateTime}. + * Leading and trailing whitespaces will be trimmed. + */ + public static ApptDateTime parseApptTime(String apptDateTime) { + requireNonNull(apptDateTime); + String trimmedApptDateTime = apptDateTime.trim(); + return new ApptDateTime(trimmedApptDateTime); + } + + /** + * Parses a {@code String apptVenue} into an {@code ApptVenue}. + * Leading and trailing whitespaces will be trimmed. + */ + public static ApptVenue parseApptVenue(String apptVenue) { + requireNonNull(apptVenue); + String trimmedApptVenue = apptVenue.trim(); + return new ApptVenue(trimmedApptVenue); + } + + /** + * Parses a {@code String apptInfo} into an {@code ApptInfo}. + * Leading and trailing whitespaces will be trimmed. + */ + public static ApptInfo parseApptInfo(String apptInfo) { + requireNonNull(apptInfo); + String trimmedApptInfo = apptInfo.trim(); + return new ApptInfo(trimmedApptInfo); + } + + /** + * Parses a {@code String apptDrName} into an {@code ApptDrName}. + * Leading and trailing whitespaces will be trimmed. + */ + public static ApptDrName parseApptDrName(String apptDrName) { + requireNonNull(apptDrName); + String trimmedApptDrName = apptDrName.trim(); + return new ApptDrName(trimmedApptDrName); + } } diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java index 7f85c8b9258b..3a95de024f9a 100644 --- a/src/main/java/seedu/address/model/AddressBook.java +++ b/src/main/java/seedu/address/model/AddressBook.java @@ -15,7 +15,7 @@ public class AddressBook implements ReadOnlyAddressBook { private final UniquePersonList persons; - + //private final UniqueReportList reports; /* * The 'unusual' code block below is an non-static initialization block, sometimes used to avoid duplication * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html @@ -27,6 +27,9 @@ public class AddressBook implements ReadOnlyAddressBook { persons = new UniquePersonList(); } + /*{ + reports = new UniqueReportList(); + }*/ public AddressBook() {} /** @@ -66,6 +69,11 @@ public boolean hasPerson(Person person) { return persons.contains(person); } + /*public boolean hasReport(MedicalReport report) { + requireNonNull(report); + return reports.contains(report); + }*/ + /** * Adds a person to the address book. * The person must not already exist in the address book. @@ -106,6 +114,7 @@ public ObservableList getPersonList() { return persons.asUnmodifiableObservableList(); } + @Override public boolean equals(Object other) { return other == this // short circuit if same object @@ -117,4 +126,5 @@ public boolean equals(Object other) { public int hashCode() { return persons.hashCode(); } + } diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index ac4521f33199..ba188e004712 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -23,6 +23,11 @@ public interface Model { */ boolean hasPerson(Person person); + /** + * Returns true if a report with the same fields {@code report} exists in the address book. + */ + //boolean hasReport(MedicalReport report); + /** * Deletes the given person. * The person must exist in the address book. @@ -35,6 +40,12 @@ public interface Model { */ void addPerson(Person person); + /** + * Adds the given report + * {@code report} must not already exist in the address book. + */ + //void addReport(MedicalReport report); + /** * Replaces the given person {@code target} with {@code editedPerson}. * {@code target} must exist in the address book. @@ -51,6 +62,15 @@ public interface Model { */ void updateFilteredPersonList(Predicate predicate); + /** Returns an unmodifiable view of the sorted person list */ + ObservableList getSortedPersonList(); + + /** + * Updates the sorted person list {@code predicate}. + * @throws NullPointerException if {@code predicate} is null. + */ + void updateSortedPersonList(Predicate predicate); + /** * Returns true if the model has previous address book states to restore. */ diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index a664602ef5b1..e14200558c95 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -3,6 +3,7 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import java.util.Comparator; import java.util.function.Predicate; import java.util.logging.Logger; @@ -22,6 +23,7 @@ public class ModelManager extends ComponentManager implements Model { private final VersionedAddressBook versionedAddressBook; private final FilteredList filteredPersons; + private final FilteredList sortedPersons; /** * Initializes a ModelManager with the given addressBook and userPrefs. @@ -34,6 +36,7 @@ public ModelManager(ReadOnlyAddressBook addressBook, UserPrefs userPrefs) { versionedAddressBook = new VersionedAddressBook(addressBook); filteredPersons = new FilteredList<>(versionedAddressBook.getPersonList()); + sortedPersons = new FilteredList<>(sortedPersonList(versionedAddressBook.getPersonList())); } public ModelManager() { @@ -61,7 +64,13 @@ public boolean hasPerson(Person person) { requireNonNull(person); return versionedAddressBook.hasPerson(person); } - + /** + @Override + public boolean hasReport(MedicalReport report) { + requireNonNull(report); + return versionedAddressBook.hasReport(report); + } + */ @Override public void deletePerson(Person target) { versionedAddressBook.removePerson(target); @@ -100,6 +109,34 @@ public void updateFilteredPersonList(Predicate predicate) { filteredPersons.setPredicate(predicate); } + //=========== Sorted Person List Accessors ============================================================= + + /** + * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of + * {@code versionedAddressBook} + */ + @Override + public ObservableList getSortedPersonList() { + return FXCollections.unmodifiableObservableList(sortedPersons); + } + /** + * Returns a sorted list + */ + + public ObservableList sortedPersonList(ObservableList personList) { + ObservableList sortedList = FXCollections.observableArrayList(); + sortedList.addAll(personList); + sortedList.sort(Comparator.comparing(person -> person.getName().fullName)); + + return FXCollections.unmodifiableObservableList(sortedList); + } + @Override + public void updateSortedPersonList(Predicate predicate) { + requireNonNull(predicate); + sortedPersons.setPredicate(predicate); + } + + //=========== Undo/Redo ================================================================================= @Override diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java index 6ddc2cd9a290..77791ad733ff 100644 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java @@ -13,5 +13,6 @@ public interface ReadOnlyAddressBook { * This list will not contain any duplicate persons. */ ObservableList getPersonList(); + //ObservableList getMedicalReportList(); } diff --git a/src/main/java/seedu/address/model/medhistory/Allergy.java b/src/main/java/seedu/address/model/medhistory/Allergy.java new file mode 100644 index 000000000000..930117f14eab --- /dev/null +++ b/src/main/java/seedu/address/model/medhistory/Allergy.java @@ -0,0 +1,48 @@ +package seedu.address.model.medhistory; + +import static java.util.Objects.requireNonNull; +//import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents the allergy of medical history. + * Guarantees: immutable; is valid as declared in {@link #isValidAllergy(String)} + */ + +public class Allergy { + + public static final String MESSAGE_ALLERGY_CONSTRAINTS = + "Allergy must not be left blank."; + + public static final String ALLERGY_VALIDATION_REGEX = "[^\\s].*"; + + public final String value; + + /** + * Constructs an {@code Allergy}. + * + * @param allergy A valid allergy. + */ + public Allergy(String allergy) { + requireNonNull(allergy); + // isValidAllergy will is found in test file. + //checkArgument(isValidAllergy(allergy), MESSAGE_ALLERGY_CONSTRAINTS); + value = allergy; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Allergy // instanceof handles nulls + && value.equals(((Allergy) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/medhistory/MedHistDate.java b/src/main/java/seedu/address/model/medhistory/MedHistDate.java new file mode 100644 index 000000000000..379068e2b320 --- /dev/null +++ b/src/main/java/seedu/address/model/medhistory/MedHistDate.java @@ -0,0 +1,48 @@ +package seedu.address.model.medhistory; + +import static java.util.Objects.requireNonNull; +//import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents the date of medical history. + * Guarantees: immutable; is valid as declared in {@link #isValidDate(String)} + */ + +public class MedHistDate { + + public static final String MESSAGE_MEDHISTDATE_CONSTRAINTS = + "ReportDate needs to be in day/month/year (dd/mm/yyyy) format."; + + public static final String MEDHISTDATE_VALIDATION_REGEX = "[^\\s].*"; + + public final String value; + + /** + * Constructs an {@code MedHistDate}. + * + * @param medHistDate A valid date. + */ + public MedHistDate(String medHistDate) { + requireNonNull(medHistDate); + // isValidDate will is found in test file. + //checkArgument(isValidDate(date), MESSAGE_DATE_CONSTRAINTS); + value = medHistDate; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof MedHistDate // instanceof handles nulls + && value.equals(((MedHistDate) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/medhistory/MedHistory.java b/src/main/java/seedu/address/model/medhistory/MedHistory.java new file mode 100644 index 000000000000..9ee4ac8fda10 --- /dev/null +++ b/src/main/java/seedu/address/model/medhistory/MedHistory.java @@ -0,0 +1,62 @@ +package seedu.address.model.medhistory; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Objects; + +/** + * Model of medical history of a patient. + * Guarantees: details are present and not null, field values are validated, immutable. + */ + +public class MedHistory { + + // Data fields + private final MedHistDate medHistDate; + private final Allergy allergy; + private final PrevCountry prevCountry; + + public MedHistory(MedHistDate medHistDate, Allergy allergy, PrevCountry prevCountry) { + requireAllNonNull(medHistDate, allergy, prevCountry); + this.medHistDate = medHistDate; + this.allergy = allergy; + this.prevCountry = prevCountry; + } + + public MedHistDate getMedHistDate() { + return medHistDate; + } + public Allergy getAllergy() { + return allergy; + } + public PrevCountry getPrevCountry() { + return prevCountry; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof MedHistory)) { + return false; + } + + MedHistory otherPerson = (MedHistory) other; + return otherPerson.getMedHistDate().equals(getMedHistDate()) + && otherPerson.getAllergy().equals(getAllergy()) + && otherPerson.getPrevCountry().equals(getPrevCountry()); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(medHistDate, allergy, prevCountry); + } + + @Override + public String toString() { + return medHistDate.toString() + " \n" + allergy.toString() + " \n" + prevCountry.toString(); + } +} diff --git a/src/main/java/seedu/address/model/medhistory/PrevCountry.java b/src/main/java/seedu/address/model/medhistory/PrevCountry.java new file mode 100644 index 000000000000..348398a0edbd --- /dev/null +++ b/src/main/java/seedu/address/model/medhistory/PrevCountry.java @@ -0,0 +1,48 @@ +package seedu.address.model.medhistory; + +import static java.util.Objects.requireNonNull; +//import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents the previous country visited of medical history. + * Guarantees: immutable; is valid as declared in {@link #isValidprevCountry(String)} + */ + +public class PrevCountry { + + public static final String MESSAGE_PREVCOUNTRY_CONSTRAINTS = + "prevCountry must not be left blank."; + + public static final String PREVCOUNTRY_VALIDATION_REGEX = "[^\\s].*"; + + public final String value; + + /** + * Constructs an {@code PrevCountry}. + * + * @param prevCountry A valid prevCountry. + */ + public PrevCountry(String prevCountry) { + requireNonNull(prevCountry); + // isValidprevCountry will is found in test file. + //checkArgument(isValidprevCountry(prevCountry), MESSAGE_PREVCOUNTRY_CONSTRAINTS); + value = prevCountry; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof PrevCountry // instanceof handles nulls + && value.equals(((PrevCountry) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/medicalreport/Information.java b/src/main/java/seedu/address/model/medicalreport/Information.java new file mode 100644 index 000000000000..4fbf6b4f45a9 --- /dev/null +++ b/src/main/java/seedu/address/model/medicalreport/Information.java @@ -0,0 +1,59 @@ +package seedu.address.model.medicalreport; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a Medical Report's information in the address book. + */ +public class Information { + public static final String MESSAGE_INFORMATION_CONSTRAINTS = + "Information in medical report should only contain alphanumeric characters and spaces," + + " and it should not be blank"; + + /* + * The first character of the information must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String INFORMATION_VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + public final String fullInformation; + + /** + * Constructs a {@code MedicalReportInformation}. + * + * @param information A valid information. + */ + public Information(String information) { + requireNonNull(information); + fullInformation = information; + } + + /** + * Returns true if a given string is a valid date. + */ + public static boolean isValidInformation(String test) { + return test.matches(INFORMATION_VALIDATION_REGEX); + } + + + @Override + public String toString() { + return fullInformation; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Information // instanceof handles nulls + && fullInformation.equals(((Information) other).fullInformation)); // state check + } + + @Override + public int hashCode() { + return fullInformation.hashCode(); + } + + public boolean isFull() { + return true; + } +} diff --git a/src/main/java/seedu/address/model/medicalreport/MedicalReport.java b/src/main/java/seedu/address/model/medicalreport/MedicalReport.java new file mode 100644 index 000000000000..3464c5314c9d --- /dev/null +++ b/src/main/java/seedu/address/model/medicalreport/MedicalReport.java @@ -0,0 +1,59 @@ +package seedu.address.model.medicalreport; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Objects; + +/** + * Represents a Person's medical report in the health book. + */ +public class MedicalReport { + + private final Title title; + private final ReportDate date; + private final Information information; + + public MedicalReport(Title title, ReportDate date, Information information) { + requireAllNonNull(title, date, information); + this.title = title; + this.date = date; + this.information = information; + } + + public Title getTitle() { + return title; + } + + public ReportDate getDate() { + return date; + } + + public Information getInformation() { + return information; + } + + @Override + public String toString() { + return title.toString() + " " + date.toString() + " " + information.toString() + " "; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof MedicalReport)) { + return false; + } + MedicalReport otherMedicalReport = (MedicalReport) other; + return otherMedicalReport.getTitle().equals(getTitle()) + && otherMedicalReport.getDate().equals(getDate()) + && otherMedicalReport.getInformation().equals(getInformation()); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(title, date, information); + } +} diff --git a/src/main/java/seedu/address/model/medicalreport/ReportDate.java b/src/main/java/seedu/address/model/medicalreport/ReportDate.java new file mode 100644 index 000000000000..80a02dcecc25 --- /dev/null +++ b/src/main/java/seedu/address/model/medicalreport/ReportDate.java @@ -0,0 +1,60 @@ +package seedu.address.model.medicalreport; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a Medical Report's date in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidDate(String)} + */ +public class ReportDate { + + public static final String MESSAGE_DATE_CONSTRAINTS = + "The full ReportDate should be of the format: DD/MM/YYYY"; + + /* + * The first character of the date must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String DATE_VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + public final String fullDate; + + /** + * Constructs a {@code ReportDate}. + * + * @param date A valid date. + */ + public ReportDate(String date) { + requireNonNull(date); + fullDate = date; + } + + /** + * Returns true if a given string is a valid date. + */ + public static boolean isValidDate(String test) { + return test.matches(DATE_VALIDATION_REGEX); + } + + + @Override + public String toString() { + return fullDate; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ReportDate // instanceof handles nulls + && fullDate.equals(((ReportDate) other).fullDate)); // state check + } + + @Override + public int hashCode() { + return fullDate.hashCode(); + } + + public boolean isFull() { + return true; + } +} diff --git a/src/main/java/seedu/address/model/medicalreport/Title.java b/src/main/java/seedu/address/model/medicalreport/Title.java new file mode 100644 index 000000000000..a734c151944c --- /dev/null +++ b/src/main/java/seedu/address/model/medicalreport/Title.java @@ -0,0 +1,60 @@ +package seedu.address.model.medicalreport; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a Medical Report's title in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidTitle(String)} + */ +public class Title { + + public static final String MESSAGE_TITLE_CONSTRAINTS = + "Titles should only contain characters and spaces, and it should not be blank"; + + /* + * The first character of the title must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String TITLE_VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + public final String fullTitle; + + /** + * Constructs a {@code Title}. + * + * @param title A valid title. + */ + public Title(String title) { + requireNonNull(title); + fullTitle = title; + } + + /** + * Returns true if a given string is a valid title. + */ + public static boolean isValidTitle(String test) { + return test.matches(TITLE_VALIDATION_REGEX); + } + + + @Override + public String toString() { + return fullTitle; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Title // instanceof handles nulls + && fullTitle.equals(((Title) other).fullTitle)); // state check + } + + @Override + public int hashCode() { + return fullTitle.hashCode(); + } + + public boolean isFull() { + return true; + } +} diff --git a/src/main/java/seedu/address/model/person/AddressContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/AddressContainsKeywordsPredicate.java new file mode 100644 index 000000000000..f4a14a3c5d7c --- /dev/null +++ b/src/main/java/seedu/address/model/person/AddressContainsKeywordsPredicate.java @@ -0,0 +1,33 @@ + +package seedu.address.model.person; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; + +/** + * Tests that a {@code Person}'s {@code Address} matches any of the keyword given. + */ +public class AddressContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public AddressContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Person person) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getAddress().value, keyword)); + } + + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddressContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((AddressContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/address/model/person/BloodType.java b/src/main/java/seedu/address/model/person/BloodType.java new file mode 100644 index 000000000000..096ad2115586 --- /dev/null +++ b/src/main/java/seedu/address/model/person/BloodType.java @@ -0,0 +1,45 @@ +package seedu.address.model.person; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents a Person's Blood Type in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidType(String)} + */ + +public class BloodType { + public static final String BLOODTYPE_CONSTRAINTS = + "Blood type should be A, B, O or AB followed by - or +"; + public static final String TYPE_VALIDATION_REGEX = "[ABO]*" + "[-+]"; + public final String value; + + /** + * Constructs a {@code BloodType}. + * + * @param type A valid bloodtype. + */ + public BloodType(String type) { + requireNonNull(type); + checkArgument(isValidType(type), BLOODTYPE_CONSTRAINTS); + value = type; + } + + /** + * Returns true if a given string is a valid phone number. + */ + public static boolean isValidType(String test) { + return test.matches(TYPE_VALIDATION_REGEX); + } + + @Override + public String toString() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/model/person/DateOfBirth.java b/src/main/java/seedu/address/model/person/DateOfBirth.java new file mode 100644 index 000000000000..9807680fd783 --- /dev/null +++ b/src/main/java/seedu/address/model/person/DateOfBirth.java @@ -0,0 +1,51 @@ +package seedu.address.model.person; + +import static java.util.Objects.requireNonNull; + +import java.text.ParseException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Represents ReportDate of Birth in Health Book + */ +public class DateOfBirth { + public static final String DATE_OF_BIRTH_CONSTRAINTS = "Date of birth should be of the format dd-MM-yyyy"; + public static final String DATE_OF_BIRTH_VALUE_EXCEEDED = "Date values have exceeded. Please check again."; + public static final String DATE_OF_BIRTH_VALIDATION_REGEX = "[0-9]{2}" + "[-]" + "[0-9]{2}" + "[-]" + "[0-9]{4}"; + + public final LocalDate value; + + private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + + /** + * Constructs a {@code DateOfBirth} + * @param value a valid date + * @throws ParseException if date format is invalid + */ + public DateOfBirth(String value) { + requireNonNull(value); + this.value = LocalDate.parse(value, dateTimeFormatter); + } + + public static boolean isValidDate(String test) { + return test.matches(DATE_OF_BIRTH_VALIDATION_REGEX); + } + + @Override + public String toString() { + return value.format(dateTimeFormatter); + } + + @Override + public boolean equals(Object other) { + return other == this + || (other instanceof DateOfBirth + && value.equals(((DateOfBirth) other).value)); + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/person/EmailContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/EmailContainsKeywordsPredicate.java new file mode 100644 index 000000000000..9d1c0f1329d1 --- /dev/null +++ b/src/main/java/seedu/address/model/person/EmailContainsKeywordsPredicate.java @@ -0,0 +1,32 @@ +package seedu.address.model.person; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; + +/** + * Tests that a {@code Person}'s {@code Phone} matches any of the keyword given. + */ +public class EmailContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public EmailContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Person person) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getEmail().value, keyword)); + } + + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof EmailContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((EmailContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java index c9b5868427ca..0f0ee13b36f9 100644 --- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java +++ b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java @@ -6,7 +6,7 @@ import seedu.address.commons.util.StringUtil; /** - * Tests that a {@code Person}'s {@code Name} matches any of the keywords given. + * Tests that a {@code Person}'s {@code Name} matches any of the keyword given. */ public class NameContainsKeywordsPredicate implements Predicate { private final List keywords; @@ -21,6 +21,7 @@ public boolean test(Person person) { .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)); } + @Override public boolean equals(Object other) { return other == this // short circuit if same object diff --git a/src/main/java/seedu/address/model/person/Nric.java b/src/main/java/seedu/address/model/person/Nric.java new file mode 100644 index 000000000000..763832dfb543 --- /dev/null +++ b/src/main/java/seedu/address/model/person/Nric.java @@ -0,0 +1,51 @@ +package seedu.address.model.person; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a person's NRIC in Health Book. + */ +public class Nric { + public static final String NRIC_VALIDATION_REGEX = "[ST]" + "[\\d]{7}" + "[A-Z]"; + public static final String MESSAGE_NRIC_CONSTRAINTS = "NRICs should adhere to the following constraints:\n" + + "1. It should begin with either S or T;\n" + + "2. The next 7 characters should be digits between 0 - 9, and;\n" + + "3. It should end of with any alphabet."; + + public final String value; + + /** + * Constructs an {@code Nric}. + * + * @param nric A valid nric. + */ + public Nric(String nric) { + requireNonNull(nric); + value = nric; + } + + /** + * Returns if a given string is a valid NRIC. + */ + public static boolean isValidNric(String test) { + return test.matches(NRIC_VALIDATION_REGEX); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Nric // instanceof handles nulls + && value.equals(((Nric) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index 557a7a60cd51..1eb0af0be5fc 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -7,7 +7,10 @@ import java.util.Objects; import java.util.Set; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medicalreport.MedicalReport; import seedu.address.model.tag.Tag; +import seedu.address.model.timetable.Appt; /** * Represents a Person in the address book. @@ -22,17 +25,30 @@ public class Person { // Data fields private final Address address; + private final Set medHistories = new HashSet<>(); + private final Set appts = new HashSet<>(); private final Set tags = new HashSet<>(); + private final Set reports = new HashSet<>(); + + // Additional information fields + private final Nric nric; + private final DateOfBirth dateOfBirth; /** * Every field must be present and not null. */ - public Person(Name name, Phone phone, Email email, Address address, Set tags) { + public Person(Name name, Phone phone, Email email, Address address, Set reports, + Set medHistories, Set appts, Nric nric, DateOfBirth dateOfBirth, Set tags) { requireAllNonNull(name, phone, email, address, tags); this.name = name; this.phone = phone; this.email = email; this.address = address; + this.nric = nric; + this.dateOfBirth = dateOfBirth; + this.reports.addAll(reports); + this.medHistories.addAll(medHistories); + this.appts.addAll(appts); this.tags.addAll(tags); } @@ -52,6 +68,26 @@ public Address getAddress() { return address; } + public Set getMedicalReports() { + return Collections.unmodifiableSet(reports); + } + + public Set getMedHistory() { + return Collections.unmodifiableSet(medHistories); + } + + public Nric getNric() { + return nric; + } + + public DateOfBirth getDateOfBirth() { + return dateOfBirth; + } + + public Set getAppts() { + return Collections.unmodifiableSet(appts); + } + /** * Returns an immutable tag set, which throws {@code UnsupportedOperationException} * if modification is attempted. diff --git a/src/main/java/seedu/address/model/person/PhoneContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/PhoneContainsKeywordsPredicate.java new file mode 100644 index 000000000000..87b46215bb06 --- /dev/null +++ b/src/main/java/seedu/address/model/person/PhoneContainsKeywordsPredicate.java @@ -0,0 +1,32 @@ +package seedu.address.model.person; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; + +/** + * Tests that a {@code Person}'s {@code Phone} matches any of the keyword given. + */ +public class PhoneContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public PhoneContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Person person) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getPhone().value, keyword)); + } + + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof PhoneContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((PhoneContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/address/model/person/TagContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/TagContainsKeywordsPredicate.java new file mode 100644 index 000000000000..19db2074ec95 --- /dev/null +++ b/src/main/java/seedu/address/model/person/TagContainsKeywordsPredicate.java @@ -0,0 +1,34 @@ +package seedu.address.model.person; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.tag.Tag; + +/** + * Tests that a {@code Person}'s {@code Tag} matches any of the keyword given. + */ +public class TagContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public TagContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Person person) { + List tags = new ArrayList<>(person.getTags()); + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(tags.get(0).tagName, keyword)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof TagContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((TagContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java index 5856aa42e6b5..1714bedc10d8 100644 --- a/src/main/java/seedu/address/model/person/UniquePersonList.java +++ b/src/main/java/seedu/address/model/person/UniquePersonList.java @@ -119,6 +119,17 @@ public int hashCode() { return internalList.hashCode(); } + /** + * Returns the sorted list as an unmodifiable {@code ObservableList}. + */ + + /*public ObservableList sortedPersonList() { + ObservableList sortedInternalList = internalList; + sortedInternalList.sort(Comparator.comparing(person -> person.getName().fullName)); + + return FXCollections.unmodifiableObservableList(sortedInternalList); + } +*/ /** * Returns true if {@code persons} contains only unique persons. */ diff --git a/src/main/java/seedu/address/model/timetable/Appt.java b/src/main/java/seedu/address/model/timetable/Appt.java new file mode 100644 index 000000000000..b4aa04eb2642 --- /dev/null +++ b/src/main/java/seedu/address/model/timetable/Appt.java @@ -0,0 +1,79 @@ +package seedu.address.model.timetable; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Objects; + +/** + * Represents a Person's remark in the address book. + * Guarantees: immutable; is always valid + */ +public class Appt { + private final ApptDateTime start; + private final ApptDateTime end; + private final ApptVenue venue; + private final ApptInfo info; + private final ApptDrName drName; + + public Appt(ApptDateTime start, ApptDateTime end, ApptVenue venue, ApptInfo info, ApptDrName drName) { + requireAllNonNull(start, end, venue, info, drName); + this.start = start; + this.end = end; + this.venue = venue; + this.info = info; + this.drName = drName; + } + + public ApptDateTime getStart() { + return start; + } + + public ApptDateTime getEnd() { + return end; + } + + public ApptVenue getVenue() { + return venue; + } + + public ApptInfo getInfo() { + return info; + } + + public ApptDrName getDrName() { + return drName; + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(start, end, venue, info, drName); + } + + // temporary + @Override + public String toString() { + return start.toString() + " " + end.toString() + " " + venue.toString() + " " + info.toString() + " " + + drName.toString(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof Appt)) { + return false; + } + + Appt otherAppt = (Appt) other; + return otherAppt.getStart().equals(getStart()) + && otherAppt.getEnd().equals(getEnd()) + && otherAppt.getVenue().equals(getVenue()) + && otherAppt.getInfo().equals(getInfo()) + && otherAppt.getDrName().equals(getDrName()); + // will probably also need to add in index/some way to identify patient into equals check + // multiple patients can have the same appts with all the same details + } +} diff --git a/src/main/java/seedu/address/model/timetable/ApptDateTime.java b/src/main/java/seedu/address/model/timetable/ApptDateTime.java new file mode 100644 index 000000000000..ce012de584db --- /dev/null +++ b/src/main/java/seedu/address/model/timetable/ApptDateTime.java @@ -0,0 +1,36 @@ +package seedu.address.model.timetable; + +import static java.util.Objects.requireNonNull; + +/** + * Represents an appt date and time in an appt in the address book. + * Guarantees: immutable; is always valid + */ +public class ApptDateTime { + public static final String MESSAGE_NAME_CONSTRAINTS = "The full ReportDate and Time should be of the format: " + + "DD/MM/YYYY HH:MM."; + + public final String value; + + public ApptDateTime(String apptDateTime) { + requireNonNull(apptDateTime); + value = apptDateTime; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ApptDateTime // instanceof handles nulls + && value.equals(((ApptDateTime) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/timetable/ApptDrName.java b/src/main/java/seedu/address/model/timetable/ApptDrName.java new file mode 100644 index 000000000000..a2b60057e6c4 --- /dev/null +++ b/src/main/java/seedu/address/model/timetable/ApptDrName.java @@ -0,0 +1,36 @@ +package seedu.address.model.timetable; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a doctor (taking an appt) in an appt in the address book. + * Guarantees: immutable; is always valid + */ +public class ApptDrName { + public static final String MESSAGE_NAME_CONSTRAINTS = + "Doctor names should only contain alphanumeric characters and spaces, and it should not be blank."; + + public final String value; + + public ApptDrName(String apptDrName) { + requireNonNull(apptDrName); + value = apptDrName; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ApptDrName // instanceof handles nulls + && value.equals(((ApptDrName) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/timetable/ApptInfo.java b/src/main/java/seedu/address/model/timetable/ApptInfo.java new file mode 100644 index 000000000000..a51e748a3033 --- /dev/null +++ b/src/main/java/seedu/address/model/timetable/ApptInfo.java @@ -0,0 +1,37 @@ +package seedu.address.model.timetable; + +import static java.util.Objects.requireNonNull; + +/** + * Represents appt info in an appt in the address book. + * Guarantees: immutable; is always valid + */ +public class ApptInfo { + + public static final String MESSAGE_NAME_CONSTRAINTS = + "Appt information should only contain alphanumeric characters and spaces, and it should not be blank."; + + public final String value; + + public ApptInfo(String apptInfo) { + requireNonNull(apptInfo); + value = apptInfo; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ApptInfo // instanceof handles nulls + && value.equals(((ApptInfo) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/timetable/ApptVenue.java b/src/main/java/seedu/address/model/timetable/ApptVenue.java new file mode 100644 index 000000000000..3698a1e91ea9 --- /dev/null +++ b/src/main/java/seedu/address/model/timetable/ApptVenue.java @@ -0,0 +1,36 @@ +package seedu.address.model.timetable; + +import static java.util.Objects.requireNonNull; + +/** + * Represents an appt venue in an appt in the address book. + * Guarantees: immutable; is always valid + */ +public class ApptVenue { + public static final String MESSAGE_NAME_CONSTRAINTS = + "Venues should only contain alphanumeric characters and spaces, and it should not be blank."; + + public final String value; + + public ApptVenue(String apptVenue) { + requireNonNull(apptVenue); + value = apptVenue; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ApptVenue // instanceof handles nulls + && value.equals(((ApptVenue) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 1806da4facfa..a511370663ba 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -1,42 +1,57 @@ package seedu.address.model.util; import java.util.Arrays; +import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import seedu.address.model.AddressBook; import seedu.address.model.ReadOnlyAddressBook; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medicalreport.MedicalReport; import seedu.address.model.person.Address; +import seedu.address.model.person.DateOfBirth; import seedu.address.model.person.Email; import seedu.address.model.person.Name; +import seedu.address.model.person.Nric; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.timetable.Appt; /** * Contains utility methods for populating {@code AddressBook} with sample data. */ public class SampleDataUtil { + + public static final Nric EMPTY_NRIC = new Nric(""); + public static final DateOfBirth EMPTY_DATE_OF_BIRTH = new DateOfBirth("01-01-1970"); + public static Person[] getSamplePersons() { return new Person[] { new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), - new Address("Blk 30 Geylang Street 29, #06-40"), - getTagSet("friends")), + new Address("Blk 30 Geylang Street 29, #06-40"), getReportSet(), + getMedHistorySet(), getApptSet(), EMPTY_NRIC, EMPTY_DATE_OF_BIRTH, getTagSet("friends")), new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), - new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), - getTagSet("colleagues", "friends")), + new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), getReportSet(), + getMedHistorySet(), getApptSet(), EMPTY_NRIC, EMPTY_DATE_OF_BIRTH, + getTagSet("colleagues", "friends")), new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), - new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), - getTagSet("neighbours")), + new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), getReportSet(), + getMedHistorySet(), getApptSet(), EMPTY_NRIC, EMPTY_DATE_OF_BIRTH, + getTagSet("neighbours")), new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), - new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), - getTagSet("family")), + new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), getReportSet(), + getMedHistorySet(), getApptSet(), EMPTY_NRIC, EMPTY_DATE_OF_BIRTH, + getTagSet("family")), new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), - new Address("Blk 47 Tampines Street 20, #17-35"), - getTagSet("classmates")), + new Address("Blk 47 Tampines Street 20, #17-35"), getReportSet(), + getMedHistorySet(), getApptSet(), EMPTY_NRIC, EMPTY_DATE_OF_BIRTH, + getTagSet("classmates")), new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), - new Address("Blk 45 Aljunied Street 85, #11-31"), - getTagSet("colleagues")) + new Address("Blk 45 Aljunied Street 85, #11-31"), getReportSet(), + getMedHistorySet(), getApptSet(), EMPTY_NRIC, EMPTY_DATE_OF_BIRTH, + getTagSet("colleagues")) }; } @@ -57,4 +72,38 @@ public static Set getTagSet(String... strings) { .collect(Collectors.toSet()); } + /** + * Returns a medical history set containing the list of medical histories. + */ + public static Set getMedHistorySet(MedHistory... medHistories) { + Set medHistorySet = new HashSet<>(); + for (MedHistory medHistory : medHistories) { + medHistorySet.add(medHistory); + } + return medHistorySet; + } + + /** + * Returns a report set containing the list of reports given. + */ + // TODO: (MedicalReport) MIGHT CONVERT TO USE STREAM IN FUTURE + public static Set getReportSet(MedicalReport ... reports) { + Set reportSet = new HashSet<>(); + for (MedicalReport report : reports) { + reportSet.add(report); + } + return reportSet; + } + + /** + * Returns an appt set containing the list of appts given. + */ + // TODO: (Appt) MIGHT CONVERT TO USE STREAM IN FUTURE + public static Set getApptSet(Appt... appts) { + Set apptSet = new HashSet<>(); + for (Appt appt : appts) { + apptSet.add(appt); + } + return apptSet; + } } diff --git a/src/main/java/seedu/address/storage/XmlAdaptedAppt.java b/src/main/java/seedu/address/storage/XmlAdaptedAppt.java new file mode 100644 index 000000000000..8c0447c90611 --- /dev/null +++ b/src/main/java/seedu/address/storage/XmlAdaptedAppt.java @@ -0,0 +1,118 @@ +package seedu.address.storage; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlElement; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.timetable.Appt; +import seedu.address.model.timetable.ApptDateTime; +import seedu.address.model.timetable.ApptDrName; +import seedu.address.model.timetable.ApptInfo; +import seedu.address.model.timetable.ApptVenue; + +/** + * JAXB-friendly version of the Appt. + */ +public class XmlAdaptedAppt { + + public static final String MISSING_FIELD_MESSAGE_FORMAT = "Appt's %s field is missing!"; + + @XmlElement + private String apptStart; + @XmlElement + private String apptEnd; + @XmlElement + private String apptVenue; + @XmlElement + private String apptInfo; + @XmlElement + private String apptDrName; + + /** + * Constructs an XmlAdaptedAppt. + * This is the no-arg constructor that is required by JAXB. + */ + public XmlAdaptedAppt() {} + + /** + * Constructs a {@code XmlAdaptedAppt} with the given appt details. + */ + public XmlAdaptedAppt(String apptStart, String apptEnd, String apptVenue, String apptInfo, String apptDrName) { + this.apptStart = apptStart; + this.apptEnd = apptEnd; + this.apptVenue = apptVenue; + this.apptInfo = apptInfo; + this.apptDrName = apptDrName; + } + + /** + * Converts a given Appt into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedAppt + */ + public XmlAdaptedAppt(Appt source) { + apptStart = source.getStart().toString(); + apptEnd = source.getEnd().toString(); + apptVenue = source.getVenue().toString(); + apptInfo = source.getInfo().toString(); + apptDrName = source.getDrName().toString(); + } + + /** + * Converts this jaxb-friendly adapted appt object into the model's Appt object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted appt + */ + public Appt toModelType() throws IllegalValueException { + if (apptStart == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ApptDateTime.class.getSimpleName())); + } + final ApptDateTime modelApptStart = new ApptDateTime(apptStart); + + if (apptEnd == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ApptDateTime.class.getSimpleName())); + } + final ApptDateTime modelApptEnd = new ApptDateTime(apptEnd); + + if (apptVenue == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ApptVenue.class.getSimpleName())); + } + final ApptVenue modelApptVenue = new ApptVenue(apptVenue); + + if (apptInfo == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ApptInfo.class.getSimpleName())); + } + final ApptInfo modelApptInfo = new ApptInfo(apptInfo); + + if (apptDrName == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ApptDrName.class.getSimpleName())); + } + final ApptDrName modelApptDrName = new ApptDrName(apptDrName); + + return new Appt(modelApptStart, modelApptEnd, modelApptVenue, modelApptInfo, modelApptDrName); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof XmlAdaptedAppt)) { + return false; + } + + XmlAdaptedAppt otherAppt = (XmlAdaptedAppt) other; + return Objects.equals(apptStart, otherAppt.apptStart) + && Objects.equals(apptEnd, otherAppt.apptEnd) + && Objects.equals(apptVenue, otherAppt.apptVenue) + && Objects.equals(apptInfo, otherAppt.apptInfo) + && Objects.equals(apptDrName, otherAppt.apptDrName); + } +} diff --git a/src/main/java/seedu/address/storage/XmlAdaptedMedHistory.java b/src/main/java/seedu/address/storage/XmlAdaptedMedHistory.java new file mode 100644 index 000000000000..9de5e980f642 --- /dev/null +++ b/src/main/java/seedu/address/storage/XmlAdaptedMedHistory.java @@ -0,0 +1,96 @@ +package seedu.address.storage; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlElement; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.medhistory.Allergy; +import seedu.address.model.medhistory.MedHistDate; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medhistory.PrevCountry; + + +/** + * JAXB-friendly version of the Medical History. + */ + +public class XmlAdaptedMedHistory { + public static final String MISSING_FIELD_MESSAGE_FORMAT = "MedHistory's %s field is missing!"; + + @XmlElement + private String medHistDate; + @XmlElement + private String allergy; + @XmlElement + private String prevCountry; + + /** + * Constructs an XmlAdaptedMedHistory. + * This is the no-arg constructor that is required by JAXB. + */ + public XmlAdaptedMedHistory() {} + + /** + * Constructs an {@code XmlAdaptedMedHistory} with the given medical history details. + */ + public XmlAdaptedMedHistory(String medHistDate, String allergy, String prevCountry) { + this.medHistDate = medHistDate; + this.allergy = allergy; + this.prevCountry = prevCountry; + } + + /** + * Converts a given medical history into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedMedHistory + */ + + public XmlAdaptedMedHistory(MedHistory source) { + medHistDate = source.getMedHistDate().toString(); + allergy = source.getAllergy().toString(); + prevCountry = source.getPrevCountry().toString(); + } + + /** + * Converts this jaxb-friendly adapted medical history object into the model's medical history object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted medical history + */ + public MedHistory toModelType() throws IllegalValueException { + if (medHistDate == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + MedHistDate.class.getSimpleName())); + } + final MedHistDate modelMedHistDate = new MedHistDate(medHistDate); + if (allergy == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + Allergy.class.getSimpleName())); + } + final Allergy modelAllergy = new Allergy(allergy); + if (prevCountry == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + PrevCountry.class.getSimpleName())); + } + final PrevCountry modelPrevCountry = new PrevCountry(prevCountry); + + return new MedHistory(modelMedHistDate, modelAllergy, modelPrevCountry); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof XmlAdaptedMedHistory)) { + return false; + } + + XmlAdaptedMedHistory otherMedHistory = (XmlAdaptedMedHistory) other; + return Objects.equals(medHistDate, otherMedHistory.medHistDate) + && Objects.equals(allergy, otherMedHistory.allergy) + && Objects.equals(prevCountry, otherMedHistory.prevCountry); + } + +} diff --git a/src/main/java/seedu/address/storage/XmlAdaptedPerson.java b/src/main/java/seedu/address/storage/XmlAdaptedPerson.java index c03785e5700f..84f3382c3af4 100644 --- a/src/main/java/seedu/address/storage/XmlAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/XmlAdaptedPerson.java @@ -10,18 +10,22 @@ import javax.xml.bind.annotation.XmlElement; import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.medhistory.MedHistory; +import seedu.address.model.medicalreport.MedicalReport; import seedu.address.model.person.Address; +import seedu.address.model.person.DateOfBirth; import seedu.address.model.person.Email; import seedu.address.model.person.Name; +import seedu.address.model.person.Nric; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.timetable.Appt; /** * JAXB-friendly version of the Person. */ public class XmlAdaptedPerson { - public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!"; @XmlElement(required = true) @@ -32,7 +36,16 @@ public class XmlAdaptedPerson { private String email; @XmlElement(required = true) private String address; - + @XmlElement(required = true) + private String nric; + @XmlElement(required = true) + private String dateOfBirth; + @XmlElement + private List reports = new ArrayList<>(); + @XmlElement + private List medHistories = new ArrayList<>(); + @XmlElement + private List appts = new ArrayList<>(); @XmlElement private List tagged = new ArrayList<>(); @@ -45,11 +58,22 @@ public XmlAdaptedPerson() {} /** * Constructs an {@code XmlAdaptedPerson} with the given person details. */ - public XmlAdaptedPerson(String name, String phone, String email, String address, List tagged) { + public XmlAdaptedPerson(String name, String phone, String email, String address, List reports, + List medHistories, List appts, + List tagged) { this.name = name; this.phone = phone; this.email = email; this.address = address; + if (reports != null) { + this.reports = new ArrayList<>(reports); + } + if (medHistories != null) { + this.medHistories = new ArrayList<>(medHistories); + } + if (appts != null) { + this.appts = new ArrayList<>(appts); + } if (tagged != null) { this.tagged = new ArrayList<>(tagged); } @@ -65,9 +89,12 @@ public XmlAdaptedPerson(Person source) { phone = source.getPhone().value; email = source.getEmail().value; address = source.getAddress().value; - tagged = source.getTags().stream() - .map(XmlAdaptedTag::new) - .collect(Collectors.toList()); + nric = source.getNric().value; + dateOfBirth = source.getDateOfBirth().toString(); + reports = source.getMedicalReports().stream().map(XmlAdaptedReport::new).collect(Collectors.toList()); + medHistories = source.getMedHistory().stream().map(XmlAdaptedMedHistory::new).collect(Collectors.toList()); + appts = source.getAppts().stream().map(XmlAdaptedAppt::new).collect(Collectors.toList()); + tagged = source.getTags().stream().map(XmlAdaptedTag::new).collect(Collectors.toList()); } /** @@ -76,11 +103,6 @@ public XmlAdaptedPerson(Person source) { * @throws IllegalValueException if there were any data constraints violated in the adapted person */ public Person toModelType() throws IllegalValueException { - final List personTags = new ArrayList<>(); - for (XmlAdaptedTag tag : tagged) { - personTags.add(tag.toModelType()); - } - if (name == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName())); } @@ -113,8 +135,67 @@ public Person toModelType() throws IllegalValueException { } final Address modelAddress = new Address(address); + /** + * ================================================== + * ADDITIONAL INFO SUBFIELDS + * ================================================== + */ + + if (nric == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Nric.class.getSimpleName())); + } + final Nric modelNric = new Nric(nric); + + if (dateOfBirth == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + DateOfBirth.class.getSimpleName())); + } + final DateOfBirth modelDateOfBirth = new DateOfBirth(dateOfBirth); + + /** + * ================================================== + * MEDICAL REPORT SUBFIELDS + * ================================================== + */ + final List personMedicalReports = new ArrayList<>(); + for (XmlAdaptedReport report : reports) { + personMedicalReports.add(report.toModelType()); + } + final Set modelReports = new HashSet<>(personMedicalReports); + + /** + * ================================================== + * MED HISTORY SUBFIELDS + * ================================================== + */ + + final List personMedHistories = new ArrayList<>(); + for (XmlAdaptedMedHistory medHistory : medHistories) { + personMedHistories.add(medHistory.toModelType()); + } + + final Set modelMedHistory = new HashSet<>(personMedHistories); + + /** + * ================================================== + * APPT SUBFIELDS + * ================================================== + */ + + final List personAppts = new ArrayList<>(); + for (XmlAdaptedAppt appt : appts) { + personAppts.add(appt.toModelType()); + } + final Set modelAppts = new HashSet<>(personAppts); + + final List personTags = new ArrayList<>(); + for (XmlAdaptedTag tag : tagged) { + personTags.add(tag.toModelType()); + } final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); + + return new Person(modelName, modelPhone, modelEmail, modelAddress, modelReports, + modelMedHistory, modelAppts, modelNric, modelDateOfBirth, modelTags); } @Override @@ -132,6 +213,11 @@ public boolean equals(Object other) { && Objects.equals(phone, otherPerson.phone) && Objects.equals(email, otherPerson.email) && Objects.equals(address, otherPerson.address) + && Objects.equals(nric, otherPerson.nric) + && Objects.equals(dateOfBirth, otherPerson.dateOfBirth) + && medHistories.equals(otherPerson.medHistories) + && reports.equals(otherPerson.reports) + && appts.equals(otherPerson.appts) && tagged.equals(otherPerson.tagged); } } diff --git a/src/main/java/seedu/address/storage/XmlAdaptedReport.java b/src/main/java/seedu/address/storage/XmlAdaptedReport.java new file mode 100644 index 000000000000..ee15b2ab7535 --- /dev/null +++ b/src/main/java/seedu/address/storage/XmlAdaptedReport.java @@ -0,0 +1,96 @@ +package seedu.address.storage; + +import java.util.Objects; + +import javax.xml.bind.annotation.XmlElement; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.medicalreport.Information; +import seedu.address.model.medicalreport.MedicalReport; +import seedu.address.model.medicalreport.ReportDate; +import seedu.address.model.medicalreport.Title; + +/** + * JAXB-friendly version of the Report. + */ +public class XmlAdaptedReport { + + public static final String MISSING_FIELD_MESSAGE_FORMAT = "Report's %s field is missing!"; + + @XmlElement + private String title; + @XmlElement + private String date; + @XmlElement + private String information; + + /** + * Constructs an XmlAdaptedReport. + * This is the no-arg constructor that is required by JAXB. + */ + public XmlAdaptedReport() {} + + /** + * Constructs a {@code XmlAdaptedReport} with the given report details. + */ + public XmlAdaptedReport(String title, String date, String information) { + this.title = title; + this.date = date; + this.information = information; + } + + /** + * Converts a given Report into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedReport + */ + public XmlAdaptedReport(MedicalReport source) { + title = source.getTitle().toString(); + date = source.getDate().toString(); + information = source.getInformation().toString(); + } + + /** + * Converts this jaxb-friendly adapted appt object into the model's Report object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted report + */ + public MedicalReport toModelType() throws IllegalValueException { + if (title == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + Title.class.getSimpleName())); + } + final Title modelTitle = new Title(title); + + if (date == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ReportDate.class.getSimpleName())); + } + final ReportDate modelDate = new ReportDate(date); + + if (information == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + Information.class.getSimpleName())); + } + final Information modelInformation = new Information(information); + + return new MedicalReport(modelTitle, modelDate, modelInformation); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof XmlAdaptedReport)) { + return false; + } + + XmlAdaptedReport otherMedicalReport = (XmlAdaptedReport) other; + return Objects.equals(title, otherMedicalReport.title) + && Objects.equals(date, otherMedicalReport.date) + && Objects.equals(information, otherMedicalReport.information); + } +} + diff --git a/src/main/java/seedu/address/storage/XmlAdaptedTag.java b/src/main/java/seedu/address/storage/XmlAdaptedTag.java index d3e2d8be9c4f..3862a1fa2129 100644 --- a/src/main/java/seedu/address/storage/XmlAdaptedTag.java +++ b/src/main/java/seedu/address/storage/XmlAdaptedTag.java @@ -29,7 +29,7 @@ public XmlAdaptedTag(String tagName) { /** * Converts a given Tag into this class for JAXB use. * - * @param source future changes to this will not affect the created + * @param source future changes to this will not affect the created XmlAdaptedTag */ public XmlAdaptedTag(Tag source) { tagName = source.tagName; diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index f6727ea83abd..37dd85ba3396 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -37,6 +37,16 @@ public class PersonCard extends UiPart { @FXML private Label email; @FXML + private Label nric; + @FXML + private Label dateOfBirth; + @FXML + private FlowPane reports; + @FXML + private FlowPane appts; + @FXML + private FlowPane medHistories; + @FXML private FlowPane tags; public PersonCard(Person person, int displayedIndex) { @@ -47,6 +57,11 @@ public PersonCard(Person person, int displayedIndex) { phone.setText(person.getPhone().value); address.setText(person.getAddress().value); email.setText(person.getEmail().value); + nric.setText(person.getNric().value); + dateOfBirth.setText(person.getDateOfBirth().toString()); + person.getMedHistory().forEach(medHistory -> medHistories.getChildren().add(new Label(medHistory.toString()))); + person.getMedicalReports().forEach(report -> reports.getChildren().add(new Label(report.toString()))); + person.getAppts().forEach(appt -> appts.getChildren().add(new Label(appt.toString()))); person.getTags().forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); } diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index f08ea32ad558..e85f39efdb58 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -31,6 +31,11 @@ diff --git a/src/test/data/XmlUtilTest/missingPersonField.xml b/src/test/data/XmlUtilTest/missingPersonField.xml index c0da5c86d080..c257fba53a38 100644 --- a/src/test/data/XmlUtilTest/missingPersonField.xml +++ b/src/test/data/XmlUtilTest/missingPersonField.xml @@ -5,4 +5,21 @@ hans@example
4th street
friends + + Asthma + 01/01/2018 + Prescribed XXX medicine, next appointment on 02/02/2018. + + + 10/10/2010 + Pollen + USA + + + 01/01/2018 14:00 + 01/01/2018 15:00 + Consultation Room 1 + Diabetes Checkup + Dr Tan +
diff --git a/src/test/data/XmlUtilTest/validAddressBook.xml b/src/test/data/XmlUtilTest/validAddressBook.xml index 6265778674d3..103a7340f1e7 100644 --- a/src/test/data/XmlUtilTest/validAddressBook.xml +++ b/src/test/data/XmlUtilTest/validAddressBook.xml @@ -5,53 +5,71 @@ 9482424 hans@example.com
4th street
+ + 10-10-2010 Ruth Mueller 87249245 ruth@example.com
81th street
+ + 01-01-1996
Heinz Kurz 95352563 heinz@example.com
wall street
+ + 25-06-2001
Cornelia Meier 87652533 cornelia@example.com
10th street
+ + 17-03-1986
Werner Meyer 9482224 werner@example.com
michegan ave
+ + 04-01-2006
Lydia Kunz 9482427 lydia@example.com
little tokyo
+ + 06-03-2016
Anna Best 9482442 anna@example.com
4th street
+ + 27-12-2003
Stefan Meier 8482424 stefan@example.com
little india
+ + 19-09-2010
Martin Mueller 8482131 hans@example.com
chicago ave
+ + 17-04-1963
diff --git a/src/test/data/XmlUtilTest/validPerson.xml b/src/test/data/XmlUtilTest/validPerson.xml index c029008d54f4..0536eba7f94c 100644 --- a/src/test/data/XmlUtilTest/validPerson.xml +++ b/src/test/data/XmlUtilTest/validPerson.xml @@ -5,4 +5,21 @@ hans@example
4th street
friends + + Asthma + 01/01/2018 + Prescribed XXX medicine, next appointment on 02/02/2018. + + + 10/10/2010 + Pollen + USA + + + 01/01/2018 14:00 + 01/01/2018 15:00 + Consultation Room 1 + Diabetes Checkup + Dr Tan +
diff --git a/src/test/java/guitests/guihandles/PersonCardHandle.java b/src/test/java/guitests/guihandles/PersonCardHandle.java index 1789735e49a8..8596858a05a7 100644 --- a/src/test/java/guitests/guihandles/PersonCardHandle.java +++ b/src/test/java/guitests/guihandles/PersonCardHandle.java @@ -19,6 +19,10 @@ public class PersonCardHandle extends NodeHandle { private static final String ADDRESS_FIELD_ID = "#address"; private static final String PHONE_FIELD_ID = "#phone"; private static final String EMAIL_FIELD_ID = "#email"; + private static final String NRIC_FIELD_ID = "#nric"; + private static final String MEDICAL_REPORTS_FIELD_ID = "#reports"; + private static final String MEDHISTORY_FIELD_ID = "#medHistories"; + private static final String APPTS_FIELD_ID = "#appts"; private static final String TAGS_FIELD_ID = "#tags"; private final Label idLabel; @@ -26,6 +30,10 @@ public class PersonCardHandle extends NodeHandle { private final Label addressLabel; private final Label phoneLabel; private final Label emailLabel; + private final Label nricLabel; + private final List