diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 42f99047c35..1d13f19dcf1 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -263,64 +263,42 @@ The following activity diagram illustrates how the complete operation is execute ### Gather Emails Feature -The **Gather Emails** feature in our software system is a critical functionality designed to efficiently collect -email addresses. This feature is facilitated through the `GatherCommand` class, which plays a central role in the process. +The **Gather Emails** feature in our software system is designed to efficiently collect email addresses. +The **Gather Emails** feature is facilitated by the `GatherCommand`, which plays a central role in the process. Below is the class diagram of the gather emails feature. -#### Implementation Overview - -The `GatherCommand` class is instantiated by the `GatherCommandParser`, which parses user input commands. The -`GatherCommandParser` class implements the following operations: +![GatherClassDiagram](images/GatherClassDiagram.png) -* `GatherCommandParser#parse(String args)` — Checks the prefixes (fp/ and t/) and instantiates `GatherCommand` -accordingly. It passes either a `GatherEmailByFinancialPlan` or a `GatherEmailByTag` object, both implementations of -the `GatherEmailPrompt` interface. +#### Implementation Overview -The `GatherCommand` takes in a `GatherEmailPrompt` object and passes it into the current `Model` model, subsequently -interacting with the `AddressBook` and `UniquePersonsList` classes. The `GatherCommand` class implements the following -operations: +The `GatherCommand` is initiated by the `GatherCommandParser`. The `GatherCommandParser` checks for the prefix `fp/` or `t/` in the user's input and creates either a `GatherEmailByFinancialPlan` or `GatherEmailByTag` object accordingly. +Both `GatherEmailByFinancialPlan` or `GatherEmailByTag` implements the `GatherEmailPrompt` interface. This interface helps with future scalability of this feature to gather emails by more fields. -* `GatherCommand#GatherCommand(GatherEmailPrompt prompt)` — Constructor that initializes the command with the -provided `GatherEmailPrompt` object. -* `GatherCommand#execute()` —  Executes the gathering operation by calling +The `GatherCommand` takes in the `GatherEmailPrompt` object and passes it into the current `Model` model, subsequently +interacting with the `AddressBook` and `UniquePersonsList` classes. The `GatherCommand#execute()` executes the gathering operation by calling `Model#gatherEmails(GatherEmailPrompt prompt)`. -The `Model` interface is implemented by the `ModelManager`, representing the in-memory model of the address book data. -It contains the following method: +The following sequence diagram shows how the gather operation works as described above: -* `ModelManager#gatherEmails(GatherEmailPrompt prompt)` —  Carries out the gathering operation by calling -`AddressBook#gatherEmails(GatherEmailPrompt prompt)`. +![GatherSequenceDiagram1](images/GatherSequenceDiagram1.png) +The `Model` interface is implemented by the `ModelManager`, representing the in-memory model of the address book data. +The `ModelManager#gatherEmails(GatherEmailPrompt prompt)` calls `AddressBook#gatherEmails(GatherEmailPrompt prompt)`. This operation is exposed in the `AddressBook` class as `AddressBook#gatherEmails(GatherEmailsPrompt prompt)`, and in the `UniquePersonsList` class as `UniquePersonsList#gatherEmails(GatherEmailsPrompt prompt)`. -The `UniquePersonsList` class maintains a list of unique persons. Additionally, it implements the following operation: -* `UniquePersonsList#gatherEmails(GatherEmailPrompt prompt)` —  This method iterates through the persons list -and calls `GatherEmailPrompt#gatherEmails(Person person)`, passing in each person. +The `UniquePersonsList` class maintains a list of unique persons and `UniquePersonsList#gatherEmails(GatherEmailPrompt prompt)` iterates through the persons list +and calls `GatherEmailPrompt#gatherEmails(Person person)`, passing in each person. Depending on the type of `GatherEmailPrompt`, it triggers either: -Depending on the scenario, it triggers either `Person#gatherEmailsContainsTag(String prompt)` or -`Person#gatherEmailsContainsFinancialPlan(String prompt)`: -* `Person#gatherEmailsContainsTag(String prompt)` —  Checks if the given prompt is a substring of the name of -any Tag in the `Set` of the current person. -* `Person#gatherEmailsContainsFinancialPlan(String prompt)` —  Checks if the given prompt is a substring of the -name of any Financial Plan in the `Set` of the current person. +* `Person#gatherEmailsContainsTag(String prompt)` —  This method calls the `Tag#containsSubstring(String substring)` to checks if the given prompt is a substring of any Tag names in the `Set` of the current person. +* `Person#gatherEmailsContainsFinancialPlan(String prompt)` —  This method calls the `FinancialPlan#containsSubstring(String substring)` to checks if the given prompt is a substring of any Financial Plan names in the `Set` of the current person. -This is the class diagram for the gather command: +To allow gather email feature to be case-insensitive, the prompt and financial plan/tag names converted to lowercase when compared. +The following sequence diagram shows how the gathering of emails by financial plan operation works: -![GatherClassDiagram](images/GatherClassDiagram.png) - -**Usage Scenario:** - -**Scenario 1:** -User enters a gather `fp/financial plan a`. The `GatherEmailByFinancialPlan` will be initialized. Each person in the -`UniquePersonList` will be passed into the `GatherEmailByFinancialPlan#gatherEmails(Person person)`. - -**Scenario 2:** -User enters a gather `t/Elderly`. The `GatherEmailByTag` will be initialized. Each person in the `UniquePersonList` -will be passed into the `GatherEmailByTag#gatherEmails(Person person)`. - -The following sequence diagram shows how the gather operation works: +![GatherSequenceDiagram2](images/GatherSequenceDiagram2.png) -![GatherSequenceDiagram](images/GatherSequenceDiagram.png) +Currently, we only allow gathering emails by `FinancialPlan` and `Tag` as these are the more likely to be searched to gather emails by. However, we can add more classes implementing the `GatherEmailPromt` +to facilitate the gathering of emails by more fields. #### Design Considerations @@ -328,19 +306,19 @@ The following sequence diagram shows how the gather operation works: **Alternative 1 (Current Choice):** User can only search by one Financial Plan or Tag. - **Pros:** Easy to implement. Limits the potential for bugs. -- **Cons:** Limited filtering options. Hard to scale to gather by other fields. +- **Cons:** Limited filtering options. **Alternative 2:** User can search by multiple Financial Plans or Tags. - **Pros:** More filtering options. Easy to scale to gather by other fields. - **Cons:** Introduces more complexity and requires additional error handling. -_{more aspects and alternatives to be added}_ ### Expanded Find feature The enhanced find mechanism is facilitated by the `CombinedPredicate` and utilises the existing `FindCommand` structure. It extends the `find` command with the ability to search for multiple terms at once, implemented using an array of `PersonContainsKeywordsPredicate`. Here's a partial class diagram of the `CombinedPredicate`. + ![CombinedPredicateClassDiagram](images/CombinedPredicateClassDiagram.png) In the `FindCommandParser`, `CombinedPredicate` is initialised with a `NameContainsKeywordsPredicate`, @@ -467,114 +445,6 @@ The `setAppointmentList()` method checks against `filteredPersons` to look for u * Cons: `filteredPersons` and `sortedAppointments` might not correspond since `sortedAppointments` is no longer dependent on `filteredPersons`. -### \[Proposed\] Undo/redo feature - -### \[Proposed\] Undo/redo feature -#### Proposed Implementation - -The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo -history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the -following operations: - -* `VersionedAddressBook#commit()` — Saves the current address book state in its history. -* `VersionedAddressBook#undo()` — Restores the previous address book state from its history. -* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history. - -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and -`Model#redoAddressBook()` respectively. - -Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. - -Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the -initial address book state, and the `currentStatePointer` pointing to that single address book state. - -![UndoRedoState0](images/UndoRedoState0.png) - -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls -`Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be -saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. - -![UndoRedoState1](images/UndoRedoState1.png) - -Step 3. The user executes `add n/David …​` to add a new person. The `add` command also calls -`Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. - -![UndoRedoState2](images/UndoRedoState2.png) - -
:information_source: **Note:** If a command fails its execution, it -will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`. - -
- -Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the -`undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once -to the left, pointing it to the previous address book state, and restores the address book to that state. - -![UndoRedoState3](images/UndoRedoState3.png) - -
:information_source: **Note:** If the `currentStatePointer` is at index -0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` -command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user -rather than attempting to perform the undo. - -
- -The following sequence diagram shows how the undo operation works: - -![UndoSequenceDiagram](images/UndoSequenceDiagram.png) - -
:information_source: **Note:** The lifeline for `UndoCommand` should end -at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. - -
- -The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` -once to the right, pointing to the previously undone state, and restores the address book to that state. - -
:information_source: **Note:** If the `currentStatePointer` is at index -`addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook -states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will -return an error to the user rather than attempting to perform the redo. - -
- -Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as -`list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. -Thus, the `addressBookStateList` remains unchanged. - -![UndoRedoState4](images/UndoRedoState4.png) - -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not -pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be -purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern -desktop applications follow. - -![UndoRedoState5](images/UndoRedoState5.png) - -The following activity diagram summarizes what happens when a user executes a new command: - - - -#### Design considerations: - -**Aspect: How undo & redo executes:** - -* **Alternative 1 (current choice):** Saves the entire address book. - * Pros: Easy to implement. - * Cons: May have performance issues in terms of memory usage. - -* **Alternative 2:** Individual command knows how to undo/redo by - itself. - * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). - * Cons: We must ensure that the implementation of each individual command are correct. - -_{more aspects and alternatives to be added}_ - -### \[Proposed\] Data archiving - -_{Explain here how the data archiving feature will be implemented}_ - - -------------------------------------------------------------------------------------------------------------------- ## **Documentation, logging, testing, configuration, dev-ops** @@ -609,47 +479,47 @@ modifying of clients’ data. Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` -| Priority | As a …​ | I want to …​ | So that I can…​ | -|----------|---------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------| -|`* * *`| financial advisor who often works with numerous clients | have a central repository for my clients’ contacts details | effectively manage the intricate details of each of my clients. | -| `* * *` | financial advisor | add clients' contacts to the contact book | accumulate contacts for future purposes. | -| `* * *` | financial advisor | remove clients contacts from the contact book | keep my contact book compact and relevant. | -| `* * *` | financial advisor | edit clients’ contacts in the contact book | keep my information updated. | -| `* *` | financial advisor | record appointments with my clients | keep track of when my next meeting with the client is. | -| `* *` | financial advisor | tag my clients by the plans they purchase | gather groups of clients based on the financial plan(s) they purchased. | -| `* *` | financial advisor | search for clients with specific financial plans | update those people about their plans more efficiently. | -| `* *` | financial advisor | sort my clients in certain orders including alphabetical order or appointment time in both ascending and descending order | view my clients in a more systematic manner. | -| `* *` | financial advisor | view my upcoming appointments I have with clients in chronological order | better plan my time. | -| `* *` | financial advisor | complete appointments | clean up the address book of completed appointments. | -| `* *` | financial advisor | gather emails of clients by their tags such as age group | collate and notify people with the same tags on any updates. | -| `* *` | financial advisor | search for clients with the same financial plan | efficiently provide targeted updates to individuals with the same plan. | -| `*` | busy financial advisor | streamline administrative tasks like tracking my clients contacts | focus most of my time on giving personalised financial advice and services to my clients. | -| `*` | financial advisor managing a substantial client portfolio | follow a standardised format to collect my clients’ information | manage data consistency among my clients. | -| `*` | financial advisor | search for specific client details | quickly contact my clients. | -| `*` | user who values both my clients' time and the quality of our interactions | set reminders for follow-up sessions with clients | ensure I never miss an important meeting. | -| `*` | financial advisor | efficiently track referral sources for my clients | manage their relationships. | -| `*` | financial advisor | sort my clients in certain orders including alphabetical order portfolio value in both ascending and descending order | view my clients in a more systematic manner. | -| `*` | financial advisor | filter my clients based on certain metrics like financial products purchased and minimum portfolio value | choose clients. | -| `*` | financial advisor | record appointments with clients with the application | keep track of when my last meeting with each client is. | -| `*` | financial advisor | export my contact data and client data in a readable format | use it for backup purposes or to run data processing with other software tools. | -| `*` | financial advisor | have a dashboard | obtain insights into my clientele base including metrics like client acquisition, retention rates and revenue I generate each month. | -| `*` | financial advisor | categorise contacts based on their financial status (high net worth regular) | prioritise my client interactions. | -| `*` | financial advisor | update my profile information (name, contact, details, company) | ensure my personal information is always accurate. | -| `*` | an experienced user | edit the data file directly | be more efficient. | -| `*` | user | undo actions | recover from my mistakes. | -| `*` | busy financial advisor | quickly add incomplete details of a client and be reminded about it | fill the rest in later. | -| `*` | financial advisor | check the appointments scheduled today | not forget to meet a client | -| `*` | financial advisor | view contacts of all my clients I am meeting for the day | efficiently search for their contacts. | -| `*` | financial advisor | view all the insurance plans my client has purchased easily | make planning during an appointment easier. | -| `*` | financial advisor | filter the plans of my client | to make it focus on certain plans during my appointment | -| `*` | financial advisor | make updates to their plans on the app easily | keep track of changes to the clients plans | -| `*` | financial advisor | check which client has been under me the longest | plan welfare to retain them as long term customers. | -| `*` | financial advisor | add notes on clients | excess them when needed | -| `*` | financial advisor | display data from the address book into a excel file | more easily present to clients | -| `*` | financial advisor | add tags to customers | collate and notify people with the same plan should there be a new change | -| `*` | manager | retrieve data on the types of plans purchased | better understand the products my team member is selling | -| `*` | manager | monitor expiring insurance plans | advice trainees on time management | -| `*` | financial advisor | import a file | easily transfer client information when client leaves | +| Priority | As a …​ | I want to …​ | So that I can…​ | +|----------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------| +| `* * *` | financial advisor who often works with numerous clients | have a central repository for my clients’ contacts details | effectively manage the intricate details of each of my clients. | +| `* * *` | financial advisor | add clients' contacts to the contact book | accumulate contacts for future purposes. | +| `* * *` | financial advisor | remove clients contacts from the contact book | keep my contact book compact and relevant. | +| `* * *` | financial advisor | edit clients’ contacts in the contact book | keep my information updated. | +| `* *` | financial advisor | record appointments with my clients | keep track of when my next meeting with the client is. | +| `* *` | financial advisor | tag my clients by the plans they purchase | gather groups of clients based on the financial plan(s) they purchased. | +| `* *` | financial advisor | search for clients with specific financial plans | update those people about their plans more efficiently. | +| `* *` | financial advisor | sort my clients in certain orders including alphabetical order or appointment time in both ascending and descending order | view my clients in a more systematic manner. | +| `* *` | financial advisor | view my upcoming appointments I have with clients in chronological order | better plan my time. | +| `* *` | financial advisor | complete appointments | clean up the address book of completed appointments. | +| `* *` | financial advisor | gather emails of clients by their tags such as age group | collate and notify people with the same tags on any updates. | +| `* *` | financial advisor | search for clients with the same financial plan | efficiently provide targeted updates to individuals with the same plan. | +| `*` | busy financial advisor | streamline administrative tasks like tracking my clients contacts | focus most of my time on giving personalised financial advice and services to my clients. | +| `*` | financial advisor managing a substantial client portfolio | follow a standardised format to collect my clients’ information | manage data consistency among my clients. | +| `*` | financial advisor | search for specific client details | quickly contact my clients. | +| `*` | user who values both my clients' time and the quality of our interactions | set reminders for follow-up sessions with clients | ensure I never miss an important meeting. | +| `*` | financial advisor | efficiently track referral sources for my clients | manage their relationships. | +| `*` | financial advisor | sort my clients in certain orders including alphabetical order portfolio value in both ascending and descending order | view my clients in a more systematic manner. | +| `*` | financial advisor | filter my clients based on certain metrics like financial products purchased and minimum portfolio value | choose clients. | +| `*` | financial advisor | record appointments with clients with the application | keep track of when my last meeting with each client is. | +| `*` | financial advisor | export my contact data and client data in a readable format | use it for backup purposes or to run data processing with other software tools. | +| `*` | financial advisor | have a dashboard | obtain insights into my clientele base including metrics like client acquisition, retention rates and revenue I generate each month. | +| `*` | financial advisor | categorise contacts based on their financial status (high net worth regular) | prioritise my client interactions. | +| `*` | financial advisor | update my profile information (name, contact, details, company) | ensure my personal information is always accurate. | +| `*` | an experienced user | edit the data file directly | be more efficient. | +| `*` | user | undo actions | recover from my mistakes. | +| `*` | busy financial advisor | quickly add incomplete details of a client and be reminded about it | fill the rest in later. | +| `*` | financial advisor | check the appointments scheduled today | not forget to meet a client | +| `*` | financial advisor | view contacts of all my clients I am meeting for the day | efficiently search for their contacts. | +| `*` | financial advisor | view all the insurance plans my client has purchased easily | make planning during an appointment easier. | +| `*` | financial advisor | filter the plans of my client | to make it focus on certain plans during my appointment | +| `*` | financial advisor | make updates to their plans on the app easily | keep track of changes to the clients plans | +| `*` | financial advisor | check which client has been under me the longest | plan welfare to retain them as long term customers. | +| `*` | financial advisor | add notes on clients | excess them when needed | +| `*` | financial advisor | display data from the address book into a excel file | more easily present to clients | +| `*` | financial advisor | add tags to customers | collate and notify people with the same plan should there be a new change | +| `*` | manager | retrieve data on the types of plans purchased | better understand the products my team member is selling | +| `*` | manager | monitor expiring insurance plans | advice trainees on time management | +| `*` | financial advisor | import a file | easily transfer client information when client leaves | *{More to be added}* @@ -864,10 +734,7 @@ validity checker for both fields. at once. To allow the gathering of all the persons emails using `gather all` command, we plan create another `GatherEmailPrompt` class, with a method that will call the Person `getEmail()` method. To allow gathering emails by multiple fields, for example using the `fp/` and `t/` prefixes at once, we plan to use a similar approach to `find` but return the person's email instead. -6. The `complete`, `add`, `edit` and `schedule` commands currently display the whole list (i.e. undoes the result of -any `find` command) after being executed, which might cause users to become disoriented. We plan to disable this -interaction between these commands and `find`. -7. The `clear` command confirmation window can be manipulated using the arrow and 'Enter' keys. The window is +6. The `clear` command confirmation window can be manipulated using the arrow and 'Enter' keys. The window is initialised with the focus on the `confirm` button. This makes it possible for a user to accidentally press 'Enter' twice and wipe the contact book anyway, bypassing the defence mechanism entirely. We plan to make the command more resistant to mistakes by having the user key in a specific phrase, or to initialise the window with the focus on the diff --git a/docs/UserGuide.md b/docs/UserGuide.md index dd664d4354e..c3b1fb034b1 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -74,16 +74,16 @@ Click on the relevant links to easily navigate through the guide and access the ### General UI information -Component | Purpose ---------|------------------ -**Navigation Bar** | Allows you to exit UNOFAS or view help -**Command Line** | Location to enter commands -**Result Line** | Displays the result after a command is entered -**Contact List** | Displays clients -**Appointment List** | Displays appointments -**Contact Card** | Displays detailed information about a patient -**Appointment Card** | Displays detailed information about an appointment -**Save Location** | Displays the location where your UNOFAS data is stored +| Component | Purpose | +|----------------------|----------------------------------------------------------| +| **Navigation Bar** | Allows you to exit UNOFAS or view help | +| **Command Line** | Location to enter commands | +| **Result Line** | Displays the result after a command is entered | +| **Contact List** | Displays clients | +| **Appointment List** | Displays appointments | +| **Contact Card** | Displays detailed information about a patient | +| **Appointment Card** | Displays detailed information about an appointment | +| **Save Location** | Displays the location where your UNOFAS data is stored | ### Contact Card @@ -138,21 +138,26 @@ Below is a table summarising common arguments used in `add`, `edit`, `find`, `sc to view the arguments' prefix, and their acceptable values. Unless specified, having only space characters i.e an empty value, is not an acceptable value and will result in a warning. -| Prefix | Argument | Acceptable Values | -|--------|-----------------------|------------------------------------------------------------------------| -| - | INDEX | Number (1 to current size of the contact book) | -| `n/` | NAME | Alphabets, numbers, and space characters only | -| `p/` | PHONE_NUMBER | Numbers only and at least 3 digits long | -| `e/` | EMAIL | Alphabets, numbers, and symbols only in a valid email format | -| `a/` | ADDRESS | Any value is possible | -| `nk/` | NEXT_KIN | Alphabets, numbers, and space characters only | -| `nkp/` | NEXT_KIN_PHONE | Numbers only and at least 3 digits long | -| `fp/` | FINANCIAL_PLAN | Alphabets, numbers, and space characters only. Empty value is accepted | -| `t/` | TAG | Alphabets and numbers only. Empty value is accepted | -| `ap/` | APPOINTMENT_NAME | Alphabets, numbers, and space characters only | -| `d/` | APPOINTMENT_DATE | Format: dd-MM-yyyy (e.g., 31-12-2023) | -| `d/` | APPOINTMENT_DATE_TIME | Format: dd-MM-yyyy HH:mm (e.g., 31-12-2023 14:30) | -| - | KEYWORD | `name` or `appointment` | +| Prefix | Argument | Acceptable Values | +|--------|-----------------------|--------------------------------------------------------------------------------------------------------------------| +| - | INDEX | Number (1 to current size of the contact book) | +| `n/` | NAME | Alphabets, numbers, and space characters only | +| `p/` | PHONE_NUMBER | Numbers only and at least 3 digits long | +| `e/` | EMAIL | Alphabets, numbers, and symbols only in a valid email format | +| `a/` | ADDRESS | Any value is possible. | +| `nk/` | NEXT_KIN | Alphabets, numbers, and space characters only | +| `nkp/` | NEXT_KIN_PHONE | Numbers only and at least 3 digits long | +| `fp/` | FINANCIAL_PLAN | Alphabets, numbers, and space characters only. Empty value is accepted when using [Edit](#editing-a-person--edit). | +| `t/` | TAG | Alphabets and numbers only. Empty value is accepted when using [Edit](#editing-a-person--edit). | +| `ap/` | APPOINTMENT_NAME | Alphabets, numbers, and space characters only | +| `d/` | APPOINTMENT_DATE | Format: dd-MM-yyyy (e.g., 31-12-2023) | +| `d/` | APPOINTMENT_DATE_TIME | Format: dd-MM-yyyy HH:mm (e.g., 31-12-2023 14:30) | +| - | KEYWORD | `name` or `appointment` | + +
:information_source: +**Do note** If the ADDRESS includes any recognized prefixes (leading space + prefix), users should be careful. +For instance, if the user inputs `a/Blk 285 n/Clementi` for the ADDRESS argument, it will trigger the identification of the prefix `n/` in the input. +
----------------------- ### Viewing help : `help` @@ -255,7 +260,8 @@ Tags:` ![result for 'edit 4 n/john doe a/23 woodlands ave 123'](images/editUi.png)
:information_source: -**Do note** that it is possible to add a client's contact with multiple tags by duplicating the `t/` prefix. The same can be done with for financial plans with the `fp/` prefix. +**Do note** that it is possible to edit a client's contact with multiple tags by duplicating the `t/` prefix. The same can be done with for financial plans with the `fp/` prefix. +However, multiple empty values for tags and financial plans are not accepted. For example, `t/ t/` and `fp/ fp/` is not accepted.
--------------- @@ -364,6 +370,7 @@ Upon triggering the overriding prompt, until confirmation or cancellation of com is not allowed (including trying to exit the program). ---------- + ### Completing an Appointment : `complete` Completes an appointment either with the person at the specified `INDEX` or complete all appointments with matching `APPOINTMENT_DATE`. @@ -447,7 +454,8 @@ UNOFAS data are saved in the hard disk automatically after any command that chan UNOFAS data are saved automatically as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
:exclamation: **Caution:** -If your changes to the data file makes its format invalid, UNOFAS will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it. +If your changes to the data file makes its format invalid, UNOFAS will discard all data and start with an empty data file at the next run. +Certain edits to the file may also cause unexpected behaviours. Please only edit the file if you are confident that it is correct, and it is recommended to take a backup of the file before editing it.
### Archiving data files `[coming in v2.0]` diff --git a/docs/diagrams/GatherClassDiagram.puml b/docs/diagrams/GatherClassDiagram.puml index 0f3367398c2..d39479002e9 100644 --- a/docs/diagrams/GatherClassDiagram.puml +++ b/docs/diagrams/GatherClassDiagram.puml @@ -4,40 +4,15 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR -Class Person { - -email: String - +gatherEmailsContainsFinancialPlan(): String - +gatherEmailsContainsTag(): String -} - -Class GatherCommandParser { - +parse(String args): GatherCommand -} - -Class GatherCommand { - -gatherPrompt: GatherEmailPrompt - +GatherCommand(GatherEmailPrompt prompt) - +execute(): void -} - -Class "<>\nGatherEmailPrompt" as GatherEmailPrompt { - +gatherEmails(Person person): void -} - -Class GatherEmailByFinancialPlan { - - promptFp: String - +gatherEmails(Person person): void -} - -Class GatherEmailByTag { - - promptTag: String - +gatherEmails(Person person): void -} +Class GatherCommandParser +Class GatherCommand +Class "<>\nGatherEmailPrompt" as GatherEmailPrompt +Class GatherEmailByFinancialPlan +Class GatherEmailByTag GatherCommandParser .down.> GatherCommand : creates > GatherCommandParser .down.> GatherEmailPrompt : creates > GatherCommand -right-> "1" GatherEmailPrompt GatherEmailByFinancialPlan .up.|> GatherEmailPrompt GatherEmailByTag .up.|> GatherEmailPrompt -GatherEmailPrompt .right.> "1" Person @enduml diff --git a/docs/diagrams/GatherSequenceDiagram.puml b/docs/diagrams/GatherSequenceDiagram.puml deleted file mode 100644 index b368683d385..00000000000 --- a/docs/diagrams/GatherSequenceDiagram.puml +++ /dev/null @@ -1,93 +0,0 @@ -@startuml -!include style.puml -skinparam ArrowFontStyle plain - -box Logic LOGIC_COLOR_T1 -participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR -participant ":GatherCommandParser" as GatherCommandParser LOGIC_COLOR -participant "command:GatherCommand" as GatherCommand LOGIC_COLOR -participant ":CommandResult" as CommandResult LOGIC_COLOR -end box - -box Model MODEL_COLOR_T1 -participant ":Model" as Model MODEL_COLOR -participant ":AddressBook" as AddressBook MODEL_COLOR -participant ":UniquePersonsList" as UniquePersonsList MODEL_COLOR -participant "prompt:GatherEmailByFinancialPlan" as GatherEmailByFinancialPlan MODEL_COLOR -participant ":Person" as Person MODEL_COLOR -end box - -[-> LogicManager : execute("gather fp/Financial Plan A") -activate LogicManager - -LogicManager -> AddressBookParser : parseCommand("gather fp/Financial Plan A") -activate AddressBookParser - -AddressBookParser -> GatherCommandParser: parse("fp/Financial Plan A") -activate GatherCommandParser - -create GatherEmailByFinancialPlan -GatherCommandParser -> GatherEmailByFinancialPlan: GatherEmailByFinancialPlan("Financial Plan A") -activate GatherEmailByFinancialPlan -GatherEmailByFinancialPlan --> GatherCommandParser -deactivate GatherEmailByFinancialPlan - -create GatherCommand -GatherCommandParser -> GatherCommand: GatherCommand(prompt) -activate GatherCommand - -GatherCommand --> GatherCommandParser : command -deactivate GatherCommand - -GatherCommandParser --> AddressBookParser : command -deactivate GatherCommandParser -'Hidden arrow to position the destroy marker below the end of the activation bar. -GatherCommandParser -[hidden]-> AddressBookParser -destroy GatherCommandParser - -AddressBookParser --> LogicManager : command -deactivate AddressBookParser - -LogicManager -> GatherCommand : execute() -activate GatherCommand - -GatherCommand -> Model: gatherEmails(prompt) -activate Model - -Model -> AddressBook: gatherEmails(prompt) -activate AddressBook - -AddressBook -> UniquePersonsList: gatherEmails(prompt) -activate UniquePersonsList - -loop through internalList - UniquePersonsList -> GatherEmailByFinancialPlan: gatherEmails(person) - activate GatherEmailByFinancialPlan - GatherEmailByFinancialPlan -> Person: gatherEmailsContainsFinancialPlan("Financial Plan A") - activate Person - Person --> GatherEmailByFinancialPlan: email (or Empty String) - deactivate Person - GatherEmailByFinancialPlan --> UniquePersonsList: email (or Empty String) - deactivate GatherEmailByFinancialPlan -end loop - -UniquePersonsList --> AddressBook: emails (or Empty String) -deactivate UniquePersonsList - -AddressBook --> Model: emails (or Empty String) -deactivate AddressBook - -Model --> GatherCommand: emails (or Empty String) -deactivate Model - -alt emails.isEmpty() - GatherCommand --> LogicManager: CommandResult(MESSAGE_NO_PERSON_FOUND + prompt.toString()) -else - GatherCommand --> LogicManager: CommandResult(emails) -end - deactivate GatherCommand - -[<--LogicManager -deactivate LogicManager -@enduml diff --git a/docs/diagrams/GatherSequenceDiagram1.puml b/docs/diagrams/GatherSequenceDiagram1.puml new file mode 100644 index 00000000000..ac8d6fd524e --- /dev/null +++ b/docs/diagrams/GatherSequenceDiagram1.puml @@ -0,0 +1,63 @@ +@startuml +!include style.puml +skinparam ArrowFontStyle plain + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":GatherCommandParser" as GatherCommandParser LOGIC_COLOR +participant "command:GatherCommand" as GatherCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("gather fp/Financial Plan A") +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand("gather fp/Financial Plan A") +activate AddressBookParser + +AddressBookParser -> GatherCommandParser : parse("fp/Financial Plan A") +activate GatherCommandParser + +create GatherCommand +GatherCommandParser -> GatherCommand : GatherCommand(prompt) +activate GatherCommand + +GatherCommand --> GatherCommandParser : command +deactivate GatherCommand + +GatherCommandParser --> AddressBookParser : command +deactivate GatherCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +GatherCommandParser -[hidden]-> AddressBookParser +destroy GatherCommandParser + +AddressBookParser --> LogicManager : command +deactivate AddressBookParser + +LogicManager -> GatherCommand : execute() +activate GatherCommand + +GatherCommand -> Model: gatherEmails(prompt) +activate Model + +Model --> GatherCommand: emails (or Empty String) +deactivate Model + +create CommandResult +GatherCommand -> CommandResult +activate CommandResult + +CommandResult --> GatherCommand +deactivate CommandResult + +GatherCommand --> LogicManager: result +deactivate GatherCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/GatherSequenceDiagram2.puml b/docs/diagrams/GatherSequenceDiagram2.puml new file mode 100644 index 00000000000..3b7ebf5354a --- /dev/null +++ b/docs/diagrams/GatherSequenceDiagram2.puml @@ -0,0 +1,41 @@ +@startuml +!include style.puml +skinparam ArrowFontStyle plain + +box Model MODEL_COLOR_T1 +participant ":ModelManager" as ModelManager MODEL_COLOR +participant ":AddressBook" as AddressBook MODEL_COLOR +participant ":UniquePersonsList" as UniquePersonsList MODEL_COLOR +participant "prompt:GatherEmailByFinancialPlan" as GatherEmailByFinancialPlan MODEL_COLOR +participant ":Person" as Person MODEL_COLOR +end box + +[-> ModelManager: gatherEmails(prompt) +activate ModelManager + +ModelManager -> AddressBook: gatherEmails(prompt) +activate AddressBook + +AddressBook -> UniquePersonsList: gatherEmails(prompt) +activate UniquePersonsList + +loop through internalList + UniquePersonsList -> GatherEmailByFinancialPlan: gatherEmails(person) + activate GatherEmailByFinancialPlan + GatherEmailByFinancialPlan -> Person: gatherEmailsContainsFinancialPlan("Financial Plan A") + activate Person + Person --> GatherEmailByFinancialPlan: email (or Empty String) + deactivate Person + GatherEmailByFinancialPlan --> UniquePersonsList: email (or Empty String) + deactivate GatherEmailByFinancialPlan +end loop + +UniquePersonsList --> AddressBook: emails (or Empty String) +deactivate UniquePersonsList + +AddressBook --> ModelManager: emails (or Empty String) +deactivate AddressBook + +[<-- ModelManager : emails (or Empty String) +deactivate ModelManager +@enduml diff --git a/docs/images/GatherClassDiagram.png b/docs/images/GatherClassDiagram.png index 21556e8c309..d9d0ffc23cb 100644 Binary files a/docs/images/GatherClassDiagram.png and b/docs/images/GatherClassDiagram.png differ diff --git a/docs/images/GatherSequenceDiagram.png b/docs/images/GatherSequenceDiagram.png deleted file mode 100644 index 4e2f1214738..00000000000 Binary files a/docs/images/GatherSequenceDiagram.png and /dev/null differ diff --git a/docs/images/GatherSequenceDiagram1.png b/docs/images/GatherSequenceDiagram1.png new file mode 100644 index 00000000000..7ca885cb970 Binary files /dev/null and b/docs/images/GatherSequenceDiagram1.png differ diff --git a/docs/images/GatherSequenceDiagram2.png b/docs/images/GatherSequenceDiagram2.png new file mode 100644 index 00000000000..ef37527bcad Binary files /dev/null and b/docs/images/GatherSequenceDiagram2.png differ diff --git a/docs/team/alyssapng.md b/docs/team/alyssapng.md index fa621e08ab1..eec51056872 100644 --- a/docs/team/alyssapng.md +++ b/docs/team/alyssapng.md @@ -5,7 +5,9 @@ title: Alyssa Png Kai Wen's Project Portfolio Page ### Overview -To be added soon. +UNOFAS is a desktop app for Financial Advisors (FA) to manage client’s contacts, optimized for use via a Command Line +Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). The app also includes features +such as sorting, scheduling and other commands to query information quickly required by the FA. ### Summary of Contributions @@ -16,19 +18,33 @@ Given below are my contributions to the project. * Highlights: * Provides a foundation for future email gathering implementations, paving the way for potential expansions into other fields. * Required a deep understanding of interfaces and integration with existing codebase. - * Credits: + * Pull request [#72](https://github.com/AY2324S1-CS2103T-F12-1/tp/pull/72) * **Code Contributed**: [RepoSense](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=alyssapng&breakdown=true) -* **Enhancements Implemented**: gather command to be able to gather emails by tags. +* **Enhancements Implemented**: + * Gather command to be able to gather emails by tags + * Pull request [#109](https://github.com/AY2324S1-CS2103T-F12-1/tp/pull/109) + * Enhancing the UI design for UNOFAS + * Justification: Provide financial advisors with a more intuitive, visually appealing interface, optimizing content visibility to reduce the likelihood of overlooking crucial details. + * Pull request [#151](https://github.com/AY2324S1-CS2103T-F12-1/tp/pull/151) * **Contributions to the UG**: + * Updated Title and Introduction + * Added Argument Summary * Added documentation for the features `gather` * **Contributions to the DG**: * Added target user profile, value proposition, user stories and user cases. * Added implementation details for gather. + * Added planned enhancement. * **Contributions to team-based tasks**: * Release v1.2 JAR file. - * Added screenshots into project notes document. + * Added screenshots into project notes document for v1.2 demo. + +* **Review/mentoring contributions**: +* PRs reviewed (with non-trivial commments): +[#108](https://github.com/AY2324S1-CS2103T-F12-1/tp/pull/108), +[#90](https://github.com/AY2324S1-CS2103T-F12-1/tp/pull/90), +[#133](https://github.com/AY2324S1-CS2103T-F12-1/tp/pull/133) diff --git a/src/main/java/seedu/address/logic/commands/GatherCommand.java b/src/main/java/seedu/address/logic/commands/GatherCommand.java index 4907f5244c4..8eec139ee36 100644 --- a/src/main/java/seedu/address/logic/commands/GatherCommand.java +++ b/src/main/java/seedu/address/logic/commands/GatherCommand.java @@ -31,7 +31,7 @@ public class GatherCommand extends Command { /** * Constructs a new GatherCommand object. - * @param prompt The user's prompt + * @param prompt The user's prompt. */ public GatherCommand(GatherEmailPrompt prompt) { this.prompt = prompt; @@ -40,7 +40,7 @@ public GatherCommand(GatherEmailPrompt prompt) { /** * Overrides Command execute method. * @param model {@code Model} which the command should operate on. - * @return The CommandResult depending on the user input + * @return The CommandResult depending on the user input. */ @Override public CommandResult execute(Model model) { diff --git a/src/main/java/seedu/address/logic/parser/GatherCommandParser.java b/src/main/java/seedu/address/logic/parser/GatherCommandParser.java index 13999eb15bb..aa15e6fb1fe 100644 --- a/src/main/java/seedu/address/logic/parser/GatherCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/GatherCommandParser.java @@ -41,7 +41,6 @@ public GatherCommand parse(String args) throws ParseException { } if (argMultimap.getValue(PREFIX_TAG).isPresent()) { - // Parse Tag String tagArgs = removePrefix(trimmedArgs, PREFIX_TAG); validateTag(tagArgs); assert isValidTagName(tagArgs) : "Prompt has to meets valid Tag requirements"; diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index a5eee457ae1..9ffaff72ebf 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -192,7 +192,7 @@ public static Appointment parseAppointment(String appointmentName, String appoin } /** - * Parses a {@code String date} into a {@code LocalDateTime}. + * Parses a {@code String appointmentDate} into a {@code LocalDateTime}. * * @throws ParseException if the given {@code date} is invalid. */ diff --git a/src/main/java/seedu/address/model/financialplan/FinancialPlan.java b/src/main/java/seedu/address/model/financialplan/FinancialPlan.java index ae6d4d6541d..878434932ea 100644 --- a/src/main/java/seedu/address/model/financialplan/FinancialPlan.java +++ b/src/main/java/seedu/address/model/financialplan/FinancialPlan.java @@ -61,7 +61,7 @@ public int hashCode() { } /** - * Format state as text for viewing. + * Formats state as text for viewing. */ public String toString() { return '[' + financialPlanName + ']'; diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index c018dd1a999..f7327263b93 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -106,7 +106,7 @@ public boolean isSamePerson(Person otherPerson) { } /** - * Checks if the given {@code prompt} is a substring of {@code financialPlan} name in {@code financialPlans} + * Checks if the given {@code prompt} is a substring of {@code financialPlan} names in {@code financialPlans} * and returns the email if true. */ public String gatherEmailsContainsFinancialPlan(String prompt) { @@ -123,7 +123,7 @@ public String gatherEmailsContainsFinancialPlan(String prompt) { } /** - * Checks if the given {@code prompt} is a substring of {@code tag} name in {@code Tags} + * Checks if the given {@code prompt} is a substring of {@code tag} names in {@code Tags} * and returns the email if true. */ public String gatherEmailsContainsTag(String prompt) { @@ -154,6 +154,9 @@ public Person clearAppointment() { tags, NullAppointment.getNullAppointment()); } + /** + * Checks if {@code Person} appoint is a NullAppointment object. + */ public boolean hasNullAppointment() { return appointment.equals(NullAppointment.getNullAppointment()); } diff --git a/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByFinancialPlan.java b/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByFinancialPlan.java index 5498f598bdd..822235986e1 100644 --- a/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByFinancialPlan.java +++ b/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByFinancialPlan.java @@ -18,7 +18,7 @@ public GatherEmailByFinancialPlan(String promptFp) { } /** - * Gathers the email of {@code person} if {@code person}'s financial plan names matches a specific prompt. + * Gathers the email of {@code person} if prompt is a substring of any {@code person}'s financial plan names. */ @Override public String gatherEmails(Person person) { diff --git a/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByTag.java b/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByTag.java index 2bb3bed08ef..be6f62f4b75 100644 --- a/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByTag.java +++ b/src/main/java/seedu/address/model/person/gatheremail/GatherEmailByTag.java @@ -18,13 +18,13 @@ public GatherEmailByTag(String promptTag) { } /** - * Gathers the email of {@code person} if {@code person}'s tag names matches a specific prompt. + * Gathers the email of {@code person} if prompt is a substring of any {@code person}'s tag names */ - @Override public String gatherEmails(Person person) { return person.gatherEmailsContainsTag(promptTag); } + @Override public boolean equals(Object other) { if (other == this) { diff --git a/src/main/java/seedu/address/model/person/gatheremail/GatherEmailPrompt.java b/src/main/java/seedu/address/model/person/gatheremail/GatherEmailPrompt.java index 302e817bc02..042ed8c2a59 100644 --- a/src/main/java/seedu/address/model/person/gatheremail/GatherEmailPrompt.java +++ b/src/main/java/seedu/address/model/person/gatheremail/GatherEmailPrompt.java @@ -8,7 +8,7 @@ */ public interface GatherEmailPrompt { /** - * Gathers the email of {@code person} if {@code person}'s financial plan or tag names matches a specific prompt. + * Gathers the email of {@code person} if prompt is a substring of any {@code person}'s financial plan or tag names */ public String gatherEmails(Person person); } diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java index b43190cae7b..4272062ab05 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/seedu/address/model/tag/Tag.java @@ -60,7 +60,7 @@ public int hashCode() { } /** - * Format state as text for viewing. + * Formats state as text for viewing. */ public String toString() { return '[' + tagName + ']';